1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * lib/crypto/aes/aes_s2k.c
10  *
11  * Copyright 2003 by the Massachusetts Institute of Technology.
12  * All Rights Reserved.
13  *
14  * Export of this software from the United States of America may
15  *   require a specific license from the United States Government.
16  *   It is the responsibility of any person or organization contemplating
17  *   export to obtain such a license before exporting.
18  *
19  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20  * distribute this software and its documentation for any purpose and
21  * without fee is hereby granted, provided that the above copyright
22  * notice appear in all copies and that both that copyright notice and
23  * this permission notice appear in supporting documentation, and that
24  * the name of M.I.T. not be used in advertising or publicity pertaining
25  * to distribution of the software without specific, written prior
26  * permission.  Furthermore if you modify this software you must label
27  * your software as modified software and not distribute it in such a
28  * fashion that it might be confused with the original M.I.T. software.
29  * M.I.T. makes no representations about the suitability of
30  * this software for any purpose.  It is provided "as is" without express
31  * or implied warranty.
32  *
33  *
34  * krb5int_aes_string_to_key
35  */
36 
37 #include <k5-int.h>
38 #include <dk.h>
39 
40 #define DEFAULT_ITERATION_COUNT		4096 /* was 0xb000L in earlier drafts */
41 #define MAX_ITERATION_COUNT		0x1000000L
42 
43 krb5_error_code
44 krb5int_aes_string_to_key(krb5_context context,
45 	const struct krb5_enc_provider *enc,
46 	const krb5_data *string,
47 	const krb5_data *salt,
48 	const krb5_data *params,
49 	krb5_keyblock *key)
50 {
51     unsigned long iter_count;
52     krb5_data out;
53     static const krb5_data usage = { KV5M_DATA, 8, "kerberos" };
54     krb5_error_code err;
55     krb5_keyblock *inkey = NULL;
56 
57     if (params) {
58 	unsigned char *p = (unsigned char *) params->data;
59 	if (params->length != 4)
60 	    return KRB5_ERR_BAD_S2K_PARAMS;
61 	iter_count = ((p[0] << 24) | (p[1] << 16) | (p[2] <<  8) | (p[3]));
62 	if (iter_count == 0) {
63 	/*
64 	    iter_count = (1L << 16) << 16;
65 	    if (((iter_count >> 16) >> 16) != 1)
66 		return KRB5_ERR_BAD_S2K_PARAMS;
67 	*/
68 	    iter_count = DEFAULT_ITERATION_COUNT;
69 	}
70     } else
71 	iter_count = DEFAULT_ITERATION_COUNT;
72 
73     /* This is not a protocol specification constraint; this is an
74        implementation limit, which should eventually be controlled by
75        a config file.  */
76     if (iter_count >= MAX_ITERATION_COUNT)
77 	return KRB5_ERR_BAD_S2K_PARAMS;
78 
79     /*
80      * Dense key space, no parity bits or anything, so take a shortcut
81      * and use the key contents buffer for the generated bytes.
82      */
83     if (key->length != 16 && key->length != 32)
84 	return KRB5_CRYPTO_INTERNAL;
85     out.data = (char *) key->contents;
86     out.length = key->length;
87 
88     err = krb5int_pbkdf2_hmac_sha1 (context, &out, iter_count, key->enctype,
89 		string, salt);
90     if (err) {
91 	memset(out.data, 0, out.length);
92 	return err;
93     }
94 
95     /*
96      * The derive key operation below will not work correctly
97      * if the input and output key pointers are to the same
98      * data.  This is because the key object handle (PKCS#11)
99      * gets out-of-sync with the original key when the contents
100      * are modified.  We copy the original key here for use
101      * below in the derive_key step, then we free this key
102      * before exiting.
103      */
104     err  = krb5_copy_keyblock(context, key, &inkey);
105     if (err) {
106 	memset(out.data, 0, out.length);
107 	return err;
108     }
109 
110     err = krb5_derive_key (context, enc, inkey, key, &usage);
111     if (err) {
112 	memset(out.data, 0, out.length);
113     }
114     krb5_free_keyblock(context, inkey);
115 
116     return (err);
117 }
118