/* * Library Initialization */ void LibraryInitializer::initialize(const std::string& arg_string) { bool thread_safe = false; const std::vector<std::string> arg_list = split_on(arg_string, ' '); for(u32bit j = 0; j != arg_list.size(); ++j) { if(arg_list[j].size() == 0) continue; std::string name, value; if(arg_list[j].find('=') == std::string::npos) { name = arg_list[j]; value = "true"; } else { std::vector<std::string> name_and_value = split_on(arg_list[j], '='); name = name_and_value[0]; value = name_and_value[1]; } bool is_on = (value == "1" || value == "true" || value == "yes" || value == "on"); if(name == "thread_safe") thread_safe = is_on; } try { /* This two stage initialization process is because Library_State's constructor will implicitly refer to global state through the allocators and so for, so global_state() has to be a valid reference before initialize() can be called. Yeah, gross. */ set_global_state(new Library_State); global_state().initialize(thread_safe); } catch(...) { deinitialize(); throw; } }
/* * Return the hash used in generating the signature */ std::string X509_Object::hash_used_for_signature() const { const OID& oid = m_sig_algo.get_oid(); const std::vector<std::string> sig_info = split_on(OIDS::lookup(oid), '/'); if(sig_info.size() == 1 && sig_info[0] == "Ed25519") return "SHA-512"; else if(sig_info.size() != 2) throw Internal_Error("Invalid name format found for " + oid.as_string()); if(sig_info[1] == "EMSA4") { return OIDS::lookup(decode_pss_params(signature_algorithm().get_parameters()).hash_algo.get_oid()); } else { const std::vector<std::string> pad_and_hash = parse_algorithm_name(sig_info[1]); if(pad_and_hash.size() != 2) { throw Internal_Error("Invalid name format " + sig_info[1]); } return pad_and_hash[1]; } }
SRP6_Authenticator_File::SRP6_Authenticator_File(std::istream& in) { if(!in) return; // no entries while(in.good()) { std::string line; std::getline(in, line); std::vector<std::string> parts = split_on(line, ':'); if(parts.size() != 4) throw Decoding_Error("Invalid line in SRP authenticator file"); std::string username = parts[0]; BigInt v = BigInt::decode(base64_decode(parts[1])); std::vector<byte> salt = unlock(base64_decode(parts[2])); BigInt group_id_idx = BigInt::decode(base64_decode(parts[3])); std::string group_id; if(group_id_idx == 1) group_id = "modp/srp/1024"; else if(group_id_idx == 2) group_id = "modp/srp/1536"; else if(group_id_idx == 3) group_id = "modp/srp/2048"; else continue; // unknown group, ignored m_entries[username] = SRP6_Data(v, salt, group_id); } }
/************************************************* * Initialize the certificate options * *************************************************/ X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, u32bit expiration_time_in_seconds) { is_CA = false; path_limit = 0; constraints = NO_CONSTRAINTS; const u32bit now = system_time(); start = X509_Time(now); end = X509_Time(now + expiration_time_in_seconds); if(initial_opts == "") return; std::vector<std::string> parsed = split_on(initial_opts, '/'); if(parsed.size() > 4) throw Invalid_Argument("X.509 cert options: Too many names: " + initial_opts); if(parsed.size() >= 1) common_name = parsed[0]; if(parsed.size() >= 2) country = parsed[1]; if(parsed.size() >= 3) organization = parsed[2]; if(parsed.size() == 4) org_unit = parsed[3]; }
bool EAC_Signed_Object::check_signature(Public_Key& pub_key, const MemoryRegion<byte>& sig) const { try { std::vector<std::string> sig_info = split_on(OIDS::lookup(sig_algo.oid), '/'); if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name()) { return false; } std::string padding = sig_info[1]; Signature_Format format = (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; SecureVector<byte> to_sign = tbs_data(); PK_Verifier verifier(pub_key, padding, format); return verifier.verify_message(to_sign, sig); } catch(...) { return false; } }
/* * Read a PEM or BER X.509 object */ void X509_Object::init(DataSource& in, const std::string& labels) { m_PEM_labels_allowed = split_on(labels, '/'); if(m_PEM_labels_allowed.size() < 1) throw Invalid_Argument("Bad labels argument to X509_Object"); m_PEM_label_pref = m_PEM_labels_allowed[0]; std::sort(m_PEM_labels_allowed.begin(), m_PEM_labels_allowed.end()); try { if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) { BER_Decoder dec(in); decode_from(dec); } else { std::string got_label; DataSource_Memory ber(PEM_Code::decode(in, got_label)); if(!std::binary_search(m_PEM_labels_allowed.begin(), m_PEM_labels_allowed.end(), got_label)) throw Decoding_Error("Invalid PEM label: " + got_label); BER_Decoder dec(ber); decode_from(dec); } } catch(Decoding_Error& e) { throw Decoding_Error(m_PEM_label_pref + " decoding failed: " + e.what()); } }
Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const { if (m_responses.empty()) return m_dummy_response_status; try { std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key()); const std::vector<std::string> sig_info = split_on(OIDS::lookup(m_sig_algo.get_oid()), '/'); if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) return Certificate_Status_Code::OCSP_RESPONSE_INVALID; std::string padding = sig_info[1]; Signature_Format format = (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; PK_Verifier verifier(*pub_key, padding, format); if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature)) return Certificate_Status_Code::OCSP_SIGNATURE_OK; else return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; } catch(Exception&) { return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; } }
bool GeneralName::matches_ip(const std::string& nam) const { u32bit ip = string_to_ipv4(nam); std::vector<std::string> p = split_on(name(),'/'); if(p.size() != 2) throw Decoding_Error("failed to parse IPv4 address"); u32bit net = string_to_ipv4(p.at(0)); u32bit mask = string_to_ipv4(p.at(1)); return (ip & mask) == net; }
/** * DataSource_Command Constructor */ DataSource_Command::DataSource_Command(const std::string& prog_and_args, const std::vector<std::string>& paths) : MAX_BLOCK_USECS(100000), KILL_WAIT(10000) { arg_list = split_on(prog_and_args, ' '); if(arg_list.size() == 0) throw Invalid_Argument("DataSource_Command: No command given"); if(arg_list.size() > 5) throw Invalid_Argument("DataSource_Command: Too many args"); pipe = 0; create_pipe(paths); }
/* * Win32_Capi_Entropysource Constructor */ Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs) { std::vector<std::string> capi_provs = split_on(provs, ':'); for(size_t i = 0; i != capi_provs.size(); ++i) { if(capi_provs[i] == "RSA_FULL") m_prov_types.push_back(PROV_RSA_FULL); if(capi_provs[i] == "INTEL_SEC") m_prov_types.push_back(PROV_INTEL_SEC); if(capi_provs[i] == "FORTEZZA") m_prov_types.push_back(PROV_FORTEZZA); if(capi_provs[i] == "RNG") m_prov_types.push_back(PROV_RNG); } if(m_prov_types.size() == 0) m_prov_types.push_back(PROV_RSA_FULL); }
/* * Decode PKCS#5 PBES2 parameters */ void PBE_PKCS5v20::decode_params(DataSource& source) { AlgorithmIdentifier kdf_algo, enc_algo; BER_Decoder(source) .start_cons(SEQUENCE) .decode(kdf_algo) .decode(enc_algo) .verify_end() .end_cons(); if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2")) { BER_Decoder(kdf_algo.parameters) .start_cons(SEQUENCE) .decode(salt, OCTET_STRING) .decode(iterations) .decode_optional(key_length, INTEGER, UNIVERSAL) .verify_end() .end_cons(); } else throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + kdf_algo.oid.as_string()); Algorithm_Factory& af = global_state().algorithm_factory(); std::string cipher = OIDS::lookup(enc_algo.oid); std::vector<std::string> cipher_spec = split_on(cipher, '/'); if(cipher_spec.size() != 2) throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); if(!known_cipher(cipher_spec[0]) || cipher_spec[1] != "CBC") throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end(); block_cipher = af.make_block_cipher(cipher_spec[0]); hash_function = af.make_hash_function("SHA-160"); if(key_length == 0) key_length = block_cipher->maximum_keylength(); if(salt.size() < 8) throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); }
/* * Return the hash used in generating the signature */ std::string X509_Object::hash_used_for_signature() const { std::vector<std::string> sig_info = split_on(OIDS::lookup(m_sig_algo.oid), '/'); if(sig_info.size() != 2) throw Internal_Error("Invalid name format found for " + m_sig_algo.oid.as_string()); std::vector<std::string> pad_and_hash = parse_algorithm_name(sig_info[1]); if(pad_and_hash.size() != 2) throw Internal_Error("Invalid name format " + sig_info[1]); return pad_and_hash[1]; }
/* * Win32_Capi_Entropysource Constructor */ Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs) { for(std::string prov_name : split_on(provs, ':')) { DWORD prov_type; if(prov_name == "RSA_FULL") prov_type = PROV_RSA_FULL; else if(prov_name == "INTEL_SEC") prov_type = PROV_INTEL_SEC; else if(prov_name == "RNG") prov_type = PROV_RNG; else continue; m_csp_provs.push_back(std::unique_ptr<CSP_Handle>(new CSP_Handle_Impl(prov_type))); } }
/************************************************* * Convert a decimal-dotted string to binary IP * *************************************************/ u32bit string_to_ipv4(const std::string& str) { std::vector<std::string> parts = split_on(str, '.'); if(parts.size() != 4) throw Decoding_Error("Invalid IP string " + str); u32bit ip = 0; for(size_t j = 0; j != parts.size(); j++) { u32bit octet = to_u32bit(parts[j]); if(octet > 255) throw Decoding_Error("Invalid IP string " + str); ip = (ip << 8) | (octet & 0xFF); } return ip; }
/* * Convert a decimal-dotted string to binary IP */ u32bit string_to_ipv4(const std::string& str) { std::vector<std::string> parts = split_on(str, '.'); if(parts.size() != 4) throw Decoding_Error("Invalid IP string " + str); u32bit ip = 0; for(auto part = parts.begin(); part != parts.end(); ++part) { u32bit octet = to_u32bit(*part); if(octet > 255) throw Decoding_Error("Invalid IP string " + str); ip = (ip << 8) | (octet & 0xFF); } return ip; }
/* * Check the signature on an object */ bool X509_Object::check_signature(const Public_Key& pub_key) const { try { std::vector<std::string> sig_info = split_on(OIDS::lookup(m_sig_algo.oid), '/'); if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name()) return false; std::string padding = sig_info[1]; Signature_Format format = (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; PK_Verifier verifier(pub_key, padding, format); return verifier.verify_message(tbs_data(), signature()); } catch(std::exception&) { return false; } }
static int with_tokens(const char *str, const char *sep, int (*cb)(char **, int n)) { char *tokens[64] = { NULL }; int n = 0, i, ret; void push_back_ptr(char *ptr) { if (n < 64) tokens[n++] = ptr; } split_on(str, sep, push_back_ptr); ret = cb(tokens, n); for(i = 0; i < n; ++i) { free(tokens[i]); } return ret; }
secure_vector<uint8_t> pbes2_decrypt(const secure_vector<uint8_t>& key_bits, const std::string& passphrase, const std::vector<uint8_t>& params) { AlgorithmIdentifier kdf_algo, enc_algo; BER_Decoder(params) .start_cons(SEQUENCE) .decode(kdf_algo) .decode(enc_algo) .end_cons(); const std::string cipher = OIDS::lookup(enc_algo.get_oid()); const std::vector<std::string> cipher_spec = split_on(cipher, '/'); if(cipher_spec.size() != 2) throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); if(!known_pbes_cipher_mode(cipher_spec[1])) throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); secure_vector<uint8_t> iv; BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end(); std::unique_ptr<Cipher_Mode> dec = Cipher_Mode::create(cipher, DECRYPTION); if(!dec) throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher); dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength())); dec->start(iv); secure_vector<uint8_t> buf = key_bits; dec->finish(buf); return buf; }
Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const { const std::vector<std::string> sig_info = split_on(OIDS::lookup(m_sig_algo.get_oid()), '/'); if(sig_info.size() < 1 || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name()) return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; std::string padding; if(sig_info.size() == 2) padding = sig_info[1]; else if(sig_info[0] == "Ed25519") padding = "Pure"; else return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; const Signature_Format format = (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; if(padding == "EMSA4") { // "MUST contain RSASSA-PSS-params" if(signature_algorithm().parameters.empty()) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } Pss_params pss_parameter = decode_pss_params(signature_algorithm().parameters); // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 const std::string hash_algo = OIDS::lookup(pss_parameter.hash_algo.oid); if(hash_algo != "SHA-160" && hash_algo != "SHA-224" && hash_algo != "SHA-256" && hash_algo != "SHA-384" && hash_algo != "SHA-512") { return Certificate_Status_Code::UNTRUSTED_HASH; } const std::string mgf_algo = OIDS::lookup(pss_parameter.mask_gen_algo.oid); if(mgf_algo != "MGF1") { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 if(pss_parameter.mask_gen_hash.oid != pss_parameter.hash_algo.oid) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } if(pss_parameter.trailer_field != 1) { return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; } // salt_len is actually not used for verification. Length is inferred from the signature padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")"; } try { PK_Verifier verifier(pub_key, padding, format); const bool valid = verifier.verify_message(tbs_data(), signature()); if(valid) return Certificate_Status_Code::VERIFIED; else return Certificate_Status_Code::SIGNATURE_ERROR; } catch(Algorithm_Not_Found&) { return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN; } catch(...) { // This shouldn't happen, fallback to generic signature error return Certificate_Status_Code::SIGNATURE_ERROR; } }
bool Ciphersuite::valid() const { if(!m_cipher_keylen) // uninitialized object return false; if(!have_hash(prf_algo())) return false; if(mac_algo() == "AEAD") { if(cipher_algo() == "ChaCha20Poly1305") { #if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) return false; #endif } else { auto cipher_and_mode = split_on(cipher_algo(), '/'); BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); if(!have_cipher(cipher_and_mode[0])) return false; const auto mode = cipher_and_mode[1]; #if !defined(BOTAN_HAS_AEAD_CCM) if(mode == "CCM" || mode == "CCM-8") return false; #endif #if !defined(BOTAN_HAS_AEAD_GCM) if(mode == "GCM") return false; #endif #if !defined(BOTAN_HAS_AEAD_OCB) if(mode == "OCB(12)" || mode == "OCB") return false; #endif } } else { // Old non-AEAD schemes if(!have_cipher(cipher_algo())) return false; if(!have_hash(mac_algo())) // HMAC return false; } if(kex_algo() == "SRP_SHA") { #if !defined(BOTAN_HAS_SRP6) return false; #endif } else if(kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK") { #if !defined(BOTAN_HAS_ECDH) return false; #endif } else if(kex_algo() == "DH" || kex_algo() == "DHE_PSK") { #if !defined(BOTAN_HAS_DIFFIE_HELLMAN) return false; #endif } if(sig_algo() == "DSA") { #if !defined(BOTAN_HAS_DSA) return false; #endif } else if(sig_algo() == "ECDSA") { #if !defined(BOTAN_HAS_ECDSA) return false; #endif } else if(sig_algo() == "RSA") { #if !defined(BOTAN_HAS_RSA) return false; #endif } return true; }
Cipher_Mode* get_cipher_mode(const std::string& algo_spec, Cipher_Dir direction) { const std::string provider = ""; const char* dir_string = (direction == ENCRYPTION) ? "_Encryption" : "_Decryption"; Cipher_Mode::Spec spec(algo_spec, dir_string); std::unique_ptr<Cipher_Mode> cipher_mode( Algo_Registry<Cipher_Mode>::global_registry().make( Cipher_Mode::Spec(algo_spec, dir_string), provider) ); if(cipher_mode) { return cipher_mode.release(); } const std::vector<std::string> algo_parts = split_on(algo_spec, '/'); if(algo_parts.size() < 2) return nullptr; const std::string cipher_name = algo_parts[0]; const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]); if(mode_info.empty()) return nullptr; std::ostringstream alg_args; alg_args << '(' << cipher_name; for(size_t i = 1; i < mode_info.size(); ++i) alg_args << ',' << mode_info[i]; for(size_t i = 2; i < algo_parts.size(); ++i) alg_args << ',' << algo_parts[i]; alg_args << ')'; const std::string mode_name = mode_info[0] + alg_args.str(); const std::string mode_name_directional = mode_info[0] + dir_string + alg_args.str(); cipher_mode.reset( Algo_Registry<Cipher_Mode>::global_registry().make( Cipher_Mode::Spec(mode_name_directional), provider) ); if(cipher_mode) { return cipher_mode.release(); } cipher_mode.reset( Algo_Registry<Cipher_Mode>::global_registry().make( Cipher_Mode::Spec(mode_name), provider) ); if(cipher_mode) { return cipher_mode.release(); } if(auto sc = StreamCipher::create(mode_name, provider)) { return new Stream_Cipher_Mode(sc.release()); } return nullptr; }
std::unique_ptr<Public_Key> load_public_key(const AlgorithmIdentifier& alg_id, const std::vector<uint8_t>& key_bits) { const std::vector<std::string> alg_info = split_on(OIDS::lookup(alg_id.get_oid()), '/'); if(alg_info.empty()) throw Decoding_Error("Unknown algorithm OID: " + alg_id.get_oid().to_string()); const std::string alg_name = alg_info[0]; #if defined(BOTAN_HAS_RSA) if(alg_name == "RSA") return std::unique_ptr<Public_Key>(new RSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_CURVE_25519) if(alg_name == "Curve25519") return std::unique_ptr<Public_Key>(new Curve25519_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_MCELIECE) if(alg_name == "McEliece") return std::unique_ptr<Public_Key>(new McEliece_PublicKey(key_bits)); #endif #if defined(BOTAN_HAS_ECDSA) if(alg_name == "ECDSA") return std::unique_ptr<Public_Key>(new ECDSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECDH) if(alg_name == "ECDH") return std::unique_ptr<Public_Key>(new ECDH_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_DIFFIE_HELLMAN) if(alg_name == "DH") return std::unique_ptr<Public_Key>(new DH_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_DSA) if(alg_name == "DSA") return std::unique_ptr<Public_Key>(new DSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ELGAMAL) if(alg_name == "ElGamal") return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECGDSA) if(alg_name == "ECGDSA") return std::unique_ptr<Public_Key>(new ECGDSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ECKCDSA) if(alg_name == "ECKCDSA") return std::unique_ptr<Public_Key>(new ECKCDSA_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_ED25519) if(alg_name == "Ed25519") return std::unique_ptr<Public_Key>(new Ed25519_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_GOST_34_10_2001) if(alg_name == "GOST-34.10") return std::unique_ptr<Public_Key>(new GOST_3410_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_SM2) if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") return std::unique_ptr<Public_Key>(new SM2_PublicKey(alg_id, key_bits)); #endif #if defined(BOTAN_HAS_XMSS) if(alg_name == "XMSS") return std::unique_ptr<Public_Key>(new XMSS_PublicKey(key_bits)); #endif throw Decoding_Error("Unhandled PK algorithm " + alg_name); }
Cipher_Mode* get_cipher_mode(const std::string& algo, Cipher_Dir direction) { if(auto sc = StreamCipher::create(algo)) { return new Stream_Cipher_Mode(sc.release()); } #if defined(BOTAN_HAS_AEAD_MODES) if(auto aead = get_aead(algo, direction)) { return aead; } #endif if(algo.find('/') != std::string::npos) { const std::vector<std::string> algo_parts = split_on(algo, '/'); const std::string cipher_name = algo_parts[0]; const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]); if(mode_info.empty()) return nullptr; std::ostringstream alg_args; alg_args << '(' << cipher_name; for(size_t i = 1; i < mode_info.size(); ++i) alg_args << ',' << mode_info[i]; for(size_t i = 2; i < algo_parts.size(); ++i) alg_args << ',' << algo_parts[i]; alg_args << ')'; const std::string mode_name = mode_info[0] + alg_args.str(); return get_cipher_mode(mode_name, direction); } #if defined(BOTAN_HAS_BLOCK_CIPHER) SCAN_Name spec(algo); if(spec.arg_count() == 0) { return nullptr; } std::unique_ptr<BlockCipher> bc(BlockCipher::create(spec.arg(0))); if(!bc) { return nullptr; } #if defined(BOTAN_HAS_MODE_CBC) if(spec.algo_name() == "CBC") { const std::string padding = spec.arg(1, "PKCS7"); if(padding == "CTS") { if(direction == ENCRYPTION) return new CTS_Encryption(bc.release()); else return new CTS_Decryption(bc.release()); } else { std::unique_ptr<BlockCipherModePaddingMethod> pad(get_bc_pad(padding)); if(pad) { if(direction == ENCRYPTION) return new CBC_Encryption(bc.release(), pad.release()); else return new CBC_Decryption(bc.release(), pad.release()); } } } #endif #if defined(BOTAN_HAS_MODE_XTS) if(spec.algo_name() == "XTS") { if(direction == ENCRYPTION) return new XTS_Encryption(bc.release()); else return new XTS_Decryption(bc.release()); } #endif #if defined(BOTAN_HAS_MODE_CFB) if(spec.algo_name() == "CFB") { const size_t feedback_bits = spec.arg_as_integer(1, 8*bc->block_size()); if(direction == ENCRYPTION) return new CFB_Encryption(bc.release(), feedback_bits); else return new CFB_Decryption(bc.release(), feedback_bits); } #endif #endif return nullptr; }
secure_vector<uint8_t> pbes2_decrypt(const secure_vector<uint8_t>& key_bits, const std::string& passphrase, const std::vector<uint8_t>& params) { AlgorithmIdentifier kdf_algo, enc_algo; BER_Decoder(params) .start_cons(SEQUENCE) .decode(kdf_algo) .decode(enc_algo) .end_cons(); AlgorithmIdentifier prf_algo; if(kdf_algo.oid != OIDS::lookup("PKCS5.PBKDF2")) throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + kdf_algo.oid.as_string()); secure_vector<uint8_t> salt; size_t iterations = 0, key_length = 0; BER_Decoder(kdf_algo.parameters) .start_cons(SEQUENCE) .decode(salt, OCTET_STRING) .decode(iterations) .decode_optional(key_length, INTEGER, UNIVERSAL) .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED, AlgorithmIdentifier("HMAC(SHA-160)", AlgorithmIdentifier::USE_NULL_PARAM)) .end_cons(); const std::string cipher = OIDS::lookup(enc_algo.oid); const std::vector<std::string> cipher_spec = split_on(cipher, '/'); if(cipher_spec.size() != 2) throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM") throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); if(salt.size() < 8) throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); secure_vector<uint8_t> iv; BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end(); const std::string prf = OIDS::lookup(prf_algo.oid); std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")")); std::unique_ptr<Cipher_Mode> dec(get_cipher_mode(cipher, DECRYPTION)); if(!dec) throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher); if(key_length == 0) key_length = dec->key_spec().maximum_keylength(); dec->set_key(pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations)); dec->start(iv); secure_vector<uint8_t> buf = key_bits; dec->finish(buf); return buf; }