xref: /titanic_50/usr/src/lib/libsmbfs/smb/crypt.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
1*613a2f6bSGordon Ross /*
2*613a2f6bSGordon Ross  * CDDL HEADER START
3*613a2f6bSGordon Ross  *
4*613a2f6bSGordon Ross  * The contents of this file are subject to the terms of the
5*613a2f6bSGordon Ross  * Common Development and Distribution License (the "License").
6*613a2f6bSGordon Ross  * You may not use this file except in compliance with the License.
7*613a2f6bSGordon Ross  *
8*613a2f6bSGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*613a2f6bSGordon Ross  * or http://www.opensolaris.org/os/licensing.
10*613a2f6bSGordon Ross  * See the License for the specific language governing permissions
11*613a2f6bSGordon Ross  * and limitations under the License.
12*613a2f6bSGordon Ross  *
13*613a2f6bSGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14*613a2f6bSGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*613a2f6bSGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16*613a2f6bSGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17*613a2f6bSGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18*613a2f6bSGordon Ross  *
19*613a2f6bSGordon Ross  * CDDL HEADER END
20*613a2f6bSGordon Ross  */
21*613a2f6bSGordon Ross 
22*613a2f6bSGordon Ross /*
23*613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*613a2f6bSGordon Ross  * Use is subject to license terms.
25*613a2f6bSGordon Ross  */
26*613a2f6bSGordon Ross 
27*613a2f6bSGordon Ross /*
28*613a2f6bSGordon Ross  * Crypto support, using libpkcs11
29*613a2f6bSGordon Ross  *
30*613a2f6bSGordon Ross  * Some code copied from the server: libsmb smb_crypt.c
31*613a2f6bSGordon Ross  * with minor changes, i.e. errno.h return values.
32*613a2f6bSGordon Ross  * XXX: Move this to a common library (later).
33*613a2f6bSGordon Ross  */
34*613a2f6bSGordon Ross 
35*613a2f6bSGordon Ross #include <sys/types.h>
36*613a2f6bSGordon Ross #include <sys/md4.h>
37*613a2f6bSGordon Ross 
38*613a2f6bSGordon Ross #include <errno.h>
39*613a2f6bSGordon Ross #include <fcntl.h>
40*613a2f6bSGordon Ross #include <string.h>
41*613a2f6bSGordon Ross 
42*613a2f6bSGordon Ross #include <security/cryptoki.h>
43*613a2f6bSGordon Ross #include <security/pkcs11.h>
44*613a2f6bSGordon Ross #include <cryptoutil.h>
45*613a2f6bSGordon Ross 
46*613a2f6bSGordon Ross #include "smb_crypt.h"
47*613a2f6bSGordon Ross 
48*613a2f6bSGordon Ross static void
49*613a2f6bSGordon Ross smb_initlmkey(uchar_t *keyout, const uchar_t *keyin);
50*613a2f6bSGordon Ross 
51*613a2f6bSGordon Ross /*
52*613a2f6bSGordon Ross  * Like libsmb smb_auth_DES,
53*613a2f6bSGordon Ross  * but use uchar_t, return errno.
54*613a2f6bSGordon Ross  */
55*613a2f6bSGordon Ross int
56*613a2f6bSGordon Ross smb_encrypt_DES(uchar_t *Result, int ResultLen,
57*613a2f6bSGordon Ross     const uchar_t *Key, int KeyLen,
58*613a2f6bSGordon Ross     const uchar_t *Data, int DataLen)
59*613a2f6bSGordon Ross {
60*613a2f6bSGordon Ross 	CK_RV rv;
61*613a2f6bSGordon Ross 	CK_MECHANISM mechanism;
62*613a2f6bSGordon Ross 	CK_OBJECT_HANDLE hKey;
63*613a2f6bSGordon Ross 	CK_SESSION_HANDLE hSession;
64*613a2f6bSGordon Ross 	CK_ULONG ciphertext_len;
65*613a2f6bSGordon Ross 	uchar_t des_key[8];
66*613a2f6bSGordon Ross 	int error = 0;
67*613a2f6bSGordon Ross 	int K, D;
68*613a2f6bSGordon Ross 	int k, d;
69*613a2f6bSGordon Ross 
70*613a2f6bSGordon Ross 	/* Calculate proper number of iterations */
71*613a2f6bSGordon Ross 	K = KeyLen / 7;
72*613a2f6bSGordon Ross 	D = DataLen / 8;
73*613a2f6bSGordon Ross 
74*613a2f6bSGordon Ross 	if (ResultLen < (K * 8 * D)) {
75*613a2f6bSGordon Ross 		return (EINVAL);
76*613a2f6bSGordon Ross 	}
77*613a2f6bSGordon Ross 
78*613a2f6bSGordon Ross 	/*
79*613a2f6bSGordon Ross 	 * Use SUNW convenience function to initialize the cryptoki
80*613a2f6bSGordon Ross 	 * library, and open a session with a slot that supports
81*613a2f6bSGordon Ross 	 * the mechanism we plan on using.
82*613a2f6bSGordon Ross 	 */
83*613a2f6bSGordon Ross 	mechanism.mechanism = CKM_DES_ECB;
84*613a2f6bSGordon Ross 	mechanism.pParameter = NULL;
85*613a2f6bSGordon Ross 	mechanism.ulParameterLen = 0;
86*613a2f6bSGordon Ross 	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
87*613a2f6bSGordon Ross 	if (rv != CKR_OK) {
88*613a2f6bSGordon Ross 		return (ENOTSUP);
89*613a2f6bSGordon Ross 	}
90*613a2f6bSGordon Ross 
91*613a2f6bSGordon Ross 	for (k = 0; k < K; k++) {
92*613a2f6bSGordon Ross 		smb_initlmkey(des_key, &Key[k * 7]);
93*613a2f6bSGordon Ross 		rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
94*613a2f6bSGordon Ross 		    des_key, 8, &hKey);
95*613a2f6bSGordon Ross 		if (rv != CKR_OK) {
96*613a2f6bSGordon Ross 			error = EIO;
97*613a2f6bSGordon Ross 			goto exit_session;
98*613a2f6bSGordon Ross 		}
99*613a2f6bSGordon Ross 		/* Initialize the encryption operation in the session */
100*613a2f6bSGordon Ross 		rv = C_EncryptInit(hSession, &mechanism, hKey);
101*613a2f6bSGordon Ross 		if (rv != CKR_OK) {
102*613a2f6bSGordon Ross 			error = EIO;
103*613a2f6bSGordon Ross 			goto exit_encrypt;
104*613a2f6bSGordon Ross 		}
105*613a2f6bSGordon Ross 		ciphertext_len = DataLen;
106*613a2f6bSGordon Ross 		for (d = 0; d < D; d++) {
107*613a2f6bSGordon Ross 			/* Read in the data and encrypt this portion */
108*613a2f6bSGordon Ross 			rv = C_EncryptUpdate(hSession,
109*613a2f6bSGordon Ross 			    (CK_BYTE_PTR)Data + (d * 8), 8,
110*613a2f6bSGordon Ross 			    &Result[(k * (8 * D)) + (d * 8)],
111*613a2f6bSGordon Ross 			    &ciphertext_len);
112*613a2f6bSGordon Ross 			if (rv != CKR_OK) {
113*613a2f6bSGordon Ross 				error = EIO;
114*613a2f6bSGordon Ross 				goto exit_encrypt;
115*613a2f6bSGordon Ross 			}
116*613a2f6bSGordon Ross 		}
117*613a2f6bSGordon Ross 		(void) C_DestroyObject(hSession, hKey);
118*613a2f6bSGordon Ross 	}
119*613a2f6bSGordon Ross 	goto exit_session;
120*613a2f6bSGordon Ross 
121*613a2f6bSGordon Ross exit_encrypt:
122*613a2f6bSGordon Ross 	(void) C_DestroyObject(hSession, hKey);
123*613a2f6bSGordon Ross exit_session:
124*613a2f6bSGordon Ross 	(void) C_CloseSession(hSession);
125*613a2f6bSGordon Ross 
126*613a2f6bSGordon Ross 	return (error);
127*613a2f6bSGordon Ross }
128*613a2f6bSGordon Ross 
129*613a2f6bSGordon Ross /*
130*613a2f6bSGordon Ross  * See "Netlogon Credential Computation" section of MS-NRPC document.
131*613a2f6bSGordon Ross  * Same as in libsmb, but output arg first.
132*613a2f6bSGordon Ross  */
133*613a2f6bSGordon Ross static void
134*613a2f6bSGordon Ross smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
135*613a2f6bSGordon Ross {
136*613a2f6bSGordon Ross 	int i;
137*613a2f6bSGordon Ross 
138*613a2f6bSGordon Ross 	keyout[0] = keyin[0] >> 0x01;
139*613a2f6bSGordon Ross 	keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
140*613a2f6bSGordon Ross 	keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
141*613a2f6bSGordon Ross 	keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
142*613a2f6bSGordon Ross 	keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
143*613a2f6bSGordon Ross 	keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
144*613a2f6bSGordon Ross 	keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
145*613a2f6bSGordon Ross 	keyout[7] = keyin[6] & 0x7f;
146*613a2f6bSGordon Ross 
147*613a2f6bSGordon Ross 	for (i = 0; i < 8; i++)
148*613a2f6bSGordon Ross 		keyout[i] = (keyout[i] << 1) & 0xfe;
149*613a2f6bSGordon Ross }
150*613a2f6bSGordon Ross 
151*613a2f6bSGordon Ross /*
152*613a2f6bSGordon Ross  * Get some random bytes from /dev/urandom
153*613a2f6bSGordon Ross  *
154*613a2f6bSGordon Ross  * There may be a preferred way to call this via libpkcs11
155*613a2f6bSGordon Ross  * XXX: (see: C_GenerateRandom, etc. -- later...)
156*613a2f6bSGordon Ross  * Just read from /dev/urandom for now.
157*613a2f6bSGordon Ross  */
158*613a2f6bSGordon Ross int
159*613a2f6bSGordon Ross smb_get_urandom(void *data, size_t dlen)
160*613a2f6bSGordon Ross {
161*613a2f6bSGordon Ross 	int fd, rlen;
162*613a2f6bSGordon Ross 
163*613a2f6bSGordon Ross 	fd = open("/dev/urandom", O_RDONLY);
164*613a2f6bSGordon Ross 	if (fd < 0)
165*613a2f6bSGordon Ross 		return (errno);
166*613a2f6bSGordon Ross 
167*613a2f6bSGordon Ross 	rlen = read(fd, data, dlen);
168*613a2f6bSGordon Ross 	close(fd);
169*613a2f6bSGordon Ross 
170*613a2f6bSGordon Ross 	if (rlen < 0)
171*613a2f6bSGordon Ross 		return (errno);
172*613a2f6bSGordon Ross 	if (rlen < dlen)
173*613a2f6bSGordon Ross 		return (EIO);
174*613a2f6bSGordon Ross 	return (0);
175*613a2f6bSGordon Ross }
176