import less(1)
[unleashed/tickless.git] / usr / src / lib / libsmbfs / smb / crypt.c
blob13569c1b8ca712853810a3b0509d1630d36d932a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
29 * Crypto support, using libpkcs11
31 * Some code copied from the server: libsmb smb_crypt.c
32 * with minor changes, i.e. errno.h return values.
33 * XXX: Later, make the server use these.
36 #include <sys/types.h>
37 #include <sys/md4.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <string.h>
43 #include <security/cryptoki.h>
44 #include <security/pkcs11.h>
45 #include <cryptoutil.h>
47 #include "smb_crypt.h"
49 static void
50 smb_initlmkey(uchar_t *keyout, const uchar_t *keyin);
53 * Like libsmb smb_auth_DES,
54 * but use uchar_t, return errno.
56 int
57 smb_encrypt_DES(uchar_t *Result, int ResultLen,
58 const uchar_t *Key, int KeyLen,
59 const uchar_t *Data, int DataLen)
61 CK_RV rv;
62 CK_MECHANISM mechanism;
63 CK_OBJECT_HANDLE hKey;
64 CK_SESSION_HANDLE hSession;
65 CK_ULONG ciphertext_len;
66 uchar_t des_key[8];
67 int error = 0;
68 int K, D;
69 int k, d;
72 * Calculate proper number of iterations.
73 * Known call cases include:
74 * ResultLen=16, KeyLen=14, DataLen=8
75 * ResultLen=24, KeyLen=21, DataLen=8
76 * ResultLen=16, KeyLen=14, DataLen=16
78 K = KeyLen / 7;
79 D = DataLen / 8;
80 if ((KeyLen % 7) || (DataLen % 8))
81 return (EINVAL);
82 if (K == 0 || D == 0)
83 return (EINVAL);
84 if (ResultLen < (K * 8))
85 return (EINVAL);
88 * Use SUNW convenience function to initialize the cryptoki
89 * library, and open a session with a slot that supports
90 * the mechanism we plan on using.
92 mechanism.mechanism = CKM_DES_ECB;
93 mechanism.pParameter = NULL;
94 mechanism.ulParameterLen = 0;
95 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
96 if (rv != CKR_OK) {
97 return (ENOTSUP);
100 for (d = k = 0; k < K; k++, d++) {
101 /* Cycle the input again, as necessary. */
102 if (d == D)
103 d = 0;
104 smb_initlmkey(des_key, &Key[k * 7]);
105 rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
106 des_key, 8, &hKey);
107 if (rv != CKR_OK) {
108 error = EIO;
109 goto exit_session;
111 /* Initialize the encryption operation in the session */
112 rv = C_EncryptInit(hSession, &mechanism, hKey);
113 if (rv != CKR_OK) {
114 error = EIO;
115 goto exit_encrypt;
117 ciphertext_len = 8;
119 /* Read in the data and encrypt this portion */
120 rv = C_EncryptUpdate(hSession,
121 (CK_BYTE_PTR)Data + (d * 8), 8,
122 (CK_BYTE_PTR)Result + (k * 8),
123 &ciphertext_len);
124 if (rv != CKR_OK) {
125 error = EIO;
126 goto exit_encrypt;
129 (void) C_DestroyObject(hSession, hKey);
131 goto exit_session;
133 exit_encrypt:
134 (void) C_DestroyObject(hSession, hKey);
135 exit_session:
136 (void) C_CloseSession(hSession);
138 return (error);
142 * See "Netlogon Credential Computation" section of MS-NRPC document.
143 * Same as in libsmb, but output arg first.
145 static void
146 smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
148 int i;
150 keyout[0] = keyin[0] >> 0x01;
151 keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
152 keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
153 keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
154 keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
155 keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
156 keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
157 keyout[7] = keyin[6] & 0x7f;
159 for (i = 0; i < 8; i++)
160 keyout[i] = (keyout[i] << 1) & 0xfe;
164 * CKM_RC4
167 smb_encrypt_RC4(uchar_t *Result, int ResultLen,
168 const uchar_t *Key, int KeyLen,
169 const uchar_t *Data, int DataLen)
171 CK_RV rv;
172 CK_MECHANISM mechanism;
173 CK_OBJECT_HANDLE hKey;
174 CK_SESSION_HANDLE hSession;
175 CK_ULONG ciphertext_len;
176 int error = EIO;
179 * Use SUNW convenience function to initialize the cryptoki
180 * library, and open a session with a slot that supports
181 * the mechanism we plan on using.
183 mechanism.mechanism = CKM_RC4;
184 mechanism.pParameter = NULL;
185 mechanism.ulParameterLen = 0;
186 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
187 if (rv != CKR_OK) {
188 return (ENOTSUP);
191 rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
192 Key, KeyLen, &hKey);
193 if (rv != CKR_OK)
194 goto exit_session;
196 /* Initialize the encryption operation in the session */
197 rv = C_EncryptInit(hSession, &mechanism, hKey);
198 if (rv != CKR_OK)
199 goto exit_encrypt;
201 ciphertext_len = ResultLen;
202 rv = C_EncryptUpdate(hSession,
203 (CK_BYTE_PTR)Data, DataLen,
204 (CK_BYTE_PTR)Result, &ciphertext_len);
205 if (rv == CKR_OK)
206 error = 0;
208 exit_encrypt:
209 (void) C_DestroyObject(hSession, hKey);
210 exit_session:
211 (void) C_CloseSession(hSession);
213 return (error);
217 * Get some random bytes from /dev/urandom
219 * There may be a preferred way to call this via libpkcs11
220 * XXX: (see: C_GenerateRandom, etc. -- later...)
221 * Just read from /dev/urandom for now.
224 smb_get_urandom(void *data, size_t dlen)
226 int fd, rlen;
228 fd = open("/dev/urandom", O_RDONLY);
229 if (fd < 0)
230 return (errno);
232 rlen = read(fd, data, dlen);
233 close(fd);
235 if (rlen < 0)
236 return (errno);
237 if (rlen < dlen)
238 return (EIO);
239 return (0);