xref: /haiku/src/system/libroot/posix/crypt/pbkdf2.cpp (revision 6889394848e2dc9f41ff53b12141d572822ca0c6)
1 /* This file is distributed under the following terms:
2 
3  * Copyright 2005-2014 Colin Percival.  All rights reserved.
4  * Copyright 2014 Sean Kelly.  All rights reserved.
5 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include <stdint.h>
30 #include <string.h>
31 #include <ByteOrder.h>
32 #include "pbkdf2.h"
33 
34 /* Function which does the zeroing. */
35 static void
36 insecure_memzero_func(volatile void * buf, size_t len)
37 {
38 	volatile uint8_t * _buf = (volatile uint8_t *)buf;
39 	size_t i;
40 
41 	for (i = 0; i < len; i++)
42 		_buf[i] = 0;
43 }
44 
45 /* Pointer to memory-zeroing function. */
46 void (* volatile insecure_memzero_ptr)(volatile void *, size_t) =
47     insecure_memzero_func;
48 
49 /**
50  * HMAC_SHA256_Init(ctx, K, Klen):
51  * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
52  * ${K}.
53  */
54 void
55 HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
56 {
57 	uint8_t pad[64];
58 	uint8_t khash[32];
59 	const uint8_t * K = (const uint8_t *)_K;
60 	size_t i;
61 
62 	/* If Klen > 64, the key is really SHA256(K). */
63 	if (Klen > 64) {
64 		ctx->ictx.Init();
65 		ctx->ictx.Update(K, Klen);
66 		memcpy(khash, ctx->ictx.Digest(), 32);
67 		K = khash;
68 		Klen = 32;
69 	}
70 
71 	/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
72 	ctx->ictx.Init();
73 	memset(pad, 0x36, 64);
74 	for (i = 0; i < Klen; i++)
75 		pad[i] ^= K[i];
76 	ctx->ictx.Update(pad, 64);
77 
78 	/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
79 	ctx->octx.Init();
80 	memset(pad, 0x5c, 64);
81 	for (i = 0; i < Klen; i++)
82 		pad[i] ^= K[i];
83 	ctx->octx.Update(pad, 64);
84 
85 	/* Clean the stack. */
86 	insecure_memzero(khash, 32);
87 	insecure_memzero(pad, 64);
88 }
89 
90 /**
91  * HMAC_SHA256_Update(ctx, in, len):
92  * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}.
93  */
94 void
95 HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len)
96 {
97 
98 	/* Feed data to the inner SHA256 operation. */
99 	ctx->ictx.Update(in, len);
100 }
101 
102 /**
103  * HMAC_SHA256_Final(digest, ctx):
104  * Output the HMAC-SHA256 of the data input to the context ${ctx} into the
105  * buffer ${digest}.
106  */
107 void
108 HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx)
109 {
110 	uint8_t ihash[32];
111 
112 	/* Finish the inner SHA256 operation. */
113 	memcpy(ihash, ctx->ictx.Digest(), 32);
114 
115 	/* Feed the inner hash to the outer SHA256 operation. */
116 	ctx->octx.Update(ihash, 32);
117 
118 	/* Finish the outer SHA256 operation. */
119 	memcpy(digest, ctx->octx.Digest(), 32);
120 
121 	/* Clean the stack. */
122 	insecure_memzero(ihash, 32);
123 }
124 
125 /**
126  * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
127  * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
128  * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
129  */
130 void
131 PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
132     size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
133 {
134 	HMAC_SHA256_CTX PShctx, hctx;
135 	size_t i;
136 	uint32_t ivec;
137 	uint8_t U[32];
138 	uint8_t T[32];
139 	uint64_t j;
140 	int k;
141 	size_t clen;
142 
143 	/* Sanity-check. */
144 	assert(dkLen <= 32 * (size_t)(UINT32_MAX));
145 
146 	/* Compute HMAC state after processing P and S. */
147 	HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
148 	HMAC_SHA256_Update(&PShctx, salt, saltlen);
149 
150 	/* Iterate through the blocks. */
151 	for (i = 0; i * 32 < dkLen; i++) {
152 		/* Generate INT(i + 1). */
153 		ivec = B_HOST_TO_BENDIAN_INT32((uint32_t)(i + 1));
154 
155 		/* Compute U_1 = PRF(P, S || INT(i)). */
156 		memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
157 		HMAC_SHA256_Update(&hctx, &ivec, 4);
158 		HMAC_SHA256_Final(U, &hctx);
159 
160 		/* T_i = U_1 ... */
161 		memcpy(T, U, 32);
162 
163 		for (j = 2; j <= c; j++) {
164 			/* Compute U_j. */
165 			HMAC_SHA256_Init(&hctx, passwd, passwdlen);
166 			HMAC_SHA256_Update(&hctx, U, 32);
167 			HMAC_SHA256_Final(U, &hctx);
168 
169 			/* ... xor U_j ... */
170 			for (k = 0; k < 32; k++)
171 				T[k] ^= U[k];
172 		}
173 
174 		/* Copy as many bytes as necessary into buf. */
175 		clen = dkLen - i * 32;
176 		if (clen > 32)
177 			clen = 32;
178 		memcpy(&buf[i * 32], T, clen);
179 	}
180 
181 	/* Clean PShctx, since we never called _Final on it. */
182 	insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX));
183 }
184