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