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 buffer
87 * with length defined as expkeylen - mac_len defined by mac_nid
89 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
90 int cipher_nid, const unsigned char *cipher_key,
91 int mac_nid, unsigned char *mac_key,
92 const unsigned char *iv, const size_t ivlen,
93 unsigned char *shared_key)
95 unsigned char iv_full[16], out[48], mac_buf[16];
97 const size_t shared_len = 32;
99 EVP_CIPHER_CTX *ciph = NULL;
100 EVP_MD_CTX *mac = NULL;
105 mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
106 (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
109 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
113 /* we expect IV of half length */
114 memset(iv_full, 0, 16);
115 memcpy(iv_full, iv, ivlen);
117 ciph = EVP_CIPHER_CTX_new();
119 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
123 if (EVP_CipherInit_ex
124 (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 0) <= 0
125 || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 0) <= 0
126 || EVP_CipherUpdate(ciph, out, &len, expkey, expkeylen) <= 0
127 || EVP_CipherFinal_ex(ciph, out + len, &len) <= 0) {
128 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
131 /*Now we have shared key and mac in out[] */
133 mac = EVP_MD_CTX_new();
135 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
139 if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
140 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
141 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
142 || EVP_DigestUpdate(mac, iv, ivlen) <= 0
143 || EVP_DigestUpdate(mac, out, shared_len) <= 0
144 /* As we set MAC length directly, we should not allow overwriting it */
145 || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
146 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
150 if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
151 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
155 memcpy(shared_key, out, shared_len);
159 OPENSSL_cleanse(out, sizeof(out));
160 EVP_MD_CTX_free(mac);
161 EVP_CIPHER_CTX_free(ciph);
165 int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len,
166 const unsigned char *key, size_t keylen,
167 const unsigned char *label, size_t label_len,
168 const unsigned char *seed, size_t seed_len,
169 const size_t representation)
172 unsigned char zero = 0;
173 unsigned char *ptr = keyout;
174 HMAC_CTX *ctx = NULL;
175 unsigned char *len_ptr = NULL;
176 uint32_t len_repr = htonl(keyout_len * 8);
177 size_t len_repr_len = 4;
179 ctx = HMAC_CTX_new();
181 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
185 if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
186 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
189 iters = keyout_len / 32;
191 len_ptr = (unsigned char *)&len_repr;
192 while (*len_ptr == 0) {
197 for (i = 1; i <= iters; i++) {
198 uint32_t iter_net = htonl(i);
199 unsigned char *rep_ptr =
200 ((unsigned char *)&iter_net) + (4 - representation);
202 if (HMAC_Init_ex(ctx, key, keylen,
203 EVP_get_digestbynid(NID_id_GostR3411_2012_256),
205 || HMAC_Update(ctx, rep_ptr, representation) <= 0
206 || HMAC_Update(ctx, label, label_len) <= 0
207 || HMAC_Update(ctx, &zero, 1) <= 0
208 || HMAC_Update(ctx, seed, seed_len) <= 0
209 || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
210 || HMAC_Final(ctx, ptr, NULL) <= 0) {
211 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
225 #ifdef ENABLE_UNIT_TESTS
228 # include <openssl/obj_mac.h>
230 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
234 fprintf(f, "%s", title);
237 fprintf(f, "\n%04x", n);
238 fprintf(f, " %02x", s[n]);
245 const unsigned char shared_key[] = {
246 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
247 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
248 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
249 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
252 const unsigned char magma_key[] = {
253 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
254 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
255 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
256 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
259 unsigned char mac_magma_key[] = {
260 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
261 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
262 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
263 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
266 const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
268 const unsigned char magma_export[] = {
269 0xCF, 0xD5, 0xA1, 0x2D, 0x5B, 0x81, 0xB6, 0xE1,
270 0xE9, 0x9C, 0x91, 0x6D, 0x07, 0x90, 0x0C, 0x6A,
271 0xC1, 0x27, 0x03, 0xFB, 0x3A, 0xBD, 0xED, 0x55,
272 0x56, 0x7B, 0xF3, 0x74, 0x2C, 0x89, 0x9C, 0x75,
273 0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9
276 unsigned char kdftree_key[] = {
277 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
278 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
279 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
280 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
283 unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
284 unsigned char kdf_seed[] =
285 { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
286 const unsigned char kdf_etalon[] = {
287 0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
288 0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
289 0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9,
290 0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B,
291 0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D,
292 0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD,
293 0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8,
294 0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9
297 unsigned char buf[32 + 16];
300 unsigned char kdf_result[64];
302 OpenSSL_add_all_algorithms();
303 memset(buf, 0, sizeof(buf));
305 ret = gost_kexp15(shared_key, 32,
306 NID_magma_ctr, magma_key,
307 NID_magma_mac, mac_magma_key, magma_iv, 4, buf, &outlen);
310 ERR_print_errors_fp(stderr);
312 hexdump(stdout, "Magma key export", buf, 40);
313 if (memcmp(buf, magma_export, 40) != 0) {
314 fprintf(stdout, "ERROR! test failed\n");
318 ret = gost_kimp15(magma_export, 40,
319 NID_magma_ctr, magma_key,
320 NID_magma_mac, mac_magma_key, magma_iv, 4, buf);
323 ERR_print_errors_fp(stderr);
325 hexdump(stdout, "Magma key import", buf, 32);
326 if (memcmp(buf, shared_key, 32) != 0) {
327 fprintf(stdout, "ERROR! test failed\n");
331 ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
334 ERR_print_errors_fp(stderr);
336 hexdump(stdout, "KDF TREE", kdf_result, 64);
337 if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
338 fprintf(stdout, "ERROR! test failed\n");