xref: /illumos-gate/usr/src/lib/libsmbfs/smb/crypt.c (revision 85e6b674)
1613a2f6bSGordon Ross /*
2613a2f6bSGordon Ross  * CDDL HEADER START
3613a2f6bSGordon Ross  *
4613a2f6bSGordon Ross  * The contents of this file are subject to the terms of the
5613a2f6bSGordon Ross  * Common Development and Distribution License (the "License").
6613a2f6bSGordon Ross  * You may not use this file except in compliance with the License.
7613a2f6bSGordon Ross  *
8613a2f6bSGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9613a2f6bSGordon Ross  * or http://www.opensolaris.org/os/licensing.
10613a2f6bSGordon Ross  * See the License for the specific language governing permissions
11613a2f6bSGordon Ross  * and limitations under the License.
12613a2f6bSGordon Ross  *
13613a2f6bSGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14613a2f6bSGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15613a2f6bSGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16613a2f6bSGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17613a2f6bSGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18613a2f6bSGordon Ross  *
19613a2f6bSGordon Ross  * CDDL HEADER END
20613a2f6bSGordon Ross  */
21613a2f6bSGordon Ross 
22613a2f6bSGordon Ross /*
23613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24613a2f6bSGordon Ross  * Use is subject to license terms.
25*85e6b674SGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
26613a2f6bSGordon Ross  */
27613a2f6bSGordon Ross 
28613a2f6bSGordon Ross /*
29613a2f6bSGordon Ross  * Crypto support, using libpkcs11
30613a2f6bSGordon Ross  *
31613a2f6bSGordon Ross  * Some code copied from the server: libsmb smb_crypt.c
32613a2f6bSGordon Ross  * with minor changes, i.e. errno.h return values.
33*85e6b674SGordon Ross  * XXX: Later, make the server use these.
34613a2f6bSGordon Ross  */
35613a2f6bSGordon Ross 
36613a2f6bSGordon Ross #include <sys/types.h>
37613a2f6bSGordon Ross #include <sys/md4.h>
38613a2f6bSGordon Ross 
39613a2f6bSGordon Ross #include <errno.h>
40613a2f6bSGordon Ross #include <fcntl.h>
41613a2f6bSGordon Ross #include <string.h>
42613a2f6bSGordon Ross 
43613a2f6bSGordon Ross #include <security/cryptoki.h>
44613a2f6bSGordon Ross #include <security/pkcs11.h>
45613a2f6bSGordon Ross #include <cryptoutil.h>
46613a2f6bSGordon Ross 
47613a2f6bSGordon Ross #include "smb_crypt.h"
48613a2f6bSGordon Ross 
49613a2f6bSGordon Ross static void
50613a2f6bSGordon Ross smb_initlmkey(uchar_t *keyout, const uchar_t *keyin);
51613a2f6bSGordon Ross 
52613a2f6bSGordon Ross /*
53613a2f6bSGordon Ross  * Like libsmb smb_auth_DES,
54613a2f6bSGordon Ross  * but use uchar_t, return errno.
55613a2f6bSGordon Ross  */
56613a2f6bSGordon Ross int
smb_encrypt_DES(uchar_t * Result,int ResultLen,const uchar_t * Key,int KeyLen,const uchar_t * Data,int DataLen)57613a2f6bSGordon Ross smb_encrypt_DES(uchar_t *Result, int ResultLen,
58613a2f6bSGordon Ross     const uchar_t *Key, int KeyLen,
59613a2f6bSGordon Ross     const uchar_t *Data, int DataLen)
60613a2f6bSGordon Ross {
61613a2f6bSGordon Ross 	CK_RV rv;
62613a2f6bSGordon Ross 	CK_MECHANISM mechanism;
63613a2f6bSGordon Ross 	CK_OBJECT_HANDLE hKey;
64613a2f6bSGordon Ross 	CK_SESSION_HANDLE hSession;
65613a2f6bSGordon Ross 	CK_ULONG ciphertext_len;
66613a2f6bSGordon Ross 	uchar_t des_key[8];
67613a2f6bSGordon Ross 	int error = 0;
68613a2f6bSGordon Ross 	int K, D;
69613a2f6bSGordon Ross 	int k, d;
70613a2f6bSGordon Ross 
71*85e6b674SGordon Ross 	/*
72*85e6b674SGordon Ross 	 * Calculate proper number of iterations.
73*85e6b674SGordon Ross 	 * Known call cases include:
74*85e6b674SGordon Ross 	 *   ResultLen=16, KeyLen=14, DataLen=8
75*85e6b674SGordon Ross 	 *   ResultLen=24, KeyLen=21, DataLen=8
76*85e6b674SGordon Ross 	 *   ResultLen=16, KeyLen=14, DataLen=16
77*85e6b674SGordon Ross 	 */
78613a2f6bSGordon Ross 	K = KeyLen / 7;
79613a2f6bSGordon Ross 	D = DataLen / 8;
80*85e6b674SGordon Ross 	if ((KeyLen % 7) || (DataLen % 8))
81*85e6b674SGordon Ross 		return (EINVAL);
82*85e6b674SGordon Ross 	if (K == 0 || D == 0)
83*85e6b674SGordon Ross 		return (EINVAL);
84*85e6b674SGordon Ross 	if (ResultLen < (K * 8))
85613a2f6bSGordon Ross 		return (EINVAL);
86613a2f6bSGordon Ross 
87613a2f6bSGordon Ross 	/*
88613a2f6bSGordon Ross 	 * Use SUNW convenience function to initialize the cryptoki
89613a2f6bSGordon Ross 	 * library, and open a session with a slot that supports
90613a2f6bSGordon Ross 	 * the mechanism we plan on using.
91613a2f6bSGordon Ross 	 */
92613a2f6bSGordon Ross 	mechanism.mechanism = CKM_DES_ECB;
93613a2f6bSGordon Ross 	mechanism.pParameter = NULL;
94613a2f6bSGordon Ross 	mechanism.ulParameterLen = 0;
95613a2f6bSGordon Ross 	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
96613a2f6bSGordon Ross 	if (rv != CKR_OK) {
97613a2f6bSGordon Ross 		return (ENOTSUP);
98613a2f6bSGordon Ross 	}
99613a2f6bSGordon Ross 
100*85e6b674SGordon Ross 	for (d = k = 0; k < K; k++, d++) {
101*85e6b674SGordon Ross 		/* Cycle the input again, as necessary. */
102*85e6b674SGordon Ross 		if (d == D)
103*85e6b674SGordon Ross 			d = 0;
104613a2f6bSGordon Ross 		smb_initlmkey(des_key, &Key[k * 7]);
105613a2f6bSGordon Ross 		rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
106613a2f6bSGordon Ross 		    des_key, 8, &hKey);
107613a2f6bSGordon Ross 		if (rv != CKR_OK) {
108613a2f6bSGordon Ross 			error = EIO;
109613a2f6bSGordon Ross 			goto exit_session;
110613a2f6bSGordon Ross 		}
111613a2f6bSGordon Ross 		/* Initialize the encryption operation in the session */
112613a2f6bSGordon Ross 		rv = C_EncryptInit(hSession, &mechanism, hKey);
113613a2f6bSGordon Ross 		if (rv != CKR_OK) {
114613a2f6bSGordon Ross 			error = EIO;
115613a2f6bSGordon Ross 			goto exit_encrypt;
116613a2f6bSGordon Ross 		}
117*85e6b674SGordon Ross 		ciphertext_len = 8;
118*85e6b674SGordon Ross 
119*85e6b674SGordon Ross 		/* Read in the data and encrypt this portion */
120*85e6b674SGordon Ross 		rv = C_EncryptUpdate(hSession,
121*85e6b674SGordon Ross 		    (CK_BYTE_PTR)Data + (d * 8), 8,
122*85e6b674SGordon Ross 		    (CK_BYTE_PTR)Result + (k * 8),
123*85e6b674SGordon Ross 		    &ciphertext_len);
124*85e6b674SGordon Ross 		if (rv != CKR_OK) {
125*85e6b674SGordon Ross 			error = EIO;
126*85e6b674SGordon Ross 			goto exit_encrypt;
127613a2f6bSGordon Ross 		}
128*85e6b674SGordon Ross 
129613a2f6bSGordon Ross 		(void) C_DestroyObject(hSession, hKey);
130613a2f6bSGordon Ross 	}
131613a2f6bSGordon Ross 	goto exit_session;
132613a2f6bSGordon Ross 
133613a2f6bSGordon Ross exit_encrypt:
134613a2f6bSGordon Ross 	(void) C_DestroyObject(hSession, hKey);
135613a2f6bSGordon Ross exit_session:
136613a2f6bSGordon Ross 	(void) C_CloseSession(hSession);
137613a2f6bSGordon Ross 
138613a2f6bSGordon Ross 	return (error);
139613a2f6bSGordon Ross }
140613a2f6bSGordon Ross 
141613a2f6bSGordon Ross /*
142613a2f6bSGordon Ross  * See "Netlogon Credential Computation" section of MS-NRPC document.
143613a2f6bSGordon Ross  * Same as in libsmb, but output arg first.
144613a2f6bSGordon Ross  */
145613a2f6bSGordon Ross static void
smb_initlmkey(uchar_t * keyout,const uchar_t * keyin)146613a2f6bSGordon Ross smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
147613a2f6bSGordon Ross {
148613a2f6bSGordon Ross 	int i;
149613a2f6bSGordon Ross 
150613a2f6bSGordon Ross 	keyout[0] = keyin[0] >> 0x01;
151613a2f6bSGordon Ross 	keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
152613a2f6bSGordon Ross 	keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
153613a2f6bSGordon Ross 	keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
154613a2f6bSGordon Ross 	keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
155613a2f6bSGordon Ross 	keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
156613a2f6bSGordon Ross 	keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
157613a2f6bSGordon Ross 	keyout[7] = keyin[6] & 0x7f;
158613a2f6bSGordon Ross 
159613a2f6bSGordon Ross 	for (i = 0; i < 8; i++)
160613a2f6bSGordon Ross 		keyout[i] = (keyout[i] << 1) & 0xfe;
161613a2f6bSGordon Ross }
162613a2f6bSGordon Ross 
163*85e6b674SGordon Ross /*
164*85e6b674SGordon Ross  * CKM_RC4
165*85e6b674SGordon Ross  */
166*85e6b674SGordon Ross int
smb_encrypt_RC4(uchar_t * Result,int ResultLen,const uchar_t * Key,int KeyLen,const uchar_t * Data,int DataLen)167*85e6b674SGordon Ross smb_encrypt_RC4(uchar_t *Result, int ResultLen,
168*85e6b674SGordon Ross 	const uchar_t *Key, int KeyLen,
169*85e6b674SGordon Ross 	const uchar_t *Data, int DataLen)
170*85e6b674SGordon Ross {
171*85e6b674SGordon Ross 	CK_RV rv;
172*85e6b674SGordon Ross 	CK_MECHANISM mechanism;
173*85e6b674SGordon Ross 	CK_OBJECT_HANDLE hKey;
174*85e6b674SGordon Ross 	CK_SESSION_HANDLE hSession;
175*85e6b674SGordon Ross 	CK_ULONG ciphertext_len;
176*85e6b674SGordon Ross 	int error = EIO;
177*85e6b674SGordon Ross 
178*85e6b674SGordon Ross 	/*
179*85e6b674SGordon Ross 	 * Use SUNW convenience function to initialize the cryptoki
180*85e6b674SGordon Ross 	 * library, and open a session with a slot that supports
181*85e6b674SGordon Ross 	 * the mechanism we plan on using.
182*85e6b674SGordon Ross 	 */
183*85e6b674SGordon Ross 	mechanism.mechanism = CKM_RC4;
184*85e6b674SGordon Ross 	mechanism.pParameter = NULL;
185*85e6b674SGordon Ross 	mechanism.ulParameterLen = 0;
186*85e6b674SGordon Ross 	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
187*85e6b674SGordon Ross 	if (rv != CKR_OK) {
188*85e6b674SGordon Ross 		return (ENOTSUP);
189*85e6b674SGordon Ross 	}
190*85e6b674SGordon Ross 
191*85e6b674SGordon Ross 	rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
192*85e6b674SGordon Ross 	    Key, KeyLen, &hKey);
193*85e6b674SGordon Ross 	if (rv != CKR_OK)
194*85e6b674SGordon Ross 		goto exit_session;
195*85e6b674SGordon Ross 
196*85e6b674SGordon Ross 	/* Initialize the encryption operation in the session */
197*85e6b674SGordon Ross 	rv = C_EncryptInit(hSession, &mechanism, hKey);
198*85e6b674SGordon Ross 	if (rv != CKR_OK)
199*85e6b674SGordon Ross 		goto exit_encrypt;
200*85e6b674SGordon Ross 
201*85e6b674SGordon Ross 	ciphertext_len = ResultLen;
202*85e6b674SGordon Ross 	rv = C_EncryptUpdate(hSession,
203*85e6b674SGordon Ross 	    (CK_BYTE_PTR)Data, DataLen,
204*85e6b674SGordon Ross 	    (CK_BYTE_PTR)Result, &ciphertext_len);
205*85e6b674SGordon Ross 	if (rv == CKR_OK)
206*85e6b674SGordon Ross 		error = 0;
207*85e6b674SGordon Ross 
208*85e6b674SGordon Ross exit_encrypt:
209*85e6b674SGordon Ross 	(void) C_DestroyObject(hSession, hKey);
210*85e6b674SGordon Ross exit_session:
211*85e6b674SGordon Ross 	(void) C_CloseSession(hSession);
212*85e6b674SGordon Ross 
213*85e6b674SGordon Ross 	return (error);
214*85e6b674SGordon Ross }
215*85e6b674SGordon Ross 
216613a2f6bSGordon Ross /*
217613a2f6bSGordon Ross  * Get some random bytes from /dev/urandom
218613a2f6bSGordon Ross  *
219613a2f6bSGordon Ross  * There may be a preferred way to call this via libpkcs11
220613a2f6bSGordon Ross  * XXX: (see: C_GenerateRandom, etc. -- later...)
221613a2f6bSGordon Ross  * Just read from /dev/urandom for now.
222613a2f6bSGordon Ross  */
223613a2f6bSGordon Ross int
smb_get_urandom(void * data,size_t dlen)224613a2f6bSGordon Ross smb_get_urandom(void *data, size_t dlen)
225613a2f6bSGordon Ross {
226613a2f6bSGordon Ross 	int fd, rlen;
227613a2f6bSGordon Ross 
228613a2f6bSGordon Ross 	fd = open("/dev/urandom", O_RDONLY);
229613a2f6bSGordon Ross 	if (fd < 0)
230613a2f6bSGordon Ross 		return (errno);
231613a2f6bSGordon Ross 
232613a2f6bSGordon Ross 	rlen = read(fd, data, dlen);
233613a2f6bSGordon Ross 	close(fd);
234613a2f6bSGordon Ross 
235613a2f6bSGordon Ross 	if (rlen < 0)
236613a2f6bSGordon Ross 		return (errno);
237613a2f6bSGordon Ross 	if (rlen < dlen)
238613a2f6bSGordon Ross 		return (EIO);
239613a2f6bSGordon Ross 	return (0);
240613a2f6bSGordon Ross }
241