linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Erlend Aasland <erlend-a@ux.his.no>
To: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: [RFC][PATCH] 1st try to convert cifs to use CryptoAPI
Date: Mon, 1 Sep 2003 22:40:35 +0200	[thread overview]
Message-ID: <20030901204035.GA2626@badne3.ux.his.no> (raw)

Hi,

I'm trying to learn a thing or two about the new CryptoAPI, and I
thought a good way to learn was to try to accomplish one of the minor
items on the Crypto-TODO list. So:

CIFS currently use it's own MD4/MD5 code. I've started to convert it
to using the CryptoAPI, but I'm far from an CIFS/CryptoAPI expert, so my
question is: is this patch totally bogus, or am I doing something
right?

I haven't tested it, it's not beautiful, it's probably broken, but I
hope I'm using the CryptoAPI correct... (yup, I know the extern things
are ugly, should create a cifsencrypt.h header or something...)

(If there is some meaning in this patch, I'd like to improve it and
try to continue to convert the rest of CIFS to the CryptoAPI)

Here it is:

diff -urN linux-2.6.0-test4-bk2/fs/cifs/cifsencrypt.c linux-2.6.0-test4-bk2-cifs-crypto/fs/cifs/cifsencrypt.c
--- linux-2.6.0-test4-bk2/fs/cifs/cifsencrypt.c	2003-08-23 01:57:13.000000000 +0200
+++ linux-2.6.0-test4-bk2-cifs-crypto/fs/cifs/cifsencrypt.c	2003-08-29 10:51:39.000000000 +0200
@@ -20,10 +20,11 @@
  */
 
 #include <linux/fs.h>
+#include <linux/crypto.h>
+#include <asm/scattelist.h>
 #include "cifspdu.h"
 #include "cifsglob.h" 
 #include "cifs_debug.h"
-#include "md5.h"
 #include "cifs_unicode.h"
 
 /* Calculate and return the CIFS signature based on the mac key and the smb pdu */
@@ -32,20 +33,37 @@
 /* Note that the smb header signature field on input contains the  
 	sequence number before this function is called */
 
-extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-	
+/* smbencrypt.c */
+extern void SMBencrypt_prepare_keys(u8 *ikey, u8 *okey, u8 *in, int len);
+extern void SMBencrypt_finish_md5(u8 *key, u8 *digest);
+
+/* cifsfs.c */
+extern spinlock_t md5_tfm_lock;
+extern spinlock_t md4_tfm_lock;
+extern struct crypto_tfm *md5_tfm;
+extern struct crypto_tfm *md4_tfm;
+
 static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature)
 {
-	struct	MD5Context context;
+	struct scatterlist sg[2];
 
 	if((cifs_pdu == NULL) || (signature == NULL))
 		return -EINVAL;
 
-	MD5Init(&context);
-	MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
-	MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
-	MD5Final(signature,&context);
+	sg[0].page = virt_to_page(key);
+	sg[0].offset = offset_in_page(key);
+	sg[0].length = CIFS_SESSION_KEY_SIZE+16;
+	sg[1].page = virt_to_page(cifs_pdu->Protocol);
+	sg[1].offset = offset_in_page(cifs_pdu->Protocol);
+	sg[1].length = cifs_pdu->smb_buf_length;
+
+	spin_lock(&md5_tfm_lock);
+	crypto_digest_init(md5_tfm);
+	crypto_digest_update(md5_tfm, sg, 2);
+	crypto_digest_final(md5_tfm, signature);
+	spin_unlock(&md5_tfm_lock);
+
 	return 0;
 }
 
@@ -136,29 +154,42 @@
 int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
 {
 	char temp_key[16];
+	struct scatterlist sg;
+
 	if ((key == NULL) || (rn == NULL) || (password == NULL))
 		return -EINVAL;
 
+	sg.page = virt_to_page(temp_key);
+	sg.offset = offset_in_page(temp_key);
+	sg.length = 16;
+
 	E_md4hash(password, temp_key);
-	mdfour(key,temp_key,16);
+
+	spin_lock(&md4_tfm_lock);
+	crypto_digest_init(md4_tfm);
+	crypto_digest_update(md4_tfm, sg, 1);
+	crypto_digest_final(md4_tfm, key);
+	spin_unlock(&md4_tfm_lock);
 	memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
+
 	return 0;
 }
 
 int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
 {
 	char temp_hash[16];
-	struct HMACMD5Context ctx;
 	char * ucase_buf;
 	wchar_t * unicode_buf;
 	unsigned int i,user_name_len,dom_name_len;
+	u8 ikey[65], okey[65];
+	struct scatterlist sg[2];
 
 	if(ses)
 		return -EINVAL;
 
 	E_md4hash(ses->password_with_pad, temp_hash);
 
-	hmac_md5_init_limK_to_64(temp_hash, 16, &ctx);
+	SMBencrypt_prepare_keys(ikey, okey, temp_hash, 16);
 	user_name_len = strlen(ses->userName);
 	if(user_name_len > MAX_USERNAME_SIZE)
 		return -EINVAL;
@@ -183,24 +214,50 @@
         dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
 
 	unicode_buf[user_name_len + dom_name_len] = 0;
-	hmac_md5_update((const unsigned char *) unicode_buf,
-		(user_name_len+dom_name_len)*2,&ctx);
 
-	hmac_md5_final(ses->mac_signing_key,&ctx);
+	sg[0].page = virt_to_page(ikey);
+	sg[0].offset = offset_in_page(ikey);
+	sg[0].length = 64;
+	sg[1].page = virt_to_page(unicode_buf);
+	sg[1].offset = offset_in_page(unicode_buf);
+	sg[1].length = (user_name_len+dom_name_len)*2;
+
+	spin_lock(&md5_tfm_lock);
+	crypto_digest_init(md5_tfm);
+	crypto_digest_update(md5_tfm, sg, 2);
+	crypto_digest_final(md5_tfm, ses->mac_signing_key);
+	spin_unlock(&md5_tfm_lock);
+
+	SMBencrypt_finish_md5(okey, ses->mac_signing_key);
+
 	kfree(ucase_buf);
 	kfree(unicode_buf);
 	return 0;
 }
 void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
 {
+	u8 ikey[65], okey[65];
+	struct scatterlist sg[2];
 	struct HMACMD5Context context;
+
 	memcpy(v2_session_response + 8, ses->server->cryptKey,8);
 	/* gen_blob(v2_session_response + 16); */
-	hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context);
 
-	hmac_md5_update(ses->server->cryptKey,8,&context);
+	SMBencrypt_prepare_keys(ikey, okey, ses->mac_signing_key, 16);
+
+	sg[0].page = virt_to_page(ikey);
+	sg[0].offset = offset_in_page(ikey);
+	sg[0].length = 64;
+	sg[1].page = virt_to_page(ses->server->cryptKey);
+	sg[1].offset = offset_in_page(ses->server->cryptKey);
+	sg[1].length = 8;
 /*	hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
 
+	spin_lock(&md5_tfm_lock);
+	crypto_digest_init(md5_tfm);
+	crypto_digest_update(md5_tfm, sg, 2);
+	crypto_digest_final(md5_tfm, v2_session_response);
+	spin_unlock(&md5_tfm_lock);
 
-	hmac_md5_final(v2_session_response,&context);
+	SMBencrypt_finish_md5(okey, v2_session_response);
 }
diff -urN linux-2.6.0-test4-bk2/fs/cifs/cifsfs.c linux-2.6.0-test4-bk2-cifs-crypto/fs/cifs/cifsfs.c
--- linux-2.6.0-test4-bk2/fs/cifs/cifsfs.c	2003-08-23 01:56:30.000000000 +0200
+++ linux-2.6.0-test4-bk2-cifs-crypto/fs/cifs/cifsfs.c	2003-08-29 10:22:17.000000000 +0200
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/seq_file.h>
 #include <linux/vfs.h>
+#include <linux/crypto.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
 #define DECLARE_GLOBALS_HERE
@@ -60,6 +61,10 @@
 unsigned int sign_CIFS_PDUs = 1;
 unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
 struct task_struct * oplockThread = NULL;
+static struct crypto_tfm *md5_tfm;
+static struct crypto_tfm *md4_tfm;
+static spinlock_t md5_tfm_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t md4_tfm_lock = SPIN_LOCK_UNLOCKED;
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
 			const char *);
@@ -643,6 +648,18 @@
 
 	rc = cifs_init_inodecache();
 	if (!rc) {
+		md5_tfm = crypto_alloc_tfm("md5", 0);
+		if (unlikely(md5_tfm == NULL)) {
+			printk(KERN_ERROR "failed to load transform for md5\n");
+			rc = 0;
+		}
+		md4_tfm = crypto_alloc_tfm("md4", 0);
+		if (unlikely(md4_tfm == NULL)) {
+			printk(KERN_ERROR "failed to load transform for md4\n");
+			rc = 0;
+		}
+	}
+	if (!rc) {
 		rc = cifs_init_mids();
 		if (!rc) {
 			rc = cifs_init_request_bufs();
@@ -659,6 +676,7 @@
 		}
 		cifs_destroy_inodecache();
 	}
+
 #ifdef CONFIG_PROC_FS
 	cifs_proc_clean();
 #endif
@@ -680,6 +698,14 @@
 		send_sig(SIGTERM, oplockThread, 1);
 		wait_for_completion(&cifs_oplock_exited);
 	}
+	if (likely(md5_tfm != NULL)) {
+		crypto_free_tfm(md5_tfm);
+		md5_tfm = NULL;
+	}
+	if (likely(md4_tfm != NULL)) {
+		crypto_free_tfm(md4_tfm);
+		md4_tfm = NULL;
+	}
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
diff -urN linux-2.6.0-test4-bk2/fs/cifs/smbencrypt.c linux-2.6.0-test4-bk2-cifs-crypto/fs/cifs/smbencrypt.c
--- linux-2.6.0-test4-bk2/fs/cifs/smbencrypt.c	2003-08-23 01:55:42.000000000 +0200
+++ linux-2.6.0-test4-bk2-cifs-crypto/fs/cifs/smbencrypt.c	2003-08-29 10:51:46.000000000 +0200
@@ -30,10 +30,12 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/random.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
 #include "cifs_unicode.h"
 #include "cifspdu.h"
-#include "md5.h"
 #include "cifs_debug.h"
+#include "cifs_encrypt.h"
 
 #ifndef FALSE
 #define FALSE 0
@@ -49,10 +51,6 @@
 #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
 #define SIVAL(buf,pos,val) SIVALX((buf),(pos),((__u32)(val)))
 
-/*The following definitions come from  lib/md4.c  */
-
-void mdfour(unsigned char *out, unsigned char *in, int n);
-
 /*The following definitions come from  libsmb/smbdes.c  */
 
 void E_P16(unsigned char *p14, unsigned char *p16);
@@ -80,6 +78,12 @@
 int decode_pw_buffer(char in_buffer[516], char *new_pwrd,
 		     int new_pwrd_size, __u32 * new_pw_len);
 
+/* cifsfs.c */
+extern spinlock_t md5_tfm_lock;
+extern spinlock_t md4_tfm_lock;
+extern struct crypto_tfm *md5_tfm;
+extern struct crypto_tfm *md4_tfm;
+
 /*
    This implements the X/Open SMB password encryption
    It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
@@ -109,6 +113,43 @@
 	memset(p21,0,21);
 }
 
+void
+SMBencrypt_prepare_keys(u8 *ikey, u8 *okey, const u8 *in, int len)
+{
+	int i;
+
+	len &= 0x2f;
+
+	memset(ikey, 0, 64);
+	memset(okey, 0, 64);
+	memcpy(ikey, in, len);
+	memcpy(okey, in, len);
+
+	for (i = 0; i < 64; i++) {
+		ikey[i] ^= 0x36;
+		okey[i] ^= 0x5c;
+	}
+}
+
+void
+SMBencrypt_finish_md5(u8 *key, u8 *digest)
+{
+	struct scatterlist[2];
+
+	sg[0].page = virt_to_page(key);
+	sg[0].offset = offset_in_page(key);
+	sg[0].length = 64;
+	sg[1].page = virt_to_page(digest);
+	sg[1].offset = offset_in_page(digest);
+	sg[1].length = 16;
+    
+	spin_lock(&md5_tfm_lock);
+	crypto_digest_init(md5_tfm);
+	crypto_digest_update(md5_tfm, sg, 2);
+	crypto_digest_final(md5_tfm, digest);
+	spin_unlock(&md5_tfm_lock);
+}
+	
 /* Routines for Windows NT MD4 Hash functions. */
 static int
 _my_wcslen(__u16 * str)
@@ -152,6 +193,7 @@
 {
 	int len;
 	__u16 wpwd[129];
+	struct scatterlist sg;
 
 	/* Password cannot be longer than 128 characters */
 	len = strlen((char *) passwd);
@@ -163,7 +205,15 @@
 	/* Calculate length in bytes */
 	len = _my_wcslen(wpwd) * sizeof (__u16);
 
-	mdfour(p16, (unsigned char *) wpwd, len);
+	sg.page = virt_to_page(wpwd);
+	sg.offset = offset_in_page(wpwd);
+	sg.length = len;
+
+	spin_lock(&md4_tfm_lock);
+	crypto_digest_init(md4_tfm);
+	crypto_digest_update(md4_tfm, sg, 1);
+	crypto_digest_final(md4_tfm, p16);
+	spin_unlock(&md4_tfm_lock);
 	memset(wpwd,0,129 * 2);
 }
 
@@ -212,17 +262,18 @@
 		const char *domain_n, unsigned char kr_buf[16],
 		const struct nls_table *nls_codepage)
 {
+	struct scatterlist sg[3];
 	wchar_t * user_u;
 	wchar_t * dom_u;
 	int user_l, domain_l;
-	struct HMACMD5Context ctx;
+	u8 ikey[65], okey[65];
 
 	/* might as well do one alloc to hold both (user_u and dom_u) */
 	user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); 
 	if(user_u == NULL)
 		return;
 	dom_u = user_u + 1024;
-    
+
 	/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
 	   push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
 
@@ -233,10 +284,25 @@
 	user_l++;		/* trailing null */
 	domain_l++;
 
-	hmac_md5_init_limK_to_64(owf, 16, &ctx);
-	hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx);
-	hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx);
-	hmac_md5_final(kr_buf, &ctx);
+	SMBencrypt_prepare_keys(ikey, okey, owf, 16);
+
+	sg[0].page = virt_to_page(ikey);
+	sg[0].offset = offset_in_page(ikey);
+	sg[0].length = 64;
+	sg[1].page = virt_to_page(user_u);
+	sg[1].offset = offset_in_page(user_u);
+	sg[1].length = user_l;
+	sg[2].page = virt_to_page(dom_u);
+	sg[2].offset = offset_in_page(dom_u);
+	sg[2].length = domain_l;
+    
+	spin_lock(&md5_tfm_lock);
+	crypto_digest_init(md5_tfm);
+	crypto_digest_update(md5_tfm, sg, 3);
+	crypto_digest_final(md5_tfm, kr_buf);
+	spin_unlock(&md5_tfm_lock);
+
+	SMBencrypt_finish_md5(okey, kr_buf);
 
 #ifdef DEBUG_PASSWORD
 	DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
@@ -307,12 +373,28 @@
                    const struct data_blob * srv_chal,
                    const struct data_blob * cli_chal, unsigned char resp_buf[16])
 {
-        struct HMACMD5Context ctx;
+        struct scatterlist sg[3];
+	u8 ikey[65], okey[65];
+
+	SMBencrypt_prepare_keys(ikey, okey, kr, 16);
+
+	sg[0].page = virt_to_page(ikey);
+	sg[0].offset = offset_in_page(ikey);
+	sg[0].length = 64;
+	sg[1].page = virt_to_page(srv_chal->data);
+	sg[1].offset = offset_in_page(srv_chal->data);
+	sg[1].length = srv_chal->length;
+	sg[2].page = virt_to_page(cli_chal->data);
+	sg[2].offset = offset_in_page(cli_chal->data);
+	sg[2].length = cli_chal->length;
+
+	spin_lock(&md5_tfm_lock);
+        crypto_digest_init(md5_tfm);
+	crypto_digest_update(md5_tfm, sg, 3);
+	crypto_digest_final(md5_tfm, resp_buf);
+	spin_unlock(&md5_tfm_lock);
 
-        hmac_md5_init_limK_to_64(kr, 16, &ctx);
-        hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
-        hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
-        hmac_md5_final(resp_buf, &ctx);
+	SMBencrypt_finish_md5(okey, resp_buf);
 
 #ifdef DEBUG_PASSWORD
         DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
@@ -390,11 +472,25 @@
 SMBsesskeygen_ntv2(const unsigned char kr[16],
 		   const unsigned char *nt_resp, __u8 sess_key[16])
 {
-	struct HMACMD5Context ctx;
+	struct scatterlist sg[2];
+	u8 ikey[65], okey[65];
 
-	hmac_md5_init_limK_to_64(kr, 16, &ctx);
-	hmac_md5_update(nt_resp, 16, &ctx);
-	hmac_md5_final((unsigned char *) sess_key, &ctx);
+	SMBencrypt_prepare_keys(ikey, okey, kr, 16);
+
+	sg[0].page = virt_to_page(ikey);
+	sg[0].offset = offset_in_page(ikey);
+	sg[0].length = 64;
+	sg[1].page = virt_to_page(nt_resp);
+	sg[1].offset = offset_in_page(nt_resp);
+	sg[1].length = 16;
+
+	spin_lock(&md5_tfm_lock);
+	crypto_digest_init(md5_tfm);
+	crypto_digest_update(md5_tfm, sg, 2);
+	crypto_digest_final(md5_tfm, sess_key);
+	spin_unlock(&md5_tfm_lock);
+
+	SMBencrypt_finish_md5(okey, sess_key);
 
 #ifdef DEBUG_PASSWORD
 	DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
@@ -406,7 +502,17 @@
 SMBsesskeygen_ntv1(const unsigned char kr[16],
 		   const unsigned char *nt_resp, __u8 sess_key[16])
 {
-	mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16);
+	struct scatterlist sg;
+
+	sg.page = virt_to_page(kr);
+	sg.offset = offset_in_page(kr);
+	sg.length = 16;
+
+	spin_lock(&md4_tfm_lock);
+	crypto_digest_init(md4_tfm);
+	crypto_digest_update(md4_tfm, sg, 1);
+	crypto_digest_final(md4_tfm, sess_key);
+	spin_unlock(&md4_tfm_lock);
 
 #ifdef DEBUG_PASSWORD
 	DEBUG(100, ("SMBsesskeygen_ntv1:\n"));

                 reply	other threads:[~2003-09-01 20:40 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030901204035.GA2626@badne3.ux.his.no \
    --to=erlend-a@ux.his.no \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).