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
31 static const char* kHexAlphabet = "0123456789abcdef";
32 static 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
41 static int
toHex(const uint8 * buffer,size_t bufferLength,char * outBuffer,size_t outBufferLength)42 toHex(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
70 static size_t
fromHex(const char * hex,uint8 * outBuffer,size_t outBufferLength)71 fromHex(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().
101 static int
crypt_gensalt_rn(char * outbuf,size_t bufsize)102 crypt_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
131 extern "C" char *
_crypt_rn(const char * key,const char * setting,struct crypt_data * data,size_t size)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
195 char *
crypt(const char * key,const char * salt)196 crypt(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.
204 char*
fcrypt(const char * key,const char * salt)205 fcrypt(const char* key, const char* salt)
206 {
207 return crypt(key, salt);
208 }
209