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