void XTS_Decryption::set_key(const SymmetricKey& key) { u32bit key_half = key.length() / 2; if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half)) throw Invalid_Key_Length(name(), key.length()); cipher->set_key(key.begin(), key_half); cipher2->set_key(key.begin() + key_half, key_half); }
bool ne7ssh_crypt::makeKexSecret (Botan::SecureVector<Botan::byte> &result, Botan::BigInt &f) { PK_Key_Agreement key_agreement(*privKexKey, "Raw"); SymmetricKey negotiated = key_agreement.derive_key(32, (byte*)f.data(), f.bytes(), ""); // SymmetricKey negotiated = privKexKey->derive_key (f); if (!negotiated.length()) return false; BigInt Kint (negotiated.begin(), negotiated.length()); ne7ssh_string::bn2vector(result, Kint); K = Botan::SecureVector<Botan::byte>(result); delete privKexKey; privKexKey = 0; return true; }
void Transform_Filter::set_key(const SymmetricKey& key) { if(Keyed_Transform* keyed = dynamic_cast<Keyed_Transform*>(m_transform.get())) keyed->set_key(key); else if(key.length() != 0) throw std::runtime_error("Transform " + name() + " does not accept keys"); }
void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply, const QByteArray &clientId) { const SshKeyExchangeReply &reply = dhReply.extractKeyExchangeReply(m_serverHostKeyAlgo); if (reply.f <= 0 || reply.f >= m_dhKey->group_p()) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Server sent invalid f."); } QByteArray concatenatedData = AbstractSshPacket::encodeString(clientId); concatenatedData += AbstractSshPacket::encodeString(m_serverId); concatenatedData += AbstractSshPacket::encodeString(m_clientKexInitPayload); concatenatedData += AbstractSshPacket::encodeString(m_serverKexInitPayload); concatenatedData += reply.k_s; concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y()); concatenatedData += AbstractSshPacket::encodeMpInt(reply.f); SymmetricKey k = m_dhKey->derive_key(reply.f); m_k = AbstractSshPacket::encodeMpInt(BigInt(k.begin(), k.length())); concatenatedData += m_k; m_hash.reset(get_hash(botanSha1Name())); const SecureVector<byte> &hashResult = m_hash->process(convertByteArray(concatenatedData), concatenatedData.size()); m_h = convertByteArray(hashResult); QScopedPointer<Public_Key> sigKey; QScopedPointer<PK_Verifier> verifier; if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) { const DL_Group group(reply.parameters.at(0), reply.parameters.at(1), reply.parameters.at(2)); DSA_PublicKey * const dsaKey = new DSA_PublicKey(group, reply.parameters.at(3)); sigKey.reset(dsaKey); verifier.reset(get_pk_verifier(*dsaKey, botanEmsaAlgoName(SshCapabilities::PubKeyDss))); } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) { RSA_PublicKey * const rsaKey = new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0)); sigKey.reset(rsaKey); verifier.reset(get_pk_verifier(*rsaKey, botanEmsaAlgoName(SshCapabilities::PubKeyRsa))); } else { Q_ASSERT(!"Impossible: Neither DSS nor RSA!"); } const byte * const botanH = convertByteArray(m_h); const Botan::byte * const botanSig = convertByteArray(reply.signatureBlob); if (!verifier->verify_message(botanH, m_h.size(), botanSig, reply.signatureBlob.size())) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Invalid signature in SSH_MSG_KEXDH_REPLY packet."); } m_sendFacility.sendNewKeysPacket(); }
SecureVector<byte> rfc3394_keyunwrap(const MemoryRegion<byte>& key, const SymmetricKey& kek, Algorithm_Factory& af) { if(key.size() < 16 || key.size() % 8 != 0) throw std::invalid_argument("Bad input key size for NIST key unwrap"); std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af)); aes->set_key(kek); const size_t n = (key.size() - 8) / 8; SecureVector<byte> R(n * 8); SecureVector<byte> A(16); for(size_t i = 0; i != 8; ++i) A[i] = key[i]; copy_mem(&R[0], key.begin() + 8, key.size() - 8); for(size_t j = 0; j <= 5; ++j) { for(size_t i = n; i != 0; --i) { const u32bit t = (5 - j) * n + i; byte t_buf[4] = { 0 }; store_be(t, t_buf); xor_buf(&A[4], &t_buf[0], 4); copy_mem(&A[8], &R[8*(i-1)], 8); aes->decrypt(&A[0]); copy_mem(&R[8*(i-1)], &A[8], 8); } } if(load_be<u64bit>(&A[0], 0) != 0xA6A6A6A6A6A6A6A6) throw Integrity_Failure("NIST key unwrap failed"); return R; }
SecureVector<byte> rfc3394_keywrap(const MemoryRegion<byte>& key, const SymmetricKey& kek, Algorithm_Factory& af) { if(key.size() % 8 != 0) throw std::invalid_argument("Bad input key size for NIST key wrap"); std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af)); aes->set_key(kek); const size_t n = key.size() / 8; SecureVector<byte> R((n + 1) * 8); SecureVector<byte> A(16); for(size_t i = 0; i != 8; ++i) A[i] = 0xA6; copy_mem(&R[8], key.begin(), key.size()); for(size_t j = 0; j <= 5; ++j) { for(size_t i = 1; i <= n; ++i) { const u32bit t = (n * j) + i; copy_mem(&A[8], &R[8*i], 8); aes->encrypt(&A[0]); copy_mem(&R[8*i], &A[8], 8); byte t_buf[4] = { 0 }; store_be(t, t_buf); xor_buf(&A[4], &t_buf[0], 4); } } copy_mem(&R[0], &A[0], 8); return R; }
/* * Create a new Client Key Exchange message */ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, Handshake_State& state, const Policy& policy, Credentials_Manager& creds, const Public_Key* server_public_key, const std::string& hostname, RandomNumberGenerator& rng) { const std::string kex_algo = state.ciphersuite().kex_algo(); if(kex_algo == "PSK") { std::string identity_hint = ""; if(state.server_kex()) { TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); identity_hint = reader.get_string(2, 0, 65535); } const std::string psk_identity = creds.psk_identity("tls-client", hostname, identity_hint); append_tls_length_value(m_key_material, psk_identity, 2); SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity); std::vector<byte> zeros(psk.length()); append_tls_length_value(m_pre_master, zeros, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } else if(state.server_kex()) { TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); SymmetricKey psk; if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") { std::string identity_hint = reader.get_string(2, 0, 65535); const std::string psk_identity = creds.psk_identity("tls-client", hostname, identity_hint); append_tls_length_value(m_key_material, psk_identity, 2); psk = creds.psk("tls-client", hostname, psk_identity); } if(kex_algo == "DH" || kex_algo == "DHE_PSK") { BigInt p = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); BigInt Y = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); if(reader.remaining_bytes()) throw Decoding_Error("Bad params size for DH key exchange"); if(p.bits() < policy.minimum_dh_group_size()) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "Server sent DH group of " + std::to_string(p.bits()) + " bits, policy requires at least " + std::to_string(policy.minimum_dh_group_size())); /* * A basic check for key validity. As we do not know q here we * cannot check that Y is in the right subgroup. However since * our key is ephemeral there does not seem to be any * advantage to bogus keys anyway. */ if(Y <= 1 || Y >= p - 1) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "Server sent bad DH key for DHE exchange"); DL_Group group(p, g); if(!group.verify_group(rng, false)) throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, "DH group validation failed"); DH_PublicKey counterparty_key(group, Y); DH_PrivateKey priv_key(rng, group); PK_Key_Agreement ka(priv_key, "Raw"); secure_vector<byte> dh_secret = CT::strip_leading_zeros( ka.derive_key(0, counterparty_key.public_value()).bits_of()); if(kex_algo == "DH") m_pre_master = dh_secret; else { append_tls_length_value(m_pre_master, dh_secret, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } append_tls_length_value(m_key_material, priv_key.public_value(), 2); } else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") { const byte curve_type = reader.get_byte(); if(curve_type != 3) throw Decoding_Error("Server sent non-named ECC curve"); const u16bit curve_id = reader.get_u16bit(); const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); if(name == "") throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id)); EC_Group group(name); std::vector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255); ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve())); ECDH_PrivateKey priv_key(rng, group); PK_Key_Agreement ka(priv_key, "Raw"); secure_vector<byte> ecdh_secret = ka.derive_key(0, counterparty_key.public_value()).bits_of(); if(kex_algo == "ECDH") m_pre_master = ecdh_secret; else { append_tls_length_value(m_pre_master, ecdh_secret, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } append_tls_length_value(m_key_material, priv_key.public_value(), 1); } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == "SRP_SHA") { const BigInt N = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); const BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); std::vector<byte> salt = reader.get_range<byte>(1, 1, 255); const BigInt B = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); const std::string srp_group = srp6_group_identifier(N, g); const std::string srp_identifier = creds.srp_identifier("tls-client", hostname); const std::string srp_password = creds.srp_password("tls-client", hostname, srp_identifier); std::pair<BigInt, SymmetricKey> srp_vals = srp6_client_agree(srp_identifier, srp_password, srp_group, "SHA-1", salt, B, rng); append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2); m_pre_master = srp_vals.second.bits_of(); } #endif else { throw Internal_Error("Client_Key_Exchange: Unknown kex " + kex_algo); } reader.assert_done(); } else { // No server key exchange msg better mean RSA kex + RSA key in cert if(kex_algo != "RSA") throw Unexpected_Message("No server kex but negotiated kex " + kex_algo); if(!server_public_key) throw Internal_Error("No server public key for RSA exchange"); if(auto rsa_pub = dynamic_cast<const RSA_PublicKey*>(server_public_key)) { const Protocol_Version offered_version = state.client_hello()->version(); m_pre_master = rng.random_vec(48); m_pre_master[0] = offered_version.major_version(); m_pre_master[1] = offered_version.minor_version(); PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15"); const std::vector<byte> encrypted_key = encryptor.encrypt(m_pre_master, rng); append_tls_length_value(m_key_material, encrypted_key, 2); } else throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Expected a RSA key in server cert but got " + server_public_key->algo_name()); } state.hash().update(io.send(*this)); }
/* * Read a Client Key Exchange message */ Client_Key_Exchange::Client_Key_Exchange(const std::vector<byte>& contents, const Handshake_State& state, const Private_Key* server_rsa_kex_key, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng) { const std::string kex_algo = state.ciphersuite().kex_algo(); if(kex_algo == "RSA") { BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(), "RSA key exchange negotiated so server sent a certificate"); if(!server_rsa_kex_key) throw Internal_Error("Expected RSA kex but no server kex key set"); if(!dynamic_cast<const RSA_PrivateKey*>(server_rsa_kex_key)) throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name()); PK_Decryptor_EME decryptor(*server_rsa_kex_key, "PKCS1v15"); Protocol_Version client_version = state.client_hello()->version(); /* * This is used as the pre-master if RSA decryption fails. * Otherwise we can be used as an oracle. See Bleichenbacher * "Chosen Ciphertext Attacks against Protocols Based on RSA * Encryption Standard PKCS #1", Crypto 98 * * Create it here instead if in the catch clause as otherwise we * expose a timing channel WRT the generation of the fake value. * Some timing channel likely remains due to exception handling * and the like. */ secure_vector<byte> fake_pre_master = rng.random_vec(48); fake_pre_master[0] = client_version.major_version(); fake_pre_master[1] = client_version.minor_version(); try { TLS_Data_Reader reader("ClientKeyExchange", contents); m_pre_master = decryptor.decrypt(reader.get_range<byte>(2, 0, 65535)); if(m_pre_master.size() != 48 || client_version.major_version() != m_pre_master[0] || client_version.minor_version() != m_pre_master[1]) { throw Decoding_Error("Client_Key_Exchange: Secret corrupted"); } } catch(...) { m_pre_master = fake_pre_master; } } else { TLS_Data_Reader reader("ClientKeyExchange", contents); SymmetricKey psk; if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") { const std::string psk_identity = reader.get_string(2, 0, 65535); psk = creds.psk("tls-server", state.client_hello()->sni_hostname(), psk_identity); if(psk.length() == 0) { if(policy.hide_unknown_users()) psk = SymmetricKey(rng, 16); else throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, "No PSK for identifier " + psk_identity); } } if(kex_algo == "PSK") { std::vector<byte> zeros(psk.length()); append_tls_length_value(m_pre_master, zeros, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == "SRP_SHA") { SRP6_Server_Session& srp = state.server_kex()->server_srp_params(); m_pre_master = srp.step2(BigInt::decode(reader.get_range<byte>(2, 0, 65535))).bits_of(); } #endif else if(kex_algo == "DH" || kex_algo == "DHE_PSK" || kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") { const Private_Key& private_key = state.server_kex()->server_kex_key(); const PK_Key_Agreement_Key* ka_key = dynamic_cast<const PK_Key_Agreement_Key*>(&private_key); if(!ka_key) throw Internal_Error("Expected key agreement key type but got " + private_key.algo_name()); try { PK_Key_Agreement ka(*ka_key, "Raw"); std::vector<byte> client_pubkey; if(ka_key->algo_name() == "DH") client_pubkey = reader.get_range<byte>(2, 0, 65535); else client_pubkey = reader.get_range<byte>(1, 0, 255); secure_vector<byte> shared_secret = ka.derive_key(0, client_pubkey).bits_of(); if(ka_key->algo_name() == "DH") shared_secret = CT::strip_leading_zeros(shared_secret); if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") { append_tls_length_value(m_pre_master, shared_secret, 2); append_tls_length_value(m_pre_master, psk.bits_of(), 2); } else m_pre_master = shared_secret; } catch(std::exception &) { /* * Something failed in the DH computation. To avoid possible * timing attacks, randomize the pre-master output and carry * on, allowing the protocol to fail later in the finished * checks. */ m_pre_master = rng.random_vec(ka_key->public_value().size()); } } else throw Internal_Error("Client_Key_Exchange: Unknown kex type " + kex_algo); } }