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