1 /* Copyright (C) 2018 vt@altlinux.org
2 * Copyright (C) 2018 Björn Esser besser82@fedoraproject.org
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted.
6 *
7 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
8 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
11 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
15 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
17 * SUCH DAMAGE.
18 */
19
20 #include "crypt-port.h"
21
22 #if INCLUDE_gost_yescrypt
23
24 #define YESCRYPT_INTERNAL
25 #include "alg-yescrypt.h"
26 #undef YESCRYPT_INTERNAL
27
28 #include "alg-gost3411-2012-hmac.h"
29
30 #include <errno.h>
31
32 /* upper level hmac for tests */
33 #ifndef outer_gost_hmac256
34 #define outer_gost_hmac256 gost_hmac256
35 #endif
36
37 /* For use in scratch space by crypt_gost_yescrypt_rn(). */
38 typedef struct
39 {
40 yescrypt_local_t local;
41 gost_hmac_256_t gostbuf;
42 uint8_t outbuf[CRYPT_OUTPUT_SIZE];
43 uint8_t gsetting[CRYPT_OUTPUT_SIZE];
44 uint8_t hk[32], interm[32], y[32];
45 uint8_t *retval;
46 } crypt_gost_yescrypt_internal_t;
47
48 static_assert (sizeof (crypt_gost_yescrypt_internal_t) <= ALG_SPECIFIC_SIZE,
49 "ALG_SPECIFIC_SIZE is too small for GOST-YESCRYPT.");
50
51 /*
52 * As OUTPUT is initialized with a failure token before gensalt_yescrypt_rn
53 * is called, in case of an error we could just set an appropriate errno
54 * and return.
55 */
56 void
57 gensalt_gost_yescrypt_rn (unsigned long count,
58 const uint8_t *rbytes, size_t nrbytes,
59 uint8_t *output, size_t o_size)
60 {
61 /* Up to 512 bits (64 bytes) of entropy for computing the salt portion
62 of the MCF-setting are supported. */
63 nrbytes = (nrbytes > 64 ? 64 : nrbytes);
64
65 if (o_size < 4 + 8 * 6 + BASE64_LEN (nrbytes) + 1 ||
66 CRYPT_GENSALT_OUTPUT_SIZE < 4 + 8 * 6 + BASE64_LEN (nrbytes) + 1)
67 {
68 errno = ERANGE;
69 return;
70 }
71
72 /* We pass 'o_size - 1' to gensalt, because we need to shift
73 the prefix by 1 char to insert the gost marker. */
74 gensalt_yescrypt_rn (count, rbytes, nrbytes, output, o_size - 1);
75
76 /* Check for failures. */
77 if (output[0] == '*')
78 return;
79
80 /* Shift output one byte further. */
81 memmove (output + 1, output, strlen ((const char *) output) + 1);
82
83 /* Insert the gost marker. */
84 output[1] = 'g';
85 }
86
87 void
88 crypt_gost_yescrypt_rn (const char *phrase, size_t phr_size,
89 const char *setting, size_t set_size,
90 uint8_t *output, size_t o_size,
91 void *scratch, size_t s_size)
92 {
93 if (o_size < set_size + 1 + 43 + 1 ||
94 CRYPT_OUTPUT_SIZE < set_size + 1 + 43 + 1 ||
95 s_size < sizeof (crypt_gost_yescrypt_internal_t))
96 {
97 errno = ERANGE;
98 return;
99 }
100
101 /* Fail when called with wrong prefix. */
102 if (strncmp (setting, "$gy$", 4))
103 {
104 errno = EINVAL;
105 return;
106 }
107
108 crypt_gost_yescrypt_internal_t *intbuf = scratch;
109
110 if (yescrypt_init_local (&intbuf->local))
111 return;
112
113 /* convert gost setting to yescrypt setting */
114 intbuf->gsetting[0] = '$';
115 intbuf->gsetting[1] = 'y';
116 intbuf->gsetting[2] = '$';
117 strcpy_or_abort (&intbuf->gsetting[3], set_size - 3, setting + 4);
118
119 intbuf->retval = yescrypt_r (NULL, &intbuf->local,
120 (const uint8_t *) phrase, phr_size,
121 intbuf->gsetting, NULL,
122 intbuf->outbuf + 1, o_size - 1);
123
124 if (!intbuf->retval)
125 errno = EINVAL;
126
127 if (yescrypt_free_local (&intbuf->local) || !intbuf->retval)
128 return;
129
130 intbuf->outbuf[0] = '$';
131 intbuf->outbuf[1] = 'g';
132
133 /* extract yescrypt output from "$y$param$salt$output" */
134 char *hptr = strchr ((const char *) intbuf->retval + 3, '$');
135 if (!hptr)
136 {
137 errno = EINVAL;
138 return;
139 }
140 hptr = strchr (hptr + 1, '$');
141 if (!hptr)
142 {
143 errno = EINVAL;
144 return;
145 }
146 hptr++; /* start of output */
147
148 /* decode yescrypt output into its raw 256-bit form */
149 size_t ylen = sizeof (intbuf->y);
150 if (!decode64 (intbuf->y, &ylen, (uint8_t *) hptr, strlen (hptr)) ||
151 ylen != sizeof (intbuf->y))
152 {
153 errno = EINVAL;
154 return;
155 }
156
157 /*
158 * HMAC_GOSTR3411_2012_256(
159 * HMAC_GOSTR3411_2012_256(GOST2012_256(K), S),
160 * yescrypt(K, S)
161 * )
162 * yescrypt output is used in place of message,
163 * thus, its crypto properties are superseded by GOST.
164 * Password is always hashed for inner hmac to avoid
165 * collisions between hashed and unhashed passwords.
166 */
167 gost_hash256 ((const uint8_t *) phrase, phr_size, intbuf->hk, &intbuf->gostbuf.ctx);
168 gost_hmac256 (intbuf->hk, sizeof (intbuf->hk),
169 (const uint8_t *) setting,
170 (size_t) ((uint8_t *) hptr - intbuf->retval),
171 intbuf->interm, &intbuf->gostbuf);
172 outer_gost_hmac256 (intbuf->interm, sizeof (intbuf->interm),
173 intbuf->y, sizeof (intbuf->y), intbuf->y, &intbuf->gostbuf);
174
175 encode64 ((uint8_t *) hptr, o_size - (size_t) ((uint8_t *) hptr - intbuf->retval),
176 intbuf->y, sizeof (intbuf->y));
177
178 strcpy_or_abort (output, o_size, intbuf->outbuf);
179 return;
180 }
181
182 #endif /* INCLUDE_gost_yescrypt */