// Encode into PKCS#8 DER ByteString BotanRSAPrivateKey::PKCS8Encode() { ByteString der; createBotanKey(); if (rsa == NULL) return der; #if BOTAN_VERSION_MINOR == 11 const Botan::secure_vector<Botan::byte> ber = Botan::PKCS8::BER_encode(*rsa); #else const Botan::SecureVector<Botan::byte> ber = Botan::PKCS8::BER_encode(*rsa); #endif der.resize(ber.size()); memcpy(&der[0], &ber[0], ber.size()); return der; }
// Decode from PKCS#8 BER bool BotanECDHPrivateKey::PKCS8Decode(const ByteString& ber) { Botan::DataSource_Memory source(ber.const_byte_str(), ber.size()); if (source.end_of_data()) return false; #if BOTAN_VERSION_MINOR == 11 Botan::secure_vector<Botan::byte> keydata; #else Botan::SecureVector<Botan::byte> keydata; #endif Botan::AlgorithmIdentifier alg_id; const Botan::OID oid("1.2.840.10045.2.1"); Botan::ECDH_PrivateKey* key = NULL; try { Botan::BER_Decoder(source) .start_cons(Botan::SEQUENCE) .decode_and_check<size_t>(0, "Unknown PKCS #8 version number") .decode(alg_id) .decode(keydata, Botan::OCTET_STRING) .discard_remaining() .end_cons(); if (keydata.empty()) throw Botan::Decoding_Error("PKCS #8 private key decoding failed"); // Botan defines == but not != ?! if (!(alg_id.oid == oid)) { ERROR_MSG("Decoded private key not ECDH"); return false; } key = new Botan::ECDH_PrivateKey(alg_id, keydata); if (key == NULL) return false; setFromBotan(key); delete key; } catch (std::exception& e) { ERROR_MSG("Decode failed on %s", e.what()); return false; } return true; }
// Decode from PKCS#8 BER bool BotanRSAPrivateKey::PKCS8Decode(const ByteString& ber) { Botan::DataSource_Memory source(ber.const_byte_str(), ber.size()); if (source.end_of_data()) return false; #if BOTAN_VERSION_MINOR == 11 Botan::secure_vector<Botan::byte> keydata; #else Botan::SecureVector<Botan::byte> keydata; #endif Botan::AlgorithmIdentifier alg_id; Botan::RSA_PrivateKey* key = NULL; try { Botan::BER_Decoder(source) .start_cons(Botan::SEQUENCE) .decode_and_check<size_t>(0, "Unknown PKCS #8 version number") .decode(alg_id) .decode(keydata, Botan::OCTET_STRING) .discard_remaining() .end_cons(); if (keydata.empty()) throw Botan::Decoding_Error("PKCS #8 private key decoding failed"); if (Botan::OIDS::lookup(alg_id.oid).compare("RSA")) { ERROR_MSG("Decoded private key not RSA"); return false; } BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG(); key = new Botan::RSA_PrivateKey(alg_id, keydata, *rng->getRNG()); if (key == NULL) return false; setFromBotan(key); delete key; } catch (std::exception& e) { ERROR_MSG("Decode failed on %s", e.what()); return false; } return true; }
// Encode into PKCS#8 DER ByteString BotanGOSTPrivateKey::PKCS8Encode() { ByteString der; createBotanKey(); if (eckey == NULL) return der; // Force EC_DOMPAR_ENC_OID const size_t PKCS8_VERSION = 0; #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,0,0) const std::vector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters); const Botan::secure_vector<Botan::byte> ber = Botan::DER_Encoder() .start_cons(Botan::SEQUENCE) .encode(PKCS8_VERSION) .encode(alg_id) .encode(eckey->private_key_bits(), Botan::OCTET_STRING) .end_cons() .get_contents(); #elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) const std::vector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters); const Botan::secure_vector<Botan::byte> ber = Botan::DER_Encoder() .start_cons(Botan::SEQUENCE) .encode(PKCS8_VERSION) .encode(alg_id) .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING) .end_cons() .get_contents(); #else const Botan::MemoryVector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); const Botan::AlgorithmIdentifier alg_id(eckey->get_oid(), parameters); const Botan::SecureVector<Botan::byte> ber = Botan::DER_Encoder() .start_cons(Botan::SEQUENCE) .encode(PKCS8_VERSION) .encode(alg_id) .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING) .end_cons() .get_contents(); #endif der.resize(ber.size()); memcpy(&der[0], &ber[0], ber.size()); return der; }
// Returns # of bytes of compressed message size_t run_compression(size_t level, Botan::Compression_Algorithm &c, Botan::Decompression_Algorithm &d, const Botan::secure_vector<uint8_t> &msg) { Botan::secure_vector<uint8_t> compressed = msg; c.start(level); c.finish(compressed); const size_t c_size = compressed.size(); Botan::secure_vector<uint8_t> decompressed = compressed; d.start(); d.finish(decompressed); EXPECT_EQ(msg, decompressed) << "compression round tripped"; return c_size; }
// Encode into PKCS#8 DER ByteString BotanECDHPrivateKey::PKCS8Encode() { ByteString der; createBotanKey(); if (eckey == NULL) return der; const size_t PKCS8_VERSION = 0; // No OID for ECDH const Botan::OID oid("1.2.840.10045.2.1"); // Force EC_DOMPAR_ENC_OID #if BOTAN_VERSION_MINOR == 11 const std::vector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); const Botan::AlgorithmIdentifier alg_id(oid, parameters); const Botan::secure_vector<Botan::byte> ber = Botan::DER_Encoder() .start_cons(Botan::SEQUENCE) .encode(PKCS8_VERSION) .encode(alg_id) .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING) .end_cons() .get_contents(); #else const Botan::MemoryVector<Botan::byte> parameters = eckey->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); const Botan::AlgorithmIdentifier alg_id(oid, parameters); const Botan::SecureVector<Botan::byte> ber = Botan::DER_Encoder() .start_cons(Botan::SEQUENCE) .encode(PKCS8_VERSION) .encode(alg_id) .encode(eckey->pkcs8_private_key(), Botan::OCTET_STRING) .end_cons() .get_contents(); #endif der.resize(ber.size()); memcpy(&der[0], &ber[0], ber.size()); return der; }
void go() override { const std::string comp_type = get_arg("type"); const size_t buf_size = get_arg_sz("buf-size"); const size_t comp_level = get_arg_sz("level"); std::unique_ptr<Botan::Compression_Algorithm> compress; compress.reset(Botan::make_compressor(comp_type)); if(!compress) { throw CLI_Error_Unsupported("Compression", comp_type); } const std::string in_file = get_arg("file"); std::ifstream in(in_file, std::ios::binary); if(!in.good()) { throw CLI_IO_Error("reading", in_file); } const std::string out_file = output_filename(in_file, comp_type); std::ofstream out(out_file, std::ios::binary); if(!in.good()) { throw CLI_IO_Error("writing", out_file); } Botan::secure_vector<uint8_t> buf; compress->start(comp_level); while(in.good()) { buf.resize(buf_size); in.read(reinterpret_cast<char*>(&buf[0]), buf.size()); buf.resize(in.gcount()); compress->update(buf); out.write(reinterpret_cast<const char*>(&buf[0]), buf.size()); } buf.clear(); compress->finish(buf); out.write(reinterpret_cast<const char*>(&buf[0]), buf.size()); out.close(); }
void go() override { const size_t buf_size = get_arg_sz("buf-size"); const std::string in_file = get_arg("file"); std::string out_file, suffix; parse_extension(in_file, out_file, suffix); std::ifstream in(in_file, std::ios::binary); if(!in.good()) { throw CLI_IO_Error("reading", in_file); } std::unique_ptr<Botan::Decompression_Algorithm> decompress; decompress.reset(Botan::make_decompressor(suffix)); if(!decompress) { throw CLI_Error_Unsupported("Decompression", suffix); } std::ofstream out(out_file, std::ios::binary); if(!out.good()) { throw CLI_IO_Error("writing", out_file); } Botan::secure_vector<uint8_t> buf; decompress->start(); while(in.good()) { buf.resize(buf_size); in.read(reinterpret_cast<char*>(&buf[0]), buf.size()); buf.resize(in.gcount()); decompress->update(buf); out.write(reinterpret_cast<const char*>(&buf[0]), buf.size()); } buf.clear(); decompress->finish(buf); out.write(reinterpret_cast<const char*>(&buf[0]), buf.size()); out.close(); }
// Decryption functions bool BotanRSA::decrypt(PrivateKey* privateKey, const ByteString& encryptedData, ByteString& data, const AsymMech::Type padding) { // Check if the private key is the right type if (!privateKey->isOfType(BotanRSAPrivateKey::type)) { ERROR_MSG("Invalid key type supplied"); return false; } std::string eme; switch (padding) { case AsymMech::RSA_PKCS: eme = "PKCS1v15"; break; case AsymMech::RSA_PKCS_OAEP: eme = "EME1(SHA-160)"; break; case AsymMech::RSA: eme = "Raw"; break; default: ERROR_MSG("Invalid padding mechanism supplied (%i)", padding); return false; } BotanRSAPrivateKey* pk = (BotanRSAPrivateKey*) privateKey; Botan::RSA_PrivateKey* botanKey = pk->getBotanKey(); if (!botanKey) { ERROR_MSG("Could not get the Botan private key"); return false; } Botan::PK_Decryptor_EME* decryptor = NULL; try { decryptor = new Botan::PK_Decryptor_EME(*botanKey, eme); } catch (...) { ERROR_MSG("Could not create the decryptor token"); return false; } // Perform the decryption operation #if BOTAN_VERSION_MINOR == 11 Botan::secure_vector<Botan::byte> decResult; #else Botan::SecureVector<Botan::byte> decResult; #endif try { decResult = decryptor->decrypt(encryptedData.const_byte_str(), encryptedData.size()); } catch (...) { ERROR_MSG("Could not decrypt the data"); delete decryptor; return false; } // Return the result if (padding == AsymMech::RSA) { // We compensate that Botan removes leading zeros int modSize = pk->getN().size(); int decSize = decResult.size(); data.resize(modSize); #if BOTAN_VERSION_MINOR == 11 memcpy(&data[0] + modSize - decSize, decResult.data(), decSize); #else memcpy(&data[0] + modSize - decSize, decResult.begin(), decSize); #endif } else { data.resize(decResult.size()); #if BOTAN_VERSION_MINOR == 11 memcpy(&data[0], decResult.data(), decResult.size()); #else memcpy(&data[0], decResult.begin(), decResult.size()); #endif } delete decryptor; return true; }
std::vector<unsigned char> Base64::decode(const std::string &str) { bool ignore_ws = true; Botan::secure_vector<Botan::byte> output = Botan::base64_decode(str, ignore_ws); return std::vector<unsigned char>(output.cbegin(), output.cend()); }
// Wrap/Unwrap keys bool BotanAES::wrapKey(const SymmetricKey* key, const SymWrap::Type mode, const ByteString& in, ByteString& out) { // Check key bit length; AES only supports 128, 192 or 256 bit keys if ((key->getBitLen() != 128) && (key->getBitLen() != 192) && (key->getBitLen() != 256)) { ERROR_MSG("Invalid AES key length (%d bits)", key->getBitLen()); return false; } // Determine the wrapping mode if (mode == SymWrap::AES_KEYWRAP) { // RFC 3394 AES key wrap if (in.size() < 16) { ERROR_MSG("key data to wrap too small"); return false; } if ((in.size() % 8) != 0) { ERROR_MSG("key data to wrap not aligned"); return false; } #if BOTAN_VERSION_MINOR == 11 Botan::secure_vector<Botan::byte> data(in.size()); memcpy(data.data(), in.const_byte_str(), in.size()); Botan::secure_vector<Botan::byte> wrapped; #else Botan::MemoryVector<Botan::byte> data(in.size()); memcpy(data.begin(), in.const_byte_str(), in.size()); Botan::SecureVector<Botan::byte> wrapped; #endif Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size()); Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); try { wrapped = Botan::rfc3394_keywrap(data, botanKey, af); } catch (...) { ERROR_MSG("AES key wrap failed"); return false; } out.resize(wrapped.size()); #if BOTAN_VERSION_MINOR == 11 memcpy(&out[0], wrapped.data(), out.size()); #else memcpy(&out[0], wrapped.begin(), out.size()); #endif return true; } #ifdef HAVE_AES_KEY_WRAP_PAD else if (mode == SymWrap::AES_KEYWRAP_PAD) { // RFC 5649 AES key wrap with pad #if BOTAN_VERSION_MINOR == 11 Botan::secure_vector<Botan::byte> data(in.size()); memcpy(data.data(), in.const_byte_str(), in.size()); Botan::secure_vector<Botan::byte> wrapped; #else Botan::MemoryVector<Botan::byte> data(in.size()); memcpy(data.begin(), in.const_byte_str(), in.size()); Botan::SecureVector<Botan::byte> wrapped; #endif Botan::SymmetricKey botanKey = Botan::SymmetricKey(key->getKeyBits().const_byte_str(), key->getKeyBits().size()); Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); try { wrapped = Botan::rfc5649_keywrap(data, botanKey, af); } catch (...) { ERROR_MSG("AES key wrap failed"); return false; } out.resize(wrapped.size()); #if BOTAN_VERSION_MINOR == 11 memcpy(&out[0], wrapped.data(), out.size()); #else memcpy(&out[0], wrapped.begin(), out.size()); #endif return true; } #endif else { ERROR_MSG("unknown AES key wrap mode %i", mode); return false; } }