1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 
11 #include "tomcrypt_private.h"
12 
13 #ifdef LTC_PKCS_12
14 
pkcs12_kdf(int hash_id,const unsigned char * pw,unsigned long pwlen,const unsigned char * salt,unsigned long saltlen,unsigned int iterations,unsigned char purpose,unsigned char * out,unsigned long outlen)15 int pkcs12_kdf(               int   hash_id,
16                const unsigned char *pw,         unsigned long pwlen,
17                const unsigned char *salt,       unsigned long saltlen,
18                      unsigned int   iterations, unsigned char purpose,
19                      unsigned char *out,        unsigned long outlen)
20 {
21    unsigned long u = hash_descriptor[hash_id]->hashsize;
22    unsigned long v = hash_descriptor[hash_id]->blocksize;
23    unsigned long c = (outlen + u - 1) / u;
24    unsigned long Slen = ((saltlen + v - 1) / v) * v;
25    unsigned long Plen = ((pwlen + v - 1) / v) * v;
26    unsigned long k = (Plen + Slen) / v;
27    unsigned long Alen, keylen = 0;
28    unsigned int tmp, i, j, n;
29    unsigned char ch;
30    unsigned char D[MAXBLOCKSIZE], A[MAXBLOCKSIZE], B[MAXBLOCKSIZE];
31    unsigned char *I, *key;
32    int err = CRYPT_ERROR;
33 
34    LTC_ARGCHK(pw   != NULL);
35    LTC_ARGCHK(salt != NULL);
36    LTC_ARGCHK(out  != NULL);
37 
38    key = XMALLOC(u * c);
39    I   = XMALLOC(Plen + Slen);
40    if (key == NULL || I == NULL) goto DONE;
41    zeromem(key, u * c);
42 
43    for (i = 0; i < v;    i++) D[i] = purpose;              /* D - diversifier */
44    for (i = 0; i < Slen; i++) I[i] = salt[i % saltlen];
45    for (i = 0; i < Plen; i++) I[Slen + i] = pw[i % pwlen]; /* I = Salt || Pass */
46 
47    for (i = 0; i < c; i++) {
48       Alen = sizeof(A);
49       err = hash_memory_multi(hash_id, A, &Alen, D, v, I, Slen + Plen, NULL); /* A = HASH(D || I) */
50       if (err != CRYPT_OK) goto DONE;
51       for (j = 1; j < iterations; j++) {
52          err = hash_memory(hash_id, A, Alen, A, &Alen); /* A = HASH(A) */
53          if (err != CRYPT_OK) goto DONE;
54       }
55       /* fill buffer B with A */
56       for (j = 0; j < v; j++) B[j] = A[j % Alen];
57       /* B += 1 */
58       for (j = v; j > 0; j--) {
59          if (++B[j - 1] != 0) break;
60       }
61       /* I_n += B */
62       for (n = 0; n < k; n++) {
63          ch = 0;
64          for (j = v; j > 0; j--) {
65             tmp = I[n * v + j - 1] + B[j - 1] + ch;
66             ch = (unsigned char)((tmp >> 8) & 0xFF);
67             I[n * v + j - 1] = (unsigned char)(tmp & 0xFF);
68          }
69       }
70       /* store derived key block */
71       XMEMCPY(&key[keylen], A, Alen);
72       keylen += Alen;
73    }
74 
75    XMEMCPY(out, key, outlen);
76    err = CRYPT_OK;
77 DONE:
78    if (I) {
79       zeromem(I, Plen + Slen);
80       XFREE(I);
81    }
82    if (key) {
83       zeromem(key, u * c);
84       XFREE(key);
85    }
86    return err;
87 }
88 
89 #endif
90 
91 /* ref:         $Format:%D$ */
92 /* git commit:  $Format:%H$ */
93 /* commit time: $Format:%ai$ */
94