///////////////////////////////////////////////////////////////////////////// // Same as above, but only changing the AES mode of operation (CBC, not CFB) SecureBinaryData CryptoAES::EncryptCBC(SecureBinaryData & data, SecureBinaryData & key, SecureBinaryData & iv) { if(CRYPTO_DEBUG) { cout << "AES Decrypt" << endl; cout << " BinData: " << data.toHexStr() << endl; cout << " BinKey : " << key.toHexStr() << endl; cout << " BinIV : " << iv.toHexStr() << endl; } if(data.getSize() == 0) return SecureBinaryData(0); SecureBinaryData encrData(data.getSize()); // Caller can supply their own IV/entropy, or let it be generated here // (variable "iv" is a reference, so check it on the way out) if(iv.getSize() == 0) iv = SecureBinaryData().GenerateRandom(BTC_AES::BLOCKSIZE); BTC_CBC_MODE<BTC_AES>::Encryption aes_enc( (byte*)key.getPtr(), key.getSize(), (byte*)iv.getPtr()); aes_enc.ProcessData( (byte*)encrData.getPtr(), (byte*)data.getPtr(), data.getSize()); return encrData; }
///////////////////////////////////////////////////////////////////////////// // Same as above, but only changing the AES mode of operation (CBC, not CFB) SecureBinaryData CryptoAES::DecryptCBC(SecureBinaryData & data, SecureBinaryData & key, SecureBinaryData iv ) { if(CRYPTO_DEBUG) { cout << "AES Decrypt" << endl; cout << " BinData: " << data.toHexStr() << endl; cout << " BinKey : " << key.toHexStr() << endl; cout << " BinIV : " << iv.toHexStr() << endl; } if(data.getSize() == 0) return SecureBinaryData(0); SecureBinaryData unencrData(data.getSize()); BTC_CBC_MODE<BTC_AES>::Decryption aes_enc( (byte*)key.getPtr(), key.getSize(), (byte*)iv.getPtr()); aes_enc.ProcessData( (byte*)unencrData.getPtr(), (byte*)data.getPtr(), data.getSize()); return unencrData; }
SecureBinaryData KdfRomix::DeriveKey(SecureBinaryData const & password) { SecureBinaryData masterKey(password); for(uint32_t i=0; i<numIterations_; i++) masterKey = DeriveKey_OneIter(masterKey); return SecureBinaryData(masterKey); }
SecureBinaryData CryptoAES::Encrypt(SecureBinaryData & data, SecureBinaryData & key, SecureBinaryData & iv) { if(CRYPTO_DEBUG) { cout << "AES Decrypt" << endl; cout << " BinData: " << data.toHexStr() << endl; cout << " BinKey : " << key.toHexStr() << endl; cout << " BinIV : " << iv.toHexStr() << endl; } if(data.getSize() == 0) return SecureBinaryData(0); SecureBinaryData encrData(data.getSize()); //cout << " StartPlain: " << data.toHexStr() << endl; //cout << " Key Data : " << key.toHexStr() << endl; // Caller can supply their own IV/entropy, or let it be generated here if(iv.getSize() == 0) iv = SecureBinaryData().GenerateRandom(BTC_AES::BLOCKSIZE); BTC_AES_MODE<BTC_AES>::Encryption aes_enc( (byte*)key.getPtr(), key.getSize(), (byte*)iv.getPtr()); aes_enc.ProcessData( (byte*)encrData.getPtr(), (byte*)data.getPtr(), data.getSize()); //cout << " IV Data : " << iv.toHexStr() << endl; //cout << " Ciphertext: " << encrData.toHexStr() << endl; return encrData; }
///////////////////////////////////////////////////////////////////////////// // Deterministically generate new public key using a chaincode SecureBinaryData CryptoECDSA::ComputeChainedPublicKey( SecureBinaryData const & binPubKey, SecureBinaryData const & chainCode, SecureBinaryData* multiplierOut) { if(CRYPTO_DEBUG) { cout << "ComputeChainedPUBLICKey:" << endl; cout << " BinPub: " << binPubKey.toHexStr() << endl; cout << " BinChn: " << chainCode.toHexStr() << endl; } static SecureBinaryData SECP256K1_ORDER_BE = SecureBinaryData::CreateFromHex( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); // Added extra entropy to chaincode by xor'ing with hash256 of pubkey BinaryData chainMod = binPubKey.getHash256(); BinaryData chainOrig = chainCode.getRawCopy(); BinaryData chainXor(32); for(uint8_t i=0; i<8; i++) { uint8_t offset = 4*i; *(uint32_t*)(chainXor.getPtr()+offset) = *(uint32_t*)( chainMod.getPtr()+offset) ^ *(uint32_t*)(chainOrig.getPtr()+offset); } // Parse the chaincode as a big-endian integer CryptoPP::Integer mult; mult.Decode(chainXor.getPtr(), chainXor.getSize(), UNSIGNED); // "new" init as "old", to make sure it's initialized on the correct curve BTC_PUBKEY oldPubKey = ParsePublicKey(binPubKey); BTC_PUBKEY newPubKey = ParsePublicKey(binPubKey); // Let Crypto++ do the EC math for us, serialize the new public key newPubKey.SetPublicElement( oldPubKey.ExponentiatePublicElement(mult) ); if(multiplierOut != NULL) (*multiplierOut) = SecureBinaryData(chainXor); //LOGINFO << "Computed new chained public key using:"; //LOGINFO << " Public key: " << binPubKey.toHexStr().c_str(); //LOGINFO << " PubKeyHash: " << chainMod.toHexStr().c_str(); //LOGINFO << " Chaincode: " << chainOrig.toHexStr().c_str(); //LOGINFO << " Multiplier: " << chainXor.toHexStr().c_str(); return CryptoECDSA::SerializePublicKey(newPubKey); }
void Payload_Version::setVersionHeaderIPv4(uint32_t version, uint64_t services, int64_t timestamp, const sockaddr& recvaddr, const sockaddr& fromaddr) { vheader_.version_ = version; vheader_.services_ = services; vheader_.timestamp_ = timestamp; vheader_.addr_recv_.setIPv4(services, recvaddr); vheader_.addr_from_.setIPv4(services, fromaddr); auto&& randombytes = SecureBinaryData().GenerateRandom(8); vheader_.nonce_ = *(uint64_t*)randombytes.getPtr(); }
///////////////////////////////////////////////////////////////////////////// // Use the secp256k1 curve to sign data of an arbitrary length. // Input: Data to sign (const SecureBinaryData&) // The private key used to sign the data (const BTC_PRIVKEY&) // A flag indicating if deterministic signing is used (const bool&) // Output: None // Return: The signature of the data (SecureBinaryData) SecureBinaryData CryptoECDSA::SignData(SecureBinaryData const & binToSign, BTC_PRIVKEY const & cppPrivKey, const bool& detSign) { // We trick the Crypto++ ECDSA module by passing it a single-hashed // message, it will do the second hash before it signs it. This is // exactly what we need. CryptoPP::SHA256 sha256; BTC_PRNG prng; // Execute the first sha256 op -- the signer will do the other one SecureBinaryData hashVal(32); sha256.CalculateDigest(hashVal.getPtr(), binToSign.getPtr(), binToSign.getSize()); // Do we want to use a PRNG or use deterministic signing (RFC 6979)? string signature; if(detSign) { BTC_DETSIGNER signer(cppPrivKey); CryptoPP::StringSource( hashVal.toBinStr(), true, new CryptoPP::SignerFilter( prng, signer, new CryptoPP::StringSink(signature))); } else { BTC_SIGNER signer(cppPrivKey); CryptoPP::StringSource( hashVal.toBinStr(), true, new CryptoPP::SignerFilter( prng, signer, new CryptoPP::StringSink(signature))); } return SecureBinaryData(signature); }
SecureBinaryData CryptoECDSA::SignData(SecureBinaryData const & binToSign, BTC_PRIVKEY const & cppPrivKey) { // We trick the Crypto++ ECDSA module by passing it a single-hashed // message, it will do the second hash before it signs it. This is // exactly what we need. static CryptoPP::SHA256 sha256; static BTC_PRNG prng; // Execute the first sha256 op -- the signer will do the other one SecureBinaryData hashVal(32); sha256.CalculateDigest(hashVal.getPtr(), binToSign.getPtr(), binToSign.getSize()); string signature; BTC_SIGNER signer(cppPrivKey); CryptoPP::StringSource( hashVal.toBinStr(), true, new CryptoPP::SignerFilter( prng, signer, new CryptoPP::StringSink(signature))); return SecureBinaryData(signature); }
///////////////////////////////////////////////////////////////////////////// // Deterministically generate new private key using a chaincode // Changed: added using the hash of the public key to the mix // b/c multiplying by the chaincode alone is too "linear" // (there's no reason to believe it's insecure, but it doesn't // hurt to add some extra entropy/non-linearity to the chain // generation process) SecureBinaryData CryptoECDSA::ComputeChainedPrivateKey( SecureBinaryData const & binPrivKey, SecureBinaryData const & chainCode, SecureBinaryData binPubKey, SecureBinaryData* multiplierOut) { if(CRYPTO_DEBUG) { cout << "ComputeChainedPrivateKey:" << endl; cout << " BinPrv: " << binPrivKey.toHexStr() << endl; cout << " BinChn: " << chainCode.toHexStr() << endl; cout << " BinPub: " << binPubKey.toHexStr() << endl; } if( binPubKey.getSize()==0 ) binPubKey = ComputePublicKey(binPrivKey); if( binPrivKey.getSize() != 32 || chainCode.getSize() != 32) { LOGERR << "***ERROR: Invalid private key or chaincode (both must be 32B)"; LOGERR << "BinPrivKey: " << binPrivKey.getSize(); LOGERR << "BinPrivKey: (not logged for security)"; //LOGERR << "BinPrivKey: " << binPrivKey.toHexStr(); LOGERR << "BinChain : " << chainCode.getSize(); LOGERR << "BinChain : " << chainCode.toHexStr(); } // Adding extra entropy to chaincode by xor'ing with hash256 of pubkey BinaryData chainMod = binPubKey.getHash256(); BinaryData chainOrig = chainCode.getRawCopy(); BinaryData chainXor(32); for(uint8_t i=0; i<8; i++) { uint8_t offset = 4*i; *(uint32_t*)(chainXor.getPtr()+offset) = *(uint32_t*)( chainMod.getPtr()+offset) ^ *(uint32_t*)(chainOrig.getPtr()+offset); } // Hard-code the order of the group static SecureBinaryData SECP256K1_ORDER_BE = SecureBinaryData().CreateFromHex( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); CryptoPP::Integer mult, origPrivExp, ecOrder; // A mult.Decode(chainXor.getPtr(), chainXor.getSize(), UNSIGNED); // B origPrivExp.Decode(binPrivKey.getPtr(), binPrivKey.getSize(), UNSIGNED); // C ecOrder.Decode(SECP256K1_ORDER_BE.getPtr(), SECP256K1_ORDER_BE.getSize(), UNSIGNED); // A*B mod C will get us a new private key exponent CryptoPP::Integer newPrivExponent = a_times_b_mod_c(mult, origPrivExp, ecOrder); // Convert new private exponent to big-endian binary string SecureBinaryData newPrivData(32); newPrivExponent.Encode(newPrivData.getPtr(), newPrivData.getSize(), UNSIGNED); if(multiplierOut != NULL) (*multiplierOut) = SecureBinaryData(chainXor); //LOGINFO << "Computed new chained private key using:"; //LOGINFO << " Public key: " << binPubKey.toHexStr().c_str(); //LOGINFO << " PubKeyHash: " << chainMod.toHexStr().c_str(); //LOGINFO << " Chaincode: " << chainOrig.toHexStr().c_str(); //LOGINFO << " Multiplier: " << chainXor.toHexStr().c_str(); return newPrivData; }
///////////////////////////////////////////////////////////////////////////// // Swap endianness of the bytes in the index range [pos1, pos2) SecureBinaryData SecureBinaryData::copySwapEndian(size_t pos1, size_t pos2) const { return SecureBinaryData(BinaryData::copySwapEndian(pos1, pos2)); }
SecureBinaryData CryptoECDSA::GenerateNewPrivateKey(SecureBinaryData entropy) { return SecureBinaryData().GenerateRandom(32, entropy); }
BTC_PRIVKEY CryptoECDSA::CreateNewPrivateKey(SecureBinaryData entropy) { return ParsePrivateKey(SecureBinaryData().GenerateRandom(32, entropy)); }
void KdfRomix::computeKdfParams(double targetComputeSec, uint32_t maxMemReqts) { // Create a random salt, even though this is probably unnecessary: // the variation in numIter and memReqts is probably effective enough salt_ = SecureBinaryData().GenerateRandom(32); // If target compute is 0s, then this method really only generates // a random salt, and sets the other params to default minimum. if(targetComputeSec == 0) { numIterations_ = 1; memoryReqtBytes_ = 1024; return; } // Here, we pick the largest memory reqt that allows the executing system // to compute the KDF is less than the target time. A maximum can be // specified, in case the target system is likely to be memory-limited // more than compute-speed limited SecureBinaryData testKey("This is an example key to test KDF iteration speed"); // Start the search for a memory value at 1kB memoryReqtBytes_ = 1024; double approxSec = 0; while(approxSec <= targetComputeSec/4 && memoryReqtBytes_ < maxMemReqts) { memoryReqtBytes_ *= 2; sequenceCount_ = memoryReqtBytes_ / hashOutputBytes_; lookupTable_.resize(memoryReqtBytes_); TIMER_RESTART("KDF_Mem_Search"); testKey = DeriveKey_OneIter(testKey); TIMER_STOP("KDF_Mem_Search"); approxSec = TIMER_READ_SEC("KDF_Mem_Search"); } // Recompute here, in case we didn't enter the search above sequenceCount_ = memoryReqtBytes_ / hashOutputBytes_; lookupTable_.resize(memoryReqtBytes_); // Depending on the search above (or if a low max memory was chosen, // we may need to do multiple iterations to achieve the desired compute // time on this system. double allItersSec = 0; uint32_t numTest = 1; while(allItersSec < 0.02) { numTest *= 2; TIMER_RESTART("KDF_Time_Search"); for(uint32_t i=0; i<numTest; i++) { SecureBinaryData testKey("This is an example key to test KDF iteration speed"); testKey = DeriveKey_OneIter(testKey); } TIMER_STOP("KDF_Time_Search"); allItersSec = TIMER_READ_SEC("KDF_Time_Search"); } double perIterSec = allItersSec / numTest; numIterations_ = (uint32_t)(targetComputeSec / (perIterSec+0.0005)); numIterations_ = (numIterations_ < 1 ? 1 : numIterations_); //cout << "System speed test results : " << endl; //cout << " Total test of the KDF took: " << allItersSec*1000 << " ms" << endl; //cout << " to execute: " << numTest << " iterations" << endl; //cout << " Target computation time is: " << targetComputeSec*1000 << " ms" << endl; //cout << " Setting numIterations to: " << numIterations_ << endl; }
BlockDataManagerConfig::BlockDataManagerConfig() : cookie_(SecureBinaryData().GenerateRandom(32).toHexStr()) { selectNetwork("Main"); }
SecureBinaryData CryptoECDSA::GenerateNewPrivateKey(void) { return SecureBinaryData().GenerateRandom(32); }