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
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
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
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
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
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
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
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 *
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 *
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 *
311 EVP_gost2814789_cnt(void)
312 {
313 	return &gost2814789_cnt;
314 }
315 #endif
316