From c960d2aa8ca8e62d21468975f2fdf8baf8dd29a9 Mon Sep 17 00:00:00 2001 From: Devrandom Date: Thu, 12 Mar 2015 15:39:47 -0700 Subject: [PATCH] ECIES encryption --- .../ethereum/crypto/EthereumIESEngine.java | 7 +- .../java/test/ethereum/crypto/ECIESTest.java | 126 +++++++++--------- 2 files changed, 70 insertions(+), 63 deletions(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/crypto/EthereumIESEngine.java b/ethereumj-core/src/main/java/org/ethereum/crypto/EthereumIESEngine.java index 1789f746..7be913a2 100644 --- a/ethereumj-core/src/main/java/org/ethereum/crypto/EthereumIESEngine.java +++ b/ethereumj-core/src/main/java/org/ethereum/crypto/EthereumIESEngine.java @@ -220,7 +220,12 @@ public class EthereumIESEngine // Apply the MAC. byte[] T = new byte[mac.getMacSize()]; - mac.init(new KeyParameter(K2)); + byte[] K2a = new byte[hash.getDigestSize()]; + hash.reset(); + hash.update(K2, 0, K2.length); + hash.doFinal(K2a, 0); + mac.init(new KeyParameter(K2a)); + mac.update(IV, 0, IV.length); mac.update(C, 0, C.length); if (P2 != null) { diff --git a/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESTest.java b/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESTest.java index fd03e67a..2c7c324e 100644 --- a/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESTest.java +++ b/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESTest.java @@ -9,14 +9,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.asn1.sec.SECNamedCurves; import org.spongycastle.asn1.x9.X9ECParameters; -import org.spongycastle.crypto.AsymmetricCipherKeyPair; -import org.spongycastle.crypto.BufferedBlockCipher; -import org.spongycastle.crypto.KeyGenerationParameters; +import org.spongycastle.crypto.*; import org.spongycastle.crypto.agreement.ECDHBasicAgreement; import org.spongycastle.crypto.digests.SHA256Digest; import org.spongycastle.crypto.engines.AESFastEngine; import org.spongycastle.crypto.generators.ECKeyPairGenerator; -import org.spongycastle.crypto.generators.KDF2BytesGenerator; import org.spongycastle.crypto.macs.HMac; import org.spongycastle.crypto.modes.SICBlockCipher; import org.spongycastle.crypto.params.*; @@ -24,22 +21,23 @@ import org.spongycastle.math.ec.ECPoint; import org.spongycastle.util.encoders.Hex; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.math.BigInteger; import java.security.SecureRandom; import java.security.Security; import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertTrue; public class ECIESTest { - public static final int MAC_KEY_SIZE = 128; + public static final int KEY_SIZE = 128; static Logger log = LoggerFactory.getLogger("test"); private static ECDomainParameters curve; private static final String CIPHERTEXT1 = "042a851331790adacf6e64fcb19d0872fcdf1285a899a12cdc897da941816b0ea6485402aaf6c2e0a5d98ae3af1b05c68b307d1e0eb7a426a46f1617ba5b94f90b606eee3b5e9d2b527a9ee52cfa377bcd118b9390ed27ffe7d48e8155004375cae209012c3e057bb13a478a64a201d79ad4ae83"; private static final X9ECParameters IES_CURVE_PARAM = SECNamedCurves.getByName("secp256r1"); private static final BigInteger PRIVATE_KEY1 = new BigInteger("51134539186617376248226283012294527978458758538121566045626095875284492680246"); - private static ECPoint pub(BigInteger d) throws Exception { + private static ECPoint pub(BigInteger d) { return curve.getG().multiply(d); } @@ -53,30 +51,78 @@ public class ECIESTest { @Test public void testKDF() { ConcatKDFBytesGenerator kdf = new ConcatKDFBytesGenerator(new SHA256Digest()); - kdf.init(new KDFParameters(new String("Hello").getBytes(), new byte[0])); + kdf.init(new KDFParameters("Hello".getBytes(), new byte[0])); byte[] bytes = new byte[2]; kdf.generateBytes(bytes, 0, bytes.length); assertArrayEquals(new byte[]{-66, -89}, bytes); } @Test - public void testDecryptTestVector() throws Throwable { + public void testDecryptTestVector() throws IOException, InvalidCipherTextException { ECPoint pub1 = pub(PRIVATE_KEY1); - byte[] cipher = Hex.decode(CIPHERTEXT1); + byte[] ciphertext = Hex.decode(CIPHERTEXT1); + byte[] plaintext = decrypt(PRIVATE_KEY1, ciphertext); + assertArrayEquals(new byte[]{1,1,1}, plaintext); + } + + @Test + public void testRoundTrip() throws InvalidCipherTextException, IOException { + ECPoint pub1 = pub(PRIVATE_KEY1); + byte[] plaintext = "Hello world".getBytes(); + byte[] ciphertext = encrypt(pub1, plaintext); + byte[] plaintext1 = decrypt(PRIVATE_KEY1, ciphertext); + assertArrayEquals(plaintext, plaintext1); + } + + public static byte[] decrypt(BigInteger prv, byte[] cipher) throws InvalidCipherTextException, IOException { ByteArrayInputStream is = new ByteArrayInputStream(cipher); byte[] ephemBytes = new byte[2*((curve.getCurve().getFieldSize()+7)/8) + 1]; is.read(ephemBytes); ECPoint ephem = curve.getCurve().decodePoint(ephemBytes); - byte[] IV = new byte[MAC_KEY_SIZE/8]; + byte[] IV = new byte[KEY_SIZE /8]; is.read(IV); byte[] cipherBody = new byte[is.available()]; is.read(cipherBody); - byte[] plaintext = decrypt(ephem, PRIVATE_KEY1, IV, cipherBody); - assertArrayEquals(new byte[]{1,1,1}, plaintext); + EthereumIESEngine iesEngine = makeIESEngine(false, ephem, prv, IV); + + byte[] message = iesEngine.processBlock(cipherBody, 0, cipherBody.length); + return message; } - public static byte[] decrypt(ECPoint ephem, BigInteger prv, byte[] IV, byte[] cipher) throws Throwable { + public static byte[] encrypt(ECPoint toPub, byte[] plaintext) throws InvalidCipherTextException, IOException { + + ECKeyPairGenerator eGen = new ECKeyPairGenerator(); + SecureRandom random = new SecureRandom(); + KeyGenerationParameters gParam = new ECKeyGenerationParameters(curve, random); + + eGen.init(gParam); + + byte[] IV = new byte[KEY_SIZE/8]; + new SecureRandom().nextBytes(IV); + + AsymmetricCipherKeyPair ephemPair = eGen.generateKeyPair(); + BigInteger prv = ((ECPrivateKeyParameters)ephemPair.getPrivate()).getD(); + ECPoint pub = ((ECPublicKeyParameters)ephemPair.getPublic()).getQ(); + EthereumIESEngine iesEngine = makeIESEngine(true, toPub, prv, IV); + + + ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(curve, random); + ECKeyPairGenerator generator = new ECKeyPairGenerator(); + generator.init(keygenParams); + + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters(ECKey.CURVE, random)); + + byte[] cipher = iesEngine.processBlock(plaintext, 0, plaintext.length); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bos.write(pub.getEncoded(false)); + bos.write(IV); + bos.write(cipher); + return bos.toByteArray(); + } + + private static EthereumIESEngine makeIESEngine(boolean isEncrypt, ECPoint pub, BigInteger prv, byte[] IV) { AESFastEngine aesFastEngine = new AESFastEngine(); EthereumIESEngine iesEngine = new EthereumIESEngine( @@ -90,54 +136,10 @@ public class ECIESTest { byte[] d = new byte[] {}; byte[] e = new byte[] {}; - IESParameters p = new IESWithCipherParameters(d, e, MAC_KEY_SIZE, MAC_KEY_SIZE); - ParametersWithIV parametersWithIV = - new ParametersWithIV(p, IV); + IESParameters p = new IESWithCipherParameters(d, e, KEY_SIZE, KEY_SIZE); + ParametersWithIV parametersWithIV = new ParametersWithIV(p, IV); - iesEngine.init(false, new ECPrivateKeyParameters(prv, curve), new ECPublicKeyParameters(ephem, curve), parametersWithIV); - - byte[] message = iesEngine.processBlock(cipher, 0, cipher.length); - return message; - } - - public static byte[] encrypt(byte[] plaintext) throws Throwable { - AESFastEngine aesFastEngine = new AESFastEngine(); - - EthereumIESEngine iesEngine = new EthereumIESEngine( - new ECDHBasicAgreement(), - new KDF2BytesGenerator(new SHA256Digest()), - new HMac(new SHA256Digest()), - new SHA256Digest(), - new BufferedBlockCipher(new SICBlockCipher(aesFastEngine))); - - - byte[] d = new byte[] {}; - byte[] e = new byte[] {}; - - IESParameters p = new IESWithCipherParameters(d, e, 256, MAC_KEY_SIZE); - ParametersWithIV parametersWithIV = new ParametersWithIV(p, new byte[256/8]); - - ECKeyPairGenerator eGen = new ECKeyPairGenerator(); - SecureRandom random = new SecureRandom(); - KeyGenerationParameters gParam = new ECKeyGenerationParameters(ECKey.CURVE, random); - - eGen.init(gParam); - - - AsymmetricCipherKeyPair p1 = eGen.generateKeyPair(); - AsymmetricCipherKeyPair p2 = eGen.generateKeyPair(); - - - ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(ECKey.CURVE, random); - ECKeyPairGenerator generator = new ECKeyPairGenerator(); - generator.init(keygenParams); - - ECKeyPairGenerator gen = new ECKeyPairGenerator(); - gen.init(new ECKeyGenerationParameters(ECKey.CURVE, random)); - - iesEngine.init(true, p1.getPrivate(), p2.getPublic(), parametersWithIV); - - byte[] cipher = iesEngine.processBlock(plaintext, 0, plaintext.length); - return cipher; + iesEngine.init(isEncrypt, new ECPrivateKeyParameters(prv, curve), new ECPublicKeyParameters(pub, curve), parametersWithIV); + return iesEngine; } }