secure_vector<byte> mceies_decrypt(const McEliece_PrivateKey& privkey, const byte ct[], size_t ct_len, const byte ad[], size_t ad_len, const std::string& algo) { try { McEliece_KEM_Decryptor kem_op(privkey); const size_t mce_code_bytes = (privkey.get_code_length() + 7) / 8; std::unique_ptr<AEAD_Mode> aead(get_aead(algo, DECRYPTION)); if(!aead) throw std::runtime_error("Unable to create AEAD instance '" + algo + "'"); const size_t nonce_len = aead->default_nonce_length(); if(ct_len < mce_code_bytes + nonce_len + aead->tag_size()) throw std::runtime_error("Input message too small to be valid"); const secure_vector<byte> mce_key = kem_op.decrypt(ct, mce_code_bytes); aead->set_key(aead_key(mce_key, *aead)); aead->set_associated_data(ad, ad_len); secure_vector<byte> pt(ct + mce_code_bytes + nonce_len, ct + ct_len); aead->start(&ct[mce_code_bytes], nonce_len); aead->finish(pt, 0); return pt; } catch(std::exception& e) { throw std::runtime_error("mce_decrypt failed: " + std::string(e.what())); } }
secure_vector<byte> mceies_encrypt(const McEliece_PublicKey& pubkey, const byte pt[], size_t pt_len, const byte ad[], size_t ad_len, RandomNumberGenerator& rng, const std::string& algo) { McEliece_KEM_Encryptor kem_op(pubkey); const std::pair<secure_vector<byte>,secure_vector<byte>> mce_ciphertext__key = kem_op.encrypt(rng); const secure_vector<byte>& mce_ciphertext = mce_ciphertext__key.first; const secure_vector<byte>& mce_key = mce_ciphertext__key.second; const size_t mce_code_bytes = (pubkey.get_code_length() + 7) / 8; BOTAN_ASSERT(mce_ciphertext.size() == mce_code_bytes, "Unexpected size"); std::unique_ptr<AEAD_Mode> aead(get_aead(algo, ENCRYPTION)); if(!aead) throw std::runtime_error("mce_encrypt unable to create AEAD instance '" + algo + "'"); const size_t nonce_len = aead->default_nonce_length(); aead->set_key(aead_key(mce_key, *aead)); aead->set_associated_data(ad, ad_len); const secure_vector<byte> nonce = rng.random_vec(nonce_len); secure_vector<byte> msg(mce_ciphertext.size() + nonce.size() + pt_len); copy_mem(msg.data(), mce_ciphertext.data(), mce_ciphertext.size()); copy_mem(msg.data() + mce_ciphertext.size(), nonce.data(), nonce.size()); copy_mem(msg.data() + mce_ciphertext.size() + nonce.size(), pt, pt_len); aead->start(nonce); aead->finish(msg, mce_ciphertext.size() + nonce.size()); return msg; }
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; }