xref: /freebsd/sys/contrib/libsodium/src/libsodium/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c (revision 3611ec604864a7d4dcc9a3ea898c80eb35eef8a0)
1 /*-
2  * Copyright 2013 Alexander Peslyak
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted.
7  *
8  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
9  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
12  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18  * SUCH DAMAGE.
19  */
20 
21 #include <stdint.h>
22 #include <string.h>
23 
24 #include "crypto_pwhash_scryptsalsa208sha256.h"
25 #include "crypto_scrypt.h"
26 #include "private/common.h"
27 #include "runtime.h"
28 #include "utils.h"
29 
30 static const char *const itoa64 =
31     "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
32 
33 static uint8_t *
encode64_uint32(uint8_t * dst,size_t dstlen,uint32_t src,uint32_t srcbits)34 encode64_uint32(uint8_t *dst, size_t dstlen, uint32_t src, uint32_t srcbits)
35 {
36     uint32_t bit;
37 
38     for (bit = 0; bit < srcbits; bit += 6) {
39         if (dstlen < 1) {
40             return NULL; /* LCOV_EXCL_LINE */
41         }
42         *dst++ = itoa64[src & 0x3f];
43         dstlen--;
44         src >>= 6;
45     }
46     return dst;
47 }
48 
49 static uint8_t *
encode64(uint8_t * dst,size_t dstlen,const uint8_t * src,size_t srclen)50 encode64(uint8_t *dst, size_t dstlen, const uint8_t *src, size_t srclen)
51 {
52     size_t i;
53 
54     for (i = 0; i < srclen;) {
55         uint8_t *dnext;
56         uint32_t value = 0, bits = 0;
57 
58         do {
59             value |= (uint32_t) src[i++] << bits;
60             bits += 8;
61         } while (bits < 24 && i < srclen);
62 
63         dnext = encode64_uint32(dst, dstlen, value, bits);
64         if (!dnext) {
65             return NULL; /* LCOV_EXCL_LINE */
66         }
67         dstlen -= dnext - dst;
68         dst = dnext;
69     }
70     return dst;
71 }
72 
73 static int
decode64_one(uint32_t * dst,uint8_t src)74 decode64_one(uint32_t *dst, uint8_t src)
75 {
76     const char *ptr = strchr(itoa64, src);
77 
78     if (ptr) {
79         *dst = (uint32_t)(ptr - itoa64);
80         return 0;
81     }
82     *dst = 0;
83 
84     return -1;
85 }
86 
87 static const uint8_t *
decode64_uint32(uint32_t * dst,uint32_t dstbits,const uint8_t * src)88 decode64_uint32(uint32_t *dst, uint32_t dstbits, const uint8_t *src)
89 {
90     uint32_t bit;
91     uint32_t value;
92 
93     value = 0;
94     for (bit = 0; bit < dstbits; bit += 6) {
95         uint32_t one;
96         if (decode64_one(&one, *src)) {
97             *dst = 0;
98             return NULL;
99         }
100         src++;
101         value |= one << bit;
102     }
103     *dst = value;
104 
105     return src;
106 }
107 
108 const uint8_t *
escrypt_parse_setting(const uint8_t * setting,uint32_t * N_log2_p,uint32_t * r_p,uint32_t * p_p)109 escrypt_parse_setting(const uint8_t *setting,
110                       uint32_t *N_log2_p, uint32_t *r_p, uint32_t *p_p)
111 {
112     const uint8_t *src;
113 
114     if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') {
115         return NULL;
116     }
117     src = setting + 3;
118 
119     if (decode64_one(N_log2_p, *src)) {
120         return NULL;
121     }
122     src++;
123 
124     src = decode64_uint32(r_p, 30, src);
125     if (!src) {
126         return NULL;
127     }
128 
129     src = decode64_uint32(p_p, 30, src);
130     if (!src) {
131         return NULL;
132     }
133     return src;
134 }
135 
136 uint8_t *
escrypt_r(escrypt_local_t * local,const uint8_t * passwd,size_t passwdlen,const uint8_t * setting,uint8_t * buf,size_t buflen)137 escrypt_r(escrypt_local_t *local, const uint8_t *passwd, size_t passwdlen,
138           const uint8_t *setting, uint8_t *buf, size_t buflen)
139 {
140     uint8_t        hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES];
141     escrypt_kdf_t  escrypt_kdf;
142     const uint8_t *src;
143     const uint8_t *salt;
144     uint8_t       *dst;
145     size_t         prefixlen;
146     size_t         saltlen;
147     size_t         need;
148     uint64_t       N;
149     uint32_t       N_log2;
150     uint32_t       r;
151     uint32_t       p;
152 
153     src = escrypt_parse_setting(setting, &N_log2, &r, &p);
154     if (!src) {
155         return NULL;
156     }
157     N = (uint64_t) 1 << N_log2;
158     prefixlen = src - setting;
159 
160     salt = src;
161     src  = (uint8_t *) strrchr((char *) salt, '$');
162     if (src) {
163         saltlen = src - salt;
164     } else {
165         saltlen = strlen((char *) salt);
166     }
167     need = prefixlen + saltlen + 1 +
168            crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1;
169     if (need > buflen || need < saltlen) {
170         return NULL;
171     }
172 #ifdef HAVE_EMMINTRIN_H
173     escrypt_kdf =
174         sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse;
175 #else
176     escrypt_kdf = escrypt_kdf_nosse;
177 #endif
178     if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, N, r, p, hash,
179                     sizeof(hash))) {
180         return NULL;
181     }
182     dst = buf;
183     memcpy(dst, setting, prefixlen + saltlen);
184     dst += prefixlen + saltlen;
185     *dst++ = '$';
186 
187     dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash));
188     sodium_memzero(hash, sizeof hash);
189     if (!dst || dst >= buf + buflen) {
190         return NULL; /* Can't happen LCOV_EXCL_LINE */
191     }
192     *dst = 0; /* NUL termination */
193 
194     return buf;
195 }
196 
197 uint8_t *
escrypt_gensalt_r(uint32_t N_log2,uint32_t r,uint32_t p,const uint8_t * src,size_t srclen,uint8_t * buf,size_t buflen)198 escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, const uint8_t *src,
199                   size_t srclen, uint8_t *buf, size_t buflen)
200 {
201     uint8_t *dst;
202     size_t   prefixlen =
203         (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */);
204     size_t saltlen = BYTES2CHARS(srclen);
205     size_t need;
206 
207     need = prefixlen + saltlen + 1;
208     if (need > buflen || need < saltlen || saltlen < srclen) {
209         return NULL; /* LCOV_EXCL_LINE */
210     }
211     if (N_log2 > 63 || ((uint64_t) r * (uint64_t) p >= (1U << 30))) {
212         return NULL; /* LCOV_EXCL_LINE */
213     }
214     dst    = buf;
215     *dst++ = '$';
216     *dst++ = '7';
217     *dst++ = '$';
218 
219     *dst++ = itoa64[N_log2];
220 
221     dst = encode64_uint32(dst, buflen - (dst - buf), r, 30);
222     if (!dst) {
223         return NULL; /* Can't happen LCOV_EXCL_LINE */
224     }
225     dst = encode64_uint32(dst, buflen - (dst - buf), p, 30);
226     if (!dst) {
227         return NULL; /* Can't happen LCOV_EXCL_LINE */
228     }
229     dst = encode64(dst, buflen - (dst - buf), src, srclen);
230     if (!dst || dst >= buf + buflen) {
231         return NULL; /* Can't happen LCOV_EXCL_LINE */
232     }
233     *dst = 0; /* NUL termination */
234 
235     return buf;
236 }
237 
238 int
crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd,size_t passwdlen,const uint8_t * salt,size_t saltlen,uint64_t N,uint32_t r,uint32_t p,uint8_t * buf,size_t buflen)239 crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t *passwd, size_t passwdlen,
240                                       const uint8_t *salt, size_t saltlen,
241                                       uint64_t N, uint32_t r, uint32_t p,
242                                       uint8_t *buf, size_t buflen)
243 {
244     escrypt_kdf_t   escrypt_kdf;
245     escrypt_local_t local;
246     int             retval;
247 
248     if (escrypt_init_local(&local)) {
249         return -1; /* LCOV_EXCL_LINE */
250     }
251 #if defined(HAVE_EMMINTRIN_H)
252     escrypt_kdf =
253         sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse;
254 #else
255     escrypt_kdf = escrypt_kdf_nosse;
256 #endif
257     retval = escrypt_kdf(&local, passwd, passwdlen, salt, saltlen, N, r, p, buf,
258                          buflen);
259     if (escrypt_free_local(&local)) {
260         return -1; /* LCOV_EXCL_LINE */
261     }
262     return retval;
263 }
264