This repository was archived by the owner on Oct 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Replace Crypto++ ECIES #3634
Open
chfast
wants to merge
13
commits into
master
Choose a base branch
from
replace-cryptopp-ecies
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Replace Crypto++ ECIES #3634
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
0484411
Refactor ECIES unit test
chfast 65ae98e
Use SHA256 from secp256k1 in decryptECIES()
chfast c93edbb
Use SHA256 from secp256k1 in encryptECIES()
chfast 07e93f6
Remove old ECIES method
chfast 0c9332d
Remove unused Crypto++ pieces
chfast 265bdfe
Add pbkdf2 unit test
chfast 5e47a2c
Fix compilation of the rlp tool
chfast af45af1
Replace pbkdf2
chfast 8d3d299
Move encrypt functions to devcrypto/Common
chfast 1499f01
Move decrypt functions to devcrypto/Common
chfast f0f8ed5
Remove CryptoPP wrapper from devcrypto
chfast 2028245
Merge branch 'develop' into replace-cryptopp-ecies
chfast 5daf4e8
Merge remote-tracking branch 'origin/develop' into replace-cryptopp-e…
chfast File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,15 +27,13 @@ | |
| #include <secp256k1_recovery.h> | ||
| #include <secp256k1_sha256.h> | ||
| #include <cryptopp/aes.h> | ||
| #include <cryptopp/pwdbased.h> | ||
| #include <cryptopp/sha.h> | ||
| #include <cryptopp/modes.h> | ||
| #include <libscrypt/libscrypt.h> | ||
| #include <libdevcore/SHA3.h> | ||
| #include <libdevcore/RLP.h> | ||
| #include "AES.h" | ||
| #include "CryptoPP.h" | ||
| #include "Exceptions.h" | ||
|
|
||
| using namespace std; | ||
| using namespace dev; | ||
| using namespace dev::crypto; | ||
|
|
@@ -104,19 +102,12 @@ Address dev::toAddress(Address const& _from, u256 const& _nonce) | |
|
|
||
| void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher) | ||
| { | ||
| bytes io = _plain.toBytes(); | ||
| Secp256k1PP::get()->encrypt(_k, io); | ||
| o_cipher = std::move(io); | ||
| encryptECIES(_k, _plain, o_cipher); | ||
| } | ||
|
|
||
| bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) | ||
| { | ||
| bytes io = _cipher.toBytes(); | ||
| Secp256k1PP::get()->decrypt(_k, io); | ||
| if (io.empty()) | ||
| return false; | ||
| o_plaintext = std::move(io); | ||
| return true; | ||
| return decryptECIES(_k, _cipher, o_plaintext); | ||
| } | ||
|
|
||
| void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher) | ||
|
|
@@ -126,9 +117,40 @@ void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher) | |
|
|
||
| void dev::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytesConstRef _plain, bytes& o_cipher) | ||
| { | ||
| bytes io = _plain.toBytes(); | ||
| Secp256k1PP::get()->encryptECIES(_k, _sharedMacData, io); | ||
| o_cipher = std::move(io); | ||
| // interop w/go ecies implementation | ||
| auto r = KeyPair::create(); | ||
| Secret z; | ||
| ecdh::agree(r.secret(), _k, z); | ||
| auto key = ecies::kdf(z, bytes(), 32); | ||
| bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); | ||
| bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); | ||
| secp256k1_sha256_t ctx; | ||
| secp256k1_sha256_initialize(&ctx); | ||
| secp256k1_sha256_write(&ctx, mKeyMaterial.data(), mKeyMaterial.size()); | ||
| bytes mKey(32); | ||
| secp256k1_sha256_finalize(&ctx, mKey.data()); | ||
|
|
||
| auto iv = h128::random(); | ||
| bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), iv, _plain); | ||
| if (cipherText.empty()) | ||
| return; | ||
|
|
||
| bytes msg(1 + Public::size + h128::size + cipherText.size() + 32); | ||
| msg[0] = 0x04; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably I would create a helper which creates a SEC.1 key. SEC.1 (http://www.secg.org/sec1-v2.pdf) section 2.3.3 describes the rules. |
||
| r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size)); | ||
| iv.ref().copyTo(bytesRef(&msg).cropped(1 + Public::size, h128::size)); | ||
| bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size()); | ||
| bytesConstRef(&cipherText).copyTo(msgCipherRef); | ||
|
|
||
| // tag message | ||
| secp256k1_hmac_sha256_t hmacCtx; | ||
| secp256k1_hmac_sha256_initialize(&hmacCtx, mKey.data(), mKey.size()); | ||
| bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size()); | ||
| secp256k1_hmac_sha256_write(&hmacCtx, cipherWithIV.data(), cipherWithIV.size()); | ||
| secp256k1_hmac_sha256_write(&hmacCtx, _sharedMacData.data(), _sharedMacData.size()); | ||
| secp256k1_hmac_sha256_finalize(&hmacCtx, msg.data() + 1 + Public::size + cipherWithIV.size()); | ||
|
|
||
| o_cipher = std::move(msg); | ||
| } | ||
|
|
||
| bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) | ||
|
|
@@ -138,10 +160,50 @@ bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plainte | |
|
|
||
| bool dev::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytesConstRef _cipher, bytes& o_plaintext) | ||
| { | ||
| bytes io = _cipher.toBytes(); | ||
| if (!Secp256k1PP::get()->decryptECIES(_k, _sharedMacData, io)) | ||
| // interop w/go ecies implementation | ||
|
|
||
| // io_cipher[0] must be 2, 3, or 4, else invalidpublickey | ||
| if (_cipher.empty() || _cipher[0] < 2 || _cipher[0] > 4) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably better to have a class for SEC.1 key (mentioned above) and just use validations on that class here. |
||
| // invalid message: publickey | ||
| return false; | ||
| o_plaintext = std::move(io); | ||
|
|
||
| if (_cipher.size() < (1 + Public::size + h128::size + 1 + h256::size)) | ||
| // invalid message: length | ||
| return false; | ||
|
|
||
| Secret z; | ||
| ecdh::agree(_k, *(Public*)(_cipher.data() + 1), z); | ||
| auto key = ecies::kdf(z, bytes(), 64); | ||
| bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); | ||
| bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); | ||
| bytes mKey(32); | ||
| // FIXME: Use crypto::sha256() | ||
| secp256k1_sha256_t ctx; | ||
| secp256k1_sha256_initialize(&ctx); | ||
| secp256k1_sha256_write(&ctx, mKeyMaterial.data(), mKeyMaterial.size()); | ||
| secp256k1_sha256_finalize(&ctx, mKey.data()); | ||
|
|
||
| bytes plain; | ||
| size_t cipherLen = _cipher.size() - 1 - Public::size - h128::size - h256::size; | ||
| bytesConstRef cipherWithIV(_cipher.data() + 1 + Public::size, h128::size + cipherLen); | ||
| 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 | ||
|
|
||
| secp256k1_hmac_sha256_t hmacCtx; | ||
| secp256k1_hmac_sha256_initialize(&hmacCtx, mKey.data(), mKey.size()); | ||
| secp256k1_hmac_sha256_write(&hmacCtx, cipherWithIV.data(), cipherWithIV.size()); | ||
| secp256k1_hmac_sha256_write(&hmacCtx, _sharedMacData.data(), _sharedMacData.size()); | ||
| h256 mac; | ||
| secp256k1_hmac_sha256_finalize(&hmacCtx, mac.data()); | ||
| for (unsigned i = 0; i < h256::size; i++) | ||
| if (mac[i] != msgMac[i]) | ||
| return false; | ||
|
|
||
| o_plaintext = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); | ||
| return true; | ||
| } | ||
|
|
||
|
|
@@ -265,18 +327,41 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) | |
|
|
||
| bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) | ||
| { | ||
| static const size_t bufSize = 32; | ||
| bytesSec secBuf(bufSize); | ||
| byte* buf = secBuf.writable().data(); | ||
|
|
||
| bytesSec ret(_dkLen); | ||
| if (PKCS5_PBKDF2_HMAC<SHA256>().DeriveKey( | ||
| ret.writable().data(), | ||
| _dkLen, | ||
| 0, | ||
| reinterpret_cast<byte const*>(_pass.data()), | ||
| _pass.size(), | ||
| _salt.data(), | ||
| _salt.size(), | ||
| _iterations | ||
| ) != _iterations) | ||
| BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); | ||
| byte* derived = ret.writable().data(); | ||
| size_t derivedLen = _dkLen; | ||
| for (unsigned int i = 1; derivedLen > 0; ++i) | ||
| { | ||
| secp256k1_hmac_sha256_t ctx; | ||
| secp256k1_hmac_sha256_initialize(&ctx, reinterpret_cast<byte const*>(_pass.data()), _pass.size()); | ||
| secp256k1_hmac_sha256_write(&ctx, _salt.data(), _salt.size()); | ||
| for (auto j = 0; j < 4; ++j) | ||
| { | ||
| byte b = byte(i >> ((3-j)*8)); | ||
| secp256k1_hmac_sha256_write(&ctx, &b, 1); | ||
| } | ||
| secp256k1_hmac_sha256_finalize(&ctx, buf); | ||
|
|
||
| size_t const segmentLen = std::min(derivedLen, bufSize); | ||
| std::copy(buf, buf + segmentLen, derived); | ||
|
|
||
| for (decltype(_iterations) j = 1; j < _iterations; ++j) | ||
| { | ||
| secp256k1_hmac_sha256_initialize(&ctx, reinterpret_cast<byte const*>(_pass.data()), _pass.size()); | ||
| secp256k1_hmac_sha256_write(&ctx, buf, bufSize); | ||
| secp256k1_hmac_sha256_finalize(&ctx, buf); | ||
| std::transform(buf, buf + segmentLen, derived, derived, | ||
| [](byte a, byte b) { return a ^ b; } | ||
| ); | ||
| } | ||
|
|
||
| derived += segmentLen; | ||
| derivedLen -= segmentLen; | ||
| } | ||
| return ret; | ||
| } | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
encrypt&decryptare now the same asencryptECIES&decryptECIES, do we still need both?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will take a look. Probably not.