1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6    @file bcrypt.c
7    bcrypt pbkdf, Steffen Jaeckel
8 */
9 #ifdef LTC_BCRYPT
10 
11 #define BCRYPT_WORDS 8
12 #define BCRYPT_HASHSIZE (BCRYPT_WORDS * 4)
13 
s_bcrypt_hash(const unsigned char * pt,const unsigned char * pass,unsigned long passlen,const unsigned char * salt,unsigned long saltlen,unsigned char * out,unsigned long * outlen)14 static int s_bcrypt_hash(const unsigned char *pt,
15                         const unsigned char *pass, unsigned long passlen,
16                         const unsigned char *salt, unsigned long saltlen,
17                               unsigned char *out,  unsigned long *outlen)
18 {
19    symmetric_key key;
20    int err, n;
21    ulong32 ct[BCRYPT_WORDS];
22 
23    if ((err = blowfish_setup_with_data(pass, passlen, salt, saltlen, &key)) != CRYPT_OK) {
24       return err;
25    }
26    for (n = 0; n < 64; ++n) {
27       if ((err = blowfish_expand(salt, saltlen, NULL, 0, &key)) != CRYPT_OK) {
28          return err;
29       }
30       if ((err = blowfish_expand(pass, passlen, NULL, 0, &key)) != CRYPT_OK) {
31          return err;
32       }
33    }
34 
35    for (n = 0; n < BCRYPT_WORDS; ++n) {
36       LOAD32H(ct[n], &pt[n*4]);
37    }
38 
39    for (n = 0; n < 64; ++n) {
40       blowfish_enc(ct, BCRYPT_WORDS/2, &key);
41    }
42 
43    for (n = 0; n < BCRYPT_WORDS; ++n) {
44       STORE32L(ct[n], &out[4 * n]);
45    }
46    *outlen = sizeof(ct);
47 #ifdef LTC_CLEAN_STACK
48    zeromem(&key, sizeof(key));
49    zeromem(ct, sizeof(ct));
50 #endif
51 
52    return CRYPT_OK;
53 }
54 
s_bcrypt_pbkdf_hash(const unsigned char * pass,unsigned long passlen,const unsigned char * salt,unsigned long saltlen,unsigned char * out,unsigned long * outlen)55 static int s_bcrypt_pbkdf_hash(const unsigned char *pass, unsigned long passlen,
56                          const unsigned char *salt, unsigned long saltlen,
57                                unsigned char *out,  unsigned long *outlen)
58 {
59    const unsigned char pt[] = "OxychromaticBlowfishSwatDynamite";
60    return s_bcrypt_hash(pt, pass, passlen, salt, saltlen, out, outlen);
61 }
62 
63 /**
64    Compatible to bcrypt_pbkdf() as provided in OpenBSD
65    @param password          The input password (or key)
66    @param password_len      The length of the password (octets)
67    @param salt              The salt (or nonce)
68    @param salt_len          The length of the salt (octets)
69    @param rounds            # of iterations desired [read specs for more]
70    @param hash_idx          The index of the hash desired
71    @param out               [out] The destination for this algorithm
72    @param outlen            [in/out] The desired size of the algorithm output
73    @return CRYPT_OK if successful
74 */
bcrypt_pbkdf_openbsd(const void * secret,unsigned long secret_len,const unsigned char * salt,unsigned long salt_len,unsigned int rounds,int hash_idx,unsigned char * out,unsigned long * outlen)75 int bcrypt_pbkdf_openbsd(const          void *secret, unsigned long secret_len,
76                          const unsigned char *salt,   unsigned long salt_len,
77                                unsigned int  rounds,            int hash_idx,
78                                unsigned char *out,    unsigned long *outlen)
79 {
80    int err;
81    ulong32 blkno;
82    unsigned long left, itts, x, y, hashed_pass_len, step_size, steps, dest, used_rounds;
83    unsigned char *buf[3], blkbuf[4];
84    unsigned char *hashed_pass;
85 
86    LTC_ARGCHK(secret != NULL);
87    LTC_ARGCHK(salt   != NULL);
88    LTC_ARGCHK(out    != NULL);
89    LTC_ARGCHK(outlen != NULL);
90 
91    if ((secret_len == 0) || (salt_len == 0) || (*outlen == 0)) {
92       return CRYPT_INVALID_ARG;
93    }
94    /* test hash IDX */
95    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
96       return err;
97    }
98    /* set default value for rounds if not given */
99    if (rounds == 0) {
100       used_rounds = LTC_BCRYPT_DEFAULT_ROUNDS;
101    } else {
102       used_rounds = rounds;
103    }
104 
105    buf[0]      = XMALLOC(MAXBLOCKSIZE * 3);
106    hashed_pass = XMALLOC(MAXBLOCKSIZE);
107    if (buf[0] == NULL || hashed_pass == NULL) {
108       if (hashed_pass != NULL) {
109          XFREE(hashed_pass);
110       }
111       if (buf[0] != NULL) {
112          XFREE(buf[0]);
113       }
114       return CRYPT_MEM;
115    }
116    /* buf[1] points to the second block of MAXBLOCKSIZE bytes */
117    buf[1] = buf[0] + MAXBLOCKSIZE;
118    buf[2] = buf[1] + MAXBLOCKSIZE;
119 
120    step_size = (*outlen + BCRYPT_HASHSIZE - 1) / BCRYPT_HASHSIZE;
121    steps = (*outlen + step_size - 1) / step_size;
122 
123    hashed_pass_len = MAXBLOCKSIZE;
124    if ((err = hash_memory(hash_idx, (unsigned char*)secret, secret_len, hashed_pass, &hashed_pass_len)) != CRYPT_OK) {
125       goto LBL_ERR;
126    }
127 
128    left   = *outlen;
129    blkno  = 0;
130    while (left != 0) {
131        /* increment and store current block number */
132        ++blkno;
133        STORE32H(blkno, blkbuf);
134 
135        /* process block number blkno */
136        zeromem(buf[0], MAXBLOCKSIZE*2);
137 
138        x = MAXBLOCKSIZE;
139        if ((err = hash_memory_multi(hash_idx, buf[0], &x,
140                                     salt, salt_len,
141                                     blkbuf, 4uL,
142                                     LTC_NULL)) != CRYPT_OK) {
143           goto LBL_ERR;
144        }
145        y = MAXBLOCKSIZE;
146        if ((err = s_bcrypt_pbkdf_hash(hashed_pass, hashed_pass_len, buf[0], x, buf[1], &y)) != CRYPT_OK) {
147           goto LBL_ERR;
148        }
149        XMEMCPY(buf[2], buf[1], y);
150 
151        /* now compute repeated and XOR it in buf[2] */
152        for (itts = 1; itts < used_rounds; ++itts) {
153           x = MAXBLOCKSIZE;
154           if ((err = hash_memory(hash_idx, buf[1], y, buf[0], &x)) != CRYPT_OK) {
155              goto LBL_ERR;
156           }
157           y = MAXBLOCKSIZE;
158           if ((err = s_bcrypt_pbkdf_hash(hashed_pass, hashed_pass_len, buf[0], x, buf[1], &y)) != CRYPT_OK) {
159              goto LBL_ERR;
160           }
161           for (x = 0; x < y; x++) {
162              buf[2][x] ^= buf[1][x];
163           }
164        }
165 
166        /* now emit upto `steps` bytes of buf[2] to output */
167        steps = MIN(steps, left);
168        for (y = 0; y < steps; ++y) {
169           dest = y * step_size + (blkno - 1);
170           if (dest >= *outlen)
171              break;
172           out[dest] = buf[2][y];
173        }
174        left -= y;
175    }
176 
177    err = CRYPT_OK;
178 LBL_ERR:
179 #ifdef LTC_CLEAN_STACK
180    zeromem(buf[0], MAXBLOCKSIZE*3);
181    zeromem(hashed_pass, MAXBLOCKSIZE);
182 #endif
183 
184    XFREE(hashed_pass);
185    XFREE(buf[0]);
186 
187    return err;
188 }
189 
190 #endif
191 
192