1 /* $OpenBSD: e_gost2814789.c,v 1.10 2022/09/10 17:39:47 jsing Exp $ */
2 /*
3 * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
4 * Copyright (c) 2005-2006 Cryptocom LTD
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * 3. All advertising materials mentioning features or use of this
19 * software must display the following acknowledgment:
20 * "This product includes software developed by the OpenSSL Project
21 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
22 *
23 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24 * endorse or promote products derived from this software without
25 * prior written permission. For written permission, please contact
26 * openssl-core@openssl.org.
27 *
28 * 5. Products derived from this software may not be called "OpenSSL"
29 * nor may "OpenSSL" appear in their names without prior written
30 * permission of the OpenSSL Project.
31 *
32 * 6. Redistributions of any form whatsoever must retain the following
33 * acknowledgment:
34 * "This product includes software developed by the OpenSSL Project
35 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48 * OF THE POSSIBILITY OF SUCH DAMAGE.
49 * ====================================================================
50 */
51
52 #include <string.h>
53
54 #include <openssl/opensslconf.h>
55
56 #ifndef OPENSSL_NO_GOST
57 #include <openssl/evp.h>
58 #include <openssl/err.h>
59 #include <openssl/gost.h>
60
61 #include "evp_locl.h"
62
63 typedef struct {
64 GOST2814789_KEY ks;
65 int param_nid;
66 } EVP_GOST2814789_CTX;
67
68 static int
gost2814789_init_key(EVP_CIPHER_CTX * ctx,const unsigned char * key,const unsigned char * iv,int enc)69 gost2814789_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
70 const unsigned char *iv, int enc)
71 {
72 EVP_GOST2814789_CTX *c = ctx->cipher_data;
73
74 return Gost2814789_set_key(&c->ks, key, ctx->key_len * 8);
75 }
76
77 static int
gost2814789_ctl(EVP_CIPHER_CTX * ctx,int type,int arg,void * ptr)78 gost2814789_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
79 {
80 EVP_GOST2814789_CTX *c = ctx->cipher_data;
81
82 switch (type) {
83 case EVP_CTRL_PBE_PRF_NID:
84 if (ptr != NULL) {
85 *((int *)ptr) = NID_id_HMACGostR3411_94;
86 return 1;
87 } else {
88 return 0;
89 }
90 case EVP_CTRL_INIT:
91 /* Default value to have any s-box set at all */
92 c->param_nid = NID_id_Gost28147_89_CryptoPro_A_ParamSet;
93 return Gost2814789_set_sbox(&c->ks, c->param_nid);
94 case EVP_CTRL_GOST_SET_SBOX:
95 return Gost2814789_set_sbox(&c->ks, arg);
96 default:
97 return -1;
98 }
99 }
100
101 int
gost2814789_set_asn1_params(EVP_CIPHER_CTX * ctx,ASN1_TYPE * params)102 gost2814789_set_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
103 {
104 int len = 0;
105 unsigned char *buf = NULL;
106 unsigned char *p = NULL;
107 EVP_GOST2814789_CTX *c = ctx->cipher_data;
108 ASN1_OCTET_STRING *os = NULL;
109 GOST_CIPHER_PARAMS *gcp = GOST_CIPHER_PARAMS_new();
110
111 if (gcp == NULL) {
112 GOSTerror(ERR_R_MALLOC_FAILURE);
113 return 0;
114 }
115 if (ASN1_OCTET_STRING_set(gcp->iv, ctx->iv, ctx->cipher->iv_len) == 0) {
116 GOST_CIPHER_PARAMS_free(gcp);
117 GOSTerror(ERR_R_ASN1_LIB);
118 return 0;
119 }
120 ASN1_OBJECT_free(gcp->enc_param_set);
121 gcp->enc_param_set = OBJ_nid2obj(c->param_nid);
122
123 len = i2d_GOST_CIPHER_PARAMS(gcp, NULL);
124 p = buf = malloc(len);
125 if (buf == NULL) {
126 GOST_CIPHER_PARAMS_free(gcp);
127 GOSTerror(ERR_R_MALLOC_FAILURE);
128 return 0;
129 }
130 i2d_GOST_CIPHER_PARAMS(gcp, &p);
131 GOST_CIPHER_PARAMS_free(gcp);
132
133 os = ASN1_OCTET_STRING_new();
134 if (os == NULL) {
135 free(buf);
136 GOSTerror(ERR_R_MALLOC_FAILURE);
137 return 0;
138 }
139 if (ASN1_OCTET_STRING_set(os, buf, len) == 0) {
140 ASN1_OCTET_STRING_free(os);
141 free(buf);
142 GOSTerror(ERR_R_ASN1_LIB);
143 return 0;
144 }
145 free(buf);
146
147 ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os);
148 return 1;
149 }
150
151 int
gost2814789_get_asn1_params(EVP_CIPHER_CTX * ctx,ASN1_TYPE * params)152 gost2814789_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
153 {
154 int ret = -1;
155 int len;
156 GOST_CIPHER_PARAMS *gcp = NULL;
157 EVP_GOST2814789_CTX *c = ctx->cipher_data;
158 unsigned char *p;
159
160 if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE)
161 return ret;
162
163 p = params->value.sequence->data;
164
165 gcp = d2i_GOST_CIPHER_PARAMS(NULL, (const unsigned char **)&p,
166 params->value.sequence->length);
167
168 len = gcp->iv->length;
169 if (len != ctx->cipher->iv_len) {
170 GOST_CIPHER_PARAMS_free(gcp);
171 GOSTerror(GOST_R_INVALID_IV_LENGTH);
172 return -1;
173 }
174
175 if (!Gost2814789_set_sbox(&c->ks, OBJ_obj2nid(gcp->enc_param_set))) {
176 GOST_CIPHER_PARAMS_free(gcp);
177 return -1;
178 }
179 c->param_nid = OBJ_obj2nid(gcp->enc_param_set);
180
181 memcpy(ctx->oiv, gcp->iv->data, len);
182 memcpy(ctx->iv, gcp->iv->data, len);
183
184 GOST_CIPHER_PARAMS_free(gcp);
185
186 return 1;
187 }
188
189 static int
gost2814789_ecb_cipher(EVP_CIPHER_CTX * ctx,unsigned char * out,const unsigned char * in,size_t inl)190 gost2814789_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl)
191 {
192 size_t i, bl;
193
194 bl = ctx->cipher->block_size;
195
196 if (inl < bl)
197 return 1;
198
199 inl -= bl;
200
201 for (i = 0; i <= inl; i += bl)
202 Gost2814789_ecb_encrypt(in + i, out + i, &((EVP_GOST2814789_CTX *)ctx->cipher_data)->ks, ctx->encrypt);
203
204 return 1;
205 }
206
207 static int
gost2814789_cfb64_cipher(EVP_CIPHER_CTX * ctx,unsigned char * out,const unsigned char * in,size_t inl)208 gost2814789_cfb64_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl)
209 {
210 size_t chunk = EVP_MAXCHUNK;
211
212 if (inl < chunk)
213 chunk = inl;
214
215 while (inl && inl >= chunk) {
216 Gost2814789_cfb64_encrypt(in, out, chunk, &((EVP_GOST2814789_CTX *)ctx->cipher_data)->ks, ctx->iv, &ctx->num, ctx->encrypt);
217 inl -= chunk;
218 in += chunk;
219 out += chunk;
220 if (inl < chunk)
221 chunk = inl;
222 }
223
224 return 1;
225 }
226
227 static int
gost2814789_cnt_cipher(EVP_CIPHER_CTX * ctx,unsigned char * out,const unsigned char * in,size_t inl)228 gost2814789_cnt_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
229 const unsigned char *in, size_t inl)
230 {
231 EVP_GOST2814789_CTX *c = ctx->cipher_data;
232
233 while (inl >= EVP_MAXCHUNK) {
234 Gost2814789_cnt_encrypt(in, out, EVP_MAXCHUNK, &c->ks,
235 ctx->iv, ctx->buf, &ctx->num);
236 inl -= EVP_MAXCHUNK;
237 in += EVP_MAXCHUNK;
238 out += EVP_MAXCHUNK;
239 }
240
241 if (inl)
242 Gost2814789_cnt_encrypt(in, out, inl, &c->ks, ctx->iv, ctx->buf,
243 &ctx->num);
244 return 1;
245 }
246
247 /* gost89 is CFB-64 */
248 #define NID_gost89_cfb64 NID_id_Gost28147_89
249
250 static const EVP_CIPHER gost2814789_ecb = {
251 .nid = NID_gost89_ecb,
252 .block_size = 8,
253 .key_len = 32,
254 .iv_len = 0,
255 .flags = EVP_CIPH_NO_PADDING | EVP_CIPH_CTRL_INIT | EVP_CIPH_ECB_MODE,
256 .init = gost2814789_init_key,
257 .do_cipher = gost2814789_ecb_cipher,
258 .cleanup = NULL,
259 .ctx_size = sizeof(EVP_GOST2814789_CTX),
260 .set_asn1_parameters = gost2814789_set_asn1_params,
261 .get_asn1_parameters = gost2814789_get_asn1_params,
262 .ctrl = gost2814789_ctl,
263 .app_data = NULL,
264 };
265
266 const EVP_CIPHER *
EVP_gost2814789_ecb(void)267 EVP_gost2814789_ecb(void)
268 {
269 return &gost2814789_ecb;
270 }
271
272 static const EVP_CIPHER gost2814789_cfb64 = {
273 .nid = NID_gost89_cfb64,
274 .block_size = 1,
275 .key_len = 32,
276 .iv_len = 8,
277 .flags = EVP_CIPH_NO_PADDING | EVP_CIPH_CTRL_INIT | EVP_CIPH_CFB_MODE,
278 .init = gost2814789_init_key,
279 .do_cipher = gost2814789_cfb64_cipher,
280 .cleanup = NULL,
281 .ctx_size = sizeof(EVP_GOST2814789_CTX),
282 .set_asn1_parameters = gost2814789_set_asn1_params,
283 .get_asn1_parameters = gost2814789_get_asn1_params,
284 .ctrl = gost2814789_ctl,
285 .app_data = NULL,
286 };
287
288 const EVP_CIPHER *
EVP_gost2814789_cfb64(void)289 EVP_gost2814789_cfb64(void)
290 {
291 return &gost2814789_cfb64;
292 }
293
294 static const EVP_CIPHER gost2814789_cnt = {
295 .nid = NID_gost89_cnt,
296 .block_size = 1,
297 .key_len = 32,
298 .iv_len = 8,
299 .flags = EVP_CIPH_NO_PADDING | EVP_CIPH_CTRL_INIT | EVP_CIPH_OFB_MODE,
300 .init = gost2814789_init_key,
301 .do_cipher = gost2814789_cnt_cipher,
302 .cleanup = NULL,
303 .ctx_size = sizeof(EVP_GOST2814789_CTX),
304 .set_asn1_parameters = gost2814789_set_asn1_params,
305 .get_asn1_parameters = gost2814789_get_asn1_params,
306 .ctrl = gost2814789_ctl,
307 .app_data = NULL,
308 };
309
310 const EVP_CIPHER *
EVP_gost2814789_cnt(void)311 EVP_gost2814789_cnt(void)
312 {
313 return &gost2814789_cnt;
314 }
315 #endif
316