Coverage Report

Created: 2025-11-11 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/krb5/src/lib/crypto/krb/s2k_pbkdf2.c
Line
Count
Source
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/*
3
 * Copyright (C) 1998 by the FundsXpress, INC.
4
 *
5
 * All rights reserved.
6
 *
7
 * Export of this software from the United States of America may require
8
 * a specific license from the United States Government.  It is the
9
 * responsibility of any person or organization contemplating export to
10
 * obtain such a license before exporting.
11
 *
12
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
 * distribute this software and its documentation for any purpose and
14
 * without fee is hereby granted, provided that the above copyright
15
 * notice appear in all copies and that both that copyright notice and
16
 * this permission notice appear in supporting documentation, and that
17
 * the name of FundsXpress. not be used in advertising or publicity pertaining
18
 * to distribution of the software without specific, written prior
19
 * permission.  FundsXpress makes no representations about the suitability of
20
 * this software for any purpose.  It is provided "as is" without express
21
 * or implied warranty.
22
 *
23
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26
 */
27
28
#include "crypto_int.h"
29
30
static const unsigned char kerberos[] = "kerberos";
31
0
#define kerberos_len (sizeof(kerberos)-1)
32
33
krb5_error_code
34
krb5int_dk_string_to_key(const struct krb5_keytypes *ktp,
35
                         const krb5_data *string, const krb5_data *salt,
36
                         const krb5_data *parms, krb5_keyblock *keyblock)
37
0
{
38
0
    krb5_error_code ret;
39
0
    size_t keybytes, keylength, concatlen;
40
0
    unsigned char *concat = NULL, *foldstring = NULL, *foldkeydata = NULL;
41
0
    krb5_data indata;
42
0
    krb5_keyblock foldkeyblock;
43
0
    krb5_key foldkey = NULL;
44
45
    /* keyblock->length is checked by krb5int_derive_key. */
46
47
0
    keybytes = ktp->enc->keybytes;
48
0
    keylength = ktp->enc->keylength;
49
50
0
    concatlen = string->length + salt->length;
51
52
0
    concat = k5alloc(concatlen, &ret);
53
0
    if (ret != 0)
54
0
        goto cleanup;
55
0
    foldstring = k5alloc(keybytes, &ret);
56
0
    if (ret != 0)
57
0
        goto cleanup;
58
0
    foldkeydata = k5alloc(keylength, &ret);
59
0
    if (ret != 0)
60
0
        goto cleanup;
61
62
    /* construct input string ( = string + salt), fold it, make_key it */
63
64
0
    if (string->length > 0)
65
0
        memcpy(concat, string->data, string->length);
66
0
    if (salt->length > 0)
67
0
        memcpy(concat + string->length, salt->data, salt->length);
68
69
0
    krb5int_nfold(concatlen*8, concat, keybytes*8, foldstring);
70
71
0
    indata.length = keybytes;
72
0
    indata.data = (char *) foldstring;
73
0
    foldkeyblock.length = keylength;
74
0
    foldkeyblock.contents = foldkeydata;
75
0
    foldkeyblock.enctype = ktp->etype;
76
77
0
    ret = ktp->rand2key(&indata, &foldkeyblock);
78
0
    if (ret != 0)
79
0
        goto cleanup;
80
81
0
    ret = krb5_k_create_key(NULL, &foldkeyblock, &foldkey);
82
0
    if (ret != 0)
83
0
        goto cleanup;
84
85
    /* now derive the key from this one */
86
87
0
    indata.length = kerberos_len;
88
0
    indata.data = (char *) kerberos;
89
90
0
    ret = krb5int_derive_keyblock(ktp->enc, NULL, foldkey, keyblock, &indata,
91
0
                                  DERIVE_RFC3961);
92
0
    if (ret != 0)
93
0
        memset(keyblock->contents, 0, keyblock->length);
94
95
0
cleanup:
96
0
    zapfree(concat, concatlen);
97
0
    zapfree(foldstring, keybytes);
98
0
    zapfree(foldkeydata, keylength);
99
0
    krb5_k_free_key(NULL, foldkey);
100
0
    return ret;
101
0
}
102
103
104
0
#define MAX_ITERATION_COUNT             0x1000000L
105
106
krb5_boolean k5_allow_weak_pbkdf2iter = FALSE;
107
108
static krb5_error_code
109
pbkdf2_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string,
110
                     const krb5_data *salt, const krb5_data *pepper,
111
                     const krb5_data *params, krb5_keyblock *key,
112
                     enum deriv_alg deriv_alg, unsigned long def_iter_count)
113
0
{
114
0
    const struct krb5_hash_provider *hash;
115
0
    unsigned long iter_count;
116
0
    krb5_data out;
117
0
    static const krb5_data usage = { KV5M_DATA, 8, "kerberos" };
118
0
    krb5_key tempkey = NULL;
119
0
    krb5_error_code err;
120
0
    krb5_data sandp = empty_data();
121
122
0
    if (params) {
123
0
        unsigned char *p = (unsigned char *) params->data;
124
0
        if (params->length != 4)
125
0
            return KRB5_ERR_BAD_S2K_PARAMS;
126
0
        iter_count = load_32_be(p);
127
        /* Zero means 2^32, which is way above what we will accept.  Also don't
128
         * accept values less than the default, unless we're running tests. */
129
0
        if (iter_count == 0 ||
130
0
            (!k5_allow_weak_pbkdf2iter && iter_count < def_iter_count))
131
0
            return KRB5_ERR_BAD_S2K_PARAMS;
132
133
0
    } else
134
0
        iter_count = def_iter_count;
135
136
    /* This is not a protocol specification constraint; this is an
137
       implementation limit, which should eventually be controlled by
138
       a config file.  */
139
0
    if (iter_count >= MAX_ITERATION_COUNT)
140
0
        return KRB5_ERR_BAD_S2K_PARAMS;
141
142
    /* Use the output keyblock contents for temporary space. */
143
0
    out.data = (char *) key->contents;
144
0
    out.length = key->length;
145
0
    if (out.length != 16 && out.length != 32)
146
0
        return KRB5_CRYPTO_INTERNAL;
147
148
0
    if (pepper != NULL) {
149
0
        err = alloc_data(&sandp, pepper->length + 1 + salt->length);
150
0
        if (err)
151
0
            return err;
152
153
0
        if (pepper->length > 0)
154
0
            memcpy(sandp.data, pepper->data, pepper->length);
155
0
        sandp.data[pepper->length] = '\0';
156
0
        if (salt->length > 0)
157
0
            memcpy(&sandp.data[pepper->length + 1], salt->data, salt->length);
158
159
0
        salt = &sandp;
160
0
    }
161
162
0
    hash = (ktp->hash != NULL) ? ktp->hash : &krb5int_hash_sha1;
163
0
    err = krb5int_pbkdf2_hmac(hash, &out, iter_count, string, salt);
164
0
    if (err)
165
0
        goto cleanup;
166
167
0
    err = krb5_k_create_key (NULL, key, &tempkey);
168
0
    if (err)
169
0
        goto cleanup;
170
171
0
    err = krb5int_derive_keyblock(ktp->enc, ktp->hash, tempkey, key, &usage,
172
0
                                  deriv_alg);
173
174
0
cleanup:
175
0
    if (sandp.data)
176
0
        free(sandp.data);
177
0
    if (err)
178
0
        memset (out.data, 0, out.length);
179
0
    krb5_k_free_key (NULL, tempkey);
180
0
    return err;
181
0
}
182
183
krb5_error_code
184
krb5int_aes_string_to_key(const struct krb5_keytypes *ktp,
185
                          const krb5_data *string,
186
                          const krb5_data *salt,
187
                          const krb5_data *params,
188
                          krb5_keyblock *key)
189
0
{
190
0
    return pbkdf2_string_to_key(ktp, string, salt, NULL, params, key,
191
0
                                DERIVE_RFC3961, 4096);
192
0
}
193
194
krb5_error_code
195
krb5int_camellia_string_to_key(const struct krb5_keytypes *ktp,
196
                               const krb5_data *string,
197
                               const krb5_data *salt,
198
                               const krb5_data *params,
199
                               krb5_keyblock *key)
200
0
{
201
0
    krb5_data pepper = string2data(ktp->name);
202
203
0
    return pbkdf2_string_to_key(ktp, string, salt, &pepper, params, key,
204
0
                                DERIVE_SP800_108_CMAC, 32768);
205
0
}
206
207
krb5_error_code
208
krb5int_aes2_string_to_key(const struct krb5_keytypes *ktp,
209
                           const krb5_data *string, const krb5_data *salt,
210
                           const krb5_data *params, krb5_keyblock *key)
211
0
{
212
0
    krb5_data pepper = string2data(ktp->name);
213
214
0
    return pbkdf2_string_to_key(ktp, string, salt, &pepper, params, key,
215
0
                                DERIVE_SP800_108_HMAC, 32768);
216
0
}