diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp
index c3b16ad3389..962c0188d59 100644
--- a/libdevcrypto/Common.cpp
+++ b/libdevcrypto/Common.cpp
@@ -277,6 +277,21 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
return _p == recover(_s, _hash);
}
+bool dev::verify(PublicCompressed const& _key, h512 const& _signature, h256 const& _hash)
+{
+ auto* ctx = getCtx();
+
+ secp256k1_ecdsa_signature rawSig;
+ if (!secp256k1_ecdsa_signature_parse_compact(ctx, &rawSig, _signature.data()))
+ return false;
+
+ secp256k1_pubkey rawPubkey;
+ if (!secp256k1_ec_pubkey_parse(ctx, &rawPubkey, _key.data(), PublicCompressed::size))
+ return false; // Invalid public key.
+
+ return secp256k1_ecdsa_verify(ctx, &rawSig, _hash.data(), &rawPubkey);
+}
+
bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen)
{
bytesSec ret(_dkLen);
diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h
index 18125918fab..f7e0e63b344 100644
--- a/libdevcrypto/Common.h
+++ b/libdevcrypto/Common.h
@@ -133,6 +133,9 @@ Signature sign(Secret const& _k, h256 const& _hash);
/// Verify signature.
bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
+// Verify signature with compressed public key
+bool verify(PublicCompressed const& _key, h512 const& _signature, h256 const& _hash);
+
/// Derive key via PBKDF2.
bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32);
diff --git a/test/unittests/libdevcrypto/crypto.cpp b/test/unittests/libdevcrypto/crypto.cpp
index 85f54e4a932..8a7e2d990d4 100644
--- a/test/unittests/libdevcrypto/crypto.cpp
+++ b/test/unittests/libdevcrypto/crypto.cpp
@@ -1,18 +1,18 @@
/*
- This file is part of cpp-ethereum.
+ This file is part of cpp-ethereum.
- cpp-ethereum is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- cpp-ethereum 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 General Public License for more details.
+ cpp-ethereum 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 General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with cpp-ethereum. If not, see .
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see .
*/
/** @file crypto.cpp
* @author Alex Leverington
@@ -52,65 +52,65 @@ namespace utf = boost::unit_test;
BOOST_AUTO_TEST_SUITE(Crypto)
struct DevcryptoTestFixture: public TestOutputHelperFixture {
- DevcryptoTestFixture() : s_secp256k1(Secp256k1PP::get()) {}
+ DevcryptoTestFixture() : s_secp256k1(Secp256k1PP::get()) {}
- Secp256k1PP* s_secp256k1;
+ Secp256k1PP* s_secp256k1;
};
BOOST_FIXTURE_TEST_SUITE(devcrypto, DevcryptoTestFixture)
static CryptoPP::AutoSeededRandomPool& rng()
{
- static CryptoPP::AutoSeededRandomPool s_rng;
- return s_rng;
+ static CryptoPP::AutoSeededRandomPool s_rng;
+ return s_rng;
}
static CryptoPP::OID& curveOID()
{
- static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1());
- return s_curveOID;
+ static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1());
+ return s_curveOID;
}
static CryptoPP::DL_GroupParameters_EC& params()
{
- static CryptoPP::DL_GroupParameters_EC s_params(curveOID());
- return s_params;
+ static CryptoPP::DL_GroupParameters_EC s_params(curveOID());
+ return s_params;
}
BOOST_AUTO_TEST_CASE(sha3general)
{
- BOOST_REQUIRE_EQUAL(sha3(""), h256("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
- BOOST_REQUIRE_EQUAL(sha3("hello"), h256("1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"));
+ BOOST_REQUIRE_EQUAL(sha3(""), h256("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
+ BOOST_REQUIRE_EQUAL(sha3("hello"), h256("1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"));
}
BOOST_AUTO_TEST_CASE(emptySHA3Types)
{
- h256 emptySHA3(fromHex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
- BOOST_REQUIRE_EQUAL(emptySHA3, EmptySHA3);
+ h256 emptySHA3(fromHex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
+ BOOST_REQUIRE_EQUAL(emptySHA3, EmptySHA3);
- h256 emptyListSHA3(fromHex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"));
- BOOST_REQUIRE_EQUAL(emptyListSHA3, EmptyListSHA3);
+ h256 emptyListSHA3(fromHex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"));
+ BOOST_REQUIRE_EQUAL(emptyListSHA3, EmptyListSHA3);
}
BOOST_AUTO_TEST_CASE(pubkeyOfZero)
{
- auto pub = toPublic({});
- BOOST_REQUIRE_EQUAL(pub, Public{});
+ auto pub = toPublic({});
+ BOOST_REQUIRE_EQUAL(pub, Public{});
}
BOOST_AUTO_TEST_CASE(KeyPairMix)
{
- KeyPair k = KeyPair::create();
- BOOST_REQUIRE(!!k.secret());
- BOOST_REQUIRE(!!k.pub());
- Public test = toPublic(k.secret());
- BOOST_CHECK_EQUAL(k.pub(), test);
+ KeyPair k = KeyPair::create();
+ BOOST_REQUIRE(!!k.secret());
+ BOOST_REQUIRE(!!k.pub());
+ Public test = toPublic(k.secret());
+ BOOST_CHECK_EQUAL(k.pub(), test);
}
BOOST_AUTO_TEST_CASE(keypairs)
{
- KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")));
- BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f")));
- BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075")));
+ KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")));
+ BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f")));
+ BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075")));
BOOST_REQUIRE(toPublicCompressed(p.secret()) ==
PublicCompressed(fromHex(
"0397466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce7")));
@@ -118,722 +118,750 @@ BOOST_AUTO_TEST_CASE(keypairs)
eth::Transaction t(
1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), {}, 0, p.secret());
auto rlp = t.rlp(eth::WithoutSignature);
- auto expectedRlp = "dc80808094944400f4b88ac9589a0f17ed4671da26bddb668b8203e880";
- BOOST_CHECK_EQUAL(toHex(rlp), expectedRlp);
- rlp = t.rlp(eth::WithSignature);
- auto expectedRlp2 = "f85f80808094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8801ca0bd2402a510c9c9afddf2a3f63c869573bd257475bea91d6f164638134a3386d6a0609ad9775fd2715e6a359c627e9338478e4adba65dd0dc6ef2bcbe6398378984";
- BOOST_CHECK_EQUAL(toHex(rlp), expectedRlp2);
- BOOST_CHECK_EQUAL(t.sender(), p.address());
+ auto expectedRlp = "dc80808094944400f4b88ac9589a0f17ed4671da26bddb668b8203e880";
+ BOOST_CHECK_EQUAL(toHex(rlp), expectedRlp);
+ rlp = t.rlp(eth::WithSignature);
+ auto expectedRlp2 = "f85f80808094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8801ca0bd2402a510c9c9afddf2a3f63c869573bd257475bea91d6f164638134a3386d6a0609ad9775fd2715e6a359c627e9338478e4adba65dd0dc6ef2bcbe6398378984";
+ BOOST_CHECK_EQUAL(toHex(rlp), expectedRlp2);
+ BOOST_CHECK_EQUAL(t.sender(), p.address());
}
BOOST_AUTO_TEST_CASE(KeyPairVerifySecret)
{
- auto keyPair = KeyPair::create();
- auto* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
- BOOST_CHECK(secp256k1_ec_seckey_verify(ctx, keyPair.secret().data()));
- secp256k1_context_destroy(ctx);
+ auto keyPair = KeyPair::create();
+ auto* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ BOOST_CHECK(secp256k1_ec_seckey_verify(ctx, keyPair.secret().data()));
+ secp256k1_context_destroy(ctx);
}
BOOST_AUTO_TEST_CASE(SignAndRecover)
{
- // This basic test that compares **fixed** results. Useful to test new
- // implementations or changes to implementations.
- auto sec = Secret{sha3("sec")};
- auto msg = sha3("msg");
- auto sig = sign(sec, msg);
- auto expectedSig = "b826808a8c41e00b7c5d71f211f005a84a7b97949d5e765831e1da4e34c9b8295d2a622eee50f25af78241c1cb7cfff11bcf2a13fe65dee1e3b86fd79a4e3ed000";
- BOOST_CHECK_EQUAL(sig.hex(), expectedSig);
+ // This basic test that compares **fixed** results. Useful to test new
+ // implementations or changes to implementations.
+ auto sec = Secret{sha3("sec")};
+ auto msg = sha3("msg");
+ auto sig = sign(sec, msg);
+ auto expectedSig = "b826808a8c41e00b7c5d71f211f005a84a7b97949d5e765831e1da4e34c9b8295d2a622eee50f25af78241c1cb7cfff11bcf2a13fe65dee1e3b86fd79a4e3ed000";
+ BOOST_CHECK_EQUAL(sig.hex(), expectedSig);
- auto pub = recover(sig, msg);
- auto expectedPub = "e40930c838d6cca526795596e368d16083f0672f4ab61788277abfa23c3740e1cc84453b0b24f49086feba0bd978bb4446bae8dff1e79fcc1e9cf482ec2d07c3";
- BOOST_CHECK_EQUAL(pub.hex(), expectedPub);
+ auto pub = recover(sig, msg);
+ auto expectedPub = "e40930c838d6cca526795596e368d16083f0672f4ab61788277abfa23c3740e1cc84453b0b24f49086feba0bd978bb4446bae8dff1e79fcc1e9cf482ec2d07c3";
+ BOOST_CHECK_EQUAL(pub.hex(), expectedPub);
}
BOOST_AUTO_TEST_CASE(SignAndRecoverLoop)
{
- auto num = 13;
- auto msg = h256::random();
- while (--num)
- {
- msg = sha3(msg);
- auto kp = KeyPair::create();
- auto sig = sign(kp.secret(), msg);
- BOOST_CHECK(verify(kp.pub(), sig, msg));
- auto pub = recover(sig, msg);
- BOOST_CHECK_EQUAL(kp.pub(), pub);
- }
+ auto num = 13;
+ auto msg = h256::random();
+ while (--num)
+ {
+ msg = sha3(msg);
+ auto kp = KeyPair::create();
+ auto sig = sign(kp.secret(), msg);
+ BOOST_CHECK(verify(kp.pub(), sig, msg));
+ auto pub = recover(sig, msg);
+ BOOST_CHECK_EQUAL(kp.pub(), pub);
+ }
}
BOOST_AUTO_TEST_CASE(cryptopp_patch)
{
- KeyPair k = KeyPair::create();
- bytes io_text;
- s_secp256k1->decrypt(k.secret(), io_text);
- BOOST_REQUIRE_EQUAL(io_text.size(), 0);
+ KeyPair k = KeyPair::create();
+ bytes io_text;
+ s_secp256k1->decrypt(k.secret(), io_text);
+ BOOST_REQUIRE_EQUAL(io_text.size(), 0);
}
BOOST_AUTO_TEST_CASE(verify_secert)
{
- Secret empty;
- KeyPair kNot(empty);
- BOOST_REQUIRE(!kNot.address());
- KeyPair k(sha3(empty));
- BOOST_REQUIRE(k.address());
+ Secret empty;
+ KeyPair kNot(empty);
+ BOOST_REQUIRE(!kNot.address());
+ KeyPair k(sha3(empty));
+ BOOST_REQUIRE(k.address());
+}
+
+BOOST_AUTO_TEST_CASE(verifyWithPublicCompressed)
+{
+ PublicCompressed const pub{
+ fromHex("0x02e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a")};
+ h512 const sig{
+ fromHex("0x90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0"
+ "b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc93")};
+ h256 const msg{fromHex("0xce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008")};
+ BOOST_REQUIRE(verify(pub, sig, msg));
+
+ h512 invalidSig{sig};
+ ++invalidSig[4];
+ BOOST_REQUIRE(!verify(pub, invalidSig, msg));
+}
+
+BOOST_AUTO_TEST_CASE(signAndVerify)
+{
+ auto const kp = KeyPair::create();
+ auto const msg = h256::random();
+ auto const sig = sign(kp.secret(), msg);
+
+ auto const pubCompressed = toPublicCompressed(kp.secret());
+ // remove recovery id (65th byte)
+ h512 const sigWithoutV{sig};
+
+ BOOST_REQUIRE(verify(pubCompressed, sigWithoutV, msg));
}
BOOST_AUTO_TEST_CASE(common_encrypt_decrypt)
{
- string message("Now is the time for all good persons to come to the aid of humanity.");
- bytes m = asBytes(message);
- bytesConstRef bcr(&m);
+ string message("Now is the time for all good persons to come to the aid of humanity.");
+ bytes m = asBytes(message);
+ bytesConstRef bcr(&m);
- KeyPair k = KeyPair::create();
- bytes cipher;
- encrypt(k.pub(), bcr, cipher);
- BOOST_REQUIRE(cipher != asBytes(message) && cipher.size() > 0);
-
- bytes plain;
- decrypt(k.secret(), bytesConstRef(&cipher), plain);
-
- BOOST_REQUIRE(asString(plain) == message);
- BOOST_REQUIRE(plain == asBytes(message));
+ KeyPair k = KeyPair::create();
+ bytes cipher;
+ encrypt(k.pub(), bcr, cipher);
+ BOOST_REQUIRE(cipher != asBytes(message) && cipher.size() > 0);
+
+ bytes plain;
+ decrypt(k.secret(), bytesConstRef(&cipher), plain);
+
+ BOOST_REQUIRE(asString(plain) == message);
+ BOOST_REQUIRE(plain == asBytes(message));
}
BOOST_AUTO_TEST_CASE(sha3_norestart)
{
- CryptoPP::Keccak_256 ctx;
- bytes input(asBytes("test"));
- ctx.Update(input.data(), 4);
- CryptoPP::Keccak_256 ctxCopy(ctx);
- bytes interimDigest(32);
- ctx.Final(interimDigest.data());
- ctx.Update(input.data(), 4);
- bytes firstDigest(32);
- ctx.Final(firstDigest.data());
- BOOST_REQUIRE(interimDigest == firstDigest);
-
- ctxCopy.Update(input.data(), 4);
- bytes finalDigest(32);
- ctxCopy.Final(interimDigest.data());
- BOOST_REQUIRE(interimDigest != finalDigest);
-
- // we can do this another way -- copy the context for final
- ctxCopy.Update(input.data(), 4);
- ctxCopy.Update(input.data(), 4);
- CryptoPP::Keccak_256 finalCtx(ctxCopy);
- bytes finalDigest2(32);
- finalCtx.Final(finalDigest2.data());
- BOOST_REQUIRE(finalDigest2 == interimDigest);
- ctxCopy.Update(input.data(), 4);
- bytes finalDigest3(32);
- finalCtx.Final(finalDigest3.data());
- BOOST_REQUIRE(finalDigest2 != finalDigest3);
+ CryptoPP::Keccak_256 ctx;
+ bytes input(asBytes("test"));
+ ctx.Update(input.data(), 4);
+ CryptoPP::Keccak_256 ctxCopy(ctx);
+ bytes interimDigest(32);
+ ctx.Final(interimDigest.data());
+ ctx.Update(input.data(), 4);
+ bytes firstDigest(32);
+ ctx.Final(firstDigest.data());
+ BOOST_REQUIRE(interimDigest == firstDigest);
+
+ ctxCopy.Update(input.data(), 4);
+ bytes finalDigest(32);
+ ctxCopy.Final(interimDigest.data());
+ BOOST_REQUIRE(interimDigest != finalDigest);
+
+ // we can do this another way -- copy the context for final
+ ctxCopy.Update(input.data(), 4);
+ ctxCopy.Update(input.data(), 4);
+ CryptoPP::Keccak_256 finalCtx(ctxCopy);
+ bytes finalDigest2(32);
+ finalCtx.Final(finalDigest2.data());
+ BOOST_REQUIRE(finalDigest2 == interimDigest);
+ ctxCopy.Update(input.data(), 4);
+ bytes finalDigest3(32);
+ finalCtx.Final(finalDigest3.data());
+ BOOST_REQUIRE(finalDigest2 != finalDigest3);
}
BOOST_AUTO_TEST_CASE(ecies_kdf)
{
- KeyPair local = KeyPair::create();
- KeyPair remote = KeyPair::create();
- // nonce
- Secret z1;
- BOOST_CHECK(ecdh::agree(local.secret(), remote.pub(), z1));
- auto key1 = ecies::kdf(z1, bytes(), 64);
- bytesConstRef eKey1 = bytesConstRef(&key1).cropped(0, 32);
- bytesRef mKey1 = bytesRef(&key1).cropped(32, 32);
- sha3(mKey1, mKey1);
-
- Secret z2;
- BOOST_CHECK(ecdh::agree(remote.secret(), local.pub(), z2));
- auto key2 = ecies::kdf(z2, bytes(), 64);
- bytesConstRef eKey2 = bytesConstRef(&key2).cropped(0, 32);
- bytesRef mKey2 = bytesRef(&key2).cropped(32, 32);
- sha3(mKey2, mKey2);
-
- BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes());
- BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes());
-
- BOOST_REQUIRE(!!z1);
- BOOST_REQUIRE(z1 == z2);
-
- BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0);
- BOOST_REQUIRE(key1 == key2);
+ KeyPair local = KeyPair::create();
+ KeyPair remote = KeyPair::create();
+ // nonce
+ Secret z1;
+ BOOST_CHECK(ecdh::agree(local.secret(), remote.pub(), z1));
+ auto key1 = ecies::kdf(z1, bytes(), 64);
+ bytesConstRef eKey1 = bytesConstRef(&key1).cropped(0, 32);
+ bytesRef mKey1 = bytesRef(&key1).cropped(32, 32);
+ sha3(mKey1, mKey1);
+
+ Secret z2;
+ BOOST_CHECK(ecdh::agree(remote.secret(), local.pub(), z2));
+ auto key2 = ecies::kdf(z2, bytes(), 64);
+ bytesConstRef eKey2 = bytesConstRef(&key2).cropped(0, 32);
+ bytesRef mKey2 = bytesRef(&key2).cropped(32, 32);
+ sha3(mKey2, mKey2);
+
+ BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes());
+ BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes());
+
+ BOOST_REQUIRE(!!z1);
+ BOOST_REQUIRE(z1 == z2);
+
+ BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0);
+ BOOST_REQUIRE(key1 == key2);
}
BOOST_AUTO_TEST_CASE(ecdh_agree_invalid_pubkey)
{
- KeyPair ok = KeyPair::create();
- Public pubkey;
- ~pubkey; // Create a pubkey of all 1s.
- Secret z;
- BOOST_CHECK(!ecdh::agree(ok.secret(), pubkey, z));
+ KeyPair ok = KeyPair::create();
+ Public pubkey;
+ ~pubkey; // Create a pubkey of all 1s.
+ Secret z;
+ BOOST_CHECK(!ecdh::agree(ok.secret(), pubkey, z));
}
BOOST_AUTO_TEST_CASE(ecdh_agree_invalid_seckey)
{
- KeyPair ok = KeyPair::create();
- Secret seckey; // "Null" seckey is invalid.
- BOOST_CHECK(!ecdh::agree(seckey, ok.pub(), seckey));
+ KeyPair ok = KeyPair::create();
+ Secret seckey; // "Null" seckey is invalid.
+ BOOST_CHECK(!ecdh::agree(seckey, ok.pub(), seckey));
}
BOOST_AUTO_TEST_CASE(ecies_standard)
{
- KeyPair k = KeyPair::create();
-
- string message("Now is the time for all good persons to come to the aid of humanity.");
- string original = message;
- bytes b = asBytes(message);
-
- s_secp256k1->encryptECIES(k.pub(), b);
- BOOST_REQUIRE(b != asBytes(original));
- BOOST_REQUIRE(b.size() > 0 && b[0] == 0x04);
-
- s_secp256k1->decryptECIES(k.secret(), b);
- BOOST_REQUIRE(bytesConstRef(&b).cropped(0, original.size()).toBytes() == asBytes(original));
+ KeyPair k = KeyPair::create();
+
+ string message("Now is the time for all good persons to come to the aid of humanity.");
+ string original = message;
+ bytes b = asBytes(message);
+
+ s_secp256k1->encryptECIES(k.pub(), b);
+ BOOST_REQUIRE(b != asBytes(original));
+ BOOST_REQUIRE(b.size() > 0 && b[0] == 0x04);
+
+ s_secp256k1->decryptECIES(k.secret(), b);
+ BOOST_REQUIRE(bytesConstRef(&b).cropped(0, original.size()).toBytes() == asBytes(original));
}
BOOST_AUTO_TEST_CASE(ecies_sharedMacData)
{
- KeyPair k = KeyPair::create();
+ KeyPair k = KeyPair::create();
- string message("Now is the time for all good persons to come to the aid of humanity.");
- bytes original = asBytes(message);
- bytes b = original;
+ string message("Now is the time for all good persons to come to the aid of humanity.");
+ bytes original = asBytes(message);
+ bytes b = original;
- string shared("shared MAC data");
- string wrongShared("wrong shared MAC data");
+ string shared("shared MAC data");
+ string wrongShared("wrong shared MAC data");
- s_secp256k1->encryptECIES(k.pub(), shared, b);
- BOOST_REQUIRE(b != original);
- BOOST_REQUIRE(b.size() > 0 && b[0] == 0x04);
+ s_secp256k1->encryptECIES(k.pub(), shared, b);
+ BOOST_REQUIRE(b != original);
+ BOOST_REQUIRE(b.size() > 0 && b[0] == 0x04);
- BOOST_REQUIRE(!s_secp256k1->decryptECIES(k.secret(), wrongShared, b));
+ BOOST_REQUIRE(!s_secp256k1->decryptECIES(k.secret(), wrongShared, b));
- s_secp256k1->decryptECIES(k.secret(), shared, b);
+ s_secp256k1->decryptECIES(k.secret(), shared, b);
- auto decrypted = bytesConstRef(&b).cropped(0, original.size()).toBytes();
- BOOST_CHECK_EQUAL(toHex(decrypted), toHex(original));
+ auto decrypted = bytesConstRef(&b).cropped(0, original.size()).toBytes();
+ BOOST_CHECK_EQUAL(toHex(decrypted), toHex(original));
}
BOOST_AUTO_TEST_CASE(ecies_eckeypair)
{
- KeyPair k = KeyPair::create();
+ KeyPair k = KeyPair::create();
- string message("Now is the time for all good persons to come to the aid of humanity.");
- string original = message;
-
- bytes b = asBytes(message);
- s_secp256k1->encrypt(k.pub(), b);
- BOOST_REQUIRE(b != asBytes(original));
+ string message("Now is the time for all good persons to come to the aid of humanity.");
+ string original = message;
+
+ bytes b = asBytes(message);
+ s_secp256k1->encrypt(k.pub(), b);
+ BOOST_REQUIRE(b != asBytes(original));
- s_secp256k1->decrypt(k.secret(), b);
- BOOST_REQUIRE(b == asBytes(original));
+ s_secp256k1->decrypt(k.secret(), b);
+ BOOST_REQUIRE(b == asBytes(original));
}
BOOST_AUTO_TEST_CASE(ecdhCryptopp)
{
- CryptoPP::ECDH::Domain dhLocal(curveOID());
- CryptoPP::SecByteBlock privLocal(dhLocal.PrivateKeyLength());
- CryptoPP::SecByteBlock pubLocal(dhLocal.PublicKeyLength());
- dhLocal.GenerateKeyPair(rng(), privLocal, pubLocal);
-
- CryptoPP::ECDH::Domain dhRemote(curveOID());
- CryptoPP::SecByteBlock privRemote(dhRemote.PrivateKeyLength());
- CryptoPP::SecByteBlock pubRemote(dhRemote.PublicKeyLength());
- dhRemote.GenerateKeyPair(rng(), privRemote, pubRemote);
-
- assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength());
-
- // local: send public to remote; remote: send public to local
-
- // Local
- CryptoPP::SecByteBlock sharedLocal(dhLocal.AgreedValueLength());
- assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote));
-
- // Remote
- CryptoPP::SecByteBlock sharedRemote(dhRemote.AgreedValueLength());
- assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal));
-
- // Test
- CryptoPP::Integer ssLocal, ssRemote;
- ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes());
- ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes());
-
- assert(ssLocal != 0);
- assert(ssLocal == ssRemote);
-
-
- // Now use our keys
- KeyPair a = KeyPair::create();
- byte puba[65] = {0x04};
- memcpy(&puba[1], a.pub().data(), 64);
-
- KeyPair b = KeyPair::create();
- byte pubb[65] = {0x04};
- memcpy(&pubb[1], b.pub().data(), 64);
-
- CryptoPP::ECDH::Domain dhA(curveOID());
- Secret shared;
- BOOST_REQUIRE(dhA.Agree(shared.writable().data(), a.secret().data(), pubb));
- BOOST_REQUIRE(shared);
+ CryptoPP::ECDH::Domain dhLocal(curveOID());
+ CryptoPP::SecByteBlock privLocal(dhLocal.PrivateKeyLength());
+ CryptoPP::SecByteBlock pubLocal(dhLocal.PublicKeyLength());
+ dhLocal.GenerateKeyPair(rng(), privLocal, pubLocal);
+
+ CryptoPP::ECDH::Domain dhRemote(curveOID());
+ CryptoPP::SecByteBlock privRemote(dhRemote.PrivateKeyLength());
+ CryptoPP::SecByteBlock pubRemote(dhRemote.PublicKeyLength());
+ dhRemote.GenerateKeyPair(rng(), privRemote, pubRemote);
+
+ assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength());
+
+ // local: send public to remote; remote: send public to local
+
+ // Local
+ CryptoPP::SecByteBlock sharedLocal(dhLocal.AgreedValueLength());
+ assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote));
+
+ // Remote
+ CryptoPP::SecByteBlock sharedRemote(dhRemote.AgreedValueLength());
+ assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal));
+
+ // Test
+ CryptoPP::Integer ssLocal, ssRemote;
+ ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes());
+ ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes());
+
+ assert(ssLocal != 0);
+ assert(ssLocal == ssRemote);
+
+
+ // Now use our keys
+ KeyPair a = KeyPair::create();
+ byte puba[65] = {0x04};
+ memcpy(&puba[1], a.pub().data(), 64);
+
+ KeyPair b = KeyPair::create();
+ byte pubb[65] = {0x04};
+ memcpy(&pubb[1], b.pub().data(), 64);
+
+ CryptoPP::ECDH::Domain dhA(curveOID());
+ Secret shared;
+ BOOST_REQUIRE(dhA.Agree(shared.writable().data(), a.secret().data(), pubb));
+ BOOST_REQUIRE(shared);
}
BOOST_AUTO_TEST_CASE(ecdhe)
{
- auto local = KeyPair::create();
- auto remote = KeyPair::create();
- BOOST_CHECK_NE(local.pub(), remote.pub());
+ auto local = KeyPair::create();
+ auto remote = KeyPair::create();
+ BOOST_CHECK_NE(local.pub(), remote.pub());
- // local tx pubkey -> remote
- Secret sremote;
- BOOST_CHECK(ecdh::agree(remote.secret(), local.pub(), sremote));
-
- // remote tx pbukey -> local
- Secret slocal;
- BOOST_CHECK(ecdh::agree(local.secret(), remote.pub(), slocal));
+ // local tx pubkey -> remote
+ Secret sremote;
+ BOOST_CHECK(ecdh::agree(remote.secret(), local.pub(), sremote));
+
+ // remote tx pbukey -> local
+ Secret slocal;
+ BOOST_CHECK(ecdh::agree(local.secret(), remote.pub(), slocal));
- BOOST_CHECK(sremote);
- BOOST_CHECK(slocal);
- BOOST_CHECK_EQUAL(sremote, slocal);
+ BOOST_CHECK(sremote);
+ BOOST_CHECK(slocal);
+ BOOST_CHECK_EQUAL(sremote, slocal);
}
BOOST_AUTO_TEST_CASE(ecdhAgree)
{
- auto sec = Secret{sha3("ecdhAgree")};
- auto pub = toPublic(sec);
- Secret sharedSec;
- BOOST_CHECK(ecdh::agree(sec, pub, sharedSec));
- BOOST_CHECK(sharedSec);
- auto expectedSharedSec = "8ac7e464348b85d9fdfc0a81f2fdc0bbbb8ee5fb3840de6ed60ad9372e718977";
- BOOST_CHECK_EQUAL(sharedSec.makeInsecure().hex(), expectedSharedSec);
+ auto sec = Secret{sha3("ecdhAgree")};
+ auto pub = toPublic(sec);
+ Secret sharedSec;
+ BOOST_CHECK(ecdh::agree(sec, pub, sharedSec));
+ BOOST_CHECK(sharedSec);
+ auto expectedSharedSec = "8ac7e464348b85d9fdfc0a81f2fdc0bbbb8ee5fb3840de6ed60ad9372e718977";
+ BOOST_CHECK_EQUAL(sharedSec.makeInsecure().hex(), expectedSharedSec);
}
BOOST_AUTO_TEST_CASE(handshakeNew)
{
- // authInitiator -> E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
- // authRecipient -> E(remote-pubk, ecdhe-random-pubk || nonce || 0x0)
-
- h256 base(sha3("privacy"));
- sha3(base.ref(), base.ref());
- Secret nodeAsecret(base);
- KeyPair nodeA(nodeAsecret);
- BOOST_REQUIRE(nodeA.pub());
-
- sha3(base.ref(), base.ref());
- Secret nodeBsecret(base);
- KeyPair nodeB(nodeBsecret);
- BOOST_REQUIRE(nodeB.pub());
-
- BOOST_REQUIRE_NE(nodeA.secret(), nodeB.secret());
-
- // Initiator is Alice (nodeA)
- auto eA = KeyPair::create();
- bytes nAbytes(fromHex("0xAAAA"));
- h256 nonceA(sha3(nAbytes));
- bytes auth(Signature::size + h256::size + Public::size + h256::size + 1);
- Secret ssA;
- {
- bytesRef sig(&auth[0], Signature::size);
- bytesRef hepubk(&auth[Signature::size], h256::size);
- bytesRef pubk(&auth[Signature::size + h256::size], Public::size);
- bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size);
-
- BOOST_CHECK(crypto::ecdh::agree(nodeA.secret(), nodeB.pub(), ssA));
- sign(eA.secret(), (ssA ^ nonceA).makeInsecure()).ref().copyTo(sig);
- sha3(eA.pub().ref(), hepubk);
- nodeA.pub().ref().copyTo(pubk);
- nonceA.ref().copyTo(nonce);
- auth[auth.size() - 1] = 0x0;
- }
- bytes authcipher;
- encrypt(nodeB.pub(), &auth, authcipher);
- BOOST_REQUIRE_EQUAL(authcipher.size(), 279);
-
- // Receipient is Bob (nodeB)
- auto eB = KeyPair::create();
- bytes nBbytes(fromHex("0xBBBB"));
- h256 nonceB(sha3(nAbytes));
- bytes ack(Public::size + h256::size + 1);
- {
- // todo: replace nodeA.pub() in encrypt()
- // decrypt public key from auth
- bytes authdecrypted;
- decrypt(nodeB.secret(), &authcipher, authdecrypted);
- Public node;
- bytesConstRef pubk(&authdecrypted[Signature::size + h256::size], Public::size);
- pubk.copyTo(node.ref());
-
- bytesRef epubk(&ack[0], Public::size);
- bytesRef nonce(&ack[Public::size], h256::size);
-
- eB.pub().ref().copyTo(epubk);
- nonceB.ref().copyTo(nonce);
- auth[auth.size() - 1] = 0x0;
- }
- bytes ackcipher;
- encrypt(nodeA.pub(), &ack, ackcipher);
- BOOST_REQUIRE_EQUAL(ackcipher.size(), 182);
-
- BOOST_REQUIRE(eA.pub());
- BOOST_REQUIRE(eB.pub());
- BOOST_REQUIRE_NE(eA.secret(), eB.secret());
-
- /// Alice (after receiving ack)
- Secret aEncryptK;
- Secret aMacK;
- Secret aEgressMac;
- Secret aIngressMac;
- {
- bytes ackdecrypted;
- decrypt(nodeA.secret(), &ackcipher, ackdecrypted);
- BOOST_REQUIRE(ackdecrypted.size());
- bytesConstRef ackRef(&ackdecrypted);
- Public eBAck;
- h256 nonceBAck;
- ackRef.cropped(0, Public::size).copyTo(bytesRef(eBAck.data(), Public::size));
- ackRef.cropped(Public::size, h256::size).copyTo(nonceBAck.ref());
- BOOST_REQUIRE_EQUAL(eBAck, eB.pub());
- BOOST_REQUIRE_EQUAL(nonceBAck, nonceB);
-
- // TODO: export ess and require equal to b
-
- bytes keyMaterialBytes(512);
- bytesRef keyMaterial(&keyMaterialBytes);
-
- Secret ess;
- // todo: ecdh-agree should be able to output bytes
- BOOST_CHECK(ecdh::agree(eA.secret(), eBAck, ess));
- ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
- ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
+ // authInitiator -> E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
+ // authRecipient -> E(remote-pubk, ecdhe-random-pubk || nonce || 0x0)
+
+ h256 base(sha3("privacy"));
+ sha3(base.ref(), base.ref());
+ Secret nodeAsecret(base);
+ KeyPair nodeA(nodeAsecret);
+ BOOST_REQUIRE(nodeA.pub());
+
+ sha3(base.ref(), base.ref());
+ Secret nodeBsecret(base);
+ KeyPair nodeB(nodeBsecret);
+ BOOST_REQUIRE(nodeB.pub());
+
+ BOOST_REQUIRE_NE(nodeA.secret(), nodeB.secret());
+
+ // Initiator is Alice (nodeA)
+ auto eA = KeyPair::create();
+ bytes nAbytes(fromHex("0xAAAA"));
+ h256 nonceA(sha3(nAbytes));
+ bytes auth(Signature::size + h256::size + Public::size + h256::size + 1);
+ Secret ssA;
+ {
+ bytesRef sig(&auth[0], Signature::size);
+ bytesRef hepubk(&auth[Signature::size], h256::size);
+ bytesRef pubk(&auth[Signature::size + h256::size], Public::size);
+ bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size);
+
+ BOOST_CHECK(crypto::ecdh::agree(nodeA.secret(), nodeB.pub(), ssA));
+ sign(eA.secret(), (ssA ^ nonceA).makeInsecure()).ref().copyTo(sig);
+ sha3(eA.pub().ref(), hepubk);
+ nodeA.pub().ref().copyTo(pubk);
+ nonceA.ref().copyTo(nonce);
+ auth[auth.size() - 1] = 0x0;
+ }
+ bytes authcipher;
+ encrypt(nodeB.pub(), &auth, authcipher);
+ BOOST_REQUIRE_EQUAL(authcipher.size(), 279);
+
+ // Receipient is Bob (nodeB)
+ auto eB = KeyPair::create();
+ bytes nBbytes(fromHex("0xBBBB"));
+ h256 nonceB(sha3(nAbytes));
+ bytes ack(Public::size + h256::size + 1);
+ {
+ // todo: replace nodeA.pub() in encrypt()
+ // decrypt public key from auth
+ bytes authdecrypted;
+ decrypt(nodeB.secret(), &authcipher, authdecrypted);
+ Public node;
+ bytesConstRef pubk(&authdecrypted[Signature::size + h256::size], Public::size);
+ pubk.copyTo(node.ref());
+
+ bytesRef epubk(&ack[0], Public::size);
+ bytesRef nonce(&ack[Public::size], h256::size);
+
+ eB.pub().ref().copyTo(epubk);
+ nonceB.ref().copyTo(nonce);
+ auth[auth.size() - 1] = 0x0;
+ }
+ bytes ackcipher;
+ encrypt(nodeA.pub(), &ack, ackcipher);
+ BOOST_REQUIRE_EQUAL(ackcipher.size(), 182);
+
+ BOOST_REQUIRE(eA.pub());
+ BOOST_REQUIRE(eB.pub());
+ BOOST_REQUIRE_NE(eA.secret(), eB.secret());
+
+ /// Alice (after receiving ack)
+ Secret aEncryptK;
+ Secret aMacK;
+ Secret aEgressMac;
+ Secret aIngressMac;
+ {
+ bytes ackdecrypted;
+ decrypt(nodeA.secret(), &ackcipher, ackdecrypted);
+ BOOST_REQUIRE(ackdecrypted.size());
+ bytesConstRef ackRef(&ackdecrypted);
+ Public eBAck;
+ h256 nonceBAck;
+ ackRef.cropped(0, Public::size).copyTo(bytesRef(eBAck.data(), Public::size));
+ ackRef.cropped(Public::size, h256::size).copyTo(nonceBAck.ref());
+ BOOST_REQUIRE_EQUAL(eBAck, eB.pub());
+ BOOST_REQUIRE_EQUAL(nonceBAck, nonceB);
+
+ // TODO: export ess and require equal to b
+
+ bytes keyMaterialBytes(512);
+ bytesRef keyMaterial(&keyMaterialBytes);
+
+ Secret ess;
+ // todo: ecdh-agree should be able to output bytes
+ BOOST_CHECK(ecdh::agree(eA.secret(), eBAck, ess));
+ ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
+ ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
// auto token = sha3(ssA);
- aEncryptK = sha3Secure(keyMaterial);
- aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
- aMacK = sha3Secure(keyMaterial);
-
- keyMaterialBytes.resize(h256::size + authcipher.size());
- keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
- (aMacK ^ nonceBAck).ref().copyTo(keyMaterial);
- bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
- aEgressMac = sha3Secure(keyMaterial);
-
- keyMaterialBytes.resize(h256::size + ackcipher.size());
- keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
- (aMacK ^ nonceA).ref().copyTo(keyMaterial);
- bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
- aIngressMac = sha3Secure(keyMaterial);
- }
-
-
- /// Bob (after sending ack)
- Secret ssB;
- BOOST_CHECK(crypto::ecdh::agree(nodeB.secret(), nodeA.pub(), ssB));
- BOOST_REQUIRE_EQUAL(ssA, ssB);
-
- Secret bEncryptK;
- Secret bMacK;
- Secret bEgressMac;
- Secret bIngressMac;
- {
- bytes authdecrypted;
- decrypt(nodeB.secret(), &authcipher, authdecrypted);
- BOOST_REQUIRE(authdecrypted.size());
- bytesConstRef ackRef(&authdecrypted);
- Signature sigAuth;
- h256 heA;
- Public eAAuth;
- Public nodeAAuth;
- h256 nonceAAuth;
- bytesConstRef sig(&authdecrypted[0], Signature::size);
- bytesConstRef hepubk(&authdecrypted[Signature::size], h256::size);
- bytesConstRef pubk(&authdecrypted[Signature::size + h256::size], Public::size);
- bytesConstRef nonce(&authdecrypted[Signature::size + h256::size + Public::size], h256::size);
-
- nonce.copyTo(nonceAAuth.ref());
- pubk.copyTo(nodeAAuth.ref());
- BOOST_REQUIRE(nonceAAuth);
- BOOST_REQUIRE_EQUAL(nonceA, nonceAAuth);
- BOOST_REQUIRE(nodeAAuth);
- BOOST_REQUIRE_EQUAL(nodeA.pub(), nodeAAuth); // bad test, bad!!!
- hepubk.copyTo(heA.ref());
- sig.copyTo(sigAuth.ref());
-
- Secret ss;
- BOOST_CHECK(ecdh::agree(nodeB.secret(), nodeAAuth, ss));
- eAAuth = recover(sigAuth, (ss ^ nonceAAuth).makeInsecure());
- // todo: test when this fails; means remote is bad or packet bits were flipped
- BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth));
- BOOST_REQUIRE_EQUAL(eAAuth, eA.pub());
-
- bytes keyMaterialBytes(512);
- bytesRef keyMaterial(&keyMaterialBytes);
-
- Secret ess;
- // todo: ecdh-agree should be able to output bytes
- BOOST_CHECK(ecdh::agree(eB.secret(), eAAuth, ess));
+ aEncryptK = sha3Secure(keyMaterial);
+ aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
+ aMacK = sha3Secure(keyMaterial);
+
+ keyMaterialBytes.resize(h256::size + authcipher.size());
+ keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
+ (aMacK ^ nonceBAck).ref().copyTo(keyMaterial);
+ bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
+ aEgressMac = sha3Secure(keyMaterial);
+
+ keyMaterialBytes.resize(h256::size + ackcipher.size());
+ keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
+ (aMacK ^ nonceA).ref().copyTo(keyMaterial);
+ bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
+ aIngressMac = sha3Secure(keyMaterial);
+ }
+
+
+ /// Bob (after sending ack)
+ Secret ssB;
+ BOOST_CHECK(crypto::ecdh::agree(nodeB.secret(), nodeA.pub(), ssB));
+ BOOST_REQUIRE_EQUAL(ssA, ssB);
+
+ Secret bEncryptK;
+ Secret bMacK;
+ Secret bEgressMac;
+ Secret bIngressMac;
+ {
+ bytes authdecrypted;
+ decrypt(nodeB.secret(), &authcipher, authdecrypted);
+ BOOST_REQUIRE(authdecrypted.size());
+ bytesConstRef ackRef(&authdecrypted);
+ Signature sigAuth;
+ h256 heA;
+ Public eAAuth;
+ Public nodeAAuth;
+ h256 nonceAAuth;
+ bytesConstRef sig(&authdecrypted[0], Signature::size);
+ bytesConstRef hepubk(&authdecrypted[Signature::size], h256::size);
+ bytesConstRef pubk(&authdecrypted[Signature::size + h256::size], Public::size);
+ bytesConstRef nonce(&authdecrypted[Signature::size + h256::size + Public::size], h256::size);
+
+ nonce.copyTo(nonceAAuth.ref());
+ pubk.copyTo(nodeAAuth.ref());
+ BOOST_REQUIRE(nonceAAuth);
+ BOOST_REQUIRE_EQUAL(nonceA, nonceAAuth);
+ BOOST_REQUIRE(nodeAAuth);
+ BOOST_REQUIRE_EQUAL(nodeA.pub(), nodeAAuth); // bad test, bad!!!
+ hepubk.copyTo(heA.ref());
+ sig.copyTo(sigAuth.ref());
+
+ Secret ss;
+ BOOST_CHECK(ecdh::agree(nodeB.secret(), nodeAAuth, ss));
+ eAAuth = recover(sigAuth, (ss ^ nonceAAuth).makeInsecure());
+ // todo: test when this fails; means remote is bad or packet bits were flipped
+ BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth));
+ BOOST_REQUIRE_EQUAL(eAAuth, eA.pub());
+
+ bytes keyMaterialBytes(512);
+ bytesRef keyMaterial(&keyMaterialBytes);
+
+ Secret ess;
+ // todo: ecdh-agree should be able to output bytes
+ BOOST_CHECK(ecdh::agree(eB.secret(), eAAuth, ess));
// s_secp256k1->agree(eB.seckey(), eAAuth, ess);
- ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
- ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
+ ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
+ ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
// auto token = sha3(ssA);
- bEncryptK = sha3Secure(keyMaterial);
- bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
- bMacK = sha3Secure(keyMaterial);
-
- // todo: replace nonceB with decrypted nonceB
- keyMaterialBytes.resize(h256::size + ackcipher.size());
- keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
- (bMacK ^ nonceAAuth).ref().copyTo(keyMaterial);
- bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
- bEgressMac = sha3Secure(keyMaterial);
-
- keyMaterialBytes.resize(h256::size + authcipher.size());
- keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
- (bMacK ^ nonceB).ref().copyTo(keyMaterial);
- bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
- bIngressMac = sha3Secure(keyMaterial);
- }
-
- BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK);
- BOOST_REQUIRE_EQUAL(aMacK, bMacK);
- BOOST_REQUIRE_EQUAL(aEgressMac, bIngressMac);
- BOOST_REQUIRE_EQUAL(bEgressMac, aIngressMac);
-
-
-
+ bEncryptK = sha3Secure(keyMaterial);
+ bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
+ bMacK = sha3Secure(keyMaterial);
+
+ // todo: replace nonceB with decrypted nonceB
+ keyMaterialBytes.resize(h256::size + ackcipher.size());
+ keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
+ (bMacK ^ nonceAAuth).ref().copyTo(keyMaterial);
+ bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
+ bEgressMac = sha3Secure(keyMaterial);
+
+ keyMaterialBytes.resize(h256::size + authcipher.size());
+ keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
+ (bMacK ^ nonceB).ref().copyTo(keyMaterial);
+ bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
+ bIngressMac = sha3Secure(keyMaterial);
+ }
+
+ BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK);
+ BOOST_REQUIRE_EQUAL(aMacK, bMacK);
+ BOOST_REQUIRE_EQUAL(aEgressMac, bIngressMac);
+ BOOST_REQUIRE_EQUAL(bEgressMac, aIngressMac);
+
+
+
}
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)
{
- SecureFixedHash<16> encryptK(sha3("..."), h128::AlignLeft);
- h256 egressMac(sha3("+++"));
- // TESTING: send encrypt magic sequence
- bytes magic {0x22,0x40,0x08,0x91};
- bytes magicCipherAndMac;
- magicCipherAndMac = encryptSymNoAuth(encryptK, h128(), &magic);
-
- magicCipherAndMac.resize(magicCipherAndMac.size() + 32);
- sha3mac(egressMac.ref(), &magic, egressMac.ref());
- egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32));
-
- bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32);
- bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher).makeInsecure();
-
- plaintext.resize(magic.size());
- // @alex @subtly TODO: FIX: this check is pointless with the above line.
- BOOST_REQUIRE(plaintext.size() > 0);
- BOOST_REQUIRE(magic == plaintext);
+ SecureFixedHash<16> encryptK(sha3("..."), h128::AlignLeft);
+ h256 egressMac(sha3("+++"));
+ // TESTING: send encrypt magic sequence
+ bytes magic {0x22,0x40,0x08,0x91};
+ bytes magicCipherAndMac;
+ magicCipherAndMac = encryptSymNoAuth(encryptK, h128(), &magic);
+
+ magicCipherAndMac.resize(magicCipherAndMac.size() + 32);
+ sha3mac(egressMac.ref(), &magic, egressMac.ref());
+ egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32));
+
+ bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32);
+ bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher).makeInsecure();
+
+ plaintext.resize(magic.size());
+ // @alex @subtly TODO: FIX: this check is pointless with the above line.
+ BOOST_REQUIRE(plaintext.size() > 0);
+ BOOST_REQUIRE(magic == plaintext);
}
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr)
{
- SecureFixedHash<16> k(sha3("0xAAAA"), h128::AlignLeft);
- string m = "AAAAAAAAAAAAAAAA";
- bytesConstRef msg((byte*)m.data(), m.size());
+ SecureFixedHash<16> k(sha3("0xAAAA"), h128::AlignLeft);
+ string m = "AAAAAAAAAAAAAAAA";
+ bytesConstRef msg((byte*)m.data(), m.size());
- bytes ciphertext;
- h128 iv;
- tie(ciphertext, iv) = encryptSymNoAuth(k, msg);
-
- bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext).makeInsecure();
- BOOST_REQUIRE_EQUAL(asString(plaintext), m);
+ bytes ciphertext;
+ h128 iv;
+ tie(ciphertext, iv) = encryptSymNoAuth(k, msg);
+
+ bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext).makeInsecure();
+ BOOST_REQUIRE_EQUAL(asString(plaintext), m);
}
BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
{
- const int aesKeyLen = 16;
- BOOST_REQUIRE(sizeof(char) == sizeof(byte));
-
- // generate test key
- CryptoPP::AutoSeededRandomPool rng;
- CryptoPP::SecByteBlock key(0x00, aesKeyLen);
- rng.GenerateBlock(key, key.size());
-
- // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr
- FixedHash ctr;
- rng.GenerateBlock(ctr.data(), sizeof(ctr));
-
- // used for decrypt
- FixedHash ctrcopy(ctr);
-
- string text = "Now is the time for all good persons to come to the aid of humanity.";
- unsigned char const* in = (unsigned char*)&text[0];
- unsigned char* out = (unsigned char*)&text[0];
- string original = text;
- string doublespeak = text + text;
-
- string cipherCopy;
- try
- {
- CryptoPP::CTR_Mode::Encryption e;
- e.SetKeyWithIV(key, key.size(), ctr.data());
-
- // 68 % 255 should be difference of counter
- e.ProcessData(out, in, text.size());
- ctr = h128(u128(ctr) + text.size() / 16);
-
- BOOST_REQUIRE(text != original);
- cipherCopy = text;
- }
- catch (CryptoPP::Exception& _e)
- {
- cerr << _e.what() << endl;
- }
-
- try
- {
- CryptoPP::CTR_Mode::Decryption d;
- d.SetKeyWithIV(key, key.size(), ctrcopy.data());
- d.ProcessData(out, in, text.size());
- BOOST_REQUIRE(text == original);
- }
- catch (CryptoPP::Exception& _e)
- {
- cerr << _e.what() << endl;
- }
-
-
- // reencrypt ciphertext...
- try
- {
- BOOST_REQUIRE(cipherCopy != text);
- in = (unsigned char*)&cipherCopy[0];
- out = (unsigned char*)&cipherCopy[0];
-
- CryptoPP::CTR_Mode::Encryption e;
- e.SetKeyWithIV(key, key.size(), ctrcopy.data());
- e.ProcessData(out, in, text.size());
-
- // yep, ctr mode.
- BOOST_REQUIRE(cipherCopy == original);
- }
- catch (CryptoPP::Exception& _e)
- {
- cerr << _e.what() << endl;
- }
-
+ const int aesKeyLen = 16;
+ BOOST_REQUIRE(sizeof(char) == sizeof(byte));
+
+ // generate test key
+ CryptoPP::AutoSeededRandomPool rng;
+ CryptoPP::SecByteBlock key(0x00, aesKeyLen);
+ rng.GenerateBlock(key, key.size());
+
+ // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr
+ FixedHash ctr;
+ rng.GenerateBlock(ctr.data(), sizeof(ctr));
+
+ // used for decrypt
+ FixedHash ctrcopy(ctr);
+
+ string text = "Now is the time for all good persons to come to the aid of humanity.";
+ unsigned char const* in = (unsigned char*)&text[0];
+ unsigned char* out = (unsigned char*)&text[0];
+ string original = text;
+ string doublespeak = text + text;
+
+ string cipherCopy;
+ try
+ {
+ CryptoPP::CTR_Mode::Encryption e;
+ e.SetKeyWithIV(key, key.size(), ctr.data());
+
+ // 68 % 255 should be difference of counter
+ e.ProcessData(out, in, text.size());
+ ctr = h128(u128(ctr) + text.size() / 16);
+
+ BOOST_REQUIRE(text != original);
+ cipherCopy = text;
+ }
+ catch (CryptoPP::Exception& _e)
+ {
+ cerr << _e.what() << endl;
+ }
+
+ try
+ {
+ CryptoPP::CTR_Mode::Decryption d;
+ d.SetKeyWithIV(key, key.size(), ctrcopy.data());
+ d.ProcessData(out, in, text.size());
+ BOOST_REQUIRE(text == original);
+ }
+ catch (CryptoPP::Exception& _e)
+ {
+ cerr << _e.what() << endl;
+ }
+
+
+ // reencrypt ciphertext...
+ try
+ {
+ BOOST_REQUIRE(cipherCopy != text);
+ in = (unsigned char*)&cipherCopy[0];
+ out = (unsigned char*)&cipherCopy[0];
+
+ CryptoPP::CTR_Mode::Encryption e;
+ e.SetKeyWithIV(key, key.size(), ctrcopy.data());
+ e.ProcessData(out, in, text.size());
+
+ // yep, ctr mode.
+ BOOST_REQUIRE(cipherCopy == original);
+ }
+ catch (CryptoPP::Exception& _e)
+ {
+ cerr << _e.what() << endl;
+ }
+
}
BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc)
{
- const int aesKeyLen = 16;
- BOOST_REQUIRE(sizeof(char) == sizeof(byte));
-
- CryptoPP::AutoSeededRandomPool rng;
- CryptoPP::SecByteBlock key(0x00, aesKeyLen);
- rng.GenerateBlock(key, key.size());
-
- // Generate random IV
- byte iv[CryptoPP::AES::BLOCKSIZE];
- rng.GenerateBlock(iv, CryptoPP::AES::BLOCKSIZE);
-
- string string128("AAAAAAAAAAAAAAAA");
- string plainOriginal = string128;
-
- CryptoPP::CBC_Mode::Encryption cbcEncryption(key, key.size(), iv);
- cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
- BOOST_REQUIRE(string128 != plainOriginal);
-
- CryptoPP::CBC_Mode::Decryption cbcDecryption(key, key.size(), iv);
- cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
- BOOST_REQUIRE(plainOriginal == string128);
-
-
- // plaintext whose size isn't divisible by block size must use stream filter for padding
- string string192("AAAAAAAAAAAAAAAABBBBBBBB");
- plainOriginal = string192;
-
- string cipher;
- CryptoPP::StreamTransformationFilter* aesStream = new CryptoPP::StreamTransformationFilter(cbcEncryption, new CryptoPP::StringSink(cipher));
- CryptoPP::StringSource source(string192, true, aesStream);
- BOOST_REQUIRE(cipher.size() == 32);
-
- byte* pOut = reinterpret_cast(&string192[0]);
- byte const* pIn = reinterpret_cast(cipher.data());
- cbcDecryption.ProcessData(pOut, pIn, cipher.size());
- BOOST_REQUIRE(string192 == plainOriginal);
+ const int aesKeyLen = 16;
+ BOOST_REQUIRE(sizeof(char) == sizeof(byte));
+
+ CryptoPP::AutoSeededRandomPool rng;
+ CryptoPP::SecByteBlock key(0x00, aesKeyLen);
+ rng.GenerateBlock(key, key.size());
+
+ // Generate random IV
+ byte iv[CryptoPP::AES::BLOCKSIZE];
+ rng.GenerateBlock(iv, CryptoPP::AES::BLOCKSIZE);
+
+ string string128("AAAAAAAAAAAAAAAA");
+ string plainOriginal = string128;
+
+ CryptoPP::CBC_Mode::Encryption cbcEncryption(key, key.size(), iv);
+ cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
+ BOOST_REQUIRE(string128 != plainOriginal);
+
+ CryptoPP::CBC_Mode::Decryption cbcDecryption(key, key.size(), iv);
+ cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size());
+ BOOST_REQUIRE(plainOriginal == string128);
+
+
+ // plaintext whose size isn't divisible by block size must use stream filter for padding
+ string string192("AAAAAAAAAAAAAAAABBBBBBBB");
+ plainOriginal = string192;
+
+ string cipher;
+ CryptoPP::StreamTransformationFilter* aesStream = new CryptoPP::StreamTransformationFilter(cbcEncryption, new CryptoPP::StringSink(cipher));
+ CryptoPP::StringSource source(string192, true, aesStream);
+ BOOST_REQUIRE(cipher.size() == 32);
+
+ byte* pOut = reinterpret_cast(&string192[0]);
+ byte const* pIn = reinterpret_cast(cipher.data());
+ cbcDecryption.ProcessData(pOut, pIn, cipher.size());
+ BOOST_REQUIRE(string192 == plainOriginal);
}
BOOST_AUTO_TEST_CASE(recoverVgt3)
{
- // base secret
- Secret secret(sha3("privacy"));
-
- // we get ec params from signer
- CryptoPP::ECDSA::Signer signer;
-
- // e := sha3(msg)
- bytes e(fromHex("0x01"));
- e.resize(32);
- int tests = 13;
- while (sha3(&e, &e), secret = sha3(secret), tests--)
- {
- KeyPair key(secret);
- Public pkey = key.pub();
- signer.AccessKey().Initialize(params(), CryptoPP::Integer(secret.data(), Secret::size));
-
- h256 he(sha3(e));
- CryptoPP::Integer heInt(he.asBytes().data(), 32);
- h256 k(crypto::kdf(secret, he));
- CryptoPP::Integer kInt(k.asBytes().data(), 32);
- kInt %= params().GetSubgroupOrder()-1;
-
- CryptoPP::ECP::Point rp = params().ExponentiateBase(kInt);
- CryptoPP::Integer const& q = params().GetGroupOrder();
- CryptoPP::Integer r = params().ConvertElementToInteger(rp);
-
- CryptoPP::Integer kInv = kInt.InverseMod(q);
- CryptoPP::Integer s = (kInv * (CryptoPP::Integer(secret.data(), 32) * r + heInt)) % q;
- BOOST_REQUIRE(!!r && !!s);
-
- //try recover function on diffrent v values (should be invalid)
- for (size_t i = 0; i < 10; i++)
- {
- Signature sig;
- sig[64] = i;
- r.Encode(sig.data(), 32);
- s.Encode(sig.data() + 32, 32);
-
- Public p = dev::recover(sig, he);
- size_t expectI = rp.y.IsOdd() ? 1 : 0;
- if (i == expectI)
- BOOST_REQUIRE(p == pkey);
- else
- BOOST_REQUIRE(p != pkey);
- }
- }
+ // base secret
+ Secret secret(sha3("privacy"));
+
+ // we get ec params from signer
+ CryptoPP::ECDSA::Signer signer;
+
+ // e := sha3(msg)
+ bytes e(fromHex("0x01"));
+ e.resize(32);
+ int tests = 13;
+ while (sha3(&e, &e), secret = sha3(secret), tests--)
+ {
+ KeyPair key(secret);
+ Public pkey = key.pub();
+ signer.AccessKey().Initialize(params(), CryptoPP::Integer(secret.data(), Secret::size));
+
+ h256 he(sha3(e));
+ CryptoPP::Integer heInt(he.asBytes().data(), 32);
+ h256 k(crypto::kdf(secret, he));
+ CryptoPP::Integer kInt(k.asBytes().data(), 32);
+ kInt %= params().GetSubgroupOrder()-1;
+
+ CryptoPP::ECP::Point rp = params().ExponentiateBase(kInt);
+ CryptoPP::Integer const& q = params().GetGroupOrder();
+ CryptoPP::Integer r = params().ConvertElementToInteger(rp);
+
+ CryptoPP::Integer kInv = kInt.InverseMod(q);
+ CryptoPP::Integer s = (kInv * (CryptoPP::Integer(secret.data(), 32) * r + heInt)) % q;
+ BOOST_REQUIRE(!!r && !!s);
+
+ //try recover function on diffrent v values (should be invalid)
+ for (size_t i = 0; i < 10; i++)
+ {
+ Signature sig;
+ sig[64] = i;
+ r.Encode(sig.data(), 32);
+ s.Encode(sig.data() + 32, 32);
+
+ Public p = dev::recover(sig, he);
+ size_t expectI = rp.y.IsOdd() ? 1 : 0;
+ if (i == expectI)
+ BOOST_REQUIRE(p == pkey);
+ else
+ BOOST_REQUIRE(p != pkey);
+ }
+ }
}
BOOST_AUTO_TEST_CASE(PerfSHA256_32, *utf::label("perf"))
{
- if (!test::Options::get().all)
- {
- std::cout << "Skipping test Crypto/devcrypto/PerfSHA256_32. Use --all to run it.\n";
- return;
- }
+ if (!test::Options::get().all)
+ {
+ std::cout << "Skipping test Crypto/devcrypto/PerfSHA256_32. Use --all to run it.\n";
+ return;
+ }
- h256 hash;
- for (auto i = 0; i < 1000000; ++i)
- hash = sha256(hash.ref());
+ h256 hash;
+ for (auto i = 0; i < 1000000; ++i)
+ hash = sha256(hash.ref());
- BOOST_CHECK_EQUAL(hash[0], 0x2a);
+ BOOST_CHECK_EQUAL(hash[0], 0x2a);
}
BOOST_AUTO_TEST_CASE(PerfSHA256_4000, *utf::label("perf"))
{
- if (!test::Options::get().all)
- {
- std::cout << "Skipping test Crypto/devcrypto/PerfSHA256_4000. Use --all to run it.\n";
- return;
- }
-
- static const size_t dataSize = 4097;
- bytes data(dataSize);
- for (auto i = 0; i < 100000; ++i)
- {
- auto hash = sha256(&data);
- auto idx = ((hash[1] << 8) | hash[2]) % (dataSize - hash.size);
- std::copy(hash.data(), hash.data() + hash.size, data.begin() + idx);
- }
-
- BOOST_CHECK_EQUAL(data[0], 0x4d);
+ if (!test::Options::get().all)
+ {
+ std::cout << "Skipping test Crypto/devcrypto/PerfSHA256_4000. Use --all to run it.\n";
+ return;
+ }
+
+ static const size_t dataSize = 4097;
+ bytes data(dataSize);
+ for (auto i = 0; i < 100000; ++i)
+ {
+ auto hash = sha256(&data);
+ auto idx = ((hash[1] << 8) | hash[2]) % (dataSize - hash.size);
+ std::copy(hash.data(), hash.data() + hash.size, data.begin() + idx);
+ }
+
+ BOOST_CHECK_EQUAL(data[0], 0x4d);
}
BOOST_AUTO_TEST_SUITE_END()