From a7208de06a6b47ef0b6947d50b46efc79d1198ce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2009 03:09:30 +0200 Subject: libcli/auth: add support for AES/HMAC-SHA256 to the netlogon schannel sign/seal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit metze Signed-off-by: Günther Deschner --- libcli/auth/schannel_sign.c | 188 ++++++++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 51 deletions(-) (limited to 'libcli/auth/schannel_sign.c') diff --git a/libcli/auth/schannel_sign.c b/libcli/auth/schannel_sign.c index 29a97b9282..ebd8f1c268 100644 --- a/libcli/auth/schannel_sign.c +++ b/libcli/auth/schannel_sign.c @@ -31,10 +31,28 @@ static void netsec_offset_and_sizes(struct schannel_state *state, uint32_t *_checksum_length, uint32_t *_confounder_ofs) { - uint32_t min_sig_size = 24; - uint32_t used_sig_size = 32; - uint32_t checksum_length = 8; - uint32_t confounder_ofs = 24; + uint32_t min_sig_size; + uint32_t used_sig_size; + uint32_t checksum_length; + uint32_t confounder_ofs; + + if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + min_sig_size = 48; + used_sig_size = 56; + /* + * Note: windows has a bug here and uses the old values... + * + * checksum_length = 32; + * confounder_ofs = 48; + */ + checksum_length = 8; + confounder_ofs = 24; + } else { + min_sig_size = 24; + used_sig_size = 32; + checksum_length = 8; + confounder_ofs = 24; + } if (do_seal) { min_sig_size += 8; @@ -65,13 +83,25 @@ static void netsec_do_seq_num(struct schannel_state *state, uint32_t checksum_length, uint8_t seq_num[8]) { - static const uint8_t zeros[4]; - uint8_t sequence_key[16]; - uint8_t digest1[16]; + if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + AES_KEY key; + uint8_t iv[AES_BLOCK_SIZE]; - hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1); - hmac_md5(digest1, checksum, checksum_length, sequence_key); - arcfour_crypt(seq_num, sequence_key, 8); + AES_set_encrypt_key(state->creds->session_key, 128, &key); + ZERO_STRUCT(iv); + memcpy(iv+0, checksum, 8); + memcpy(iv+8, checksum, 8); + + aes_cfb8_encrypt(seq_num, seq_num, 8, &key, iv, AES_ENCRYPT); + } else { + static const uint8_t zeros[4]; + uint8_t sequence_key[16]; + uint8_t digest1[16]; + + hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1); + hmac_md5(digest1, checksum, checksum_length, sequence_key); + arcfour_crypt(seq_num, sequence_key, 8); + } state->seq_num++; } @@ -79,23 +109,48 @@ static void netsec_do_seq_num(struct schannel_state *state, static void netsec_do_seal(struct schannel_state *state, const uint8_t seq_num[8], uint8_t confounder[8], - uint8_t *data, uint32_t length) + uint8_t *data, uint32_t length, + bool forward) { - uint8_t sealing_key[16]; - static const uint8_t zeros[4]; - uint8_t digest2[16]; - uint8_t sess_kf0[16]; - int i; - - for (i = 0; i < 16; i++) { - sess_kf0[i] = state->creds->session_key[i] ^ 0xf0; - } + if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + AES_KEY key; + uint8_t iv[AES_BLOCK_SIZE]; + uint8_t sess_kf0[16]; + int i; + + for (i = 0; i < 16; i++) { + sess_kf0[i] = state->creds->session_key[i] ^ 0xf0; + } + + AES_set_encrypt_key(sess_kf0, 128, &key); + ZERO_STRUCT(iv); + memcpy(iv+0, seq_num, 8); + memcpy(iv+8, seq_num, 8); + + if (forward) { + aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_ENCRYPT); + aes_cfb8_encrypt(data, data, length, &key, iv, AES_ENCRYPT); + } else { + aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_DECRYPT); + aes_cfb8_encrypt(data, data, length, &key, iv, AES_DECRYPT); + } + } else { + uint8_t sealing_key[16]; + static const uint8_t zeros[4]; + uint8_t digest2[16]; + uint8_t sess_kf0[16]; + int i; + + for (i = 0; i < 16; i++) { + sess_kf0[i] = state->creds->session_key[i] ^ 0xf0; + } - hmac_md5(sess_kf0, zeros, 4, digest2); - hmac_md5(digest2, seq_num, 8, sealing_key); + hmac_md5(sess_kf0, zeros, 4, digest2); + hmac_md5(digest2, seq_num, 8, sealing_key); - arcfour_crypt(confounder, sealing_key, 8); - arcfour_crypt(data, sealing_key, length); + arcfour_crypt(confounder, sealing_key, 8); + arcfour_crypt(data, sealing_key, length); + } } /******************************************************************* @@ -104,38 +159,67 @@ static void netsec_do_seal(struct schannel_state *state, ********************************************************************/ static void netsec_do_sign(struct schannel_state *state, const uint8_t *confounder, - const uint8_t *data, size_t data_len, + const uint8_t *data, size_t length, uint8_t header[8], uint8_t *checksum) { - uint8_t packet_digest[16]; - static const uint8_t zeros[4]; - struct MD5Context ctx; + if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + struct HMACSHA256Context ctx; - MD5Init(&ctx); - MD5Update(&ctx, zeros, 4); - if (confounder) { - SSVAL(header, 0, NL_SIGN_HMAC_MD5); - SSVAL(header, 2, NL_SEAL_RC4); - SSVAL(header, 4, 0xFFFF); - SSVAL(header, 6, 0x0000); + hmac_sha256_init(state->creds->session_key, + sizeof(state->creds->session_key), + &ctx); - MD5Update(&ctx, header, 8); - MD5Update(&ctx, confounder, 8); - } else { - SSVAL(header, 0, NL_SIGN_HMAC_MD5); - SSVAL(header, 2, NL_SEAL_NONE); - SSVAL(header, 4, 0xFFFF); - SSVAL(header, 6, 0x0000); + if (confounder) { + SSVAL(header, 0, NL_SIGN_HMAC_SHA256); + SSVAL(header, 2, NL_SEAL_AES128); + SSVAL(header, 4, 0xFFFF); + SSVAL(header, 6, 0x0000); - MD5Update(&ctx, header, 8); - } - MD5Update(&ctx, data, data_len); - MD5Final(packet_digest, &ctx); + hmac_sha256_update(header, 8, &ctx); + hmac_sha256_update(confounder, 8, &ctx); + } else { + SSVAL(header, 0, NL_SIGN_HMAC_SHA256); + SSVAL(header, 2, NL_SEAL_NONE); + SSVAL(header, 4, 0xFFFF); + SSVAL(header, 6, 0x0000); - hmac_md5(state->creds->session_key, - packet_digest, sizeof(packet_digest), - checksum); + hmac_sha256_update(header, 8, &ctx); + } + + hmac_sha256_update(data, length, &ctx); + + hmac_sha256_final(checksum, &ctx); + } else { + uint8_t packet_digest[16]; + static const uint8_t zeros[4]; + struct MD5Context ctx; + + MD5Init(&ctx); + MD5Update(&ctx, zeros, 4); + if (confounder) { + SSVAL(header, 0, NL_SIGN_HMAC_MD5); + SSVAL(header, 2, NL_SEAL_RC4); + SSVAL(header, 4, 0xFFFF); + SSVAL(header, 6, 0x0000); + + MD5Update(&ctx, header, 8); + MD5Update(&ctx, confounder, 8); + } else { + SSVAL(header, 0, NL_SIGN_HMAC_MD5); + SSVAL(header, 2, NL_SEAL_NONE); + SSVAL(header, 4, 0xFFFF); + SSVAL(header, 6, 0x0000); + + MD5Update(&ctx, header, 8); + } + MD5Update(&ctx, data, length); + MD5Final(packet_digest, &ctx); + + hmac_md5(state->creds->session_key, + packet_digest, sizeof(packet_digest), + checksum); + } } NTSTATUS netsec_incoming_packet(struct schannel_state *state, @@ -177,7 +261,8 @@ NTSTATUS netsec_incoming_packet(struct schannel_state *state, if (do_unseal) { netsec_do_seal(state, seq_num, confounder, - data, length); + data, length, + false); } netsec_do_sign(state, confounder, @@ -257,7 +342,8 @@ NTSTATUS netsec_outgoing_packet(struct schannel_state *state, if (do_seal) { netsec_do_seal(state, seq_num, confounder, - data, length); + data, length, + true); } netsec_do_seq_num(state, checksum, checksum_length, seq_num); -- cgit