1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6    @file pkcs_5_2.c
7    PKCS #5, Algorithm #2, Tom St Denis
8 */
9 #ifdef LTC_PKCS_5
10 
11 /**
12    Execute PKCS #5 v2
13    @param password          The input password (or key)
14    @param password_len      The length of the password (octets)
15    @param salt              The salt (or nonce)
16    @param salt_len          The length of the salt (octets)
17    @param iteration_count   # of iterations desired for PKCS #5 v2 [read specs for more]
18    @param hash_idx          The index of the hash desired
19    @param out               [out] The destination for this algorithm
20    @param outlen            [in/out] The max size and resulting size of the algorithm output
21    @return CRYPT_OK if successful
22 */
pkcs_5_alg2(const unsigned char * password,unsigned long password_len,const unsigned char * salt,unsigned long salt_len,int iteration_count,int hash_idx,unsigned char * out,unsigned long * outlen)23 int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
24                 const unsigned char *salt,     unsigned long salt_len,
25                 int iteration_count,           int hash_idx,
26                 unsigned char *out,            unsigned long *outlen)
27 {
28    int err, itts;
29    ulong32  blkno;
30    unsigned long stored, left, x, y;
31    unsigned char *buf[2];
32    hmac_state    *hmac;
33 
34    LTC_ARGCHK(password != NULL);
35    LTC_ARGCHK(salt     != NULL);
36    LTC_ARGCHK(out      != NULL);
37    LTC_ARGCHK(outlen   != NULL);
38 
39    if (iteration_count <= 0) {
40       return CRYPT_INVALID_ARG;
41    }
42 
43    /* test hash IDX */
44    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
45       return err;
46    }
47 
48    buf[0] = XMALLOC(MAXBLOCKSIZE * 2);
49    hmac   = XMALLOC(sizeof(hmac_state));
50    if (hmac == NULL || buf[0] == NULL) {
51       if (hmac != NULL) {
52          XFREE(hmac);
53       }
54       if (buf[0] != NULL) {
55          XFREE(buf[0]);
56       }
57       return CRYPT_MEM;
58    }
59    /* buf[1] points to the second block of MAXBLOCKSIZE bytes */
60    buf[1] = buf[0] + MAXBLOCKSIZE;
61 
62    left   = *outlen;
63    blkno  = 1;
64    stored = 0;
65    while (left != 0) {
66        /* process block number blkno */
67        zeromem(buf[0], MAXBLOCKSIZE*2);
68 
69        /* store current block number and increment for next pass */
70        STORE32H(blkno, buf[1]);
71        ++blkno;
72 
73        /* get PRF(P, S||int(blkno)) */
74        if ((err = hmac_init(hmac, hash_idx, password, password_len)) != CRYPT_OK) {
75           goto LBL_ERR;
76        }
77        if ((err = hmac_process(hmac, salt, salt_len)) != CRYPT_OK) {
78           goto LBL_ERR;
79        }
80        if ((err = hmac_process(hmac, buf[1], 4)) != CRYPT_OK) {
81           goto LBL_ERR;
82        }
83        x = MAXBLOCKSIZE;
84        if ((err = hmac_done(hmac, buf[0], &x)) != CRYPT_OK) {
85           goto LBL_ERR;
86        }
87 
88        /* now compute repeated and XOR it in buf[1] */
89        XMEMCPY(buf[1], buf[0], x);
90        for (itts = 1; itts < iteration_count; ++itts) {
91            if ((err = hmac_memory(hash_idx, password, password_len, buf[0], x, buf[0], &x)) != CRYPT_OK) {
92               goto LBL_ERR;
93            }
94            for (y = 0; y < x; y++) {
95                buf[1][y] ^= buf[0][y];
96            }
97        }
98 
99        /* now emit upto x bytes of buf[1] to output */
100        for (y = 0; y < x && left != 0; ++y) {
101            out[stored++] = buf[1][y];
102            --left;
103        }
104    }
105    *outlen = stored;
106 
107    err = CRYPT_OK;
108 LBL_ERR:
109 #ifdef LTC_CLEAN_STACK
110    zeromem(buf[0], MAXBLOCKSIZE*2);
111    zeromem(hmac, sizeof(hmac_state));
112 #endif
113 
114    XFREE(hmac);
115    XFREE(buf[0]);
116 
117    return err;
118 }
119 
120 #endif
121 
122