Commit 5a0ca770 authored by Namjae Jeon's avatar Namjae Jeon Committed by Steve French
Browse files

cifsd: add support for AES256 encryption



Now that 256 bit encryption can be negotiated, update
names of the nonces to match the updated official protocol
documentation (e.g. AES_GCM_NONCE instead of AES_128GCM_NONCE)
since they apply to both 128 bit and 256 bit encryption.
update smb encryption code to set 32 byte key length and to
set gcm256/ccm256 when requested on mount.

Signed-off-by: default avatarNamjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 1fca8038
Loading
Loading
Loading
Loading
+37 −16
Original line number Diff line number Diff line
@@ -835,7 +835,8 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label,
{
	unsigned char zero = 0x0;
	__u8 i[4] = {0, 0, 0, 1};
	__u8 L[4] = {0, 0, 0, 128};
	__u8 L128[4] = {0, 0, 0, 128};
	__u8 L256[4] = {0, 0, 1, 0};
	int rc = -EINVAL;
	unsigned char prfhash[SMB2_HMACSHA256_SIZE];
	unsigned char *hashptr = prfhash;
@@ -890,7 +891,11 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label,
		goto smb3signkey_ret;
	}

	rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L, 4);
	if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
	    sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
		rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4);
	else
		rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4);
	if (rc) {
		ksmbd_debug(AUTH, "could not update with L\n");
		goto smb3signkey_ret;
@@ -981,24 +986,33 @@ static int generate_smb3encryptionkey(struct ksmbd_session *sess,

	rc = generate_key(sess, ptwin->encryption.label,
			ptwin->encryption.context, sess->smb3encryptionkey,
			SMB3_SIGN_KEY_SIZE);
			SMB3_ENC_DEC_KEY_SIZE);
	if (rc)
		return rc;

	rc = generate_key(sess, ptwin->decryption.label,
			ptwin->decryption.context,
			sess->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
			sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
	if (rc)
		return rc;

	ksmbd_debug(AUTH, "dumping generated AES encryption keys\n");
	ksmbd_debug(AUTH, "Cipher type   %d\n", sess->conn->cipher_type);
	ksmbd_debug(AUTH, "Session Id    %llu\n", sess->id);
	ksmbd_debug(AUTH, "Session Key   %*ph\n",
			SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
	if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
	    sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
		ksmbd_debug(AUTH, "ServerIn Key  %*ph\n",
			SMB3_SIGN_KEY_SIZE, sess->smb3encryptionkey);
			SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey);
		ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
			SMB3_SIGN_KEY_SIZE, sess->smb3decryptionkey);
			SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3decryptionkey);
	} else {
		ksmbd_debug(AUTH, "ServerIn Key  %*ph\n",
			SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3encryptionkey);
		ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
			SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3decryptionkey);
	}
	return rc;
}

@@ -1136,7 +1150,7 @@ static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id,

	ses_enc_key = enc ? sess->smb3encryptionkey :
		sess->smb3decryptionkey;
	memcpy(key, ses_enc_key, SMB3_SIGN_KEY_SIZE);
	memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);

	return 0;
}
@@ -1224,7 +1238,7 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
	int rc = 0;
	struct scatterlist *sg;
	u8 sign[SMB2_SIGNATURE_SIZE] = {};
	u8 key[SMB3_SIGN_KEY_SIZE];
	u8 key[SMB3_ENC_DEC_KEY_SIZE];
	struct aead_request *req;
	char *iv;
	unsigned int iv_len;
@@ -1241,7 +1255,8 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
		return 0;
	}

	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM)
	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
		ctx = ksmbd_crypto_ctx_find_gcm();
	else
		ctx = ksmbd_crypto_ctx_find_ccm();
@@ -1250,12 +1265,17 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
		return -EINVAL;
	}

	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM)
	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
		tfm = CRYPTO_GCM(ctx);
	else
		tfm = CRYPTO_CCM(ctx);

	rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE);
	if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
		rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
	else
		rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE);
	if (rc) {
		ksmbd_err("Failed to set aead key %d\n", rc);
		goto free_ctx;
@@ -1294,11 +1314,12 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
		goto free_sg;
	}

	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM) {
		memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES128GCM_NONCE);
	if (conn->cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
		memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
	} else {
		iv[0] = 3;
		memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CCM_NONCE);
		memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
	}

	aead_request_set_crypt(req, sg, sg, crypt_len, iv);
+4 −4
Original line number Diff line number Diff line
@@ -42,10 +42,10 @@ static struct crypto_aead *alloc_aead(int id)
	struct crypto_aead *tfm = NULL;

	switch (id) {
	case CRYPTO_AEAD_AES128_GCM:
	case CRYPTO_AEAD_AES_GCM:
		tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
		break;
	case CRYPTO_AEAD_AES128_CCM:
	case CRYPTO_AEAD_AES_CCM:
		tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
		break;
	default:
@@ -248,12 +248,12 @@ static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id)

struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void)
{
	return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES128_GCM);
	return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_GCM);
}

struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void)
{
	return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES128_CCM);
	return ____crypto_aead_ctx_find(CRYPTO_AEAD_AES_CCM);
}

void ksmbd_crypto_destroy(void)
+4 −4
Original line number Diff line number Diff line
@@ -21,8 +21,8 @@ enum {
};

enum {
	CRYPTO_AEAD_AES128_GCM = 16,
	CRYPTO_AEAD_AES128_CCM,
	CRYPTO_AEAD_AES_GCM = 16,
	CRYPTO_AEAD_AES_CCM,
	CRYPTO_AEAD_MAX,
};

@@ -55,8 +55,8 @@ struct ksmbd_crypto_ctx {
#define CRYPTO_MD4_TFM(c)	((c)->desc[CRYPTO_SHASH_MD4]->tfm)
#define CRYPTO_MD5_TFM(c)	((c)->desc[CRYPTO_SHASH_MD5]->tfm)

#define CRYPTO_GCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES128_GCM])
#define CRYPTO_CCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES128_CCM])
#define CRYPTO_GCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES_GCM])
#define CRYPTO_CCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES_CCM])

void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx);

+2 −2
Original line number Diff line number Diff line
@@ -56,8 +56,8 @@ struct ksmbd_session {



	__u8				smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
	__u8				smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
	__u8				smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE];
	__u8				smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
	__u8				smb3signingkey[SMB3_SIGN_KEY_SIZE];

	struct list_head		sessions_entry;
+7 −4
Original line number Diff line number Diff line
@@ -904,7 +904,9 @@ static int decode_encrypt_ctxt(struct ksmbd_conn *conn,

	for (i = 0; i < cph_cnt; i++) {
		if (pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_GCM ||
		    pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_CCM) {
		    pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_CCM ||
		    pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_CCM ||
		    pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES256_GCM) {
			ksmbd_debug(SMB, "Cipher ID = 0x%x\n",
				pneg_ctxt->Ciphers[i]);
			conn->cipher_type = pneg_ctxt->Ciphers[i];
@@ -7979,10 +7981,11 @@ static void fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, char *old_buf,
	tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
	tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
	tr_hdr->Flags = cpu_to_le16(0x01);
	if (cipher_type == SMB2_ENCRYPTION_AES128_GCM)
		get_random_bytes(&tr_hdr->Nonce, SMB3_AES128GCM_NONCE);
	if (cipher_type == SMB2_ENCRYPTION_AES128_GCM ||
	    cipher_type == SMB2_ENCRYPTION_AES256_GCM)
		get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
	else
		get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CCM_NONCE);
		get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
	memcpy(&tr_hdr->SessionId, &hdr->SessionId, 8);
	inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4);
	inc_rfc1001_len(tr_hdr, orig_len);
Loading