PaymentCode::PaymentCode(const std::string& base58) { OTData rawCode; App::Me().Crypto().Util().Base58CheckDecode(base58, rawCode); if (81 == rawCode.GetSize()) { uint8_t prependByte, features; rawCode.OTfread(&prependByte, 1); rawCode.OTfread(&version_, 1); rawCode.OTfread(&features, 1); if (features & 0x80) { hasBitmessage_ = true; } OTData key; key.SetSize(33); chain_code_.SetSize(32); OT_ASSERT(33 == key.GetSize()); OT_ASSERT(32 == chain_code_.GetSize()); rawCode.OTfread(static_cast<uint8_t*>(const_cast<void*>(key.GetPointer())), key.GetSize()); rawCode.OTfread(static_cast<uint8_t*>(const_cast<void*>(chain_code_.GetPointer())), chain_code_.GetSize()); ConstructKey(key, chain_code_); if (hasBitmessage_) { rawCode.OTfread(&bitmessage_version_, 1); rawCode.OTfread(&bitmessage_stream_, 1); } } }
// This function will base64 ENCODE theData, // and then Set() that as the string contents. bool OTASCIIArmor::SetData(const OTData & theData, bool bLineBreaks/*=true*/) { return SetAndPackData(theData, bLineBreaks); char * pString = NULL; Release(); if (theData.GetSize() < 1) return true; pString = OT_base64_encode((const uint8_t*)theData.GetPointer(), theData.GetSize(), (bLineBreaks ? 1 : 0)); if (pString) { Set(pString); delete [] pString; pString=NULL; return true; } else { OTLog::Error("Error while base64_encoding in OTASCIIArmor::GetData.\n"); return false; } }
// This function will base64 ENCODE theData, // and then Set() that as the string contents. // Additionally it will pack and compress the data! // bool OTASCIIArmor::SetAndPackData(const OTData & theData, bool bLineBreaks/*=true*/) { char * pString = NULL; Release(); if (theData.GetSize() < 1) return true; // -------------------------------------------------------- OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either. // Here I use the default storage context to create the object (the blob.) // I also originally created OTASCIIArmor::GetPacker() using OTDB_DEFAULT_PACKER, // so I know everything is compatible. // OTDB::Blob * pBlob = dynamic_cast<OTDB::Blob *>(OTDB::CreateObject(OTDB::STORED_OBJ_BLOB)); OT_ASSERT(NULL != pBlob); // Beyond this point, responsible to delete pBlob. OTCleanup<OTDB::Blob> theBlobAngel(*pBlob); // make sure memory is cleaned up. // ---------------------------- pBlob->m_memBuffer.assign(static_cast<const unsigned char *>(theData.GetPointer()), static_cast<const unsigned char *>(theData.GetPointer())+theData.GetSize()); OTDB::PackedBuffer * pBuffer = pPacker->Pack(*pBlob); // Now we PACK our data before compressing/encoding it. if (NULL == pBuffer) { OTLog::Error("Failed packing data in OTASCIIArmor::SetAndPackData. \n"); return false; } OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // make sure memory is cleaned up. // -------------------------------------------------------- const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData()); const size_t theSize = pBuffer->GetSize(); if (NULL != pUint) pString = OTCrypto::It()->Base64Encode(pUint, static_cast<int>(theSize), bLineBreaks); // pString = OT_base64_encode(pUint, static_cast<int> (theSize), (bLineBreaks ? 1 : 0)); else { OTLog::Error("Error while base64_encoding in OTASCIIArmor::SetAndPackData.\n"); return false; } // ------------------------------------- if (NULL != pString) { Set(pString); delete [] pString; pString=NULL; return true; } else { OTLog::Error("Error while base64_encoding in OTASCIIArmor::SetAndPackData.\n"); return false; } }
void PaymentCode::ConstructKey(const OTData& pubkey, const OTData& chaincode) { proto::AsymmetricKey newKey; newKey.set_version(1); newKey.set_type(proto::AKEYTYPE_SECP256K1); newKey.set_mode(proto::KEYMODE_PUBLIC); newKey.set_role(proto::KEYROLE_SIGN); newKey.set_key(pubkey.GetPointer(), pubkey.GetSize()); newKey.set_chaincode(chaincode.GetPointer(), chaincode.GetSize()); OTAsymmetricKey* key = OTAsymmetricKey::KeyFactory(newKey); pubkey_.reset(key); }
serializedAsymmetricKey TrezorCrypto::HDNodeToSerialized( const HDNode& node, const DerivationMode privateVersion) const { serializedAsymmetricKey key = std::make_shared<proto::AsymmetricKey>(); key->set_version(1); key->set_type(proto::AKEYTYPE_SECP256K1); if (privateVersion) { key->set_mode(proto::KEYMODE_PRIVATE); key->set_chaincode(node.chain_code, sizeof(node.chain_code)); OTPassword plaintextKey; plaintextKey.setMemory(node.private_key, sizeof(node.private_key)); OTData encryptedKey; BinarySecret masterPassword( App::Me().Crypto().AES().InstantiateBinarySecretSP()); masterPassword = CryptoSymmetric::GetMasterKey(""); bool encrypted = Libsecp256k1::EncryptPrivateKey( plaintextKey, *masterPassword, encryptedKey); if (encrypted) { key->set_key(encryptedKey.GetPointer(), encryptedKey.GetSize()); } } else { key->set_mode(proto::KEYMODE_PUBLIC); key->set_key(node.public_key, sizeof(node.public_key)); } return key; }
const Identifier PaymentCode::ID() const { uint8_t core[65]{}; OTData pubkey = Pubkey(); OTPassword::safe_memcpy( &core[0], 33, pubkey.GetPointer(), pubkey.GetSize(), false); if (chain_code_.GetSize() == 32) { OTPassword::safe_memcpy( &core[33], 32, chain_code_.GetPointer(), chain_code_.GetSize(), false); } OTData dataVersion(core, sizeof(core)); Identifier paymentCodeID; paymentCodeID.CalculateDigest(dataVersion); return paymentCodeID; }
const std::string PaymentCode::asBase58() const { OTData pubkey = Pubkey(); uint8_t serialized[81]{}; serialized[0] = PaymentCode::BIP47_VERSION_BYTE; serialized[1] = version_; serialized[2] = hasBitmessage_ ? 0x80 : 0; OTPassword::safe_memcpy( &serialized[3], 33, pubkey.GetPointer(), pubkey.GetSize(), false); OTPassword::safe_memcpy( &serialized[36], 32, chain_code_.GetPointer(), chain_code_.GetSize(), false); serialized[68] = bitmessage_version_; serialized[69] = bitmessage_stream_; OTData binaryVersion(serialized, sizeof(serialized)); return App::Me().Crypto().Util().Base58CheckEncode(binaryVersion).Get(); }
int32_t OTPassword::setMemory(const OTData& data) { const uint32_t dataSize = data.GetSize(); uint32_t returnedSize = dataSize; bool memorySet = setMemory(data.GetPointer(), returnedSize); // TODO maybe we should check for truncation? return memorySet; }
uint32_t OTPayload::ReadBytesFrom(OTData & theData, uint32_t lSize) { // The size requested to read MUST be less or equal to size of theData if (theData.GetSize() < lSize) abort(); OTPayload & refPayload = (OTPayload &)theData; // Copy from theData to this, up until lSize Assign(refPayload.GetPayloadPointer(), lSize); // Create a temp var, starting from theData+lSize, copying to the end of theData OTData TEMPdata((unsigned char *)refPayload.GetPayloadPointer() + lSize, theData.GetSize() - lSize); // theData is assigned to TEMPdata (thus removing from it the bytes that we just read into this.) theData.Assign(TEMPdata); return lSize; }
// Base64-encode bool OTASCIIArmor::SetData(const OTData& theData, bool bLineBreaks) { Release(); if (theData.GetSize() < 1) return true; char* pString = App::Me().Crypto().Util().Base64Encode( static_cast<const uint8_t*>(theData.GetPointer()), theData.GetSize(), bLineBreaks); if (!pString) { otErr << __FUNCTION__ << "Base64Encode fail\n"; return false; } Set(pString); delete[] pString; return true; }
const OTData PaymentCode::Pubkey() const { OTData pubkey; pubkey.SetSize(33); if (pubkey_) { std::dynamic_pointer_cast<AsymmetricKeySecp256k1>(pubkey_)->GetKey(pubkey); } OT_ASSERT(33 == pubkey.GetSize()); return pubkey; }
SerializedPaymentCode PaymentCode::Serialize() const { SerializedPaymentCode serialized = std::make_shared<proto::PaymentCode>(); serialized->set_version(version_); if (pubkey_) { OTData pubkey = Pubkey(); serialized->set_key(pubkey.GetPointer(), pubkey.GetSize()); } serialized->set_chaincode(chain_code_.GetPointer(), chain_code_.GetSize()); serialized->set_bitmessageversion(bitmessage_version_); serialized->set_bitmessagestream(bitmessage_stream_); return serialized; }
bool Identifier::CalculateDigest(const OTData& dataInput) { auto dataPtr = static_cast<const unsigned char*>(dataInput.GetPointer()); return CalculateDigest(dataPtr, dataInput.GetSize()); }
bool OTEnvelope::Decrypt(String& theOutput, const OTSymmetricKey& theKey, const OTPassword& thePassword) { const char* szFunc = "OTEnvelope::Decrypt"; OT_ASSERT( (thePassword.isPassword() && (thePassword.getPasswordSize() > 0)) || (thePassword.isMemory() && (thePassword.getMemorySize() > 0))); OT_ASSERT(theKey.IsGenerated()); OTPassword theRawSymmetricKey; if (false == theKey.GetRawKeyFromPassphrase(thePassword, theRawSymmetricKey)) { otErr << szFunc << ": Failed trying to retrieve raw symmetric key " "using password. (Wrong password?)\n"; return false; } uint32_t nRead = 0; uint32_t nRunningTotal = 0; m_dataContents.reset(); // Reset the fread position on this object to 0. // // Read the ENVELOPE TYPE (as network order version -- and convert to host // version.) // // 0 == Error // 1 == Asymmetric Key (this function -- Seal / Open) // 2 == Symmetric Key (other functions -- Encrypt / Decrypt use this.) // Anything else: error. // uint16_t env_type_n = 0; if (0 == (nRead = m_dataContents.OTfread( reinterpret_cast<uint8_t*>(&env_type_n), static_cast<uint32_t>(sizeof(env_type_n))))) { otErr << szFunc << ": Error reading Envelope Type. Expected " "asymmetric(1) or symmetric (2).\n"; return false; } nRunningTotal += nRead; OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(env_type_n))); // convert that envelope type from network to HOST endian. // const uint16_t env_type = ntohs(env_type_n); // nRunningTotal += env_type; // NOPE! Just because envelope type is 1 // or 2, doesn't mean we add 1 or 2 extra bytes to the length here. Nope! if (2 != env_type) { const uint32_t l_env_type = static_cast<uint32_t>(env_type); otErr << szFunc << ": Error: Expected Envelope for Symmetric key (type " "2) but instead found type: " << l_env_type << ".\n"; return false; } // Read network-order IV size (and convert to host version) // const uint32_t max_iv_length = OTCryptoConfig::SymmetricIvSize(); // I believe this is a max length, so // it may not match the actual length // of the IV. // Read the IV SIZE (network order version -- convert to host version.) // uint32_t iv_size_n = 0; if (0 == (nRead = m_dataContents.OTfread( reinterpret_cast<uint8_t*>(&iv_size_n), static_cast<uint32_t>(sizeof(iv_size_n))))) { otErr << szFunc << ": Error reading IV Size.\n"; return false; } nRunningTotal += nRead; OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(iv_size_n))); // convert that iv size from network to HOST endian. // const uint32_t iv_size_host_order = ntohl(iv_size_n); if (iv_size_host_order > max_iv_length) { otErr << szFunc << ": Error: iv_size (" << static_cast<int64_t>(iv_size_host_order) << ") is larger than max_iv_length (" << static_cast<int64_t>(max_iv_length) << ").\n"; return false; } // nRunningTotal += iv_size_host_order; // Nope! // Then read the IV (initialization vector) itself. // OTData theIV; theIV.SetSize(iv_size_host_order); if (0 == (nRead = m_dataContents.OTfread( static_cast<uint8_t*>(const_cast<void*>(theIV.GetPointer())), static_cast<uint32_t>(iv_size_host_order)))) { otErr << szFunc << ": Error reading initialization vector.\n"; return false; } nRunningTotal += nRead; OT_ASSERT(nRead == static_cast<uint32_t>(iv_size_host_order)); OT_ASSERT(nRead <= max_iv_length); // We create an OTData object to store the ciphertext itself, which // begins AFTER the end of the IV. // So we see pointer + nRunningTotal as the starting point for the // ciphertext. // the size of the ciphertext, meanwhile, is the size of the entire thing, // MINUS nRunningTotal. // OTData theCipherText( static_cast<const void*>( static_cast<const uint8_t*>(m_dataContents.GetPointer()) + nRunningTotal), m_dataContents.GetSize() - nRunningTotal); // Now we've got all the pieces together, let's try to decrypt it... // OTData thePlaintext; // for output. const bool bDecrypted = OTCrypto::It()->Decrypt( theRawSymmetricKey, // The symmetric key, in clear form. static_cast<const char*>( theCipherText.GetPointer()), // This is the Ciphertext. theCipherText.GetSize(), theIV, thePlaintext); // OUTPUT. (Recovered plaintext.) You can pass // OTPassword& OR OTData& here (either will // work.) // theOutput is where we'll put the decrypted data. // theOutput.Release(); if (bDecrypted) { // Make sure it's null-terminated... // uint32_t nIndex = thePlaintext.GetSize() - 1; (static_cast<uint8_t*>( const_cast<void*>(thePlaintext.GetPointer())))[nIndex] = '\0'; // Set it into theOutput (to return the plaintext to the caller) // theOutput.Set(static_cast<const char*>(thePlaintext.GetPointer())); } return bDecrypted; }
bool OTEnvelope::Encrypt(const String& theInput, OTSymmetricKey& theKey, const OTPassword& thePassword) { OT_ASSERT( (thePassword.isPassword() && (thePassword.getPasswordSize() > 0)) || (thePassword.isMemory() && (thePassword.getMemorySize() > 0))); OT_ASSERT(theInput.Exists()); // Generate a random initialization vector. // OTData theIV; if (!theIV.Randomize(OTCryptoConfig::SymmetricIvSize())) { otErr << __FUNCTION__ << ": Failed trying to randomly generate IV.\n"; return false; } // If the symmetric key hasn't already been generated, we'll just do that // now... // (The passphrase is used to derive another key that is used to encrypt the // actual symmetric key, and to access it later.) // if ((false == theKey.IsGenerated()) && (false == theKey.GenerateKey(thePassword))) { otErr << __FUNCTION__ << ": Failed trying to generate symmetric key using password.\n"; return false; } if (!theKey.HasHashCheck()) { if (!theKey.GenerateHashCheck(thePassword)) { otErr << __FUNCTION__ << ": Failed trying to generate hash check using password.\n"; return false; } } OT_ASSERT(theKey.HasHashCheck()); OTPassword theRawSymmetricKey; if (false == theKey.GetRawKeyFromPassphrase(thePassword, theRawSymmetricKey)) { otErr << __FUNCTION__ << ": Failed trying to retrieve raw symmetric " "key using password.\n"; return false; } OTData theCipherText; const bool bEncrypted = OTCrypto::It()->Encrypt( theRawSymmetricKey, // The symmetric key, in clear form. theInput.Get(), // This is the Plaintext. theInput.GetLength() + 1, // for null terminator theIV, // Initialization vector. theCipherText); // OUTPUT. (Ciphertext.) // // Success? // if (!bEncrypted) { otErr << __FUNCTION__ << ": (static) call failed to encrypt. Wrong " "key? (Returning false.)\n"; return false; } // This is where the envelope final contents will be placed, // including the envelope type, the size of the IV, the IV // itself, and the ciphertext. // m_dataContents.Release(); // Write the ENVELOPE TYPE (network order version.) // // 0 == Error // 1 == Asymmetric Key (other functions -- Seal / Open.) // 2 == Symmetric Key (this function -- Encrypt / Decrypt.) // Anything else: error. // Calculate "network-order" version of envelope type 2. uint16_t env_type_n = htons(static_cast<uint16_t>(2)); m_dataContents.Concatenate(reinterpret_cast<void*>(&env_type_n), // (uint32_t here is the 2nd parameter to // Concatenate, and has nothing to do with // env_type_n being uint16_t) static_cast<uint32_t>(sizeof(env_type_n))); // Write IV size (in network-order) // uint32_t ivlen = OTCryptoConfig::SymmetricIvSize(); // Length of IV for this cipher... OT_ASSERT(ivlen >= theIV.GetSize()); uint32_t ivlen_n = htonl( theIV.GetSize()); // Calculate "network-order" version of iv length. m_dataContents.Concatenate(reinterpret_cast<void*>(&ivlen_n), static_cast<uint32_t>(sizeof(ivlen_n))); // Write the IV itself. // m_dataContents.Concatenate(theIV.GetPointer(), theIV.GetSize()); // Write the Ciphertext. // m_dataContents.Concatenate(theCipherText.GetPointer(), theCipherText.GetSize()); // We don't write the size of the ciphertext before the ciphertext itself, // since the decryption is able to deduce the size based on the total // envelope // size minus the other pieces. We might still want to add that size here, // however. // (for security / safety reasons.) return true; }
bool OTEnvelope::Open(const OTPseudonym & theRecipient, OTString & theContents) { bool retval = false; EVP_CIPHER_CTX ctx; unsigned char buffer[4096]; unsigned char buffer_out[4096 + EVP_MAX_IV_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; size_t len = 0; int len_out = 0; unsigned char * ek = NULL; int eklen = 0; uint32_t eklen_n = 0; memset(buffer, 0, 4096); memset(buffer_out, 0, 4096 + EVP_MAX_IV_LENGTH); memset(iv, 0, EVP_MAX_IV_LENGTH); OTAsymmetricKey & privateKey = (OTAsymmetricKey &)theRecipient.GetPrivateKey(); EVP_PKEY * pkey = (EVP_PKEY *)privateKey.GetKey(); if (NULL == pkey) { OTLog::Error("Null private key in OTEnvelope::Open\n"); return false; } EVP_CIPHER_CTX_init(&ctx); ek = (unsigned char*)malloc(EVP_PKEY_size(pkey)); // I assume this is for the AES key OT_ASSERT(NULL != ek); memset(ek, 0, EVP_PKEY_size(pkey)); eklen = EVP_PKEY_size(pkey); //int EVP_OpenInit(EVP_CIPHER_CTX *ctx, //EVP_CIPHER *type, //unsigned char *ek, //int ekl, //unsigned char *iv, //EVP_PKEY *priv); //EVP_OpenInit() initializes a cipher context ctx for decryption with cipher type. It decrypts the encrypted // symmetric key of length ekl bytes passed in the ek parameter using the private key priv. The IV is supplied // in the iv parameter. theContents.Release(); // This is where we'll put the decrypted data. m_dataContents.reset(); // reset the fread position on this object. int nReadLength = 0; int nReadKey = 0; int nReadIV = 0; // First we read the encrypted key size. if (0 == (nReadLength = m_dataContents.OTfread((char*)&eklen_n, sizeof(eklen_n)))) { OTLog::Error("Error reading encrypted key size in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } // convert it from network to host endian. eklen = ntohl(eklen_n); // Next we read the encrypted key itself. if (0 == (nReadKey = m_dataContents.OTfread((char*)ek, eklen))) { OTLog::Error("Error reading encrypted key size in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } // Next we read the initialization vector. if (0 == (nReadIV = m_dataContents.OTfread((char*)iv, EVP_CIPHER_iv_length(EVP_aes_128_cbc())))) { OTLog::Error("Error reading initialization vector in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } OTData ciphertext((const void*)((unsigned char *)m_dataContents.GetPointer() + nReadLength + nReadKey + nReadIV), m_dataContents.GetSize() - nReadLength - nReadKey - nReadIV); // Now we process ciphertext and write the decrypted data to plaintext. OTData plaintext; if (!EVP_OpenInit(&ctx, EVP_aes_128_cbc(), ek, eklen, iv, pkey)) { OTLog::Error("EVP_OpenInit: failed.\n"); free(ek); ek = NULL; return false; } while ((len = ciphertext.OTfread((char*)buffer, sizeof(buffer))) > 0) { if (!EVP_OpenUpdate(&ctx, buffer_out, &len_out, buffer, len)) { OTLog::Error("EVP_OpenUpdate: failed.\n"); free(ek); ek = NULL; return false; } OTData dataOpenUpdate(buffer_out, len_out); plaintext += dataOpenUpdate; } if (!EVP_OpenFinal(&ctx, buffer_out, &len_out)) { OTLog::Error("EVP_OpenFinal: failed.\n"); free(ek); ek = NULL; return false; } OTData dataOpenFinal(buffer_out, len_out); plaintext += dataOpenFinal; // Make sure it's null terminated int nIndex = plaintext.GetSize()-1; ((unsigned char*)plaintext.GetPointer())[nIndex] = 0; // Set it into theContents (to return the plaintext to the caller) theContents.Set((const char *)plaintext.GetPointer()); retval = true; free(ek); ek = NULL; return retval; }