The branch, master has been updated via c9219fe libcli/smb/smbXcli: use smb2_key_deviration() to setup SMB 2.24 keys via 39ae473 libcli/smb/smb2_signing: implement aes_cmac_128 based signing for SMB 2.24 via 7f5e569 libcli/smb/smb2_signing: add smb2_key_deviration() via 7102eaf lib/crypto: add aes_cmac_128_test.c as local.crypto.aes_cmac_128 test via 062d1a0 lib/crypto: add aes_cmac_128* (rfc 4493) from de870e9 s3: Introduce "req" helper var in reply_lockingX_success
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit c9219fe5859957589570ff0deeaccd17125d347e Author: Stefan Metzmacher <me...@samba.org> Date: Mon Feb 27 09:33:46 2012 +0100 libcli/smb/smbXcli: use smb2_key_deviration() to setup SMB 2.24 keys This uses the key diveration function from "NIST Special Publication 800-108" in counter mode (section 5.1). Thanks to Jeremy, Michael and Volker for the debugging! metze Autobuild-User: Stefan Metzmacher <me...@samba.org> Autobuild-Date: Wed Feb 29 04:54:48 CET 2012 on sn-devel-104 commit 39ae4737e0fbf8db348db76f7a534a55304918f0 Author: Stefan Metzmacher <me...@samba.org> Date: Mon Feb 27 09:32:33 2012 +0100 libcli/smb/smb2_signing: implement aes_cmac_128 based signing for SMB 2.24 metze commit 7f5e56971f617fd71ec47a54866577d08dabd1d7 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 22 13:13:47 2012 +0100 libcli/smb/smb2_signing: add smb2_key_deviration() This implements a simplified version of "NIST Special Publication 800-108" section 5.1 using hmac-sha256. Thanks to Jeremy, Michael and Volker for the debugging! metze commit 7102eafc266e82121b1a267991584885ebfa9a65 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 29 01:39:31 2012 +0100 lib/crypto: add aes_cmac_128_test.c as local.crypto.aes_cmac_128 test metze commit 062d1a09c2ef5efcdb85c77d7d27109b1317b46c Author: Stefan Metzmacher <me...@samba.org> Date: Sat Feb 18 11:47:31 2012 +0100 lib/crypto: add aes_cmac_128* (rfc 4493) Thanks to Jeremy, Michael and Volker for the debugging! metze ----------------------------------------------------------------------- Summary of changes: lib/crypto/aes_cmac_128.c | 184 ++++++++++++++++++++ .../netlogon.h => lib/crypto/aes_cmac_128.h | 40 ++-- lib/crypto/aes_cmac_128_test.c | 92 ++++++++++ lib/crypto/crypto.h | 1 + lib/crypto/wscript_build | 11 +- libcli/smb/smb2_signing.c | 108 ++++++++++-- libcli/smb/smb2_signing.h | 5 + libcli/smb/smbXcli_base.c | 43 +++++- source3/Makefile.in | 3 +- source4/torture/local/local.c | 2 + 10 files changed, 443 insertions(+), 46 deletions(-) create mode 100644 lib/crypto/aes_cmac_128.c copy libcli/netlogon/netlogon.h => lib/crypto/aes_cmac_128.h (50%) create mode 100644 lib/crypto/aes_cmac_128_test.c Changeset truncated at 500 lines: diff --git a/lib/crypto/aes_cmac_128.c b/lib/crypto/aes_cmac_128.c new file mode 100644 index 0000000..b630eea --- /dev/null +++ b/lib/crypto/aes_cmac_128.c @@ -0,0 +1,184 @@ +/* + AES-CMAC-128 (rfc 4493) + Copyright (C) Stefan Metzmacher 2012 + Copyright (C) Jeremy Allison 2012 + Copyright (C) Michael Adam 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "../lib/crypto/crypto.h" + +static const uint8_t const_Zero[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const uint8_t const_Rb[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 +}; + +#define _MSB(x) (((x)[0] & 0x80)?1:0) + +static inline void aes_cmac_128_left_shift_1(const uint8_t in[AES_BLOCK_SIZE], + uint8_t out[AES_BLOCK_SIZE]) +{ + uint8_t overflow = 0; + int8_t i; + + for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) { + out[i] = in[i] << 1; + + out[i] |= overflow; + + overflow = _MSB(&in[i]); + } +} + +static inline void aes_cmac_128_xor(const uint8_t in1[AES_BLOCK_SIZE], + const uint8_t in2[AES_BLOCK_SIZE], + uint8_t out[AES_BLOCK_SIZE]) +{ + uint8_t i; + + for (i = 0; i < AES_BLOCK_SIZE; i++) { + out[i] = in1[i] ^ in2[i]; + } +} + +void aes_cmac_128_init(struct aes_cmac_128_context *ctx, + const uint8_t K[AES_BLOCK_SIZE]) +{ + uint8_t L[AES_BLOCK_SIZE]; + + ZERO_STRUCTP(ctx); + + AES_set_encrypt_key(K, 128, &ctx->aes_key); + + /* step 1 - generate subkeys k1 and k2 */ + + AES_encrypt(const_Zero, L, &ctx->aes_key); + + if (_MSB(L) == 0) { + aes_cmac_128_left_shift_1(L, ctx->K1); + } else { + uint8_t tmp_block[AES_BLOCK_SIZE]; + + aes_cmac_128_left_shift_1(L, tmp_block); + aes_cmac_128_xor(tmp_block, const_Rb, ctx->K1); + ZERO_STRUCT(tmp_block); + } + + if (_MSB(ctx->K1) == 0) { + aes_cmac_128_left_shift_1(ctx->K1, ctx->K2); + } else { + uint8_t tmp_block[AES_BLOCK_SIZE]; + + aes_cmac_128_left_shift_1(ctx->K1, tmp_block); + aes_cmac_128_xor(tmp_block, const_Rb, ctx->K2); + ZERO_STRUCT(tmp_block); + } + + ZERO_STRUCT(L); +} + +void aes_cmac_128_update(struct aes_cmac_128_context *ctx, + const uint8_t *_msg, size_t _msg_len) +{ + uint8_t tmp_block[AES_BLOCK_SIZE]; + uint8_t Y[AES_BLOCK_SIZE]; + const uint8_t *msg = _msg; + size_t msg_len = _msg_len; + + /* + * copy the remembered last block + */ + ZERO_STRUCT(tmp_block); + if (ctx->last_len) { + memcpy(tmp_block, ctx->last, ctx->last_len); + } + + /* + * check if we expand the block + */ + if (ctx->last_len < AES_BLOCK_SIZE) { + size_t len = MIN(AES_BLOCK_SIZE - ctx->last_len, msg_len); + + memcpy(&tmp_block[ctx->last_len], msg, len); + memcpy(ctx->last, tmp_block, AES_BLOCK_SIZE); + msg += len; + msg_len -= len; + ctx->last_len += len; + } + + if (msg_len == 0) { + /* if it is still the last block, we are done */ + ZERO_STRUCT(tmp_block); + return; + } + + /* + * It is not the last block anymore + */ + ZERO_STRUCT(ctx->last); + ctx->last_len = 0; + + /* + * now checksum everything but the last block + */ + aes_cmac_128_xor(ctx->X, tmp_block, Y); + AES_encrypt(Y, ctx->X, &ctx->aes_key); + + while (msg_len > AES_BLOCK_SIZE) { + memcpy(tmp_block, msg, AES_BLOCK_SIZE); + msg += AES_BLOCK_SIZE; + msg_len -= AES_BLOCK_SIZE; + + aes_cmac_128_xor(ctx->X, tmp_block, Y); + AES_encrypt(Y, ctx->X, &ctx->aes_key); + } + + /* + * copy the last block, it will be processed in + * aes_cmac_128_final(). + */ + memcpy(ctx->last, msg, msg_len); + ctx->last_len = msg_len; + + ZERO_STRUCT(tmp_block); + ZERO_STRUCT(Y); +} + +void aes_cmac_128_final(struct aes_cmac_128_context *ctx, + uint8_t T[AES_BLOCK_SIZE]) +{ + uint8_t tmp_block[AES_BLOCK_SIZE]; + uint8_t Y[AES_BLOCK_SIZE]; + + if (ctx->last_len < AES_BLOCK_SIZE) { + ctx->last[ctx->last_len] = 0x80; + aes_cmac_128_xor(ctx->last, ctx->K2, tmp_block); + } else { + aes_cmac_128_xor(ctx->last, ctx->K1, tmp_block); + } + + aes_cmac_128_xor(tmp_block, ctx->X, Y); + AES_encrypt(Y, T, &ctx->aes_key); + + ZERO_STRUCT(tmp_block); + ZERO_STRUCT(Y); + ZERO_STRUCTP(ctx); +} diff --git a/libcli/netlogon/netlogon.h b/lib/crypto/aes_cmac_128.h similarity index 50% copy from libcli/netlogon/netlogon.h copy to lib/crypto/aes_cmac_128.h index 0bf2a4c..28117a0 100644 --- a/libcli/netlogon/netlogon.h +++ b/lib/crypto/aes_cmac_128.h @@ -1,9 +1,6 @@ /* - Unix SMB/CIFS implementation. - - CLDAP server structures - - Copyright (C) Andrew Bartlett <abart...@samba.org> 2008 + AES-CMAC-128 (rfc 4493) + Copyright (C) Stefan Metzmacher 2012 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,23 +16,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef __LIBCLI_NETLOGON_H__ -#define __LIBCLI_NETLOGON_H__ +#ifndef LIB_CRYPTO_AES_CMAC_128_H +#define LIB_CRYPTO_AES_CMAC_128_H -#include "librpc/gen_ndr/ndr_nbt.h" +struct aes_cmac_128_context { + AES_KEY aes_key; -#include "librpc/gen_ndr/ndr_misc.h" -#include "librpc/gen_ndr/ndr_security.h" + uint8_t K1[AES_BLOCK_SIZE]; + uint8_t K2[AES_BLOCK_SIZE]; -struct nbt_netlogon_response -{ - enum {NETLOGON_GET_PDC, NETLOGON_SAMLOGON, NETLOGON_RESPONSE2} response_type; - union { - struct nbt_netlogon_response_from_pdc get_pdc; - struct netlogon_samlogon_response samlogon; - struct nbt_netlogon_response2 response2; - } data; + uint8_t X[AES_BLOCK_SIZE]; + + uint8_t last[AES_BLOCK_SIZE]; + size_t last_len; }; -#include "../libcli/netlogon/netlogon_proto.h" -#endif /* __CLDAP_SERVER_PROTO_H__ */ +void aes_cmac_128_init(struct aes_cmac_128_context *ctx, + const uint8_t K[AES_BLOCK_SIZE]); +void aes_cmac_128_update(struct aes_cmac_128_context *ctx, + const uint8_t *_msg, size_t _msg_len); +void aes_cmac_128_final(struct aes_cmac_128_context *ctx, + uint8_t T[AES_BLOCK_SIZE]); + +#endif /* LIB_CRYPTO_AES_CMAC_128_H */ diff --git a/lib/crypto/aes_cmac_128_test.c b/lib/crypto/aes_cmac_128_test.c new file mode 100644 index 0000000..173087f --- /dev/null +++ b/lib/crypto/aes_cmac_128_test.c @@ -0,0 +1,92 @@ +/* + AES-CMAC-128 tests + Copyright (C) Stefan Metzmacher 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "replace.h" +#include "../lib/util/samba_util.h" +#include "../lib/crypto/crypto.h" + +struct torture_context; +bool torture_local_crypto_aes_cmac_128(struct torture_context *torture); + +/* + This uses the test values from rfc 4493 +*/ +bool torture_local_crypto_aes_cmac_128(struct torture_context *torture) +{ + bool ret = true; + uint32_t i; + DATA_BLOB key; + struct { + DATA_BLOB data; + DATA_BLOB cmac; + } testarray[5]; + + TALLOC_CTX *tctx = talloc_new(torture); + if (!tctx) { return false; }; + + key = strhex_to_data_blob(tctx, "2b7e151628aed2a6abf7158809cf4f3c"); + + testarray[0].data = data_blob_null; + testarray[0].cmac = strhex_to_data_blob(tctx, + "bb1d6929e95937287fa37d129b756746"); + + testarray[1].data = strhex_to_data_blob(tctx, + "6bc1bee22e409f96e93d7e117393172a"); + testarray[1].cmac = strhex_to_data_blob(tctx, + "070a16b46b4d4144f79bdd9dd04a287c"); + + testarray[2].data = strhex_to_data_blob(tctx, + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411"); + testarray[2].cmac = strhex_to_data_blob(tctx, + "dfa66747de9ae63030ca32611497c827"); + + testarray[3].data = strhex_to_data_blob(tctx, + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"); + testarray[3].cmac = strhex_to_data_blob(tctx, + "51f0bebf7e3b9d92fc49741779363cfe"); + + ZERO_STRUCT(testarray[4]); + + for (i=0; testarray[i].cmac.length != 0; i++) { + struct aes_cmac_128_context ctx; + uint8_t cmac[AES_BLOCK_SIZE]; + int e; + + aes_cmac_128_init(&ctx, key.data); + aes_cmac_128_update(&ctx, + testarray[i].data.data, + testarray[i].data.length); + aes_cmac_128_final(&ctx, cmac); + + e = memcmp(testarray[i].cmac.data, cmac, sizeof(cmac)); + if (e != 0) { + printf("aes_cmac_128 test[%u]: failed\n", i); + dump_data(0, key.data, key.length); + dump_data(0, testarray[i].data.data, testarray[i].data.length); + dump_data(0, testarray[i].cmac.data, testarray[i].cmac.length); + dump_data(0, cmac, sizeof(cmac)); + ret = false; + } + } + talloc_free(tctx); + return ret; +} diff --git a/lib/crypto/crypto.h b/lib/crypto/crypto.h index b5ea9c7..c0d85c8 100644 --- a/lib/crypto/crypto.h +++ b/lib/crypto/crypto.h @@ -25,4 +25,5 @@ #include "../lib/crypto/hmacsha256.h" #include "../lib/crypto/arcfour.h" #include "../lib/crypto/aes.h" +#include "../lib/crypto/aes_cmac_128.h" diff --git a/lib/crypto/wscript_build b/lib/crypto/wscript_build index 6ad1cad..f502698 100644 --- a/lib/crypto/wscript_build +++ b/lib/crypto/wscript_build @@ -8,13 +8,14 @@ else: extra_source += ' md5.c' bld.SAMBA_SUBSYSTEM('LIBCRYPTO', - source='crc32.c hmacmd5.c md4.c arcfour.c sha256.c hmacsha256.c aes.c rijndael-alg-fst.c' + extra_source, - deps='talloc' + extra_deps - ) - + source='''crc32.c hmacmd5.c md4.c arcfour.c sha256.c hmacsha256.c + aes.c rijndael-alg-fst.c aes_cmac_128.c + ''' + extra_source, + deps='talloc' + extra_deps + ) bld.SAMBA_SUBSYSTEM('TORTURE_LIBCRYPTO', - source='md4test.c md5test.c hmacmd5test.c', + source='md4test.c md5test.c hmacmd5test.c aes_cmac_128_test.c', autoproto='test_proto.h', deps='LIBCRYPTO' ) diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c index 3017277..4204ed1 100644 --- a/libcli/smb/smb2_signing.c +++ b/libcli/smb/smb2_signing.c @@ -30,8 +30,7 @@ NTSTATUS smb2_signing_sign_pdu(DATA_BLOB signing_key, { uint8_t *hdr; uint64_t session_id; - struct HMACSHA256Context m; - uint8_t res[SHA256_DIGEST_LENGTH]; + uint8_t res[16]; int i; if (count < 2) { @@ -63,13 +62,33 @@ NTSTATUS smb2_signing_sign_pdu(DATA_BLOB signing_key, SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED); - ZERO_STRUCT(m); - hmac_sha256_init(signing_key.data, MIN(signing_key.length, 16), &m); - for (i=0; i < count; i++) { - hmac_sha256_update((const uint8_t *)vector[i].iov_base, - vector[i].iov_len, &m); + if (protocol >= PROTOCOL_SMB2_24) { + struct aes_cmac_128_context ctx; + uint8_t key[AES_BLOCK_SIZE]; + + ZERO_STRUCT(key); + memcpy(key, signing_key.data, MIN(signing_key.length, 16)); + + aes_cmac_128_init(&ctx, key); + for (i=0; i < count; i++) { + aes_cmac_128_update(&ctx, + (const uint8_t *)vector[i].iov_base, + vector[i].iov_len); + } + aes_cmac_128_final(&ctx, res); + } else { + struct HMACSHA256Context m; + uint8_t digest[SHA256_DIGEST_LENGTH]; + + ZERO_STRUCT(m); + hmac_sha256_init(signing_key.data, MIN(signing_key.length, 16), &m); + for (i=0; i < count; i++) { + hmac_sha256_update((const uint8_t *)vector[i].iov_base, + vector[i].iov_len, &m); + } + hmac_sha256_final(digest, &m); + memcpy(res, digest, 16); } - hmac_sha256_final(res, &m); DEBUG(5,("signed SMB2 message\n")); memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16); @@ -85,8 +104,7 @@ NTSTATUS smb2_signing_check_pdu(DATA_BLOB signing_key, const uint8_t *hdr; const uint8_t *sig; uint64_t session_id; - struct HMACSHA256Context m; - uint8_t res[SHA256_DIGEST_LENGTH]; + uint8_t res[16]; static const uint8_t zero_sig[16] = { 0, }; int i; @@ -116,15 +134,37 @@ NTSTATUS smb2_signing_check_pdu(DATA_BLOB signing_key, sig = hdr+SMB2_HDR_SIGNATURE; - ZERO_STRUCT(m); - hmac_sha256_init(signing_key.data, MIN(signing_key.length, 16), &m); - hmac_sha256_update(hdr, SMB2_HDR_SIGNATURE, &m); - hmac_sha256_update(zero_sig, 16, &m); - for (i=1; i < count; i++) { - hmac_sha256_update((const uint8_t *)vector[i].iov_base, - vector[i].iov_len, &m); + if (protocol >= PROTOCOL_SMB2_24) { + struct aes_cmac_128_context ctx; + uint8_t key[AES_BLOCK_SIZE]; + + ZERO_STRUCT(key); + memcpy(key, signing_key.data, MIN(signing_key.length, 16)); + + aes_cmac_128_init(&ctx, key); + aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE); + aes_cmac_128_update(&ctx, zero_sig, 16); + for (i=1; i < count; i++) { + aes_cmac_128_update(&ctx, + (const uint8_t *)vector[i].iov_base, + vector[i].iov_len); + } + aes_cmac_128_final(&ctx, res); + } else { + struct HMACSHA256Context m; + uint8_t digest[SHA256_DIGEST_LENGTH]; + + ZERO_STRUCT(m); + hmac_sha256_init(signing_key.data, MIN(signing_key.length, 16), &m); + hmac_sha256_update(hdr, SMB2_HDR_SIGNATURE, &m); + hmac_sha256_update(zero_sig, 16, &m); + for (i=1; i < count; i++) { + hmac_sha256_update((const uint8_t *)vector[i].iov_base, + vector[i].iov_len, &m); + } + hmac_sha256_final(digest, &m); + memcpy(res, digest, 16); } - hmac_sha256_final(res, &m); if (memcmp(res, sig, 16) != 0) { DEBUG(0,("Bad SMB2 signature for message\n")); @@ -135,3 +175,35 @@ NTSTATUS smb2_signing_check_pdu(DATA_BLOB signing_key, return NT_STATUS_OK; } + +void smb2_key_deviration(const uint8_t *KI, size_t KI_len, + const uint8_t *Label, size_t Label_len, -- Samba Shared Repository