2 * Copyright 2017, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Andrew Aldridge, i80and@foxquill.com
18 #include <SupportDefs.h>
20 #include "crypt_legacy.h"
21 #include "crypto_scrypt.h"
24 #define SALT_STR_BYTES (SALT_BYTES * 2 + 1)
25 #define DEFAULT_N_LOG2 14
27 // $s$99$ salt $ hash \0
28 #define CRYPT_OUTPUT_BYTES (6 + 64 + 1 + 64 + 1)
30 static const char* kHexAlphabet
= "0123456789abcdef";
31 static const char kHexLookup
[] = {
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
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, 0, 1, 2, 3,
35 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
36 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
37 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15};
41 toHex(const uint8
* buffer
, size_t bufferLength
, char* outBuffer
,
42 size_t outBufferLength
)
47 if (outBufferLength
<= bufferLength
* 2) {
52 for (i
= 0; i
< bufferLength
; i
+= 1) {
53 const uint8 n
= buffer
[i
];
54 const uint8 upper
= n
>> 4;
55 const uint8 lower
= n
& 0x0f;
57 assert(lower
< 16 && upper
< 16);
58 outBuffer
[outIndex
++] = kHexAlphabet
[upper
];
59 outBuffer
[outIndex
++] = kHexAlphabet
[lower
];
60 outBuffer
[outIndex
] = '\0';
63 outBuffer
[outIndex
] = '\0';
70 fromHex(const char* hex
, uint8
* outBuffer
, size_t outBufferLength
)
75 if (hex
[0] == '\0' || outBufferLength
== 0)
78 while (hex
[i
] != '\0' && hex
[i
+ 1] != '\0') {
79 const uint8 char1
= hex
[i
];
80 const uint8 char2
= hex
[i
+ 1];
82 if (char1
>= sizeof(kHexLookup
) || char2
>= sizeof(kHexLookup
))
85 const char index1
= kHexLookup
[char1
];
86 const char index2
= kHexLookup
[char2
];
88 if (outIndex
>= outBufferLength
)
91 outBuffer
[outIndex
++] = (index1
<< 4) | index2
;
99 //! Generate a new salt appropriate for crypt().
103 static char result
[CRYPT_OUTPUT_BYTES
];
104 uint8 salt
[SALT_BYTES
];
105 char saltString
[SALT_STR_BYTES
];
106 size_t totalBytesRead
= 0;
108 int fd
= open("/dev/random", O_RDONLY
, 0);
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) {
121 totalBytesRead
+= bytesRead
;
125 assert(toHex(salt
, sizeof(salt
), saltString
, sizeof(saltString
)) == 0);
126 snprintf(result
, sizeof(result
), "$s$%d$%s$", DEFAULT_N_LOG2
, saltString
);
132 crypt(const char* key
, const char* setting
)
134 static char outBuffer
[CRYPT_OUTPUT_BYTES
];
135 uint8 saltBinary
[SALT_BYTES
];
136 char saltString
[SALT_STR_BYTES
];
137 uint8 resultBuffer
[32];
138 char hexResultBuffer
[64 + 1];
139 int nLog2
= DEFAULT_N_LOG2
;
141 if (setting
== NULL
) {
142 setting
= crypt_gensalt();
143 if (setting
== NULL
) {
144 // crypt_gensalt should set errno itself.
149 // Some idioms existed where the password was also used as the salt.
150 // As a crude heuristic, use the old crypt algorithm if the salt is
152 if (strlen(setting
) < 16)
153 return crypt_legacy(key
, setting
);
155 // We don't want to fall into the old algorithm by accident somehow, so
156 // if our salt is kind of like our salt, but not exactly, return an
158 if (sscanf(setting
, "$s$%2d$%64s$", &nLog2
, saltString
) != 2) {
163 // Set a lower bound on N_log2: below 12 scrypt is weaker than bcrypt.
169 size_t saltBinaryLength
= fromHex(saltString
, saltBinary
,
171 if (saltBinaryLength
!= sizeof(saltBinary
)) {
176 long n
= static_cast<long>(pow(2, nLog2
));
177 if (crypto_scrypt(reinterpret_cast<const uint8
*>(key
), strlen(key
),
178 saltBinary
, saltBinaryLength
, n
, 8, 1, resultBuffer
,
179 sizeof(resultBuffer
)) != 0) {
180 // crypto_scrypt sets errno itself
184 assert(toHex(resultBuffer
, sizeof(resultBuffer
), hexResultBuffer
,
185 sizeof(hexResultBuffer
)) == 0);
186 snprintf(outBuffer
, sizeof(outBuffer
), "$s$%d$%s$%s", nLog2
, saltString
,
193 //! To make fcrypt users happy. They don't need to call init_des.
195 fcrypt(const char* key
, const char* salt
)
197 return crypt(key
, salt
);