From b8cc3feedba714829b11eb86e38e5121c5d84a31 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Sun, 22 Nov 2015 03:16:35 +0200 Subject: [PATCH] EC encryption code; compiles but not tested --- bulletin-board-server/build.gradle | 1 - meerkat-common/build.gradle | 2 +- .../main/java/meerkat/crypto/Encryption.java | 3 +- .../crypto/concrete/ECElGamalEncryption.java | 111 ++++++++++++++++++ .../main/proto/meerkat/concrete_crypto.proto | 22 ++++ .../src/main/proto/meerkat/crypto.proto | 4 + polling-station/build.gradle | 1 - restful-api-common/build.gradle | 1 - voting-booth/build.gradle | 1 - 9 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java create mode 100644 meerkat-common/src/main/proto/meerkat/concrete_crypto.proto diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index ae8e028..031ce36 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -90,7 +90,6 @@ idea { def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" - println "Adding $srcDir" // add protobuf generated sources to generated source dir. if ("test".equals(sourceSet.name)) { testSourceDirs += file(srcDir) diff --git a/meerkat-common/build.gradle b/meerkat-common/build.gradle index 236bd82..d445fff 100644 --- a/meerkat-common/build.gradle +++ b/meerkat-common/build.gradle @@ -46,6 +46,7 @@ dependencies { compile 'com.google.protobuf:protobuf-java:3.+' // Crypto + compile 'org.factcenter.qilin:qilin:1.+' compile 'org.bouncycastle:bcprov-jdk15on:1.53' compile 'org.bouncycastle:bcpkix-jdk15on:1.53' @@ -81,7 +82,6 @@ idea { def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" - println "Adding $srcDir" // add protobuf generated sources to generated source dir. if ("test".equals(sourceSet.name)) { testSourceDirs += file(srcDir) diff --git a/meerkat-common/src/main/java/meerkat/crypto/Encryption.java b/meerkat-common/src/main/java/meerkat/crypto/Encryption.java index 0ec6c11..385e1dd 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/Encryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Encryption.java @@ -1,5 +1,6 @@ package meerkat.crypto; +import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import static meerkat.protobuf.Crypto.*; @@ -15,6 +16,6 @@ public interface Encryption { */ RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd); // TODO: type of exception; throws - RerandomizableEncryptedMessage rerandomize(RerandomizableEncryptedMessage msg, EncryptionRandomness rnd); + RerandomizableEncryptedMessage rerandomize(RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException; } diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java new file mode 100644 index 0000000..276c1a7 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -0,0 +1,111 @@ +package meerkat.crypto.concrete; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.Encryption; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.util.PublicKeyFactory; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import qilin.primitives.PseudorandomGenerator; +import qilin.util.PRGRandom; +import qilin.util.Pair; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.spec.*; + +/** + * Created by talm on 17/11/15. + */ +public class ECElGamalEncryption implements Encryption { + final Logger logger = LoggerFactory.getLogger(getClass()); + + public final static String KEY_ALGORITHM = "ECDH"; + + /** + * The Qilin format El-Gamal public key + */ + ECElGamal.PK elGamalPK; + + ECCurve curve; + + ECGroup group; + + public void init(ConcreteCrypto.ElGamalPublicKey serializedPk) throws InvalidKeySpecException { + AsymmetricKeyParameter keyParam; + + try { + keyParam = PublicKeyFactory.createKey(serializedPk.getSubjectPublicKeyInfo().toByteArray()); + } catch (IOException e) { + // Shouldn't every happen + logger.error("Invalid Public Key Encoding", e); + throw new InvalidKeySpecException("Invalid Public Key Encoding", e); + } + + if (!(keyParam instanceof ECPublicKeyParameters)) { + logger.error("Public key is a {}, not a valid public EC Key!", keyParam.getClass()); + throw new InvalidKeySpecException("Not a valid EC public key!"); + } + + ECDomainParameters params = ((ECKeyParameters) keyParam).getParameters(); + ECParameterSpec ecParams = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH(), + params.getSeed()); + + curve = params.getCurve(); + group = new ECGroup(ecParams); + + elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ()); + } + + + @Override + public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) { + byte[] msg = plaintext.toByteArray(); + ECPoint encodedMsg = group.injectiveEncode(plaintext.toByteArray(), new PRGRandom(msg)); + + BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); + Pair cipherText = elGamalPK.encrypt(encodedMsg, rndInt); + ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder() + .setC1(ByteString.copyFrom(cipherText.a.getEncoded(true))) + .setC2(ByteString.copyFrom(cipherText.b.getEncoded(true))) + .build(); + + return Crypto.RerandomizableEncryptedMessage.newBuilder() + .setData(encodedCipherText.toByteString()) + .build(); + } + + @Override + public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException { + BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); + Pair randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); + ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); + + Pair originalCipher = new Pair<>( + curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), + curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); + Pair newCipher = elGamalPK.add(originalCipher, randomizer); + + return Crypto.RerandomizableEncryptedMessage.newBuilder() + .setData( + ConcreteCrypto.ElGamalCiphertext.newBuilder() + .setC1(ByteString.copyFrom(newCipher.a.getEncoded(true))) + .setC2(ByteString.copyFrom(newCipher.b.getEncoded(true))) + .build().toByteString() + ).build(); + } +} diff --git a/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto b/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto new file mode 100644 index 0000000..d8c40d3 --- /dev/null +++ b/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto @@ -0,0 +1,22 @@ +// Protobufs for specific crypto primitives + +syntax = "proto3"; + +package meerkat; + +import 'meerkat/crypto.proto'; + +option java_package = "meerkat.protobuf"; + + +message ElGamalPublicKey { + // DER-encoded SubjectPublicKeyInfo as in RFC 3279 + bytes subject_public_key_info = 1; +} + +// An El-Gamal ciphertext +// Each group element should be an ASN.1 encoded curve point with compression. +message ElGamalCiphertext { + bytes c1 = 1; // First group element + bytes c2 = 2; // Second group element +} \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/crypto.proto b/meerkat-common/src/main/proto/meerkat/crypto.proto index ecd9478..eeec159 100644 --- a/meerkat-common/src/main/proto/meerkat/crypto.proto +++ b/meerkat-common/src/main/proto/meerkat/crypto.proto @@ -9,6 +9,10 @@ enum SignatureType { DSA = 1; } +message BigInteger { + bytes data = 1; +} + // A digital signature message Signature { SignatureType type = 1; diff --git a/polling-station/build.gradle b/polling-station/build.gradle index a0c7e72..34fe58d 100644 --- a/polling-station/build.gradle +++ b/polling-station/build.gradle @@ -73,7 +73,6 @@ idea { def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" - println "Adding $srcDir" // add protobuf generated sources to generated source dir. if ("test".equals(sourceSet.name)) { testSourceDirs += file(srcDir) diff --git a/restful-api-common/build.gradle b/restful-api-common/build.gradle index 1dea7a3..3c0ad1e 100644 --- a/restful-api-common/build.gradle +++ b/restful-api-common/build.gradle @@ -73,7 +73,6 @@ idea { def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" - println "Adding $srcDir" // add protobuf generated sources to generated source dir. if ("test".equals(sourceSet.name)) { testSourceDirs += file(srcDir) diff --git a/voting-booth/build.gradle b/voting-booth/build.gradle index a52e1f6..70d7340 100644 --- a/voting-booth/build.gradle +++ b/voting-booth/build.gradle @@ -72,7 +72,6 @@ idea { def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java" - println "Adding $srcDir" // add protobuf generated sources to generated source dir. if ("test".equals(sourceSet.name)) { testSourceDirs += file(srcDir)