+ len_ptr = (unsigned char *)&len_repr;
+ while (*len_ptr == 0) {
+ len_ptr++;
+ len_repr_len--;
+ }
+
+ for (i = 1; i <= iters; i++) {
+ uint32_t iter_net = be32(i);
+ unsigned char *rep_ptr =
+ ((unsigned char *)&iter_net) + (4 - representation);
+
+ if (HMAC_Init_ex(ctx, key, keylen,
+ EVP_get_digestbynid(NID_id_GostR3411_2012_256),
+ NULL) <= 0
+ || HMAC_Update(ctx, rep_ptr, representation) <= 0
+ || HMAC_Update(ctx, label, label_len) <= 0
+ || HMAC_Update(ctx, &zero, 1) <= 0
+ || HMAC_Update(ctx, seed, seed_len) <= 0
+ || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
+ || HMAC_Final(ctx, ptr, NULL) <= 0) {
+ GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
+ HMAC_CTX_free(ctx);
+ return 0;
+ }
+
+ HMAC_CTX_reset(ctx);
+ ptr += 32;
+ }
+
+ HMAC_CTX_free(ctx);
+
+ return 1;
+}
+
+int gost_tlstree(int cipher_nid, const unsigned char *in, unsigned char *out,
+ const unsigned char *tlsseq)
+{
+ uint64_t gh_c1 = 0x00000000FFFFFFFF, gh_c2 = 0x0000F8FFFFFFFFFF,
+ gh_c3 = 0xC0FFFFFFFFFFFFFF;
+ uint64_t mg_c1 = 0x00000000C0FFFFFF, mg_c2 = 0x000000FEFFFFFFFF,
+ mg_c3 = 0x00F0FFFFFFFFFFFF;
+ uint64_t c1, c2, c3;
+ uint64_t seed1, seed2, seed3;
+ uint64_t seq;
+ unsigned char ko1[32], ko2[32];
+
+ switch (cipher_nid) {
+ case NID_magma_cbc:
+ c1 = mg_c1;
+ c2 = mg_c2;
+ c3 = mg_c3;
+ break;
+ case NID_grasshopper_cbc:
+ c1 = gh_c1;
+ c2 = gh_c2;
+ c3 = gh_c3;
+ break;
+ default:
+ return 0;
+ }
+#ifndef L_ENDIAN
+ BUF_reverse((unsigned char *)&seq, tlsseq, 8);
+#else
+ memcpy(&seq, tlsseq, 8);
+#endif
+ seed1 = seq & c1;
+ seed2 = seq & c2;
+ seed3 = seq & c3;
+
+ if (gost_kdftree2012_256(ko1, 32, in, 32, (const unsigned char *)"level1", 6,
+ (const unsigned char *)&seed1, 8, 1) <= 0
+ || gost_kdftree2012_256(ko2, 32, ko1, 32, (const unsigned char *)"level2", 6,
+ (const unsigned char *)&seed2, 8, 1) <= 0
+ || gost_kdftree2012_256(out, 32, ko2, 32, (const unsigned char *)"level3", 6,
+ (const unsigned char *)&seed3, 8, 1) <= 0)
+ return 0;
+
+ return 1;
+}
+
+#define GOST_WRAP_FLAGS EVP_CIPH_CTRL_INIT | EVP_CIPH_WRAP_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | EVP_CIPH_FLAG_DEFAULT_ASN1
+
+#define MAGMA_MAC_WRAP_LEN 8
+#define KUZNYECHIK_MAC_WRAP_LEN 16
+#define MAX_MAC_WRAP_LEN KUZNYECHIK_MAC_WRAP_LEN
+#define GOSTKEYLEN 32
+#define MAGMA_WRAPPED_KEY_LEN GOSTKEYLEN + MAGMA_MAC_WRAP_LEN
+#define KUZNYECHIK_WRAPPED_KEY_LEN GOSTKEYLEN + KUZNYECHIK_MAC_WRAP_LEN
+#define MAX_WRAPPED_KEY_LEN KUZNYECHIK_WRAPPED_KEY_LEN
+
+typedef struct {
+ unsigned char iv[8]; /* Max IV size is half of base cipher block length */
+ unsigned char key[GOSTKEYLEN*2]; /* Combined cipher and mac keys */
+ unsigned char wrapped[MAX_WRAPPED_KEY_LEN]; /* Max size */
+ size_t wrap_count;
+} GOST_WRAP_CTX;
+
+static int magma_wrap_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+{
+ GOST_WRAP_CTX *cctx = EVP_CIPHER_CTX_get_cipher_data(ctx);
+ memset(cctx->wrapped, 0, MAX_WRAPPED_KEY_LEN);
+ cctx->wrap_count = 0;
+
+ if (iv) {
+ memset(cctx->iv, 0, 8);
+ memcpy(cctx->iv, iv, 4);