/* * Copyright (c) [2016] [ <ether.camp> ] * This file is part of the ethereumJ library. * * The ethereumJ library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The ethereumJ library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>. */ package org.ethereum.crypto; import org.ethereum.util.Utils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.crypto.AsymmetricCipherKeyPair; import org.spongycastle.crypto.BufferedBlockCipher; import org.spongycastle.crypto.KeyEncoder; 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.engines.IESEngine; import org.spongycastle.crypto.generators.ECKeyPairGenerator; import org.spongycastle.crypto.generators.EphemeralKeyPairGenerator; 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.crypto.parsers.ECIESPublicKeyParser; import org.spongycastle.math.ec.ECPoint; import org.spongycastle.util.encoders.Hex; import java.math.BigInteger; import java.security.SecureRandom; import static org.ethereum.crypto.HashUtil.sha3; import static org.junit.Assert.assertEquals; public class CryptoTest { private static final Logger log = LoggerFactory.getLogger("test"); @Test public void test1() { byte[] result = HashUtil.sha3("horse".getBytes()); assertEquals("c87f65ff3f271bf5dc8643484f66b200109caffe4bf98c4cb393dc35740b28c0", Hex.toHexString(result)); result = HashUtil.sha3("cow".getBytes()); assertEquals("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", Hex.toHexString(result)); } @Test public void test3() { BigInteger privKey = new BigInteger("cd244b3015703ddf545595da06ada5516628c5feadbf49dc66049c4b370cc5d8", 16); byte[] addr = ECKey.fromPrivate(privKey).getAddress(); assertEquals("89b44e4d3c81ede05d0f5de8d1a68f754d73d997", Hex.toHexString(addr)); } @Test public void test4() { byte[] cowBytes = HashUtil.sha3("cow".getBytes()); byte[] addr = ECKey.fromPrivate(cowBytes).getAddress(); assertEquals("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826", Hex.toHexString(addr).toUpperCase()); } @Test public void test5() { byte[] horseBytes = HashUtil.sha3("horse".getBytes()); byte[] addr = ECKey.fromPrivate(horseBytes).getAddress(); assertEquals("13978AEE95F38490E9769C39B2773ED763D9CD5F", Hex.toHexString(addr).toUpperCase()); } @Test /* performance test */ public void test6() { long firstTime = System.currentTimeMillis(); System.out.println(firstTime); for (int i = 0; i < 1000; ++i) { byte[] horseBytes = HashUtil.sha3("horse".getBytes()); byte[] addr = ECKey.fromPrivate(horseBytes).getAddress(); assertEquals("13978AEE95F38490E9769C39B2773ED763D9CD5F", Hex.toHexString(addr).toUpperCase()); } long secondTime = System.currentTimeMillis(); System.out.println(secondTime); System.out.println(secondTime - firstTime + " millisec"); // 1) result: ~52 address calculation every second } @Test /* real tx hash calc */ public void test7() { String txRaw = "F89D80809400000000000000000000000000000000000000008609184E72A000822710B3606956330C0D630000003359366000530A0D630000003359602060005301356000533557604060005301600054630000000C5884336069571CA07F6EB94576346488C6253197BDE6A7E59DDC36F2773672C849402AA9C402C3C4A06D254E662BF7450DD8D835160CBB053463FED0B53F2CDD7F3EA8731919C8E8CC"; byte[] txHashB = HashUtil.sha3(Hex.decode(txRaw)); String txHash = Hex.toHexString(txHashB); assertEquals("4b7d9670a92bf120d5b43400543b69304a14d767cf836a7f6abff4edde092895", txHash); } @Test /* real block hash calc */ public void test8() { String blockRaw = "F885F8818080A01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347940000000000000000000000000000000000000000A0BCDDD284BF396739C224DBA0411566C891C32115FEB998A3E2B4E61F3F35582AA01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D4934783800000808080C0C0"; byte[] blockHashB = HashUtil.sha3(Hex.decode(blockRaw)); String blockHash = Hex.toHexString(blockHashB); System.out.println(blockHash); } @Test public void test9() { // TODO: https://tools.ietf.org/html/rfc6979#section-2.2 // TODO: https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java System.out.println(new BigInteger(Hex.decode("3913517ebd3c0c65000000"))); System.out.println(Utils.getValueShortString(new BigInteger("69000000000000000000000000"))); } @Test public void test10() { BigInteger privKey = new BigInteger("74ef8a796480dda87b4bc550b94c408ad386af0f65926a392136286784d63858", 16); byte[] addr = ECKey.fromPrivate(privKey).getAddress(); assertEquals("ba73facb4f8291f09f27f90fe1213537b910065e", Hex.toHexString(addr)); } @Test // basic encryption/decryption public void test11() throws Throwable { byte[] keyBytes = sha3("...".getBytes()); log.info("key: {}", Hex.toHexString(keyBytes)); byte[] ivBytes = new byte[16]; byte[] payload = Hex.decode("22400891000000000000000000000000"); KeyParameter key = new KeyParameter(keyBytes); ParametersWithIV params = new ParametersWithIV(key, new byte[16]); AESFastEngine engine = new AESFastEngine(); SICBlockCipher ctrEngine = new SICBlockCipher(engine); ctrEngine.init(true, params); byte[] cipher = new byte[16]; ctrEngine.processBlock(payload, 0, cipher, 0); log.info("cipher: {}", Hex.toHexString(cipher)); byte[] output = new byte[cipher.length]; ctrEngine.init(false, params); ctrEngine.processBlock(cipher, 0, output, 0); assertEquals(Hex.toHexString(output), Hex.toHexString(payload)); log.info("original: {}", Hex.toHexString(payload)); } @Test // big packet encryption public void test12() throws Throwable { AESFastEngine engine = new AESFastEngine(); SICBlockCipher ctrEngine = new SICBlockCipher(engine); byte[] keyBytes = Hex.decode("a4627abc2a3c25315bff732cb22bc128f203912dd2a840f31e66efb27a47d2b1"); byte[] ivBytes = new byte[16]; byte[] payload = Hex.decode("0109efc76519b683d543db9d0991bcde99cc9a3d14b1d0ecb8e9f1f66f31558593d746eaa112891b04ef7126e1dce17c9ac92ebf39e010f0028b8ec699f56f5d0c0d00"); byte[] cipherText = Hex.decode("f9fab4e9dd9fc3e5d0d0d16da254a2ac24df81c076e3214e2c57da80a46e6ae4752f4b547889fa692b0997d74f36bb7c047100ba71045cb72cfafcc7f9a251762cdf8f"); KeyParameter key = new KeyParameter(keyBytes); ParametersWithIV params = new ParametersWithIV(key, ivBytes); ctrEngine.init(true, params); byte[] in = payload; byte[] out = new byte[in.length]; int i = 0; while(i < in.length){ ctrEngine.processBlock(in, i, out, i); i += engine.getBlockSize(); if (in.length - i < engine.getBlockSize()) break; } // process left bytes if (in.length - i > 0){ byte[] tmpBlock = new byte[16]; System.arraycopy(in, i, tmpBlock, 0, in.length - i); ctrEngine.processBlock(tmpBlock, 0, tmpBlock, 0); System.arraycopy(tmpBlock, 0, out, i, in.length - i); } log.info("cipher: {}", Hex.toHexString(out)); assertEquals(Hex.toHexString(cipherText), Hex.toHexString(out)); } @Test // cpp keys demystified public void test13() throws Throwable { // us.secret() a4627abc2a3c25315bff732cb22bc128f203912dd2a840f31e66efb27a47d2b1 // us.public() caa3d5086b31529bb00207eabf244a0a6c54d807d2ac0ec1f3b1bdde0dbf8130c115b1eaf62ce0f8062bcf70c0fefbc97cec79e7faffcc844a149a17fcd7bada // us.address() 47d8cb63a7965d98b547b9f0333a654b60ffa190 ECKey key = ECKey.fromPrivate(Hex.decode("a4627abc2a3c25315bff732cb22bc128f203912dd2a840f31e66efb27a47d2b1")); String address = Hex.toHexString(key.getAddress()); String pubkey = Hex.toHexString(key.getPubKeyPoint().getEncoded(/* uncompressed form */ false)); log.info("address: " + address); log.info("pubkey: " + pubkey); assertEquals("47d8cb63a7965d98b547b9f0333a654b60ffa190", address); assertEquals("04caa3d5086b31529bb00207eabf244a0a6c54d807d2ac0ec1f3b1bdde0dbf8130c115b1eaf62ce0f8062bcf70c0fefbc97cec79e7faffcc844a149a17fcd7bada", pubkey); } @Test // ECIES_AES128_SHA256 + No Ephemeral Key + IV(all zeroes) public void test14() throws Throwable{ AESFastEngine aesFastEngine = new AESFastEngine(); IESEngine iesEngine = new IESEngine( new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()), new HMac(new SHA256Digest()), new BufferedBlockCipher(new SICBlockCipher(aesFastEngine))); byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; IESParameters p = new IESWithCipherParameters(d, e, 64, 128); ParametersWithIV parametersWithIV = new ParametersWithIV(p, new byte[16]); ECKeyPairGenerator eGen = new ECKeyPairGenerator(); KeyGenerationParameters gParam = new ECKeyGenerationParameters(ECKey.CURVE, new SecureRandom()); eGen.init(gParam); AsymmetricCipherKeyPair p1 = eGen.generateKeyPair(); AsymmetricCipherKeyPair p2 = eGen.generateKeyPair(); ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(ECKey.CURVE, new SecureRandom()); ECKeyPairGenerator generator = new ECKeyPairGenerator(); generator.init(keygenParams); ECKeyPairGenerator gen = new ECKeyPairGenerator(); gen.init(new ECKeyGenerationParameters(ECKey.CURVE, new SecureRandom())); iesEngine.init(true, p1.getPrivate(), p2.getPublic(), parametersWithIV); byte[] message = Hex.decode("010101"); log.info("payload: {}", Hex.toHexString(message)); byte[] cipher = iesEngine.processBlock(message, 0, message.length); log.info("cipher: {}", Hex.toHexString(cipher)); IESEngine decryptorIES_Engine = new IESEngine( new ECDHBasicAgreement(), new KDF2BytesGenerator (new SHA256Digest()), new HMac(new SHA256Digest()), new BufferedBlockCipher(new SICBlockCipher(aesFastEngine))); decryptorIES_Engine.init(false, p2.getPrivate(), p1.getPublic(), parametersWithIV); byte[] orig = decryptorIES_Engine.processBlock(cipher, 0, cipher.length); log.info("orig: " + Hex.toHexString(orig)); } @Test // ECIES_AES128_SHA256 + Ephemeral Key + IV(all zeroes) public void test15() throws Throwable{ byte[] privKey = Hex.decode("a4627abc2a3c25315bff732cb22bc128f203912dd2a840f31e66efb27a47d2b1"); ECKey ecKey = ECKey.fromPrivate(privKey); ECPrivateKeyParameters ecPrivKey = new ECPrivateKeyParameters(ecKey.getPrivKey(), ECKey.CURVE); ECPublicKeyParameters ecPubKey = new ECPublicKeyParameters(ecKey.getPubKeyPoint(), ECKey.CURVE); AsymmetricCipherKeyPair myKey = new AsymmetricCipherKeyPair(ecPubKey, ecPrivKey); AESFastEngine aesFastEngine = new AESFastEngine(); IESEngine iesEngine = new IESEngine( new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()), new HMac(new SHA256Digest()), new BufferedBlockCipher(new SICBlockCipher(aesFastEngine))); byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; IESParameters p = new IESWithCipherParameters(d, e, 64, 128); ParametersWithIV parametersWithIV = new ParametersWithIV(p, new byte[16]); ECKeyPairGenerator eGen = new ECKeyPairGenerator(); KeyGenerationParameters gParam = new ECKeyGenerationParameters(ECKey.CURVE, new SecureRandom()); eGen.init(gParam); ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(ECKey.CURVE, new SecureRandom()); ECKeyPairGenerator generator = new ECKeyPairGenerator(); generator.init(keygenParams); EphemeralKeyPairGenerator kGen = new EphemeralKeyPairGenerator(generator, new KeyEncoder() { public byte[] getEncoded(AsymmetricKeyParameter keyParameter) { return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded(); } }); ECKeyPairGenerator gen = new ECKeyPairGenerator(); gen.init(new ECKeyGenerationParameters(ECKey.CURVE, new SecureRandom())); iesEngine.init(myKey.getPublic(), parametersWithIV, kGen); byte[] message = Hex.decode("010101"); log.info("payload: {}", Hex.toHexString(message)); byte[] cipher = iesEngine.processBlock(message, 0, message.length); log.info("cipher: {}", Hex.toHexString(cipher)); IESEngine decryptorIES_Engine = new IESEngine( new ECDHBasicAgreement(), new KDF2BytesGenerator (new SHA256Digest()), new HMac(new SHA256Digest()), new BufferedBlockCipher(new SICBlockCipher(aesFastEngine))); decryptorIES_Engine.init(myKey.getPrivate(), parametersWithIV, new ECIESPublicKeyParser(ECKey.CURVE)); byte[] orig = decryptorIES_Engine.processBlock(cipher, 0, cipher.length); log.info("orig: " + Hex.toHexString(orig)); } }