xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c (revision e5803b76927480e8f9b67b22201c484ccf4c2bcf)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/md4.h>
30 #include <sys/types.h>
31 #include <string.h>
32 #include <security/cryptoki.h>
33 #include <security/pkcs11.h>
34 #include <cryptoutil.h>
35 #include <smbsrv/libsmb.h>
36 
37 static void smb_initlmkey(unsigned char *keyin, unsigned char *keyout);
38 
39 /*
40  * smb_auth_md4
41  *
42  * Compute an MD4 digest.
43  */
44 int
45 smb_auth_md4(unsigned char *result, unsigned char *input, int length)
46 {
47 	MD4_CTX md4_context;
48 
49 	MD4Init(&md4_context);
50 	MD4Update(&md4_context, input, length);
51 	MD4Final(result, &md4_context);
52 	return (SMBAUTH_SUCCESS);
53 }
54 
55 int
56 smb_auth_hmac_md5(unsigned char *data,
57 	int data_len,
58 	unsigned char *key,
59 	int key_len,
60 	unsigned char *digest)
61 {
62 	CK_RV rv;
63 	CK_MECHANISM mechanism;
64 	CK_OBJECT_HANDLE hKey;
65 	CK_SESSION_HANDLE hSession;
66 	CK_ULONG diglen = MD_DIGEST_LEN;
67 
68 	mechanism.mechanism = CKM_MD5_HMAC;
69 	mechanism.pParameter = 0;
70 	mechanism.ulParameterLen = 0;
71 	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
72 	if (rv != CKR_OK) {
73 		return (SMBAUTH_FAILURE);
74 	}
75 
76 	rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
77 	    key, key_len, &hKey);
78 	if (rv != CKR_OK) {
79 		(void) C_CloseSession(hSession);
80 		return (SMBAUTH_FAILURE);
81 	}
82 
83 	/* Initialize the digest operation in the session */
84 	rv = C_SignInit(hSession, &mechanism, hKey);
85 	if (rv != CKR_OK) {
86 		(void) C_DestroyObject(hSession, hKey);
87 		(void) C_CloseSession(hSession);
88 		return (SMBAUTH_FAILURE);
89 	}
90 	rv = C_SignUpdate(hSession, (CK_BYTE_PTR)data, data_len);
91 	if (rv != CKR_OK) {
92 		(void) C_DestroyObject(hSession, hKey);
93 		(void) C_CloseSession(hSession);
94 		return (SMBAUTH_FAILURE);
95 	}
96 	rv = C_SignFinal(hSession, (CK_BYTE_PTR)digest, &diglen);
97 	if (rv != CKR_OK) {
98 		(void) C_DestroyObject(hSession, hKey);
99 		(void) C_CloseSession(hSession);
100 		return (SMBAUTH_FAILURE);
101 	}
102 	(void) C_DestroyObject(hSession, hKey);
103 	(void) C_CloseSession(hSession);
104 	if (diglen != MD_DIGEST_LEN) {
105 		return (SMBAUTH_FAILURE);
106 	}
107 	return (SMBAUTH_SUCCESS);
108 }
109 
110 int
111 smb_auth_DES(unsigned char *Result, int ResultLen,
112     unsigned char *Key, int KeyLen,
113     unsigned char *Data, int DataLen)
114 {
115 	CK_RV rv;
116 	CK_MECHANISM mechanism;
117 	CK_OBJECT_HANDLE hKey;
118 	CK_SESSION_HANDLE hSession;
119 	CK_ULONG ciphertext_len;
120 	uchar_t des_key[8];
121 	int error = 0;
122 	int K, D;
123 	int k, d;
124 
125 	/* Calculate proper number of iterations */
126 	K = KeyLen / 7;
127 	D = DataLen / 8;
128 
129 	if (ResultLen < (K * 8 * D)) {
130 		return (SMBAUTH_FAILURE);
131 	}
132 
133 	/*
134 	 * Use SUNW convenience function to initialize the cryptoki
135 	 * library, and open a session with a slot that supports
136 	 * the mechanism we plan on using.
137 	 */
138 	mechanism.mechanism = CKM_DES_ECB;
139 	mechanism.pParameter = NULL;
140 	mechanism.ulParameterLen = 0;
141 	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
142 	if (rv != CKR_OK) {
143 		return (SMBAUTH_FAILURE);
144 	}
145 
146 	for (k = 0; k < K; k++) {
147 		smb_initlmkey(&Key[k * 7], des_key);
148 		rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
149 		    des_key, 8, &hKey);
150 		if (rv != CKR_OK) {
151 			error = 1;
152 			goto exit_session;
153 		}
154 		/* Initialize the encryption operation in the session */
155 		rv = C_EncryptInit(hSession, &mechanism, hKey);
156 		if (rv != CKR_OK) {
157 			error = 1;
158 			goto exit_encrypt;
159 		}
160 		ciphertext_len = DataLen;
161 		for (d = 0; d < D; d++) {
162 			/* Read in the data and encrypt this portion */
163 			rv = C_EncryptUpdate(hSession,
164 			    (CK_BYTE_PTR)Data + (d * 8), 8,
165 			    &Result[(k * (8 * D)) + (d * 8)],
166 			    &ciphertext_len);
167 			if (rv != CKR_OK) {
168 				error = 1;
169 				goto exit_encrypt;
170 			}
171 		}
172 		(void) C_DestroyObject(hSession, hKey);
173 	}
174 	goto exit_session;
175 
176 exit_encrypt:
177 	(void) C_DestroyObject(hSession, hKey);
178 exit_session:
179 	(void) C_CloseSession(hSession);
180 
181 	if (error)
182 		return (SMBAUTH_FAILURE);
183 
184 	return (SMBAUTH_SUCCESS);
185 }
186 
187 /*
188  * See "Netlogon Credential Computation" section of MS-NRPC document.
189  */
190 static void
191 smb_initlmkey(unsigned char *keyin, unsigned char *keyout)
192 {
193 	int i;
194 
195 	keyout[0] = keyin[0] >> 0x01;
196 	keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
197 	keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
198 	keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
199 	keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
200 	keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
201 	keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
202 	keyout[7] = keyin[6] & 0x7f;
203 
204 	for (i = 0; i < 8; i++)
205 		keyout[i] = (keyout[i] << 1) & 0xfe;
206 }
207