Line data Source code
1 : /**
2 : * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
3 : *
4 : * Permission to use, copy, modify, and distribute this software for any
5 : * purpose with or without fee is hereby granted, provided that the above
6 : * copyright notice and this permission notice appear in all copies.
7 : *
8 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 : */
16 : // This file is based loosly off libutil/pkcs5_pbkdf2.c in OpenBSD.
17 :
18 : #include "precompiled.h"
19 :
20 : #include "pkcs5_pbkdf2.h"
21 :
22 : #include <cstring>
23 :
24 : // This does not match libsodium crypto_auth_hmacsha256, which has a constant key_len.
25 400 : static void hmac_sha256(unsigned char (&digest)[crypto_hash_sha256_BYTES],
26 : const unsigned char* text, size_t text_len,
27 : const unsigned char* key, size_t key_len)
28 : {
29 : crypto_hash_sha256_state state;
30 400 : crypto_hash_sha256_init(&state);
31 :
32 : unsigned char tk[crypto_hash_sha256_BYTES]; // temporary key in case we need to pad the key with zero unsigned chars
33 400 : if (key_len > crypto_hash_sha256_BYTES)
34 : {
35 0 : crypto_hash_sha256_update(&state, key, key_len);
36 0 : crypto_hash_sha256_final(&state, tk);
37 0 : key = tk;
38 0 : key_len = crypto_hash_sha256_BYTES;
39 : }
40 :
41 : unsigned char k_pad[crypto_hash_sha256_BYTES];
42 :
43 400 : memset(k_pad, 0, sizeof k_pad);
44 400 : memcpy(k_pad, key, key_len);
45 13200 : for (unsigned int i = 0; i < crypto_hash_sha256_BYTES; ++i)
46 12800 : k_pad[i] ^= 0x36;
47 400 : crypto_hash_sha256_init(&state);
48 400 : crypto_hash_sha256_update(&state, k_pad, crypto_hash_sha256_BYTES);
49 400 : crypto_hash_sha256_update(&state, text, text_len);
50 400 : crypto_hash_sha256_final(&state, digest);
51 :
52 :
53 400 : memset(k_pad, 0, sizeof k_pad);
54 400 : memcpy(k_pad, key, key_len);
55 13200 : for (unsigned int i = 0; i < crypto_hash_sha256_BYTES; ++i)
56 12800 : k_pad[i] ^= 0x5c;
57 :
58 400 : crypto_hash_sha256_init(&state);
59 400 : crypto_hash_sha256_update(&state, k_pad, crypto_hash_sha256_BYTES);
60 400 : crypto_hash_sha256_update(&state, digest, crypto_hash_sha256_BYTES);
61 400 : crypto_hash_sha256_final(&state, digest);
62 400 : }
63 :
64 :
65 6 : int pbkdf2(unsigned char (&output)[crypto_hash_sha256_BYTES],
66 : const unsigned char* key, size_t key_len,
67 : const unsigned char* salt, size_t salt_len,
68 : unsigned rounds)
69 : {
70 : unsigned char asalt[crypto_hash_sha256_BYTES + 4], obuf[crypto_hash_sha256_BYTES], d1[crypto_hash_sha256_BYTES], d2[crypto_hash_sha256_BYTES];
71 :
72 6 : if (rounds < 1 || key_len == 0 || salt_len == 0)
73 0 : return -1;
74 :
75 6 : if (salt_len > crypto_hash_sha256_BYTES) salt_len = crypto_hash_sha256_BYTES; // length cap for the salt
76 6 : memset(asalt, 0, salt_len);
77 6 : memcpy(asalt, salt, salt_len);
78 :
79 6 : for (unsigned count = 1; ; ++count)
80 : {
81 6 : asalt[salt_len + 0] = (count >> 24) & 0xff;
82 6 : asalt[salt_len + 1] = (count >> 16) & 0xff;
83 6 : asalt[salt_len + 2] = (count >> 8) & 0xff;
84 6 : asalt[salt_len + 3] = count & 0xff;
85 6 : hmac_sha256(d1, asalt, salt_len + 4, key, key_len);
86 6 : memcpy(obuf, d1, crypto_hash_sha256_BYTES);
87 :
88 400 : for (unsigned i = 1; i < rounds; i++)
89 : {
90 394 : hmac_sha256(d2, d1, crypto_hash_sha256_BYTES, key, key_len);
91 394 : memcpy(d1, d2, crypto_hash_sha256_BYTES);
92 13002 : for (unsigned j = 0; j < crypto_hash_sha256_BYTES; j++)
93 12608 : obuf[j] ^= d1[j];
94 : }
95 :
96 6 : memcpy(output, obuf, crypto_hash_sha256_BYTES);
97 6 : key += crypto_hash_sha256_BYTES;
98 6 : if (key_len < crypto_hash_sha256_BYTES)
99 6 : break;
100 0 : key_len -= crypto_hash_sha256_BYTES;
101 0 : };
102 6 : return 0;
103 3 : }
104 :
|