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);
86 * Function expects that shared_key is a preallocated 32-bytes buffer
88 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
89 int cipher_nid, const unsigned char *cipher_key,
90 int mac_nid, unsigned char *mac_key,
91 const unsigned char *iv, const size_t ivlen,
92 unsigned char *shared_key)
94 unsigned char iv_full[16], out[48], mac_buf[16];
96 const size_t shared_len = 32;
98 EVP_CIPHER_CTX *ciph = NULL;
99 EVP_MD_CTX *mac = NULL;
104 mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
105 (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
108 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
112 /* we expect IV of half length */
113 memset(iv_full, 0, 16);
114 memcpy(iv_full, iv, ivlen);
116 ciph = EVP_CIPHER_CTX_new();
118 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
122 if (EVP_CipherInit_ex
123 (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 0) <= 0
124 || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 0) <= 0
125 || EVP_CipherUpdate(ciph, out, &len, expkey, expkeylen) <= 0
126 || EVP_CipherFinal_ex(ciph, out + len, &len) <= 0) {
127 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
130 /*Now we have shared key and mac in out[] */
132 mac = EVP_MD_CTX_new();
134 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
138 if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
139 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
140 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
141 || EVP_DigestUpdate(mac, iv, ivlen) <= 0
142 || EVP_DigestUpdate(mac, out, shared_len) <= 0
143 /* As we set MAC length directly, we should not allow overwriting it */
144 || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
145 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
149 if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
150 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
154 memcpy(shared_key, out, shared_len);
158 OPENSSL_cleanse(out, sizeof(out));
159 EVP_MD_CTX_free(mac);
160 EVP_CIPHER_CTX_free(ciph);
164 int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len,
165 const unsigned char *key, size_t keylen,
166 const unsigned char *label, size_t label_len,
167 const unsigned char *seed, size_t seed_len,
168 const size_t representation)
171 unsigned char zero = 0;
172 unsigned char *ptr = keyout;
173 HMAC_CTX *ctx = NULL;
174 unsigned char *len_ptr = NULL;
175 uint32_t len_repr = htonl(keyout_len * 8);
176 size_t len_repr_len = 4;
178 ctx = HMAC_CTX_new();
180 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
184 if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
185 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
188 iters = keyout_len / 32;
190 len_ptr = (unsigned char *)&len_repr;
191 while (*len_ptr == 0) {
196 for (i = 1; i <= iters; i++) {
197 uint32_t iter_net = htonl(i);
198 unsigned char *rep_ptr =
199 ((unsigned char *)&iter_net) + (4 - representation);
201 if (HMAC_Init_ex(ctx, key, keylen,
202 EVP_get_digestbynid(NID_id_GostR3411_2012_256),
204 || HMAC_Update(ctx, rep_ptr, representation) <= 0
205 || HMAC_Update(ctx, label, label_len) <= 0
206 || HMAC_Update(ctx, &zero, 1) <= 0
207 || HMAC_Update(ctx, seed, seed_len) <= 0
208 || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
209 || HMAC_Final(ctx, ptr, NULL) <= 0) {
210 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
224 #ifdef ENABLE_UNIT_TESTS
227 # include <openssl/obj_mac.h>
229 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
233 fprintf(f, "%s", title);
236 fprintf(f, "\n%04x", n);
237 fprintf(f, " %02x", s[n]);
244 const unsigned char shared_key[] = {
245 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
246 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
247 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
248 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
251 const unsigned char magma_key[] = {
252 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
253 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
254 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
255 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
258 unsigned char mac_magma_key[] = {
259 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
260 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
261 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
262 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
265 const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
267 const unsigned char magma_export[] = {
268 0xCF, 0xD5, 0xA1, 0x2D, 0x5B, 0x81, 0xB6, 0xE1,
269 0xE9, 0x9C, 0x91, 0x6D, 0x07, 0x90, 0x0C, 0x6A,
270 0xC1, 0x27, 0x03, 0xFB, 0x3A, 0xBD, 0xED, 0x55,
271 0x56, 0x7B, 0xF3, 0x74, 0x2C, 0x89, 0x9C, 0x75,
272 0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9
275 unsigned char kdftree_key[] = {
276 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
277 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
278 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
279 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
282 unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
283 unsigned char kdf_seed[] =
284 { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
285 const unsigned char kdf_etalon[] = {
286 0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
287 0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
288 0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9,
289 0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B,
290 0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D,
291 0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD,
292 0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8,
293 0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9
296 unsigned char buf[32 + 16];
299 unsigned char kdf_result[64];
301 OpenSSL_add_all_algorithms();
302 memset(buf, 0, sizeof(buf));
304 ret = gost_kexp15(shared_key, 32,
305 NID_magma_ctr, magma_key,
306 NID_magma_mac, mac_magma_key, magma_iv, 4, buf, &outlen);
309 ERR_print_errors_fp(stderr);
311 hexdump(stdout, "Magma key export", buf, 40);
312 if (memcmp(buf, magma_export, 40) != 0) {
313 fprintf(stdout, "ERROR! test failed\n");
317 ret = gost_kimp15(magma_export, 40,
318 NID_magma_ctr, magma_key,
319 NID_magma_mac, mac_magma_key, magma_iv, 4, buf);
322 ERR_print_errors_fp(stderr);
324 hexdump(stdout, "Magma key import", buf, 32);
325 if (memcmp(buf, shared_key, 32) != 0) {
326 fprintf(stdout, "ERROR! test failed\n");
330 ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
333 ERR_print_errors_fp(stderr);
335 hexdump(stdout, "KDF TREE", kdf_result, 64);
336 if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
337 fprintf(stdout, "ERROR! test failed\n");