File Index
Files and directories
Sign in
FILE

cifsencrypt.c

File preview with syntax highlighting.

linux-6.19.14/fs/smb/client/cifsencrypt.c C
  1// SPDX-License-Identifier: LGPL-2.1
  2/*
  3 *
  4 *   Encryption and hashing operations relating to NTLM, NTLMv2.  See MS-NLMP
  5 *   for more detailed information
  6 *
  7 *   Copyright (C) International Business Machines  Corp., 2005,2013
  8 *   Author(s): Steve French (sfrench@us.ibm.com)
  9 *
 10 */
 11
 12#include <linux/fs.h>
 13#include <linux/slab.h>
 14#include "cifspdu.h"
 15#include "cifsglob.h"
 16#include "cifs_debug.h"
 17#include "cifs_unicode.h"
 18#include "cifsproto.h"
 19#include "ntlmssp.h"
 20#include <linux/ctype.h>
 21#include <linux/random.h>
 22#include <linux/highmem.h>
 23#include <linux/fips.h>
 24#include <linux/iov_iter.h>
 25#include <crypto/aead.h>
 26#include <crypto/arc4.h>
 27#include <crypto/md5.h>
 28#include <crypto/sha2.h>
 29
 30static int cifs_sig_update(struct cifs_calc_sig_ctx *ctx,
 31			   const u8 *data, size_t len)
 32{
 33	if (ctx->md5) {
 34		md5_update(ctx->md5, data, len);
 35		return 0;
 36	}
 37	if (ctx->hmac) {
 38		hmac_sha256_update(ctx->hmac, data, len);
 39		return 0;
 40	}
 41	return crypto_shash_update(ctx->shash, data, len);
 42}
 43
 44static int cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
 45{
 46	if (ctx->md5) {
 47		md5_final(ctx->md5, out);
 48		return 0;
 49	}
 50	if (ctx->hmac) {
 51		hmac_sha256_final(ctx->hmac, out);
 52		return 0;
 53	}
 54	return crypto_shash_final(ctx->shash, out);
 55}
 56
 57static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
 58			    void *priv, void *priv2)
 59{
 60	struct cifs_calc_sig_ctx *ctx = priv;
 61	int ret, *pret = priv2;
 62
 63	ret = cifs_sig_update(ctx, iter_base, len);
 64	if (ret < 0) {
 65		*pret = ret;
 66		return len;
 67	}
 68	return 0;
 69}
 70
 71/*
 72 * Pass the data from an iterator into a hash.
 73 */
 74static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize,
 75			 struct cifs_calc_sig_ctx *ctx)
 76{
 77	struct iov_iter tmp_iter = *iter;
 78	size_t did;
 79	int err;
 80
 81	did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err,
 82					 cifs_sig_step);
 83	if (did != maxsize)
 84		return smb_EIO2(smb_eio_trace_sig_iter, did, maxsize);
 85	return 0;
 86}
 87
 88int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 89			  char *signature, struct cifs_calc_sig_ctx *ctx)
 90{
 91	struct iov_iter iter;
 92	ssize_t rc;
 93	size_t size = 0;
 94
 95	for (int i = 0; i < rqst->rq_nvec; i++)
 96		size += rqst->rq_iov[i].iov_len;
 97
 98	iov_iter_kvec(&iter, ITER_SOURCE, rqst->rq_iov, rqst->rq_nvec, size);
 99
100	if (iov_iter_count(&iter) <= 4)
101		return smb_EIO2(smb_eio_trace_sig_data_too_small,
102				iov_iter_count(&iter), 4);
103
104	rc = cifs_sig_iter(&iter, iov_iter_count(&iter), ctx);
105	if (rc < 0)
106		return rc;
107
108	rc = cifs_sig_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), ctx);
109	if (rc < 0)
110		return rc;
111
112	rc = cifs_sig_final(ctx, signature);
113	if (rc)
114		cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
115
116	return rc;
117}
118
119/*
120 * Calculate and return the CIFS signature based on the mac key and SMB PDU.
121 * The 16 byte signature must be allocated by the caller. Note we only use the
122 * 1st eight bytes and that the smb header signature field on input contains
123 * the sequence number before this function is called. Also, this function
124 * should be called with the server->srv_mutex held.
125 */
126static int cifs_calc_signature(struct smb_rqst *rqst,
127			struct TCP_Server_Info *server, char *signature)
128{
129	struct md5_ctx ctx;
130
131	if (!rqst->rq_iov || !signature || !server)
132		return -EINVAL;
133	if (fips_enabled) {
134		cifs_dbg(VFS,
135			 "MD5 signature support is disabled due to FIPS\n");
136		return -EOPNOTSUPP;
137	}
138
139	md5_init(&ctx);
140	md5_update(&ctx, server->session_key.response, server->session_key.len);
141
142	return __cifs_calc_signature(
143		rqst, server, signature,
144		&(struct cifs_calc_sig_ctx){ .md5 = &ctx });
145}
146
147/* must be called with server->srv_mutex held */
148int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
149		   __u32 *pexpected_response_sequence_number)
150{
151	int rc = 0;
152	char smb_signature[20];
153	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
154
155	if ((cifs_pdu == NULL) || (server == NULL))
156		return -EINVAL;
157
158	spin_lock(&server->srv_lock);
159	if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
160	    server->tcpStatus == CifsNeedNegotiate) {
161		spin_unlock(&server->srv_lock);
162		return rc;
163	}
164	spin_unlock(&server->srv_lock);
165
166	if (!server->session_estab) {
167		memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
168		return rc;
169	}
170
171	cifs_pdu->Signature.Sequence.SequenceNumber =
172				cpu_to_le32(server->sequence_number);
173	cifs_pdu->Signature.Sequence.Reserved = 0;
174
175	*pexpected_response_sequence_number = ++server->sequence_number;
176	++server->sequence_number;
177
178	rc = cifs_calc_signature(rqst, server, smb_signature);
179	if (rc)
180		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
181	else
182		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
183
184	return rc;
185}
186
187int cifs_verify_signature(struct smb_rqst *rqst,
188			  struct TCP_Server_Info *server,
189			  __u32 expected_sequence_number)
190{
191	unsigned int rc;
192	char server_response_sig[8];
193	char what_we_think_sig_should_be[20];
194	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
195
196	if (cifs_pdu == NULL || server == NULL)
197		return -EINVAL;
198
199	if (!server->session_estab)
200		return 0;
201
202	if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
203		struct smb_com_lock_req *pSMB =
204			(struct smb_com_lock_req *)cifs_pdu;
205		if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
206			return 0;
207	}
208
209	/* BB what if signatures are supposed to be on for session but
210	   server does not send one? BB */
211
212	/* Do not need to verify session setups with signature "BSRSPYL "  */
213	if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
214		cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
215			 cifs_pdu->Command);
216
217	/* save off the original signature so we can modify the smb and check
218		its signature against what the server sent */
219	memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
220
221	cifs_pdu->Signature.Sequence.SequenceNumber =
222					cpu_to_le32(expected_sequence_number);
223	cifs_pdu->Signature.Sequence.Reserved = 0;
224
225	cifs_server_lock(server);
226	rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
227	cifs_server_unlock(server);
228
229	if (rc)
230		return rc;
231
232/*	cifs_dump_mem("what we think it should be: ",
233		      what_we_think_sig_should_be, 16); */
234
235	if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
236		return -EACCES;
237	else
238		return 0;
239
240}
241
242/* Build a proper attribute value/target info pairs blob.
243 * Fill in netbios and dns domain name and workstation name
244 * and client time (total five av pairs and + one end of fields indicator.
245 * Allocate domain name which gets freed when session struct is deallocated.
246 */
247static int
248build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
249{
250	unsigned int dlen;
251	unsigned int size = 2 * sizeof(struct ntlmssp2_name);
252	char *defdmname = "WORKGROUP";
253	unsigned char *blobptr;
254	struct ntlmssp2_name *attrptr;
255
256	if (!ses->domainName) {
257		ses->domainName = kstrdup(defdmname, GFP_KERNEL);
258		if (!ses->domainName)
259			return -ENOMEM;
260	}
261
262	dlen = strlen(ses->domainName);
263
264	/*
265	 * The length of this blob is two times the size of a
266	 * structure (av pair) which holds name/size
267	 * ( for NTLMSSP_AV_NB_DOMAIN_NAME followed by NTLMSSP_AV_EOL ) +
268	 * unicode length of a netbios domain name
269	 */
270	kfree_sensitive(ses->auth_key.response);
271	ses->auth_key.len = size + 2 * dlen;
272	ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
273	if (!ses->auth_key.response) {
274		ses->auth_key.len = 0;
275		return -ENOMEM;
276	}
277
278	blobptr = ses->auth_key.response;
279	attrptr = (struct ntlmssp2_name *) blobptr;
280
281	/*
282	 * As defined in MS-NTLM 3.3.2, just this av pair field
283	 * is sufficient as part of the temp
284	 */
285	attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME);
286	attrptr->length = cpu_to_le16(2 * dlen);
287	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
288	cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, nls_cp);
289
290	return 0;
291}
292
293#define AV_TYPE(av)		(le16_to_cpu(av->type))
294#define AV_LEN(av)		(le16_to_cpu(av->length))
295#define AV_DATA_PTR(av)	((void *)av->data)
296
297#define av_for_each_entry(ses, av) \
298	for (av = NULL; (av = find_next_av(ses, av));)
299
300static struct ntlmssp2_name *find_next_av(struct cifs_ses *ses,
301					  struct ntlmssp2_name *av)
302{
303	u16 len;
304	u8 *end;
305
306	end = (u8 *)ses->auth_key.response + ses->auth_key.len;
307	if (!av) {
308		if (unlikely(!ses->auth_key.response || !ses->auth_key.len))
309			return NULL;
310		av = (void *)ses->auth_key.response;
311	} else {
312		av = (void *)((u8 *)av + sizeof(*av) + AV_LEN(av));
313	}
314
315	if ((u8 *)av + sizeof(*av) > end)
316		return NULL;
317
318	len = AV_LEN(av);
319	if (AV_TYPE(av) == NTLMSSP_AV_EOL)
320		return NULL;
321	if ((u8 *)av + sizeof(*av) + len > end)
322		return NULL;
323	return av;
324}
325
326/*
327 * Check if server has provided av pair of @type in the NTLMSSP
328 * CHALLENGE_MESSAGE blob.
329 */
330static int find_av_name(struct cifs_ses *ses, u16 type, char **name, u16 maxlen)
331{
332	const struct nls_table *nlsc = ses->local_nls;
333	struct ntlmssp2_name *av;
334	u16 len, nlen;
335
336	if (*name)
337		return 0;
338
339	av_for_each_entry(ses, av) {
340		len = AV_LEN(av);
341		if (AV_TYPE(av) != type || !len)
342			continue;
343		if (!IS_ALIGNED(len, sizeof(__le16))) {
344			cifs_dbg(VFS | ONCE, "%s: bad length(%u) for type %u\n",
345				 __func__, len, type);
346			continue;
347		}
348		nlen = len / sizeof(__le16);
349		if (nlen <= maxlen) {
350			++nlen;
351			*name = kmalloc(nlen, GFP_KERNEL);
352			if (!*name)
353				return -ENOMEM;
354			cifs_from_utf16(*name, AV_DATA_PTR(av), nlen,
355					len, nlsc, NO_MAP_UNI_RSVD);
356			break;
357		}
358	}
359	return 0;
360}
361
362/* Server has provided av pairs/target info in the type 2 challenge
363 * packet and we have plucked it and stored within smb session.
364 * We parse that blob here to find the server given timestamp
365 * as part of ntlmv2 authentication (or local current time as
366 * default in case of failure)
367 */
368static __le64 find_timestamp(struct cifs_ses *ses)
369{
370	struct ntlmssp2_name *av;
371	struct timespec64 ts;
372
373	av_for_each_entry(ses, av) {
374		if (AV_TYPE(av) == NTLMSSP_AV_TIMESTAMP &&
375		    AV_LEN(av) == sizeof(u64))
376			return *((__le64 *)AV_DATA_PTR(av));
377	}
378	ktime_get_real_ts64(&ts);
379	return cpu_to_le64(cifs_UnixTimeToNT(ts));
380}
381
382static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
383			    const struct nls_table *nls_cp)
384{
385	int len;
386	char nt_hash[CIFS_NTHASH_SIZE];
387	struct hmac_md5_ctx hmac_ctx;
388	__le16 *user;
389	wchar_t *domain;
390	wchar_t *server;
391
392	/* calculate md4 hash of password */
393	E_md4hash(ses->password, nt_hash, nls_cp);
394
395	hmac_md5_init_usingrawkey(&hmac_ctx, nt_hash, CIFS_NTHASH_SIZE);
396
397	/* convert ses->user_name to unicode */
398	len = ses->user_name ? strlen(ses->user_name) : 0;
399	user = kmalloc(2 + (len * 2), GFP_KERNEL);
400	if (user == NULL)
401		return -ENOMEM;
402
403	if (len) {
404		len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
405		UniStrupr(user);
406	} else {
407		*(u16 *)user = 0;
408	}
409
410	hmac_md5_update(&hmac_ctx, (const u8 *)user, 2 * len);
411	kfree(user);
412
413	/* convert ses->domainName to unicode and uppercase */
414	if (ses->domainName) {
415		len = strlen(ses->domainName);
416
417		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
418		if (domain == NULL)
419			return -ENOMEM;
420
421		len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
422				      nls_cp);
423		hmac_md5_update(&hmac_ctx, (const u8 *)domain, 2 * len);
424		kfree(domain);
425	} else {
426		/* We use ses->ip_addr if no domain name available */
427		len = strlen(ses->ip_addr);
428
429		server = kmalloc(2 + (len * 2), GFP_KERNEL);
430		if (server == NULL)
431			return -ENOMEM;
432
433		len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp);
434		hmac_md5_update(&hmac_ctx, (const u8 *)server, 2 * len);
435		kfree(server);
436	}
437
438	hmac_md5_final(&hmac_ctx, ntlmv2_hash);
439	return 0;
440}
441
442static void CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
443{
444	struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
445	    (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
446	unsigned int hash_len;
447
448	/* The MD5 hash starts at challenge_key.key */
449	hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
450		offsetof(struct ntlmv2_resp, challenge.key[0]));
451
452	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
453		memcpy(ntlmv2->challenge.key, ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
454	else
455		memcpy(ntlmv2->challenge.key, ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
456
457	/* Note that the HMAC-MD5 value overwrites ntlmv2->challenge.key */
458	hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
459			     ntlmv2->challenge.key, hash_len,
460			     ntlmv2->ntlmv2_hash);
461}
462
463/*
464 * Set up NTLMv2 response blob with SPN (cifs/<hostname>) appended to the
465 * existing list of AV pairs.
466 */
467static int set_auth_key_response(struct cifs_ses *ses)
468{
469	size_t baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
470	size_t len, spnlen, tilen = 0, num_avs = 2 /* SPN + EOL */;
471	struct TCP_Server_Info *server = ses->server;
472	char *spn __free(kfree) = NULL;
473	struct ntlmssp2_name *av;
474	char *rsp = NULL;
475	int rc;
476
477	spnlen = strlen(server->hostname);
478	len = sizeof("cifs/") + spnlen;
479	spn = kmalloc(len, GFP_KERNEL);
480	if (!spn) {
481		rc = -ENOMEM;
482		goto out;
483	}
484
485	spnlen = scnprintf(spn, len, "cifs/%.*s",
486			   (int)spnlen, server->hostname);
487
488	av_for_each_entry(ses, av)
489		tilen += sizeof(*av) + AV_LEN(av);
490
491	len = baselen + tilen + spnlen * sizeof(__le16) + num_avs * sizeof(*av);
492	rsp = kmalloc(len, GFP_KERNEL);
493	if (!rsp) {
494		rc = -ENOMEM;
495		goto out;
496	}
497
498	memcpy(rsp + baselen, ses->auth_key.response, tilen);
499	av = (void *)(rsp + baselen + tilen);
500	av->type = cpu_to_le16(NTLMSSP_AV_TARGET_NAME);
501	av->length = cpu_to_le16(spnlen * sizeof(__le16));
502	cifs_strtoUTF16((__le16 *)av->data, spn, spnlen, ses->local_nls);
503	av = (void *)((__u8 *)av + sizeof(*av) + AV_LEN(av));
504	av->type = cpu_to_le16(NTLMSSP_AV_EOL);
505	av->length = 0;
506
507	rc = 0;
508	ses->auth_key.len = len;
509out:
510	ses->auth_key.response = rsp;
511	return rc;
512}
513
514int
515setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
516{
517	unsigned char *tiblob = NULL; /* target info blob */
518	struct ntlmv2_resp *ntlmv2;
519	char ntlmv2_hash[16];
520	__le64 rsp_timestamp;
521	__u64 cc;
522	int rc;
523
524	if (nls_cp == NULL) {
525		cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__);
526		return -EINVAL;
527	}
528
529	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
530		if (!ses->domainName) {
531			if (ses->domainAuto) {
532				/*
533				 * Domain (workgroup) hasn't been specified in
534				 * mount options, so try to find it in
535				 * CHALLENGE_MESSAGE message and then use it as
536				 * part of NTLMv2 authentication.
537				 */
538				rc = find_av_name(ses, NTLMSSP_AV_NB_DOMAIN_NAME,
539						  &ses->domainName,
540						  CIFS_MAX_DOMAINNAME_LEN);
541				if (rc)
542					goto setup_ntlmv2_rsp_ret;
543			} else {
544				ses->domainName = kstrdup("", GFP_KERNEL);
545				if (!ses->domainName) {
546					rc = -ENOMEM;
547					goto setup_ntlmv2_rsp_ret;
548				}
549			}
550		}
551		rc = find_av_name(ses, NTLMSSP_AV_DNS_DOMAIN_NAME,
552				  &ses->dns_dom, CIFS_MAX_DOMAINNAME_LEN);
553		if (rc)
554			goto setup_ntlmv2_rsp_ret;
555	} else {
556		rc = build_avpair_blob(ses, nls_cp);
557		if (rc) {
558			cifs_dbg(VFS, "error %d building av pair blob\n", rc);
559			goto setup_ntlmv2_rsp_ret;
560		}
561	}
562
563	/* Must be within 5 minutes of the server (or in range +/-2h
564	 * in case of Mac OS X), so simply carry over server timestamp
565	 * (as Windows 7 does)
566	 */
567	rsp_timestamp = find_timestamp(ses);
568	get_random_bytes(&cc, sizeof(cc));
569
570	cifs_server_lock(ses->server);
571
572	tiblob = ses->auth_key.response;
573	rc = set_auth_key_response(ses);
574	if (rc) {
575		ses->auth_key.len = 0;
576		goto unlock;
577	}
578
579	ntlmv2 = (struct ntlmv2_resp *)
580			(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
581	ntlmv2->blob_signature = cpu_to_le32(0x00000101);
582	ntlmv2->reserved = 0;
583	ntlmv2->time = rsp_timestamp;
584	ntlmv2->client_chal = cc;
585	ntlmv2->reserved2 = 0;
586
587	if (fips_enabled) {
588		cifs_dbg(VFS, "NTLMv2 support is disabled due to FIPS\n");
589		rc = -EOPNOTSUPP;
590		goto unlock;
591	}
592
593	/* calculate ntlmv2_hash */
594	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
595	if (rc) {
596		cifs_dbg(VFS, "Could not get NTLMv2 hash, rc=%d\n", rc);
597		goto unlock;
598	}
599
600	/* calculate first part of the client response (CR1) */
601	CalcNTLMv2_response(ses, ntlmv2_hash);
602
603	/* now calculate the session key for NTLMv2 */
604	hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
605			     ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
606			     ses->auth_key.response);
607	rc = 0;
608unlock:
609	cifs_server_unlock(ses->server);
610setup_ntlmv2_rsp_ret:
611	kfree_sensitive(tiblob);
612
613	return rc;
614}
615
616int
617calc_seckey(struct cifs_ses *ses)
618{
619	unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */
620	struct arc4_ctx *ctx_arc4;
621
622	if (fips_enabled)
623		return -ENODEV;
624
625	get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
626
627	ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
628	if (!ctx_arc4) {
629		cifs_dbg(VFS, "Could not allocate arc4 context\n");
630		return -ENOMEM;
631	}
632
633	arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
634	arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
635		   CIFS_CPHTXT_SIZE);
636
637	/* make secondary_key/nonce as session key */
638	memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
639	/* and make len as that of session key only */
640	ses->auth_key.len = CIFS_SESS_KEY_SIZE;
641
642	memzero_explicit(sec_key, CIFS_SESS_KEY_SIZE);
643	kfree_sensitive(ctx_arc4);
644	return 0;
645}
646
647void
648cifs_crypto_secmech_release(struct TCP_Server_Info *server)
649{
650	cifs_free_hash(&server->secmech.aes_cmac);
651
652	if (server->secmech.enc) {
653		crypto_free_aead(server->secmech.enc);
654		server->secmech.enc = NULL;
655	}
656	if (server->secmech.dec) {
657		crypto_free_aead(server->secmech.dec);
658		server->secmech.dec = NULL;
659	}
660}
~/ Read-only file preview.