Browse Source

ecies interop fix and tests. 128-bit keys.

cl-refactor
subtly 10 years ago
parent
commit
e3fbf63f8f
  1. 21
      libdevcrypto/Common.cpp
  2. 51
      libdevcrypto/CryptoPP.cpp
  3. 48
      test/crypto.cpp

21
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);
o_cipher.resize(_plain.size());
bytes underflowBytes(16);
if (o_cipher.size() != _plain.size())
_plain.cropped(trimmedSize, extraBytes).copyTo(&underflowBytes);
const int c_aesKeyLen = 32;
const int c_aesKeyLen = 16;
SecByteBlock key(_k.data(), c_aesKeyLen);
try
{
CTR_Mode<AES>::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
{

51
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<SHA256> ctx(mKey.data(), mKey.size());
CryptoPP::HMAC<SHA256> 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<SHA256> ctx(mKey.data(), mKey.size());
ctx.Update(cipherWithIV.data(), cipherWithIV.size());
CryptoPP::HMAC<SHA256> 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);

48
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)

Loading…
Cancel
Save