8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / common / crypto / dh / dh_impl.c
blobd6cd4799317c2a3bdcd4cc1bd08fc01389c0ce7d
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This file contains DH helper routines common to
28 * the PKCS11 soft token code and the kernel DH code.
31 #include <sys/types.h>
32 #include <sys/sysmacros.h>
33 #include <bignum.h>
35 #ifdef _KERNEL
36 #include <sys/param.h>
37 #else
38 #include <strings.h>
39 #include <cryptoutil.h>
40 #endif
42 #include <sys/crypto/common.h>
43 #include <des/des_impl.h>
44 #include "dh_impl.h"
47 static CK_RV
48 convert_rv(BIG_ERR_CODE err)
50 switch (err) {
52 case BIG_OK:
53 return (CKR_OK);
55 case BIG_NO_MEM:
56 return (CKR_HOST_MEMORY);
58 case BIG_NO_RANDOM:
59 return (CKR_DEVICE_ERROR);
61 case BIG_INVALID_ARGS:
62 return (CKR_ARGUMENTS_BAD);
64 case BIG_DIV_BY_0:
65 default:
66 return (CKR_GENERAL_ERROR);
70 /* size is in bits */
71 static BIG_ERR_CODE
72 DH_key_init(DHkey *key, int size)
74 BIG_ERR_CODE err = BIG_OK;
75 int len;
77 len = BITLEN2BIGNUMLEN(size);
78 key->size = size;
80 if ((err = big_init(&(key->p), len)) != BIG_OK)
81 return (err);
82 if ((err = big_init(&(key->g), len)) != BIG_OK)
83 goto ret1;
84 if ((err = big_init(&(key->x), len)) != BIG_OK)
85 goto ret2;
86 if ((err = big_init(&(key->y), len)) != BIG_OK)
87 goto ret3;
89 return (BIG_OK);
91 ret3:
92 big_finish(&(key->x));
93 ret2:
94 big_finish(&(key->g));
95 ret1:
96 big_finish(&(key->p));
97 return (err);
100 static void
101 DH_key_finish(DHkey *key)
104 big_finish(&(key->y));
105 big_finish(&(key->x));
106 big_finish(&(key->g));
107 big_finish(&(key->p));
112 * Generate DH key pair x and y, given prime p and base g.
113 * Can optionally provided bit length of x, not to exceed bit length of p.
115 * For those not familiar with DH keys, there are 4 components:
116 * p - a known prime
117 * g - the base 0 < g < p
118 * x - a random number 0 < x < p-1, or if a smaller value is desired,
119 * 2^(len-1) <= x < 2^(len)
120 * y = g^x mod p, this implies 0 < y < p. That is important!
122 CK_RV
123 dh_genkey_pair(DHbytekey *bkey)
125 CK_RV rv = CKR_OK;
126 BIG_ERR_CODE brv;
127 uint32_t primebit_len;
128 DHkey dhkey;
129 int (*rf)(void *, size_t);
130 uint32_t prime_bytes;
132 if (bkey == NULL)
133 return (CKR_ARGUMENTS_BAD);
135 /* Must have prime and base set, value bits can be 0 or non-0 */
136 if (bkey->prime_bits == 0 || bkey->prime == NULL ||
137 bkey->base_bytes == 0 || bkey->base == NULL)
138 return (CKR_ARGUMENTS_BAD);
140 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
142 if ((prime_bytes < MIN_DH_KEYLENGTH_IN_BYTES) ||
143 (prime_bytes > MAX_DH_KEYLENGTH_IN_BYTES)) {
144 return (CKR_KEY_SIZE_RANGE);
148 * Initialize the DH key.
149 * Note: big_extend takes length in words.
151 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) {
152 rv = convert_rv(brv);
153 goto ret;
156 /* Convert prime p to bignum. */
157 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) !=
158 BIG_OK) {
159 rv = convert_rv(brv);
160 goto ret;
162 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes);
164 /* Convert base g to bignum. */
165 if ((brv = big_extend(&(dhkey.g),
166 CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) {
167 rv = convert_rv(brv);
168 goto ret;
170 bytestring2bignum(&(dhkey.g), bkey->base, bkey->base_bytes);
172 /* Base g cannot be greater than prime p. */
173 if (big_cmp_abs(&(dhkey.g), &(dhkey.p)) >= 0) {
174 rv = CKR_ATTRIBUTE_VALUE_INVALID;
175 goto ret;
179 * The intention of selecting a private-value length is to reduce
180 * the computation time for key agreement, while maintaining a
181 * given level of security.
184 /* Maximum bit length for private-value x is bit length of prime p */
185 primebit_len = big_bitlength(&(dhkey.p));
187 if (bkey->value_bits == 0)
188 bkey->value_bits = primebit_len;
190 if (bkey->value_bits > primebit_len) {
191 rv = CKR_ATTRIBUTE_VALUE_INVALID;
192 goto ret;
195 /* Generate DH key pair private and public values. */
196 if ((brv = big_extend(&(dhkey.x), BITLEN2BIGNUMLEN(bkey->value_bits)))
197 != BIG_OK) {
198 rv = convert_rv(brv);
199 goto ret;
202 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes)))
203 != BIG_OK) {
204 rv = convert_rv(brv);
205 goto ret;
209 * The big integer of the private value shall be generated privately
210 * and randomly.
212 rf = bkey->rfunc;
213 if (rf == NULL) {
214 #ifdef _KERNEL
215 rf = random_get_pseudo_bytes;
216 #else
217 rf = pkcs11_get_urandom;
218 #endif
221 if ((brv = big_random(&(dhkey.x), bkey->value_bits, rf)) != BIG_OK) {
222 rv = convert_rv(brv);
223 goto ret;
227 * The base g shall be raised to the private value x modulo p to
228 * give an integer y, the integer public value, i.e. y = (g^x) mod p.
230 if ((brv = big_modexp(&(dhkey.y), &(dhkey.g), &(dhkey.x),
231 &(dhkey.p), NULL)) != BIG_OK) {
232 rv = convert_rv(brv);
233 goto ret;
236 bignum2bytestring(bkey->private_x, &(dhkey.x),
237 CRYPTO_BITS2BYTES(bkey->value_bits));
238 bignum2bytestring(bkey->public_y, &(dhkey.y), prime_bytes);
240 ret:
241 DH_key_finish(&dhkey);
243 return (rv);
247 * DH key derive operation, flag is ignored in userland
249 CK_RV
250 dh_key_derive(DHbytekey *bkey, uint32_t key_type, /* = CKK_KEY_TYPE */
251 uchar_t *secretkey, uint32_t *secretkey_len, /* derived secret */
252 int flag)
254 CK_RV rv = CKR_OK;
255 BIG_ERR_CODE brv;
256 DHkey dhkey;
257 uchar_t *s = NULL;
258 uint32_t s_bytes = 0;
259 uint32_t prime_bytes;
260 uint32_t value_bytes;
261 size_t s_alloc;
263 if (bkey == NULL)
264 return (CKR_ARGUMENTS_BAD);
266 /* Must have prime, private value and public value */
267 if (bkey->prime_bits == 0 || bkey->prime == NULL ||
268 bkey->value_bits == 0 || bkey->private_x == NULL ||
269 bkey->public_y == NULL)
270 return (CKR_ARGUMENTS_BAD);
272 if (secretkey == NULL) {
273 return (CKR_ARGUMENTS_BAD);
276 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
277 value_bytes = CRYPTO_BITS2BYTES(bkey->value_bits);
280 * Initialize the DH key.
281 * Note: big_extend takes length in words.
283 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) {
284 rv = convert_rv(brv);
285 goto ret;
288 /* Convert prime p to bignum. */
289 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) !=
290 BIG_OK) {
291 rv = convert_rv(brv);
292 goto ret;
294 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes);
296 /* Convert private-value x to bignum. */
297 if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(value_bytes))) !=
298 BIG_OK) {
299 rv = convert_rv(brv);
300 goto ret;
302 bytestring2bignum(&(dhkey.x), bkey->private_x, value_bytes);
304 /* Convert public-value y to bignum. */
305 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes))) !=
306 BIG_OK) {
307 rv = convert_rv(brv);
308 goto ret;
310 bytestring2bignum(&(dhkey.y), bkey->public_y, prime_bytes);
313 * Recycle base g as a temporary variable to compute the derived
314 * secret value which is "g" = (y^x) mod p. (Not recomputing g.)
316 if ((brv = big_extend(&(dhkey.g), CHARLEN2BIGNUMLEN(prime_bytes))) !=
317 BIG_OK) {
318 rv = convert_rv(brv);
319 goto ret;
322 if ((brv = big_modexp(&(dhkey.g), &(dhkey.y), &(dhkey.x),
323 &(dhkey.p), NULL)) != BIG_OK) {
324 rv = convert_rv(brv);
325 goto ret;
328 s_alloc = P2ROUNDUP_TYPED(prime_bytes, sizeof (BIG_CHUNK_TYPE), size_t);
330 #ifdef _KERNEL
331 if ((s = kmem_alloc(s_alloc, flag)) == NULL) {
332 rv = CKR_HOST_MEMORY;
333 goto ret;
335 #else
336 if ((s = malloc(s_alloc)) == NULL) {
337 rv = CKR_HOST_MEMORY;
338 goto ret;
340 #endif
341 s_bytes = dhkey.g.len * (int)sizeof (BIG_CHUNK_TYPE);
342 bignum2bytestring(s, &(dhkey.g), s_bytes);
344 switch (key_type) {
346 case CKK_DES:
347 *secretkey_len = DES_KEYSIZE;
348 break;
349 case CKK_DES2:
350 *secretkey_len = DES2_KEYSIZE;
351 break;
352 case CKK_DES3:
353 *secretkey_len = DES3_KEYSIZE;
354 break;
355 case CKK_RC4:
356 case CKK_AES:
357 case CKK_GENERIC_SECRET:
358 /* use provided secret key length, if any */
359 break;
360 default:
361 /* invalid key type */
362 rv = CKR_ATTRIBUTE_TYPE_INVALID;
363 goto ret;
366 if (*secretkey_len == 0) {
367 *secretkey_len = s_bytes;
370 if (*secretkey_len > s_bytes) {
371 rv = CKR_ATTRIBUTE_VALUE_INVALID;
372 goto ret;
376 * The truncation removes bytes from the leading end of the
377 * secret value.
379 (void) memcpy(secretkey, (s + s_bytes - *secretkey_len),
380 *secretkey_len);
382 ret:
383 if (s != NULL)
384 #ifdef _KERNEL
385 kmem_free(s, s_alloc);
386 #else
387 free(s);
388 #endif
390 DH_key_finish(&dhkey);
392 return (rv);