From fd736f7f18294aa1589aacd495b2a48bbaf8715c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 20 Jul 2012 09:16:08 +0200 Subject: libcli/smb: add smb2_signing_[en|e]crypt_pdu() metze --- libcli/smb/smb2_signing.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++ libcli/smb/smb2_signing.h | 9 ++++ 2 files changed, 141 insertions(+) (limited to 'libcli/smb') diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c index 43c9ba5c1c..bb621fd27e 100644 --- a/libcli/smb/smb2_signing.c +++ b/libcli/smb/smb2_signing.c @@ -207,3 +207,135 @@ void smb2_key_derivation(const uint8_t *KI, size_t KI_len, memcpy(KO, digest, 16); } + +NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key, + enum protocol_types protocol, + struct iovec *vector, + int count) +{ + uint8_t *tf; + uint16_t alg; + uint8_t sig[16]; + int i; + size_t a_total; + size_t m_total = 0; + struct aes_ccm_128_context ctx; + uint8_t key[AES_BLOCK_SIZE]; + + if (count < 1) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (vector[0].iov_len != SMB2_TF_HDR_SIZE) { + return NT_STATUS_INVALID_PARAMETER; + } + + tf = (uint8_t *)vector[0].iov_base; + + if (encryption_key.length == 0) { + DEBUG(2,("Wrong encryption key length %u for SMB2 signing\n", + (unsigned)encryption_key.length)); + return NT_STATUS_ACCESS_DENIED; + } + + alg = SMB2_ENCRYPTION_AES128_CCM; + SSVAL(tf, SMB2_TF_ALGORITHM, alg); + + a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE; + for (i=1; i < count; i++) { + m_total += vector[i].iov_len; + } + ZERO_STRUCT(key); + memcpy(key, encryption_key.data, + MIN(encryption_key.length, AES_BLOCK_SIZE)); + aes_ccm_128_init(&ctx, key, + tf + SMB2_TF_NONCE, + a_total, m_total); + aes_ccm_128_update(&ctx, tf + SMB2_TF_NONCE, a_total); + for (i=1; i < count; i++) { + aes_ccm_128_update(&ctx, + (const uint8_t *)vector[i].iov_base, + vector[i].iov_len); + } + for (i=1; i < count; i++) { + aes_ccm_128_crypt(&ctx, + (uint8_t *)vector[i].iov_base, + vector[i].iov_len); + } + aes_ccm_128_digest(&ctx, sig); + + memcpy(tf + SMB2_TF_SIGNATURE, sig, 16); + + DEBUG(5,("encrypt SMB2 message\n")); + + return NT_STATUS_OK; +} + +NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key, + enum protocol_types protocol, + struct iovec *vector, + int count) +{ + uint8_t *tf; + uint16_t alg; + uint8_t *sig_ptr = NULL; + uint8_t sig[16]; + int i; + size_t a_total; + size_t m_total = 0; + struct aes_ccm_128_context ctx; + uint8_t key[AES_BLOCK_SIZE]; + + if (count < 1) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (vector[0].iov_len != SMB2_TF_HDR_SIZE) { + return NT_STATUS_INVALID_PARAMETER; + } + + tf = (uint8_t *)vector[0].iov_base; + + if (decryption_key.length == 0) { + DEBUG(2,("Wrong decryption key length %u for SMB2 signing\n", + (unsigned)decryption_key.length)); + return NT_STATUS_ACCESS_DENIED; + } + + alg = SVAL(tf, SMB2_TF_ALGORITHM); + if (alg != SMB2_ENCRYPTION_AES128_CCM) { + return NT_STATUS_ACCESS_DENIED; + } + + a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE; + for (i=1; i < count; i++) { + m_total += vector[i].iov_len; + } + ZERO_STRUCT(key); + memcpy(key, decryption_key.data, + MIN(decryption_key.length, AES_BLOCK_SIZE)); + aes_ccm_128_init(&ctx, key, + tf + SMB2_TF_NONCE, + a_total, m_total); + for (i=1; i < count; i++) { + aes_ccm_128_crypt(&ctx, + (uint8_t *)vector[i].iov_base, + vector[i].iov_len); + } + aes_ccm_128_update(&ctx, tf + SMB2_TF_NONCE, a_total); + for (i=1; i < count; i++) { + aes_ccm_128_update(&ctx, + ( uint8_t *)vector[i].iov_base, + vector[i].iov_len); + } + aes_ccm_128_digest(&ctx, sig); + + sig_ptr = tf + SMB2_TF_SIGNATURE; + if (memcmp(sig_ptr, sig, 16) != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + DEBUG(5,("decrypt SMB2 message\n")); + + return NT_STATUS_OK; +} diff --git a/libcli/smb/smb2_signing.h b/libcli/smb/smb2_signing.h index 200274ba6d..e8e2e6a718 100644 --- a/libcli/smb/smb2_signing.h +++ b/libcli/smb/smb2_signing.h @@ -38,4 +38,13 @@ void smb2_key_derivation(const uint8_t *KI, size_t KI_len, const uint8_t *Context, size_t Context_len, uint8_t KO[16]); +NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key, + enum protocol_types protocol, + struct iovec *vector, + int count); +NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key, + enum protocol_types protocol, + struct iovec *vector, + int count); + #endif /* _LIBCLI_SMB_SMB2_SIGNING_H_ */ -- cgit