1/*
2 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * lib/crypto/pbkdf2.c
8 *
9 * Copyright 2002 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
11 *
12 * Export of this software from the United States of America may
13 *   require a specific license from the United States Government.
14 *   It is the responsibility of any person or organization contemplating
15 *   export to obtain such a license before exporting.
16 *
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission.  Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose.  It is provided "as is" without express
29 * or implied warranty.
30 *
31 *
32 * Implementation of PBKDF2 from RFC 2898.
33 * Not currently used; likely to be used when we get around to AES support.
34 */
35
36#ifndef _KERNEL
37
38#include <ctype.h>
39#include "k5-int.h"
40#include "hash_provider.h"
41
42/*
43 * Solaris Kerberos:
44 * MIT code ripped out, use PBKDF2 algorithm from PKCS#11
45 * provider.
46 */
47krb5_error_code
48krb5int_pbkdf2_hmac_sha1(
49	krb5_context context,
50	const krb5_data *out,
51	unsigned long count,
52	krb5_enctype enctype,
53	const krb5_data *pass, const krb5_data *salt)
54{
55	krb5_error_code ret = 0;
56	CK_RV rv;
57	CK_PKCS5_PBKD2_PARAMS params;
58	CK_MECHANISM mechanism;
59	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
60	CK_ATTRIBUTE tmpl[3];
61	CK_KEY_TYPE	keytype;
62	CK_OBJECT_HANDLE hKey;
63	int attrs = 0;
64	CK_ULONG outlen, passlen;
65
66	mechanism.mechanism = CKM_PKCS5_PBKD2;
67	mechanism.pParameter = &params;
68	mechanism.ulParameterLen = sizeof (params);
69
70	tmpl[attrs].type = CKA_CLASS;
71	tmpl[attrs].pValue = &class;
72	tmpl[attrs].ulValueLen = sizeof (class);
73	attrs++;
74
75	rv = get_key_type(enctype, &keytype);
76	if (rv != CKR_OK)
77		return (PKCS_ERR);
78
79	tmpl[attrs].type = CKA_KEY_TYPE;
80	tmpl[attrs].pValue = &keytype;
81	tmpl[attrs].ulValueLen = sizeof (keytype);
82	attrs++;
83
84	/*
85	 * For DES key types, do not include the value len attr.
86	 */
87	if (out->length > 0 &&
88	    enctype != ENCTYPE_DES_CBC_CRC &&
89	    enctype != ENCTYPE_DES_CBC_MD5 &&
90	    enctype != ENCTYPE_DES_CBC_RAW &&
91	    enctype != ENCTYPE_DES_HMAC_SHA1 &&
92	    enctype != ENCTYPE_DES3_CBC_SHA1 &&
93	    enctype != ENCTYPE_DES3_CBC_RAW) {
94		tmpl[attrs].type = CKA_VALUE_LEN;
95		/* using outlen to avoid 64bit alignment issues */
96		outlen = (CK_ULONG)out->length;
97		tmpl[attrs].pValue = &outlen;
98		tmpl[attrs].ulValueLen = sizeof (outlen);
99		attrs++;
100	}
101
102	params.saltSource = CKZ_SALT_SPECIFIED;
103	params.pSaltSourceData = (void *)salt->data;
104	params.ulSaltSourceDataLen = salt->length;
105	params.iterations = count;
106	params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
107	params.pPrfData = NULL;
108	params.ulPrfDataLen = 0;
109	params.pPassword = (CK_UTF8CHAR_PTR)pass->data;
110	/* using passlen to avoid 64bit alignment issues */
111	passlen = (CK_ULONG)pass->length;
112	params.ulPasswordLen = &passlen;
113
114	rv = C_GenerateKey(krb_ctx_hSession(context), &mechanism, tmpl,
115	    attrs, &hKey);
116
117	if (rv != CKR_OK)
118		ret = PKCS_ERR;
119	else {
120		/* Get the value from the key object. */
121		tmpl[0].type = CKA_VALUE;
122		tmpl[0].pValue = out->data;
123		tmpl[0].ulValueLen = out->length;
124		rv = C_GetAttributeValue(krb_ctx_hSession(context), hKey,
125		    tmpl, 1);
126		if (rv != CKR_OK)
127			ret = PKCS_ERR;
128		(void) C_DestroyObject(krb_ctx_hSession(context), hKey);
129	}
130
131	return (ret);
132}
133#endif /* !_KERNEL */
134