From b0548ea0ae8bec669131f69b9918487625ea5ace Mon Sep 17 00:00:00 2001 From: Roman Mandeleil Date: Fri, 13 Mar 2015 00:42:20 +0200 Subject: [PATCH] Introduce Coder/Decoder for ECIES --- .../java/org/ethereum/crypto/ECIESCoder.java | 120 ++++++++++++++++++ .../test/ethereum/crypto/ECIESCoderTest.java | 33 +++++ .../java/test/ethereum/crypto/ECIESTest.java | 1 + 3 files changed, 154 insertions(+) create mode 100644 ethereumj-core/src/main/java/org/ethereum/crypto/ECIESCoder.java create mode 100644 ethereumj-core/src/test/java/test/ethereum/crypto/ECIESCoderTest.java diff --git a/ethereumj-core/src/main/java/org/ethereum/crypto/ECIESCoder.java b/ethereumj-core/src/main/java/org/ethereum/crypto/ECIESCoder.java new file mode 100644 index 00000000..0fa6e805 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/crypto/ECIESCoder.java @@ -0,0 +1,120 @@ +package org.ethereum.crypto; + +import org.ethereum.ConcatKDFBytesGenerator; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.KeyGenerationParameters; +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.*; +import org.spongycastle.math.ec.ECPoint; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.SecureRandom; + +import static org.ethereum.crypto.ECKey.CURVE; + +public class ECIESCoder { + + + public static final int MAC_KEY_SIZE = 128; + + + public static byte[] decrypt(BigInteger privKey, byte[] cipher) { + + byte[] plaintext = new byte[0]; + try { + 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]; + is.read(IV); + byte[] cipherBody = new byte[is.available()]; + is.read(cipherBody); + + plaintext = decrypt(ephem, privKey, IV, cipherBody); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + + return plaintext; + } + + public static byte[] decrypt(ECPoint ephem, BigInteger prv, byte[] IV, byte[] cipher) throws Throwable { + AESFastEngine aesFastEngine = new AESFastEngine(); + + EthereumIESEngine iesEngine = new EthereumIESEngine( + new ECDHBasicAgreement(), + new ConcatKDFBytesGenerator(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, MAC_KEY_SIZE, MAC_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) { + 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(CURVE, random); + + eGen.init(gParam); + + + AsymmetricCipherKeyPair p1 = eGen.generateKeyPair(); + AsymmetricCipherKeyPair p2 = eGen.generateKeyPair(); + + + ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(CURVE, random); + ECKeyPairGenerator generator = new ECKeyPairGenerator(); + generator.init(keygenParams); + + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters(CURVE, random)); + + iesEngine.init(true, p1.getPrivate(), p2.getPublic(), parametersWithIV); + + byte[] cipher = new byte[0]; + try { + cipher = iesEngine.processBlock(plaintext, 0, plaintext.length); + } catch (InvalidCipherTextException e1) {e1.printStackTrace();} + return cipher; + } + +} diff --git a/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESCoderTest.java b/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESCoderTest.java new file mode 100644 index 00000000..5fbbfd8b --- /dev/null +++ b/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESCoderTest.java @@ -0,0 +1,33 @@ +package test.ethereum.crypto; + +import org.ethereum.crypto.ECIESCoder; +import org.junit.Assert; +import org.junit.Test; +import org.spongycastle.util.encoders.Hex; + +import java.math.BigInteger; + +public class ECIESCoderTest { + + + @Test // decrypt cpp data + public void test1(){ + BigInteger privKey = new BigInteger("5e173f6ac3c669587538e7727cf19b782a4f2fda07c1eaa662c593e5e85e3051", 16); + byte[] cipher = Hex.decode("049934a7b2d7f9af8fd9db941d9da281ac9381b5740e1f64f7092f3588d4f87f5ce55191a6653e5e80c1c5dd538169aa123e70dc6ffc5af1827e546c0e958e42dad355bcc1fcb9cdf2cf47ff524d2ad98cbf275e661bf4cf00960e74b5956b799771334f426df007350b46049adb21a6e78ab1408d5e6ccde6fb5e69f0f4c92bb9c725c02f99fa72b9cdc8dd53cff089e0e73317f61cc5abf6152513cb7d833f09d2851603919bf0fbe44d79a09245c6e8338eb502083dc84b846f2fee1cc310d2cc8b1b9334728f97220bb799376233e113"); + byte[] payload = ECIESCoder.decrypt(privKey, cipher); + + + Assert.assertEquals("802b052f8b066640bba94a4fc39d63815c377fced6fcb84d27f791c9921ddf3e9bf0108e298f490812847109cbd778fae393e80323fd643209841a3b7f110397f37ec61d84cea03dcc5e8385db93248584e8af4b4d1c832d8c7453c0089687a700", + Hex.toHexString(payload)); + } + + + @Test + public void test2(){ + + byte[] output = ECIESCoder.encrypt("roman".getBytes()); + System.out.println(Hex.toHexString(output)); + + } + +} 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..7a2d9ab0 100644 --- a/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESTest.java +++ b/ethereumj-core/src/test/java/test/ethereum/crypto/ECIESTest.java @@ -140,4 +140,5 @@ public class ECIESTest { byte[] cipher = iesEngine.processBlock(plaintext, 0, plaintext.length); return cipher; } + }