From 5e867e4c90977d52657666938f67f22f4c727ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Moreno?= Date: Fri, 21 Sep 2018 12:50:19 +0200 Subject: [PATCH 1/5] mixnet: Use pycryptodome instead of pycrypto pycrypto is unmaintained and is unsecure: https://github.com/dlitz/pycrypto/issues/253 It's better to use the modern version pycryptodome that's more up to date --- decide/booth/static/crypto/elgamal.js | 2 +- decide/mixnet/mixcrypt.py | 8 ++++---- decide/mixnet/models.py | 2 +- decide/mixnet/tests.py | 2 +- decide/test-scripts/js/crypto/elgamal.js | 2 +- decide/test-scripts/test-decrypt.py | 2 +- decide/test-scripts/test-encrypt.py | 2 +- decide/voting/management/commands/testvoting.py | 2 +- decide/voting/tests.py | 2 +- requirements.txt | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/decide/booth/static/crypto/elgamal.js b/decide/booth/static/crypto/elgamal.js index 53969df033..b04d573bb7 100644 --- a/decide/booth/static/crypto/elgamal.js +++ b/decide/booth/static/crypto/elgamal.js @@ -1,5 +1,5 @@ ElGamal = {}; -ElGamal.BITS = 8; +ElGamal.BITS = 256; ElGamal.getRandomInteger = function(max) { var bit_length = max.bitLength(); diff --git a/decide/mixnet/mixcrypt.py b/decide/mixnet/mixcrypt.py index 2ca1ece391..28b4119701 100644 --- a/decide/mixnet/mixcrypt.py +++ b/decide/mixnet/mixcrypt.py @@ -1,5 +1,5 @@ ''' ->>> B = 64 +>>> B = 256 >>> k1 = MixCrypt(bits=B) >>> k2 = MixCrypt(k=k1.k, bits=B) >>> k3 = gen_multiple_key(k1, k2) @@ -12,7 +12,7 @@ >>> sorted(clears) == sorted(d) True ->>> B = 8 +>>> B = 256 >>> k1 = MixCrypt(bits=B) >>> k1.setk(167,156,89,130) #doctest: +ELLIPSIS @@ -75,7 +75,7 @@ def multiple_decrypt_shuffle(ciphers, *crypts): def multiple_decrypt_shuffle2(ciphers, *crypts, pubkey=None): ''' - >>> B = 64 + >>> B = 256 >>> k1 = MixCrypt(bits=B) >>> k2 = MixCrypt(k=k1.k, bits=B) >>> k3 = gen_multiple_key(k1, k2) @@ -164,7 +164,7 @@ def shuffle_decrypt(self, msgs, last=True): def reencrypt(self, cipher, pubkey=None): ''' - >>> B = 64 + >>> B = 256 >>> k = MixCrypt(bits=B) >>> clears = [random.StrongRandom().randint(1, B) for i in range(5)] >>> cipher = [k.encrypt(i) for i in clears] diff --git a/decide/mixnet/models.py b/decide/mixnet/models.py index c8768f83be..1314f01df3 100644 --- a/decide/mixnet/models.py +++ b/decide/mixnet/models.py @@ -9,7 +9,7 @@ # number of bits for the key, all auths should use the same number of bits # TODO: move this to the settings -B = 8 +B = 256 class Mixnet(models.Model): diff --git a/decide/mixnet/tests.py b/decide/mixnet/tests.py index 87f54f6fc3..bc7c1709d3 100644 --- a/decide/mixnet/tests.py +++ b/decide/mixnet/tests.py @@ -17,7 +17,7 @@ def setUp(self): def tearDown(self): self.client = None - def encrypt_msgs(self, msgs, pk, bits=8): + def encrypt_msgs(self, msgs, pk, bits=256): p, g, y = pk k = MixCrypt(bits=bits) k.k = ElGamal.construct((p, g, y)) diff --git a/decide/test-scripts/js/crypto/elgamal.js b/decide/test-scripts/js/crypto/elgamal.js index 53969df033..b04d573bb7 100644 --- a/decide/test-scripts/js/crypto/elgamal.js +++ b/decide/test-scripts/js/crypto/elgamal.js @@ -1,5 +1,5 @@ ElGamal = {}; -ElGamal.BITS = 8; +ElGamal.BITS = 256; ElGamal.getRandomInteger = function(max) { var bit_length = max.bitLength(); diff --git a/decide/test-scripts/test-decrypt.py b/decide/test-scripts/test-decrypt.py index 7233d4a653..13018bfca8 100755 --- a/decide/test-scripts/test-decrypt.py +++ b/decide/test-scripts/test-decrypt.py @@ -11,7 +11,7 @@ p, g, y, x = map(int, SK.split(',')) a, b = map(int, MSG.split(',')) -k = MixCrypt(bits=8) +k = MixCrypt(bits=256) k.k = ElGamal.construct((p, g, y, x)) print(k.decrypt((a, b))) diff --git a/decide/test-scripts/test-encrypt.py b/decide/test-scripts/test-encrypt.py index de7147eb41..594c59baa1 100755 --- a/decide/test-scripts/test-encrypt.py +++ b/decide/test-scripts/test-encrypt.py @@ -9,7 +9,7 @@ MSG = sys.argv[2] p, g, y = map(int, PK.split(',')) -k = MixCrypt(bits=8) +k = MixCrypt(bits=256) k.k = ElGamal.construct((p, g, y)) print(','.join(map(str, k.encrypt(int(MSG))))) diff --git a/decide/voting/management/commands/testvoting.py b/decide/voting/management/commands/testvoting.py index 8fa855e195..93ab41dbda 100644 --- a/decide/voting/management/commands/testvoting.py +++ b/decide/voting/management/commands/testvoting.py @@ -18,7 +18,7 @@ class Command(BaseCommand): help = 'Test the full voting process with one auth (self)' - def encrypt_msg(self, msg, v, bits=8): + def encrypt_msg(self, msg, v, bits=256): pk = v.pub_key p, g, y = (pk.p, pk.g, pk.y) k = MixCrypt(bits=bits) diff --git a/decide/voting/tests.py b/decide/voting/tests.py index 3c9c6af632..541aba6f88 100644 --- a/decide/voting/tests.py +++ b/decide/voting/tests.py @@ -24,7 +24,7 @@ def setUp(self): def tearDown(self): super().tearDown() - def encrypt_msg(self, msg, v, bits=8): + def encrypt_msg(self, msg, v, bits=256): pk = v.pub_key p, g, y = (pk.p, pk.g, pk.y) k = MixCrypt(bits=bits) diff --git a/requirements.txt b/requirements.txt index e1f650158c..3f4f228d6a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ Django==2.0 -pycrypto==2.6.1 +pycryptodome==3.6.6 djangorestframework==3.7.7 django-cors-headers==2.1.0 requests==2.18.4 From 54e9c87c34c94171738f00637004b341e105c99b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Moreno?= Date: Fri, 21 Sep 2018 17:18:05 +0200 Subject: [PATCH 2/5] mixnet: Store key as textfield to avoid db problems IntegerField isn't valid for big keys so we need to store as textfield in the database and convert to int in the python code. --- .../migrations/0002_auto_20180921_1056.py | 33 ++++++++++++++++++ .../migrations/0003_auto_20180921_1119.py | 34 +++++++++++++++++++ decide/base/models.py | 27 ++++++++++++--- decide/base/serializers.py | 4 +++ .../migrations/0003_auto_20180921_1522.py | 24 +++++++++++++ decide/store/models.py | 5 +-- decide/store/serializers.py | 3 ++ 7 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 decide/base/migrations/0002_auto_20180921_1056.py create mode 100644 decide/base/migrations/0003_auto_20180921_1119.py create mode 100644 decide/store/migrations/0003_auto_20180921_1522.py diff --git a/decide/base/migrations/0002_auto_20180921_1056.py b/decide/base/migrations/0002_auto_20180921_1056.py new file mode 100644 index 0000000000..e7582f11b2 --- /dev/null +++ b/decide/base/migrations/0002_auto_20180921_1056.py @@ -0,0 +1,33 @@ +# Generated by Django 2.0 on 2018-09-21 10:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='key', + name='g', + field=models.BigIntegerField(), + ), + migrations.AlterField( + model_name='key', + name='p', + field=models.BigIntegerField(), + ), + migrations.AlterField( + model_name='key', + name='x', + field=models.BigIntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name='key', + name='y', + field=models.BigIntegerField(), + ), + ] diff --git a/decide/base/migrations/0003_auto_20180921_1119.py b/decide/base/migrations/0003_auto_20180921_1119.py new file mode 100644 index 0000000000..eef3af603a --- /dev/null +++ b/decide/base/migrations/0003_auto_20180921_1119.py @@ -0,0 +1,34 @@ +# Generated by Django 2.0 on 2018-09-21 11:19 + +import base.models +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0002_auto_20180921_1056'), + ] + + operations = [ + migrations.AlterField( + model_name='key', + name='g', + field=base.models.BigBigField(), + ), + migrations.AlterField( + model_name='key', + name='p', + field=base.models.BigBigField(), + ), + migrations.AlterField( + model_name='key', + name='x', + field=base.models.BigBigField(blank=True, null=True), + ), + migrations.AlterField( + model_name='key', + name='y', + field=base.models.BigBigField(), + ), + ] diff --git a/decide/base/models.py b/decide/base/models.py index 9d21e7a676..c4da20710b 100644 --- a/decide/base/models.py +++ b/decide/base/models.py @@ -1,6 +1,25 @@ from django.db import models +class BigBigField(models.TextField): + def to_python(self, value): + if isinstance(value, str): + return int(value) + if value is None: + return 0 + return int(str(value)) + + def get_prep_value(self, value): + if value is None: + return 0 + return str(value) + + def from_db_value(self, value, expression, connection): + if value is None: + return 0 + return int(value) + + class Auth(models.Model): name = models.CharField(max_length=200) url = models.URLField() @@ -11,10 +30,10 @@ def __str__(self): class Key(models.Model): - p = models.IntegerField() - g = models.IntegerField() - y = models.IntegerField() - x = models.IntegerField(blank=True, null=True) + p = BigBigField() + g = BigBigField() + y = BigBigField() + x = BigBigField(blank=True, null=True) def __str__(self): if self.x: diff --git a/decide/base/serializers.py b/decide/base/serializers.py index fed6cc1792..36d53cff6d 100644 --- a/decide/base/serializers.py +++ b/decide/base/serializers.py @@ -10,6 +10,10 @@ class Meta: class KeySerializer(serializers.HyperlinkedModelSerializer): + p = serializers.IntegerField() + g = serializers.IntegerField() + y = serializers.IntegerField() + class Meta: model = Key fields = ('p', 'g', 'y') diff --git a/decide/store/migrations/0003_auto_20180921_1522.py b/decide/store/migrations/0003_auto_20180921_1522.py new file mode 100644 index 0000000000..a57789ed68 --- /dev/null +++ b/decide/store/migrations/0003_auto_20180921_1522.py @@ -0,0 +1,24 @@ +# Generated by Django 2.0 on 2018-09-21 15:22 + +import base.models +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0002_vote_voted'), + ] + + operations = [ + migrations.AlterField( + model_name='vote', + name='a', + field=base.models.BigBigField(), + ), + migrations.AlterField( + model_name='vote', + name='b', + field=base.models.BigBigField(), + ), + ] diff --git a/decide/store/models.py b/decide/store/models.py index 2ae43e6008..14d3272fcb 100644 --- a/decide/store/models.py +++ b/decide/store/models.py @@ -1,12 +1,13 @@ from django.db import models +from base.models import BigBigField class Vote(models.Model): voting_id = models.PositiveIntegerField() voter_id = models.PositiveIntegerField() - a = models.PositiveIntegerField() - b = models.PositiveIntegerField() + a = BigBigField() + b = BigBigField() voted = models.DateTimeField(auto_now=True) diff --git a/decide/store/serializers.py b/decide/store/serializers.py index 3a321714db..759947c12e 100644 --- a/decide/store/serializers.py +++ b/decide/store/serializers.py @@ -4,6 +4,9 @@ class VoteSerializer(serializers.HyperlinkedModelSerializer): + a = serializers.IntegerField() + b = serializers.IntegerField() + class Meta: model = Vote fields = ('voting_id', 'voter_id', 'a', 'b') From 2a49b0b3c3ab9eca401095a91fb656c0df6302be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Moreno?= Date: Fri, 21 Sep 2018 18:22:40 +0200 Subject: [PATCH 3/5] mixnet: key bits configuable in settings --- decide/booth/templates/booth/booth.html | 1 + decide/booth/views.py | 1 + decide/decide/settings.py | 3 +++ decide/local_settings.example.py | 3 +++ decide/mixnet/models.py | 4 ++-- decide/mixnet/tests.py | 3 ++- decide/voting/management/commands/testvoting.py | 2 +- decide/voting/tests.py | 2 +- 8 files changed, 14 insertions(+), 5 deletions(-) diff --git a/decide/booth/templates/booth/booth.html b/decide/booth/templates/booth/booth.html index bcc3d94826..2933af171b 100644 --- a/decide/booth/templates/booth/booth.html +++ b/decide/booth/templates/booth/booth.html @@ -41,6 +41,7 @@

{{ voting.question.desc }}