File: pkcs5_pbkdf2.cpp

package info (click to toggle)
0ad 0.27.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 173,296 kB
  • sloc: cpp: 194,003; javascript: 19,098; ansic: 15,066; python: 6,328; sh: 1,699; perl: 1,575; java: 533; xml: 482; php: 192; makefile: 99
file content (104 lines) | stat: -rw-r--r-- 3,642 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
 * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
// This file is based loosly off libutil/pkcs5_pbkdf2.c in OpenBSD.

#include "precompiled.h"

#include "pkcs5_pbkdf2.h"

#include <cstring>

// This does not match libsodium crypto_auth_hmacsha256, which has a constant key_len.
static void hmac_sha256(unsigned char (&digest)[crypto_hash_sha256_BYTES],
						const unsigned char* text, size_t text_len,
						const unsigned char* key, size_t key_len)
{
	crypto_hash_sha256_state state;
	crypto_hash_sha256_init(&state);

	unsigned char tk[crypto_hash_sha256_BYTES]; // temporary key in case we need to pad the key with zero unsigned chars
	if (key_len > crypto_hash_sha256_BYTES)
	{
		crypto_hash_sha256_update(&state, key, key_len);
		crypto_hash_sha256_final(&state, tk);
		key = tk;
		key_len = crypto_hash_sha256_BYTES;
	}

	unsigned char k_pad[crypto_hash_sha256_BYTES];

	memset(k_pad, 0, sizeof k_pad);
	memcpy(k_pad, key, key_len);
	for (unsigned int i = 0; i < crypto_hash_sha256_BYTES; ++i)
		k_pad[i] ^= 0x36;
	crypto_hash_sha256_init(&state);
	crypto_hash_sha256_update(&state, k_pad, crypto_hash_sha256_BYTES);
	crypto_hash_sha256_update(&state, text, text_len);
	crypto_hash_sha256_final(&state, digest);


	memset(k_pad, 0, sizeof k_pad);
	memcpy(k_pad, key, key_len);
	for (unsigned int i = 0; i < crypto_hash_sha256_BYTES; ++i)
		k_pad[i] ^= 0x5c;

	crypto_hash_sha256_init(&state);
	crypto_hash_sha256_update(&state, k_pad, crypto_hash_sha256_BYTES);
	crypto_hash_sha256_update(&state, digest, crypto_hash_sha256_BYTES);
	crypto_hash_sha256_final(&state, digest);
}


int pbkdf2(unsigned char (&output)[crypto_hash_sha256_BYTES],
			const unsigned char* key, size_t key_len,
			const unsigned char* salt, size_t salt_len,
			unsigned rounds)
{
	unsigned char asalt[crypto_hash_sha256_BYTES + 4], obuf[crypto_hash_sha256_BYTES], d1[crypto_hash_sha256_BYTES], d2[crypto_hash_sha256_BYTES];

	if (rounds < 1 || key_len == 0 || salt_len == 0)
		return -1;

	if (salt_len > crypto_hash_sha256_BYTES) salt_len = crypto_hash_sha256_BYTES; // length cap for the salt
	memset(asalt, 0, salt_len);
	memcpy(asalt, salt, salt_len);

	for (unsigned count = 1; ; ++count)
	{
		asalt[salt_len + 0] = (count >> 24) & 0xff;
		asalt[salt_len + 1] = (count >> 16) & 0xff;
		asalt[salt_len + 2] = (count >> 8) & 0xff;
		asalt[salt_len + 3] = count & 0xff;
		hmac_sha256(d1, asalt, salt_len + 4, key, key_len);
		memcpy(obuf, d1, crypto_hash_sha256_BYTES);

		for (unsigned i = 1; i < rounds; i++)
		{
			hmac_sha256(d2, d1, crypto_hash_sha256_BYTES, key, key_len);
			memcpy(d1, d2, crypto_hash_sha256_BYTES);
			for (unsigned j = 0; j < crypto_hash_sha256_BYTES; j++)
				obuf[j] ^= d1[j];
		}

		memcpy(output, obuf, crypto_hash_sha256_BYTES);
		key += crypto_hash_sha256_BYTES;
		if (key_len < crypto_hash_sha256_BYTES)
			break;
		key_len -= crypto_hash_sha256_BYTES;
	};
	return 0;
}