/* * Cipher Modes * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include #include #if defined(BOTAN_HAS_BLOCK_CIPHER) #include #endif #if defined(BOTAN_HAS_AEAD_MODES) #include #endif #if defined(BOTAN_HAS_MODE_CBC) #include #endif #if defined(BOTAN_HAS_MODE_CFB) #include #endif #if defined(BOTAN_HAS_MODE_XTS) #include #endif #if defined(BOTAN_HAS_OPENSSL) #include #endif namespace Botan { std::unique_ptr Cipher_Mode::create_or_throw(const std::string& algo, Cipher_Dir direction, const std::string& provider) { if(auto mode = Cipher_Mode::create(algo, direction, provider)) return mode; throw Lookup_Error("Cipher mode", algo, provider); } std::unique_ptr Cipher_Mode::create(const std::string& algo, Cipher_Dir direction, const std::string& provider) { #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { std::unique_ptr openssl_cipher(make_openssl_cipher_mode(algo, direction)); if(openssl_cipher) return openssl_cipher; if(!provider.empty()) return std::unique_ptr(); } #endif #if defined(BOTAN_HAS_STREAM_CIPHER) if(auto sc = StreamCipher::create(algo)) { return std::unique_ptr(new Stream_Cipher_Mode(sc.release())); } #endif #if defined(BOTAN_HAS_AEAD_MODES) if(auto aead = AEAD_Mode::create(algo, direction)) { return std::unique_ptr(aead.release()); } #endif if(algo.find('/') != std::string::npos) { const std::vector algo_parts = split_on(algo, '/'); const std::string cipher_name = algo_parts[0]; const std::vector mode_info = parse_algorithm_name(algo_parts[1]); if(mode_info.empty()) return std::unique_ptr(); 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 Cipher_Mode::create(mode_name, direction, provider); } #if defined(BOTAN_HAS_BLOCK_CIPHER) SCAN_Name spec(algo); if(spec.arg_count() == 0) { return std::unique_ptr(); } std::unique_ptr bc(BlockCipher::create(spec.arg(0), provider)); if(!bc) { return std::unique_ptr(); } #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 std::unique_ptr(new CTS_Encryption(bc.release())); else return std::unique_ptr(new CTS_Decryption(bc.release())); } else { std::unique_ptr pad(get_bc_pad(padding)); if(pad) { if(direction == ENCRYPTION) return std::unique_ptr(new CBC_Encryption(bc.release(), pad.release())); else return std::unique_ptr(new CBC_Decryption(bc.release(), pad.release())); } } } #endif #if defined(BOTAN_HAS_MODE_XTS) if(spec.algo_name() == "XTS") { if(direction == ENCRYPTION) return std::unique_ptr(new XTS_Encryption(bc.release())); else return std::unique_ptr(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 std::unique_ptr(new CFB_Encryption(bc.release(), feedback_bits)); else return std::unique_ptr(new CFB_Decryption(bc.release(), feedback_bits)); } #endif #endif return std::unique_ptr(); } //static std::vector Cipher_Mode::providers(const std::string& algo_spec) { const std::vector& possible = { "base", "openssl" }; std::vector providers; for(auto&& prov : possible) { std::unique_ptr mode = Cipher_Mode::create(algo_spec, ENCRYPTION, prov); if(mode) { providers.push_back(prov); // available } } return providers; } }