diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 08eb9bd3d..4abac7eed 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -118,26 +118,15 @@ h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_ciph h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv) { - const int c_aesBlockLen = 16; - size_t extraBytes = _plain.size() % c_aesBlockLen; - size_t trimmedSize = _plain.size() - extraBytes; - size_t paddedSize = _plain.size() + ((16 - extraBytes) % 16); - o_cipher.resize(paddedSize); - - bytes underflowBytes(16); - if (o_cipher.size() != _plain.size()) - _plain.cropped(trimmedSize, extraBytes).copyTo(&underflowBytes); - - const int c_aesKeyLen = 32; + o_cipher.resize(_plain.size()); + + const int c_aesKeyLen = 16; SecByteBlock key(_k.data(), c_aesKeyLen); try { CTR_Mode::Encryption e; e.SetKeyWithIV(key, key.size(), _iv.data()); - if (trimmedSize) - e.ProcessData(o_cipher.data(), _plain.data(), trimmedSize); - if (extraBytes) - e.ProcessData(o_cipher.data() + trimmedSize, underflowBytes.data(), underflowBytes.size()); + e.ProcessData(o_cipher.data(), _plain.data(), _plain.size()); return _iv; } catch(CryptoPP::Exception& e) @@ -150,11 +139,9 @@ h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_ciph bool dev::decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext) { - const int c_aesBlockLen = 16; - asserts(_cipher.size() % c_aesBlockLen == 0); o_plaintext.resize(_cipher.size()); - const int c_aesKeyLen = 32; + const size_t c_aesKeyLen = 16; SecByteBlock key(_k.data(), c_aesKeyLen); try { diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index ba53cb7a7..82d426a76 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -32,22 +32,17 @@ static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); -bytes Secp256k1::eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen) +bytes Secp256k1::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen) { // interop w/go ecies implementation - if (!_s1.size()) - { - _s1.resize(1); - asserts(_s1[0] == 0); - } - - // for sha3, hash.blocksize is 1088 bits, but this might really be digest size - auto reps = ((kdBitLen + 7) * 8) / (32 * 8); + // for sha3, blocksize is 136 bytes + // for sha256, blocksize is 64 bytes + auto reps = ((kdByteLen + 7) * 8) / (64 * 8); bytes ctr({0, 0, 0, 1}); bytes k; CryptoPP::SHA256 ctx; - while (reps--) + for (unsigned i = 0; i <= reps; i++) { ctx.Update(ctr.data(), ctr.size()); ctx.Update(_z.data(), Secret::size); @@ -70,7 +65,7 @@ bytes Secp256k1::eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen) ctr[0]++; } - k.resize(kdBitLen / 8); + k.resize(kdByteLen); return move(k); } @@ -83,7 +78,9 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher) auto key = eciesKDF(z, bytes(), 512); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 32); bytesRef mKey = bytesRef(&key).cropped(32, 32); - sha3(mKey, mKey); + CryptoPP::SHA256 ctx; + ctx.Update(mKey.data(), mKey.size()); + ctx.Final(mKey.data()); bytes cipherText; encryptSymNoAuth(*(Secret*)eKey.data(), bytesConstRef(&io_cipher), cipherText, h128()); @@ -97,10 +94,10 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher) bytesConstRef(&cipherText).copyTo(msgCipherRef); // tag message - CryptoPP::HMAC ctx(mKey.data(), mKey.size()); + CryptoPP::HMAC hmacctx(mKey.data(), mKey.size()); bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size()); - ctx.Update(cipherWithIV.data(), cipherWithIV.size()); - ctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size()); + hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); + hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size()); io_cipher.resize(msg.size()); io_cipher.swap(msg); @@ -121,27 +118,31 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text) h256 z; ecdh::agree(_k, *(Public*)(io_text.data()+1), z); - auto key = eciesKDF(z, bytes(), 512); + auto key = eciesKDF(z, bytes(), 64); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 32); - bytesRef mKey = bytesRef(&key).cropped(32, 32); - sha3(mKey, mKey); + bytesRef mKey = bytesRef(&key).cropped(16, 16); + CryptoPP::SHA256 ctx; + ctx.Update(mKey.data(), mKey.size()); + ctx.Final(mKey.data()); bytes plain; size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size; bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen); - bytesConstRef cipher = cipherWithIV.cropped(h128::size, cipherLen); - bytesConstRef msgMac(cipher.data() + cipher.size(), h256::size); + bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size); + bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen); + bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size); + h128 iv(cipherIV.toBytes()); // verify tag - CryptoPP::HMAC ctx(mKey.data(), mKey.size()); - ctx.Update(cipherWithIV.data(), cipherWithIV.size()); + CryptoPP::HMAC hmacctx(mKey.data(), mKey.size()); + hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); h256 mac; - ctx.Final(mac.data()); + hmacctx.Final(mac.data()); for (unsigned i = 0; i < h256::size; i++) if (mac[i] != msgMac[i]) - return false; + 0; - decryptSymNoAuth(*(Secret*)eKey.data(), h128(), cipher, plain); + decryptSymNoAuth(*(Secret*)eKey.data(), iv, cipherNoIV, plain); io_text.resize(plain.size()); io_text.swap(plain); diff --git a/test/crypto.cpp b/test/crypto.cpp index 56fb8a51c..5673dd530 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -228,6 +228,44 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) } } +BOOST_AUTO_TEST_CASE(ecies_interop_test) +{ + Secret input1(fromHex("0x0de72f1223915fa8b8bf45dffef67aef8d89792d116eb61c9a1eb02c422a4663")); + bytes expect1(fromHex("0x1d0c446f9899a3426f2b89a8cb75c14b")); + bytes test1; + test1 = s_secp256k1.eciesKDF(input1, bytes(), 16); + BOOST_REQUIRE(test1 == expect1); + + KeyPair k(Secret(fromHex("0x332143e9629eedff7d142d741f896258f5a1bfab54dab2121d3ec5000093d74b"))); + Public p(fromHex("0xf0d2b97981bd0d415a843b5dfe8ab77a30300daab3658c578f2340308a2da1a07f0821367332598b6aa4e180a41e92f4ebbae3518da847f0b1c0bbfe20bcf4e1")); + Secret agreeExpected(fromHex("0xee1418607c2fcfb57fda40380e885a707f49000a5dda056d828b7d9bd1f29a08")); + Secret agreeTest; + s_secp256k1.agree(k.sec(), p, agreeTest); + BOOST_REQUIRE(agreeExpected == agreeTest); + + KeyPair kenc(Secret(fromHex("0x472413e97f1fd58d84e28a559479e6b6902d2e8a0cee672ef38a3a35d263886b"))); + Public penc(Public(fromHex("0x7a2aa2951282279dc1171549a7112b07c38c0d97c0fe2c0ae6c4588ba15be74a04efc4f7da443f6d61f68a9279bc82b73e0cc8d090048e9f87e838ae65dd8d4c"))); + BOOST_REQUIRE(penc == kenc.pub()); + + bytes cipher1(fromHex("0x046f647e1bd8a5cd1446d31513bac233e18bdc28ec0e59d46de453137a72599533f1e97c98154343420d5f16e171e5107999a7c7f1a6e26f57bcb0d2280655d08fb148d36f1d4b28642d3bb4a136f0e33e3dd2e3cffe4b45a03fb7c5b5ea5e65617250fdc89e1a315563c20504b9d3a72555")); + bytes plainTest1 = cipher1; + bytes expectedPlain1 = asBytes("a"); + BOOST_REQUIRE(s_secp256k1.decryptECIES(kenc.sec(), plainTest1)); + BOOST_REQUIRE(plainTest1 == expectedPlain1); + + bytes cipher2(fromHex("0x0443c24d6ccef3ad095140760bb143078b3880557a06392f17c5e368502d79532bc18903d59ced4bbe858e870610ab0d5f8b7963dd5c9c4cf81128d10efd7c7aa80091563c273e996578403694673581829e25a865191bdc9954db14285b56eb0043b6288172e0d003c10f42fe413222e273d1d4340c38a2d8344d7aadcbc846ee")); + bytes plainTest2 = cipher2; + bytes expectedPlain2 = asBytes("aaaaaaaaaaaaaaaa"); + BOOST_REQUIRE(s_secp256k1.decryptECIES(kenc.sec(), plainTest2)); + BOOST_REQUIRE(plainTest2 == expectedPlain2); + + bytes cipher3(fromHex("0x04c4e40c86bb5324e017e598c6d48c19362ae527af8ab21b077284a4656c8735e62d73fb3d740acefbec30ca4c024739a1fcdff69ecaf03301eebf156eb5f17cca6f9d7a7e214a1f3f6e34d1ee0ec00ce0ef7d2b242fbfec0f276e17941f9f1bfbe26de10a15a6fac3cda039904ddd1d7e06e7b96b4878f61860e47f0b84c8ceb64f6a900ff23844f4359ae49b44154980a626d3c73226c19e")); + bytes plainTest3 = cipher3; + bytes expectedPlain3 = asBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + BOOST_REQUIRE(s_secp256k1.decryptECIES(kenc.sec(), plainTest3)); + BOOST_REQUIRE(plainTest3 == expectedPlain3); +} + BOOST_AUTO_TEST_CASE(ecies_kdf) { KeyPair local = KeyPair::create(); @@ -552,16 +590,6 @@ BOOST_AUTO_TEST_CASE(handshakeNew) -} - -BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) -{ - // New connections require new ECDH keypairs - // Every new connection requires a new EC keypair - // Every new trust requires a new EC keypair - // All connections should share seed for PRF (or PRNG) for nonces - - } BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)