-
Notifications
You must be signed in to change notification settings - Fork 193
Expand file tree
/
Copy pathgost_keyexpimp.c
More file actions
180 lines (153 loc) · 4.69 KB
/
gost_keyexpimp.c
File metadata and controls
180 lines (153 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* Copyright (c) 2019 Dmitry Belyavskiy <beldmit@gmail.com>
* Copyright (c) 2020 Vitaly Chikunov <vt@altlinux.org>
*
* Contents licensed under the terms of the OpenSSL license
* See https://www.openssl.org/source/license.html for details
*/
#include <string.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/buffer.h>
#include "gost_lcl.h"
#include "gost_gost2015.h"
#include "gost_grasshopper_cipher.h"
#include "gost_tls12_additional.h"
#include "e_gost_err.h"
#include "gost_cipher_details.h"
#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(GOST_cipher_ctx *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
GOST_WRAP_CTX *cctx = GOST_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);
}
if (key) {
memcpy(cctx->key, key, GOSTKEYLEN*2);
}
return 1;
}
static int magma_wrap_do(GOST_cipher_ctx *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
GOST_WRAP_CTX *cctx = GOST_cipher_ctx_get_cipher_data(ctx);
int enc = GOST_cipher_ctx_encrypting(ctx) ? 1 : 0;
if (out == NULL)
return GOSTKEYLEN;
if (inl <= MAGMA_WRAPPED_KEY_LEN) {
if (cctx->wrap_count + inl > MAGMA_WRAPPED_KEY_LEN)
return -1;
if (cctx->wrap_count + inl <= MAGMA_WRAPPED_KEY_LEN)
{
memcpy(cctx->wrapped+cctx->wrap_count, in, inl);
cctx->wrap_count += inl;
}
}
if (cctx->wrap_count < MAGMA_WRAPPED_KEY_LEN)
return 0;
if (enc) {
#if 0
return gost_kexp15(cctx->key, 32, NID_magma_ctr, in, NID_magma_mac,
cctx->key, /* FIXME mac_key, */ cctx->iv, 4, out, &outl);
#endif
return -1;
} else {
return gost_kimp15(cctx->wrapped, cctx->wrap_count, NID_magma_ctr,
cctx->key+GOSTKEYLEN, NID_magma_mac, cctx->key, cctx->iv, 4, out) > 0 ? GOSTKEYLEN : 0;
}
}
static int kuznyechik_wrap_init(GOST_cipher_ctx *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
GOST_WRAP_CTX *cctx = GOST_cipher_ctx_get_cipher_data(ctx);
memset(cctx->wrapped, 0, KUZNYECHIK_WRAPPED_KEY_LEN);
cctx->wrap_count = 0;
if (iv) {
memset(cctx->iv, 0, 8);
memcpy(cctx->iv, iv, 8);
}
if (key) {
memcpy(cctx->key, key, GOSTKEYLEN*2);
}
return 1;
}
static int kuznyechik_wrap_do(GOST_cipher_ctx *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
GOST_WRAP_CTX *cctx = GOST_cipher_ctx_get_cipher_data(ctx);
int enc = GOST_cipher_ctx_encrypting(ctx) ? 1 : 0;
if (out == NULL)
return GOSTKEYLEN;
if (inl <= KUZNYECHIK_WRAPPED_KEY_LEN) {
if (cctx->wrap_count + inl > KUZNYECHIK_WRAPPED_KEY_LEN)
return -1;
if (cctx->wrap_count + inl <= KUZNYECHIK_WRAPPED_KEY_LEN)
{
memcpy(cctx->wrapped+cctx->wrap_count, in, inl);
cctx->wrap_count += inl;
}
}
if (cctx->wrap_count < KUZNYECHIK_WRAPPED_KEY_LEN)
return 0;
if (enc) {
#if 0
return gost_kexp15(cctx->key, 32, NID_magma_ctr, in, NID_magma_mac,
cctx->key, /* FIXME mac_key, */ cctx->iv, 4, out, &outl);
#endif
return -1;
} else {
return gost_kimp15(cctx->wrapped, cctx->wrap_count, NID_kuznyechik_ctr,
cctx->key+GOSTKEYLEN, NID_kuznyechik_mac, cctx->key, cctx->iv, 8, out) > 0 ? GOSTKEYLEN : 0;
}
}
static int wrap_ctrl (GOST_cipher_ctx *ctx, int type, int arg, void *ptr)
{
switch(type)
{
case EVP_CTRL_INIT:
GOST_cipher_ctx_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
return 1;
default:
return -2;
}
}
static GOST_cipher wrap_template_cipher = {
.key_len = GOSTKEYLEN * 2,
.flags = GOST_WRAP_FLAGS,
.ctx_size = sizeof(GOST_WRAP_CTX),
.ctrl = wrap_ctrl,
};
GOST_cipher magma_kexp15_cipher = {
.template = &wrap_template_cipher,
.nid = NID_magma_kexp15,
.block_size = 8,
.iv_len = 4,
.init = magma_wrap_init,
.do_cipher = magma_wrap_do,
};
GOST_cipher kuznyechik_kexp15_cipher = {
.template = &wrap_template_cipher,
.nid = NID_kuznyechik_kexp15,
.block_size = 16,
.iv_len = 8,
.init = kuznyechik_wrap_init,
.do_cipher = kuznyechik_wrap_do,
};
/* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */