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
|
/*
* Written by Solar Designer and placed in the public domain.
* See crypt-bcrypt.c for more information.
*
* This file contains setting-string generation code shared among the
* MD5, SHA256, and SHA512 hash algorithms, which use very similar
* setting formats. Setting-string generation for bcrypt and DES is
* entirely in crypt-bcrypt.c and crypt-des.c respectively.
*/
#include "crypt-port.h"
#include <errno.h>
#include <stdio.h>
#if INCLUDE_md5crypt || INCLUDE_sha256crypt || INCLUDE_sha512crypt
void
gensalt_sha_rn (char tag, size_t maxsalt, unsigned long defcount,
unsigned long mincount, unsigned long maxcount,
unsigned long count,
const uint8_t *rbytes, size_t nrbytes,
uint8_t *output, size_t output_size)
{
/* We will use more rbytes if available, but at least this much is
required. */
if (nrbytes < 3)
{
errno = EINVAL;
return;
}
if (count == 0)
count = defcount;
if (count < mincount)
count = mincount;
if (count > maxcount)
count = maxcount;
/* Compute how much space we need. */
size_t output_len = 8; /* $x$ssss\0 */
if (count != defcount)
{
output_len += 9; /* rounds=1$ */
for (unsigned long ceiling = 10; ceiling < count; ceiling *= 10)
output_len += 1;
}
if (output_size < output_len)
{
errno = ERANGE;
return;
}
size_t written;
if (count == defcount)
{
output[0] = '$';
output[1] = (unsigned char)tag;
output[2] = '$';
written = 3;
}
else
written = (size_t) snprintf ((char *)output, output_size,
"$%c$rounds=%lu$", tag, count);
/* The length calculation above should ensure that this is always true. */
assert (written + 5 < output_size);
size_t used_rbytes = 0;
while (written + 5 < output_size &&
used_rbytes + 3 < nrbytes &&
(used_rbytes * 4 / 3) < maxsalt)
{
unsigned long value =
((unsigned long) (unsigned char) rbytes[used_rbytes + 0] << 0) |
((unsigned long) (unsigned char) rbytes[used_rbytes + 1] << 8) |
((unsigned long) (unsigned char) rbytes[used_rbytes + 2] << 16);
output[written + 0] = ascii64[value & 0x3f];
output[written + 1] = ascii64[(value >> 6) & 0x3f];
output[written + 2] = ascii64[(value >> 12) & 0x3f];
output[written + 3] = ascii64[(value >> 18) & 0x3f];
written += 4;
used_rbytes += 3;
}
output[written] = '\0';
}
#endif
|