2 #include <openssl/evp.h>
5 #include "e_gost_err.h"
8 * Function expects that out is a preallocated buffer of length
9 * defined as sum of shared_len and mac length defined by mac_nid
11 int gost_kexp15(const unsigned char *shared_key, const int shared_len,
12 int cipher_nid, const unsigned char *cipher_key,
13 const size_t cipher_key_len, int mac_nid,
14 unsigned char *mac_key, const size_t mac_key_len,
15 const unsigned char *iv, const size_t ivlen, unsigned char *out,
18 unsigned char iv_full[16], mac_buf[16];
21 EVP_CIPHER_CTX *ciph = NULL;
22 EVP_MD_CTX *mac = NULL;
27 mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
28 (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
31 GOSTerr(GOST_F_GOST_KEXP15, GOST_R_INVALID_CIPHER);
35 /* we expect IV of half length */
36 memset(iv_full, 0, 16);
37 memcpy(iv_full, iv, ivlen);
39 mac = EVP_MD_CTX_new();
41 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
45 if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
46 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, mac_key_len, mac_key) <= 0
47 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
48 || EVP_DigestUpdate(mac, iv, ivlen) <= 0
49 || EVP_DigestUpdate(mac, shared_key, shared_len) <= 0
50 /* As we set MAC length directly, we should not allow overwriting it */
51 || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
52 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
56 ciph = EVP_CIPHER_CTX_new();
58 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
63 (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 1) <= 0
64 || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 1) <= 0
65 || EVP_CipherUpdate(ciph, out, &len, shared_key, shared_len) <= 0
66 || EVP_CipherUpdate(ciph, out + shared_len, &len, mac_buf, mac_len) <= 0
67 || EVP_CipherFinal_ex(ciph, out + shared_len + len, out_len) <= 0) {
68 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
72 *out_len = shared_len + mac_len;
77 OPENSSL_cleanse(mac_buf, mac_len);
79 EVP_CIPHER_CTX_free(ciph);
84 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
85 int cipher_nid, const unsigned char *cipher_key,
86 const size_t cipher_key_len, int mac_nid,
87 unsigned char *mac_key, const size_t mac_key_len,
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_KEXP15, 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_KEXP15, 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, mac_key_len, 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);
161 * keyout expected to be 64 bytes
163 int gost_keg(const unsigned char *seckey, const size_t seckey_len,
164 const EC_POINT *pub, const unsigned char *h, unsigned char *keyout)
169 #ifdef ENABLE_UNIT_TESTS
172 # include <openssl/obj_mac.h>
174 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
178 fprintf(f, "%s", title);
181 fprintf(f, "\n%04x", n);
182 fprintf(f, " %02x", s[n]);
189 const unsigned char shared_key[] = {
190 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
191 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
192 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
193 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
196 const unsigned char magma_key[] = {
197 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
198 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
199 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
200 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
203 unsigned char mac_magma_key[] = {
204 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
205 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
206 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
207 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
210 const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
212 const unsigned char magma_export[] = {
213 0xCF, 0xD5, 0xA1, 0x2D, 0x5B, 0x81, 0xB6, 0xE1,
214 0xE9, 0x9C, 0x91, 0x6D, 0x07, 0x90, 0x0C, 0x6A,
215 0xC1, 0x27, 0x03, 0xFB, 0x3A, 0xBD, 0xED, 0x55,
216 0x56, 0x7B, 0xF3, 0x74, 0x2C, 0x89, 0x9C, 0x75,
217 0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9
220 unsigned char buf[32 + 16];
224 OpenSSL_add_all_algorithms();
225 memset(buf, 0, sizeof(buf));
227 ret = gost_kexp15(shared_key, 32,
228 NID_magma_ctr, magma_key, 32,
229 NID_magma_mac, mac_magma_key, 32,
230 magma_iv, 4, buf, &outlen);
233 ERR_print_errors_fp(stderr);
235 hexdump(stdout, "Magma key export", buf, 40);
236 if (memcmp(buf, magma_export, 40) != 0) {
237 fprintf(stdout, "ERROR! test failed\n");
241 ret = gost_kimp15(magma_export, 40,
242 NID_magma_ctr, magma_key, 32,
243 NID_magma_mac, mac_magma_key, 32, magma_iv, 4, buf, 32);
246 ERR_print_errors_fp(stderr);
248 hexdump(stdout, "Magma key import", buf, 32);
249 if (memcmp(buf, shared_key, 32) != 0) {
250 fprintf(stdout, "ERROR! test failed\n");