3 #include <openssl/evp.h>
4 #include <openssl/hmac.h>
7 #include "e_gost_err.h"
10 * Function expects that out is a preallocated buffer of length
11 * defined as sum of shared_len and mac length defined by mac_nid
13 int gost_kexp15(const unsigned char *shared_key, const int shared_len,
14 int cipher_nid, const unsigned char *cipher_key,
15 int mac_nid, unsigned char *mac_key,
16 const unsigned char *iv, const size_t ivlen,
17 unsigned char *out, int *out_len)
19 unsigned char iv_full[16], mac_buf[16];
22 EVP_CIPHER_CTX *ciph = NULL;
23 EVP_MD_CTX *mac = NULL;
28 mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
29 (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
32 GOSTerr(GOST_F_GOST_KEXP15, GOST_R_INVALID_CIPHER);
36 /* we expect IV of half length */
37 memset(iv_full, 0, 16);
38 memcpy(iv_full, iv, ivlen);
40 mac = EVP_MD_CTX_new();
42 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
46 if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
47 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
48 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
49 || EVP_DigestUpdate(mac, iv, ivlen) <= 0
50 || EVP_DigestUpdate(mac, shared_key, shared_len) <= 0
51 /* As we set MAC length directly, we should not allow overwriting it */
52 || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
53 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
57 ciph = EVP_CIPHER_CTX_new();
59 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
64 (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 1) <= 0
65 || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 1) <= 0
66 || EVP_CipherUpdate(ciph, out, &len, shared_key, shared_len) <= 0
67 || EVP_CipherUpdate(ciph, out + shared_len, &len, mac_buf, mac_len) <= 0
68 || EVP_CipherFinal_ex(ciph, out + shared_len + len, out_len) <= 0) {
69 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
73 *out_len = shared_len + mac_len;
78 OPENSSL_cleanse(mac_buf, mac_len);
80 EVP_CIPHER_CTX_free(ciph);
85 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
86 int cipher_nid, const unsigned char *cipher_key,
87 int mac_nid, unsigned char *mac_key,
88 const unsigned char *iv, const size_t ivlen,
89 unsigned char *shared_key, size_t shared_len)
91 unsigned char iv_full[16], out[48], mac_buf[16];
94 EVP_CIPHER_CTX *ciph = NULL;
95 EVP_MD_CTX *mac = NULL;
100 mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
101 (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
104 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
108 /* we expect IV of half length */
109 memset(iv_full, 0, 16);
110 memcpy(iv_full, iv, ivlen);
112 ciph = EVP_CIPHER_CTX_new();
114 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
118 if (EVP_CipherInit_ex
119 (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 0) <= 0
120 || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 0) <= 0
121 || EVP_CipherUpdate(ciph, out, &len, expkey, expkeylen) <= 0
122 || EVP_CipherFinal_ex(ciph, out + len, &len) <= 0) {
123 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
126 /*Now we have shared key and mac in out[] */
128 mac = EVP_MD_CTX_new();
130 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
134 if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
135 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
136 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
137 || EVP_DigestUpdate(mac, iv, ivlen) <= 0
138 || EVP_DigestUpdate(mac, out, shared_len) <= 0
139 /* As we set MAC length directly, we should not allow overwriting it */
140 || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
141 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
145 if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
146 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
150 memcpy(shared_key, out, shared_len);
154 OPENSSL_cleanse(out, sizeof(out));
155 EVP_MD_CTX_free(mac);
156 EVP_CIPHER_CTX_free(ciph);
160 int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len,
161 const unsigned char *key, size_t keylen,
162 const unsigned char *label, size_t label_len,
163 const unsigned char *seed, size_t seed_len,
164 const size_t representation)
167 unsigned char zero = 0;
168 unsigned char *ptr = keyout;
169 HMAC_CTX *ctx = NULL;
170 unsigned char *len_ptr = NULL;
171 uint32_t len_repr = htonl(keyout_len * 8);
172 size_t len_repr_len = 4;
174 ctx = HMAC_CTX_new();
176 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
180 if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
181 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
184 iters = keyout_len / 32;
186 len_ptr = (unsigned char *)&len_repr;
187 while (*len_ptr == 0) {
192 for (i = 1; i <= iters; i++) {
193 uint32_t iter_net = htonl(i);
194 unsigned char *rep_ptr =
195 ((unsigned char *)&iter_net) + (4 - representation);
197 if (HMAC_Init_ex(ctx, key, keylen,
198 EVP_get_digestbynid(NID_id_GostR3411_2012_256),
200 || HMAC_Update(ctx, rep_ptr, representation) <= 0
201 || HMAC_Update(ctx, label, label_len) <= 0
202 || HMAC_Update(ctx, &zero, 1) <= 0
203 || HMAC_Update(ctx, seed, seed_len) <= 0
204 || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
205 || HMAC_Final(ctx, ptr, NULL) <= 0) {
206 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
220 #ifdef ENABLE_UNIT_TESTS
223 # include <openssl/obj_mac.h>
225 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
229 fprintf(f, "%s", title);
232 fprintf(f, "\n%04x", n);
233 fprintf(f, " %02x", s[n]);
240 const unsigned char shared_key[] = {
241 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
242 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
243 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
244 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
247 const unsigned char magma_key[] = {
248 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
249 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
250 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
251 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
254 unsigned char mac_magma_key[] = {
255 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
256 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
257 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
258 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
261 const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
263 const unsigned char magma_export[] = {
264 0xCF, 0xD5, 0xA1, 0x2D, 0x5B, 0x81, 0xB6, 0xE1,
265 0xE9, 0x9C, 0x91, 0x6D, 0x07, 0x90, 0x0C, 0x6A,
266 0xC1, 0x27, 0x03, 0xFB, 0x3A, 0xBD, 0xED, 0x55,
267 0x56, 0x7B, 0xF3, 0x74, 0x2C, 0x89, 0x9C, 0x75,
268 0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9
271 unsigned char kdftree_key[] = {
272 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
273 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
274 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
275 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
278 unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
279 unsigned char kdf_seed[] =
280 { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
281 const unsigned char kdf_etalon[] = {
282 0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
283 0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
284 0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9,
285 0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B,
286 0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D,
287 0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD,
288 0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8,
289 0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9
292 unsigned char buf[32 + 16];
295 unsigned char kdf_result[64];
297 OpenSSL_add_all_algorithms();
298 memset(buf, 0, sizeof(buf));
300 ret = gost_kexp15(shared_key, 32,
301 NID_magma_ctr, magma_key,
302 NID_magma_mac, mac_magma_key, magma_iv, 4, buf, &outlen);
305 ERR_print_errors_fp(stderr);
307 hexdump(stdout, "Magma key export", buf, 40);
308 if (memcmp(buf, magma_export, 40) != 0) {
309 fprintf(stdout, "ERROR! test failed\n");
313 ret = gost_kimp15(magma_export, 40,
314 NID_magma_ctr, magma_key,
315 NID_magma_mac, mac_magma_key, magma_iv, 4, buf, 32);
318 ERR_print_errors_fp(stderr);
320 hexdump(stdout, "Magma key import", buf, 32);
321 if (memcmp(buf, shared_key, 32) != 0) {
322 fprintf(stdout, "ERROR! test failed\n");
326 ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
329 ERR_print_errors_fp(stderr);
331 hexdump(stdout, "KDF TREE", kdf_result, 64);
332 if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
333 fprintf(stdout, "ERROR! test failed\n");