1/*
2 * Copyright 2017, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * 		Andrew Aldridge, i80and@foxquill.com
7 */
8
9
10#include <assert.h>
11#include <crypt.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <inttypes.h>
15#include <math.h>
16#include <stdio.h>
17#include <string.h>
18
19#include <SupportDefs.h>
20
21#include "../musl/crypt/crypt_des.h"
22#include "crypto_scrypt.h"
23
24#define SALT_BYTES 32
25#define SALT_STR_BYTES (SALT_BYTES * 2 + 1)
26#define DEFAULT_N_LOG2 14
27
28#define CRYPT_OUTPUT_BYTES (6 + 64 + 1 + 64 + 1)
29#define SALT_OUTPUT_BYTES (6 + 64 + 1 + 1)
30
31static const char* kHexAlphabet = "0123456789abcdef";
32static const int8 kHexLookup[] = {
33	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3,
36	4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
37	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
38	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15};
39
40
41static int
42toHex(const uint8* buffer, size_t bufferLength, char* outBuffer,
43	size_t outBufferLength)
44{
45	size_t i;
46	size_t outIndex = 0;
47
48	if (outBufferLength <= bufferLength * 2) {
49		outBuffer[0] = '\0';
50		return 1;
51	}
52
53	for (i = 0; i < bufferLength; i += 1) {
54		const uint8 n = buffer[i];
55		const uint8 upper = n >> 4;
56		const uint8 lower = n & 0x0f;
57
58		assert(lower < 16 && upper < 16);
59		outBuffer[outIndex++] = kHexAlphabet[upper];
60		outBuffer[outIndex++] = kHexAlphabet[lower];
61		outBuffer[outIndex] = '\0';
62	}
63
64	outBuffer[outIndex] = '\0';
65
66	return 0;
67}
68
69
70static size_t
71fromHex(const char* hex, uint8* outBuffer, size_t outBufferLength)
72{
73	size_t i = 0;
74	size_t outIndex = 0;
75
76	if (hex[0] == '\0' || outBufferLength == 0)
77		return 0;
78
79	while (hex[i] != '\0' && hex[i + 1] != '\0') {
80		const uint8 char1 = hex[i];
81		const uint8 char2 = hex[i + 1];
82
83		if (char1 >= sizeof(kHexLookup) || char2 >= sizeof(kHexLookup))
84			return outIndex;
85
86		const char index1 = kHexLookup[char1];
87		const char index2 = kHexLookup[char2];
88
89		if (outIndex >= outBufferLength)
90			return 0;
91
92		outBuffer[outIndex++] = (index1 << 4) | index2;
93		i += 2;
94	}
95
96	return outIndex;
97}
98
99
100//! Generate a new salt appropriate for crypt().
101static int
102crypt_gensalt_rn(char *outbuf, size_t bufsize)
103{
104	uint8 salt[SALT_BYTES];
105	char saltString[SALT_STR_BYTES];
106	size_t totalBytesRead = 0;
107
108	int fd = open("/dev/random", O_RDONLY, 0);
109	if (fd < 0)
110		return -1;
111
112	while (totalBytesRead < sizeof(salt)) {
113		const ssize_t bytesRead = read(fd,
114			static_cast<void*>(salt + totalBytesRead),
115			sizeof(salt) - totalBytesRead);
116		if (bytesRead <= 0) {
117			close(fd);
118			return -1;
119		}
120
121		totalBytesRead += bytesRead;
122	}
123	close(fd);
124
125	assert(toHex(salt, sizeof(salt), saltString, sizeof(saltString)) == 0);
126	snprintf(outbuf, bufsize, "$s$%d$%s$", DEFAULT_N_LOG2, saltString);
127	return 0;
128}
129
130
131extern "C" char *
132_crypt_rn(const char* key, const char* setting, struct crypt_data* data, size_t size)
133{
134	uint8 saltBinary[SALT_BYTES];
135	char saltString[SALT_STR_BYTES];
136	char gensaltResult[SALT_OUTPUT_BYTES];
137	uint8 resultBuffer[32];
138	char hexResultBuffer[64 + 1];
139	int nLog2 = DEFAULT_N_LOG2;
140
141	if (setting == NULL) {
142		int res = crypt_gensalt_rn(gensaltResult, sizeof(gensaltResult));
143
144		// crypt_gensalt_r should set errno itself.
145		if (res < 0)
146			return NULL;
147
148		setting = gensaltResult;
149	}
150
151	// Some idioms existed where the password was also used as the salt.
152	// As a crude heuristic, use the old crypt algorithm if the salt is
153	// shortish.
154	if (strlen(setting) < 16)
155		return _crypt_des_r(key, setting, data->buf);
156
157	// We don't want to fall into the old algorithm by accident somehow, so
158	// if our salt is kind of like our salt, but not exactly, return an
159	// error.
160	if (sscanf(setting, "$s$%2d$%64s$", &nLog2, saltString) != 2) {
161		errno = EINVAL;
162		return NULL;
163	}
164
165	// Set a lower bound on N_log2: below 12 scrypt is weaker than bcrypt.
166	if (nLog2 < 12) {
167		errno = EINVAL;
168		return NULL;
169	}
170
171	size_t saltBinaryLength = fromHex(saltString, saltBinary,
172		sizeof(saltBinary));
173	if (saltBinaryLength != sizeof(saltBinary)) {
174		errno = EINVAL;
175		return NULL;
176	}
177
178	long n = static_cast<long>(pow(2, nLog2));
179	if (crypto_scrypt(reinterpret_cast<const uint8*>(key), strlen(key),
180		saltBinary, saltBinaryLength, n, 8, 1, resultBuffer,
181		sizeof(resultBuffer)) != 0) {
182		// crypto_scrypt sets errno itself
183		return NULL;
184	}
185
186	assert(toHex(resultBuffer, sizeof(resultBuffer), hexResultBuffer,
187		sizeof(hexResultBuffer)) == 0);
188	snprintf(data->buf, size - sizeof(int), "$s$%d$%s$%s", nLog2, saltString,
189		hexResultBuffer);
190
191	return data->buf;
192}
193
194
195char *
196crypt(const char* key, const char* salt)
197{
198	static struct crypt_data data;
199	return _crypt_rn(key, salt, &data, sizeof(struct crypt_data));
200}
201
202
203//! To make fcrypt users happy. They don't need to call init_des.
204char*
205fcrypt(const char* key, const char* salt)
206{
207	return crypt(key, salt);
208}
209