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