From 2c50a6fab945194f2bf57e81ca5b4ab522e75f7f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 3 Apr 2012 21:41:53 -0700 Subject: [PATCH 1/5] Don't require the very latest version of Boost. --- src/UniqueNodeList.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/UniqueNodeList.h b/src/UniqueNodeList.h index ecc641f4bb..e622c10165 100644 --- a/src/UniqueNodeList.h +++ b/src/UniqueNodeList.h @@ -1,6 +1,8 @@ #ifndef __UNIQUE_NODE_LIST__ #define __UNIQUE_NODE_LIST__ +#include + #include "../json/value.h" #include "NewcoinAddress.h" @@ -8,7 +10,6 @@ #include "HttpsClient.h" #include -#include // Guarantees minimum thoughput of 1 node per second. #define NODE_FETCH_JOBS 10 @@ -27,7 +28,7 @@ private: boost::mutex mFetchLock; int mFetchActive; // count of active fetches - boost::container::deque mFetchPending; + std::deque mFetchPending; void fetchNext(); void fetchProcess(std::string strDomain); From c2c94b8a8b1fddf3ec80b96df439f5e1a11a2079 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 4 Apr 2012 12:45:54 -0700 Subject: [PATCH 2/5] The crux of ECIES. Generate a secret from two EC keys. At least one private key must be known, but it doesn't matter which. --- src/DeterministicKeys.cpp | 35 +++++++++++++++++++++++++++++++++++ src/key.h | 3 +++ 2 files changed, 38 insertions(+) diff --git a/src/DeterministicKeys.cpp b/src/DeterministicKeys.cpp index e9bb109f0f..4cb416e1ff 100644 --- a/src/DeterministicKeys.cpp +++ b/src/DeterministicKeys.cpp @@ -285,4 +285,39 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& family, cons return pkey; } + +static void* ecies_key_derivation(const void *input, size_t ilen, void *output, size_t *olen) +{ // This function must not be changed as it must be what ECDH_compute_key expects + if (*olen < SHA512_DIGEST_LENGTH) + return NULL; + *olen = SHA512_DIGEST_LENGTH; + return SHA512(static_cast(input), ilen, static_cast(output)); +} + + +std::vector CKey::getECIESSecret(CKey& otherKey) +{ // Retrieve a secret generated from an EC key pair. At least one private key must be known. + if(!pkey || !otherKey.pkey) + throw std::runtime_error("missing key"); + + EC_KEY *pubkey, *privkey; + if(EC_KEY_get0_private_key(pkey)) + { + privkey=pkey; + pubkey=otherKey.pkey; + } + else if(EC_KEY_get0_private_key(otherKey.pkey)) + { + privkey=otherKey.pkey; + pubkey=pkey; + } + else throw std::runtime_error("no private key"); + + std::vector ret(SHA512_DIGEST_LENGTH); + if (ECDH_compute_key(&(ret.front()), SHA512_DIGEST_LENGTH, EC_KEY_get0_public_key(pubkey), + privkey, ecies_key_derivation) != SHA512_DIGEST_LENGTH) + throw std::runtime_error("ecdh key failed"); + return ret; +} + // vim:ts=4 diff --git a/src/key.h b/src/key.h index 7eb4d0aeae..3caa26e4e9 100644 --- a/src/key.h +++ b/src/key.h @@ -273,6 +273,9 @@ public: return false; return true; } + + // Returns a 64-byte secret unique to these two keys. At least one private key must be known. + std::vector getECIESSecret(CKey& otherKey); }; #endif From b7d72553ec62e6910472e6607a81610b6dbfbf91 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 4 Apr 2012 15:06:06 -0700 Subject: [PATCH 3/5] Add the ECIES definitions. I'm going to put them in their own file. --- src/DeterministicKeys.cpp | 35 +---------------------------------- src/key.h | 9 ++++++++- 2 files changed, 9 insertions(+), 35 deletions(-) diff --git a/src/DeterministicKeys.cpp b/src/DeterministicKeys.cpp index 4cb416e1ff..e6717540bc 100644 --- a/src/DeterministicKeys.cpp +++ b/src/DeterministicKeys.cpp @@ -1,3 +1,4 @@ + #include #include #include @@ -286,38 +287,4 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& family, cons return pkey; } -static void* ecies_key_derivation(const void *input, size_t ilen, void *output, size_t *olen) -{ // This function must not be changed as it must be what ECDH_compute_key expects - if (*olen < SHA512_DIGEST_LENGTH) - return NULL; - *olen = SHA512_DIGEST_LENGTH; - return SHA512(static_cast(input), ilen, static_cast(output)); -} - - -std::vector CKey::getECIESSecret(CKey& otherKey) -{ // Retrieve a secret generated from an EC key pair. At least one private key must be known. - if(!pkey || !otherKey.pkey) - throw std::runtime_error("missing key"); - - EC_KEY *pubkey, *privkey; - if(EC_KEY_get0_private_key(pkey)) - { - privkey=pkey; - pubkey=otherKey.pkey; - } - else if(EC_KEY_get0_private_key(otherKey.pkey)) - { - privkey=otherKey.pkey; - pubkey=pkey; - } - else throw std::runtime_error("no private key"); - - std::vector ret(SHA512_DIGEST_LENGTH); - if (ECDH_compute_key(&(ret.front()), SHA512_DIGEST_LENGTH, EC_KEY_get0_public_key(pubkey), - privkey, ecies_key_derivation) != SHA512_DIGEST_LENGTH) - throw std::runtime_error("ecdh key failed"); - return ret; -} - // vim:ts=4 diff --git a/src/key.h b/src/key.h index 3caa26e4e9..f61892801e 100644 --- a/src/key.h +++ b/src/key.h @@ -274,8 +274,15 @@ public: return true; } - // Returns a 64-byte secret unique to these two keys. At least one private key must be known. + // ECIES functions. These throw on failure + + // returns a 64-byte secret unique to these two keys. At least one private key must be known. std::vector getECIESSecret(CKey& otherKey); + + // encrypt/decrypt functions with integrity checking. + // Note that the other side must somehow know what keys to use + std::vector encryptECIES(CKey& otherKey, const std::vector& plaintext); + std::vector decryptECIES(CKey& otherKey, const std::vector& ciphertext); }; #endif From 65c3059647ee786f95ecefe0604074c414e650f7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 4 Apr 2012 15:06:27 -0700 Subject: [PATCH 4/5] Some of the ECIES code. WIP. --- src/ECIES.cpp | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/ECIES.cpp diff --git a/src/ECIES.cpp b/src/ECIES.cpp new file mode 100644 index 0000000000..203d83ec04 --- /dev/null +++ b/src/ECIES.cpp @@ -0,0 +1,127 @@ + +#include +#include +#include +#include +#include + +#include +#include + +#include "key.h" + +static void* ecies_key_derivation(const void *input, size_t ilen, void *output, size_t *olen) +{ // This function must not be changed as it must be what ECDH_compute_key expects + if (*olen < SHA512_DIGEST_LENGTH) + return NULL; + *olen = SHA512_DIGEST_LENGTH; + return SHA512(static_cast(input), ilen, static_cast(output)); +} + +std::vector CKey::getECIESSecret(CKey& otherKey) +{ // Retrieve a secret generated from an EC key pair. At least one private key must be known. + if(!pkey || !otherKey.pkey) + throw std::runtime_error("missing key"); + + EC_KEY *pubkey, *privkey; + if(EC_KEY_get0_private_key(pkey)) + { + privkey=pkey; + pubkey=otherKey.pkey; + } + else if(EC_KEY_get0_private_key(otherKey.pkey)) + { + privkey=otherKey.pkey; + pubkey=pkey; + } + else throw std::runtime_error("no private key"); + + std::vector ret(SHA512_DIGEST_LENGTH); + if (ECDH_compute_key(&(ret.front()), SHA512_DIGEST_LENGTH, EC_KEY_get0_public_key(pubkey), + privkey, ecies_key_derivation) != SHA512_DIGEST_LENGTH) + throw std::runtime_error("ecdh key failed"); + return ret; +} + +// Our ciphertext is all encrypted. The encrypted data decodes as follows: +// 1) 256-bits of SHA-512 HMAC of original plaintext +// 2) 128-bit IV +// 3) Original plaintext + +static uint256 makeHMAC(const std::vector& secret, const std::vector data) +{ + HMAC_CTX ctx; + HMAC_CTX_init(&ctx); + + if(HMAC_Init_ex(&ctx, &(secret.front()), secret.size(), EVP_sha512(), NULL) != 1) + { + HMAC_CTX_cleanup(&ctx); + throw std::runtime_error("init hmac"); + } + + if(HMAC_Update(&ctx, &(data.front()), data.size()) != 1) + { + HMAC_CTX_cleanup(&ctx); + throw std::runtime_error("update hmac"); + } + + unsigned int ml=EVP_MAX_MD_SIZE; + std::vector hmac(ml); + if(!HMAC_Final(&ctx, &(hmac.front()), &ml) != 1) + { + HMAC_CTX_cleanup(&ctx); + throw std::runtime_error("finalize hmac"); + } + assert((ml>=32) && (ml<=EVP_MAX_MD_SIZE)); + + uint256 ret; + memcpy(ret.begin(), &(hmac.front()), 32); + + return ret; +} + +#if 0 + +std::vector CKey::encryptECIES(CKey& otherKey, const std::vector& plaintext) +{ + std::vector secret=getECIESSecret(otherKey); + + uint256 hmac=makeHMAC(secret, plaintext); + + uint128 iv; + if(RAND_bytes((unsigned char *) iv.begin(), 128/8) != 1) + throw std::runtime_error("insufficient entropy"); + + ECP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + + if (EVP_EncryptInit_ex(&ctx, EVP_AES_128_cbc(), NULL, key, iv) != 1) + { + EVP_CIPHER_CTX_cleanup(&ctx); + throw std::runtime_error("init cipher ctx"); + } + + EVP_EncryptUpdate + EVP_EncryptUpdate + EVP_EncryptUpdate + + ECP_EncryptFinal_ex +} + +std::vector CKey::decryptECIES(CKey& otherKey, const std::Vector& ciphertext) +{ + std::vector secret=getECIESSecret(otherKey); + + // 1) Decrypt + + // 2) Extract length and plaintext + + // 3) Compute HMAC + + // 4) Verify + +} + +#endif + +// vim:ts=4 From 18fc5bd93c1e868c17e8cbbe0f5e80492ddb03da Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 4 Apr 2012 18:11:24 -0700 Subject: [PATCH 5/5] Finish encrypt operation. --- src/ECIES.cpp | 63 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/src/ECIES.cpp b/src/ECIES.cpp index 203d83ec04..ed6d5e5c96 100644 --- a/src/ECIES.cpp +++ b/src/ECIES.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -43,10 +44,9 @@ std::vector CKey::getECIESSecret(CKey& otherKey) return ret; } -// Our ciphertext is all encrypted. The encrypted data decodes as follows: +// Our ciphertext is all encrypted except the IV. The encrypted data decodes as follows: // 1) 256-bits of SHA-512 HMAC of original plaintext -// 2) 128-bit IV -// 3) Original plaintext +// 2) Original plaintext static uint256 makeHMAC(const std::vector& secret, const std::vector data) { @@ -80,8 +80,6 @@ static uint256 makeHMAC(const std::vector& secret, const std::vec return ret; } -#if 0 - std::vector CKey::encryptECIES(CKey& otherKey, const std::vector& plaintext) { std::vector secret=getECIESSecret(otherKey); @@ -89,26 +87,61 @@ std::vector CKey::encryptECIES(CKey& otherKey, const std::vector< uint256 hmac=makeHMAC(secret, plaintext); uint128 iv; - if(RAND_bytes((unsigned char *) iv.begin(), 128/8) != 1) + if(RAND_bytes(static_cast(iv.begin()), 128/8) != 1) throw std::runtime_error("insufficient entropy"); - ECP_CIPHER_CTX ctx; + EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX_init(&ctx); - if (EVP_EncryptInit_ex(&ctx, EVP_AES_128_cbc(), NULL, key, iv) != 1) + if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + &(secret.front()), static_cast(iv.begin())) != 1) { EVP_CIPHER_CTX_cleanup(&ctx); throw std::runtime_error("init cipher ctx"); } - EVP_EncryptUpdate - EVP_EncryptUpdate - EVP_EncryptUpdate - - ECP_EncryptFinal_ex + std::vector out(plaintext.size() + (256/8) + (512/8) + 48, 0); + int len=0, bytesWritten; + + // output 256-bit IV + memcpy(&(out.front()), iv.begin(), 32); + len=32; + + // Encrypt/output 512-bit HMAC + bytesWritten=out.capacity()-len; + assert(bytesWritten>0); + if(EVP_EncryptUpdate(&ctx, &(out.front())+len, &bytesWritten, hmac.begin(), 64) < 0) + { + EVP_CIPHER_CTX_cleanup(&ctx); + throw std::runtime_error(""); + } + len+=bytesWritten; + + // encrypt/output plaintext + bytesWritten=out.capacity()-len; + assert(bytesWritten>0); + if(EVP_EncryptUpdate(&ctx, &(out.front())+len, &bytesWritten, &(plaintext.front()), plaintext.size()) < 0) + { + EVP_CIPHER_CTX_cleanup(&ctx); + throw std::runtime_error(""); + } + len+=bytesWritten; + + // finalize + bytesWritten=out.capacity()-len; + if(EVP_EncryptFinal_ex(&ctx, &(out.front())+len, &bytesWritten) < 0) + { + EVP_CIPHER_CTX_cleanup(&ctx); + throw std::runtime_error(""); + } + len+=bytesWritten; + + out.resize(len); + EVP_CIPHER_CTX_cleanup(&ctx); + return out; } -std::vector CKey::decryptECIES(CKey& otherKey, const std::Vector& ciphertext) +std::vector CKey::decryptECIES(CKey& otherKey, const std::vector& ciphertext) { std::vector secret=getECIESSecret(otherKey); @@ -122,6 +155,4 @@ std::vector CKey::decryptECIES(CKey& otherKey, const std::Vector< } -#endif - // vim:ts=4