4cf8a0ba8029a30629827b6c07406924b07c8e85
[openssl.git] / engines / ccgost / gost94_keyx.c
1 /**********************************************************************
2  *                             gost94_keyx.c                          *
3  *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4  *         This file is distributed under the same license as OpenSSL *
5  *                                                                    *
6  *     Implements generation and parsing of GOST_KEY_TRANSPORT for    *
7  *                      GOST R 34.10-94 algorithms                            *
8  *                                                                                                                                        *
9  *          Requires OpenSSL 0.9.9 for compilation                    *
10  **********************************************************************/
11 #include <string.h>
12 #include <openssl/dh.h>
13 #include <openssl/rand.h>
14 #include <openssl/evp.h>
15 #include <openssl/objects.h>
16
17 #include "gostkeyx.h"
18 #include "gost_asn1.h"
19 #include "gost89.h"
20 #include "gosthash.h"
21 #include "crypt.h"
22 #include "e_gost_err.h"
23 #include "pmeth.h"
24 #include "keywrap.h"
25 #include "tools.h"
26 /* Common functions for both 94 and 2001 key exchange schemes */
27 int decrypt_cryptocom_key(unsigned char *sess_key,int max_key_len,
28                 const unsigned char *crypted_key,int crypted_key_len, gost_ctx *ctx)
29 {
30         int i;
31         int j;
32         int blocks = crypted_key_len >>3;
33         unsigned char gamma[8];
34         if (max_key_len <crypted_key_len) {
35                 GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_NOT_ENOUGH_SPACE_FOR_KEY);
36                 return 0;
37         }       
38         if ((crypted_key_len & 7) !=0) 
39         {
40                 GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_INVALID_ENCRYPTED_KEY_SIZE);
41                 return 0;
42         }       
43         for (i=blocks-1;i>0;i--) 
44         {
45                 gostcrypt(ctx,crypted_key+(i-1)*8,gamma);
46                 for(j=0;j<8;j++) 
47                 {
48                         sess_key[i*8+j]=gamma[j]^crypted_key[i*8+j];
49                 }
50         }       
51         gostcrypt(ctx,sess_key+crypted_key_len-8,gamma);        
52         for(j=0;j<8;j++) 
53         {
54                 sess_key[j]=gamma[j]^crypted_key[j];
55         }
56         return 1;
57 }
58 int encrypt_cryptocom_key(const unsigned char *sess_key,int key_len,
59                 unsigned char *crypted_key, gost_ctx *ctx)
60 {
61         int i;
62         int j;
63         unsigned char gamma[8];
64         memcpy(gamma,sess_key+key_len-8,8);
65         for (i=0;i<key_len;i+=8)
66         {
67                 gostcrypt(ctx,gamma,gamma);
68                 for (j=0;j<8;j++)
69                         gamma[j]=crypted_key[i+j]=sess_key[i+j]^gamma[j];
70         }
71         return 1;
72 }
73 /* Implementation of the Diffi-Hellman key agreement scheme based on
74  * GOST-94 keys */
75
76 /* Computes Diffie-Hellman key and stores it into buffer in
77  * little-endian byte order as expected by both versions of GOST 94
78  * algorigthm
79  */
80 static int compute_pair_key_le(unsigned char *pair_key,BIGNUM *pub_key,DH *dh) 
81 {
82         unsigned char be_key[128];
83         int i,key_size;
84         key_size=DH_compute_key(be_key,pub_key,dh);
85         if (!key_size) return 0;
86         memset(pair_key,0,128);
87         for (i=0;i<key_size;i++) {
88                 pair_key[i]=be_key[key_size-1-i];
89         }
90         return key_size;        
91 }       
92 /*
93  * Computes 256 bit key exchange key for CryptoCom variation of GOST 94
94  * algorithm
95  */
96 static int make_gost_shared_key(DH *dh,EVP_PKEY *pubk,unsigned char *shared_key) 
97 {
98         unsigned char dh_key [128];
99         int i;
100         /* Compute key */
101         memset(dh_key,0,128);
102         if (!compute_pair_key_le(dh_key,((DSA *)EVP_PKEY_get0(pubk))->pub_key,dh)) return 0;    
103         /* Fold it down to 256 bit */
104         /* According to GOST  either 2^1020<p<2^1024 or 
105          * 2^509<p<2^512, so DH_size can be exactly 128 or exactly 64 only
106          */
107         
108         if (DH_size(dh)==128) 
109                 for (i=0;i<64;i++) {
110                         dh_key[i]^=dh_key[64+i];
111                 }       
112         for (i=0;i<32;i++) {
113                 shared_key[i]=dh_key[i]^dh_key[32+i];
114         }
115         return 1;
116 }
117
118 static DH *make_ephemeral_key(EVP_PKEY *pubk,BIGNUM *ephemeral_key)
119 {
120         DH *dh = DH_new();
121         dh->g = BN_dup(pubk->pkey.dsa->g);
122         dh->p = BN_dup(pubk->pkey.dsa->p);
123         dh->priv_key = BN_dup(ephemeral_key);
124         /* Generate ephemeral key pair */
125         if (!DH_generate_key(dh)) {
126                 DH_free(dh);
127                 return NULL;
128         }       
129         return dh;
130 }       
131 /*
132  * Computes 256 bit Key exchange key as specified in RFC 4357 
133  */
134 static int make_cp_exchange_key(DH *dh,EVP_PKEY *pubk, unsigned char *shared_key)
135 {
136         unsigned char dh_key [128];
137         gost_hash_ctx hash_ctx;
138         memset(dh_key,0,128);
139         if (!compute_pair_key_le(dh_key,((DSA *)(EVP_PKEY_get0(pubk)))->pub_key,dh)) return 0;
140         init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet);
141         start_hash(&hash_ctx);
142         hash_block(&hash_ctx,dh_key,128);
143         finish_hash(&hash_ctx,shared_key);
144         done_gost_hash_ctx(&hash_ctx);
145         return 1;
146 }       
147 /* EVP_PKEY_METHOD callback encrypt for
148  * GOST R 34.10-94 cryptopro modification
149  */
150
151 int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len ) 
152 {
153         GOST_KEY_TRANSPORT *gkt=NULL;
154         DH *dh = NULL;
155         unsigned char shared_key[32], ukm[8],crypted_key[44];
156         const struct gost_cipher_info *param=get_encryption_params(NULL);
157         EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx);
158         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
159         int size=-1;
160         gost_ctx cctx;
161
162
163         if (!(data->eph_seckey)) {
164                 GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
165                 GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT);
166                 return -1;
167         }       
168
169         dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey));
170         gost_init(&cctx,param->sblock); 
171         make_cp_exchange_key(dh,pubk,shared_key);
172         if (RAND_bytes(ukm,8)<=0) {
173                 GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
174                 GOST_R_RANDOM_GENERATOR_FAILURE);
175                 return -1;
176         }       
177         keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key);
178         gkt = GOST_KEY_TRANSPORT_new();
179         if (!gkt) {
180                 goto memerr;
181         }       
182         if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,
183                                                 ukm,8)) {
184                 goto memerr;
185         }       
186         if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) {
187                 goto memerr;
188         }
189         if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) {
190                 goto memerr;
191         }
192         if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) {
193                 GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
194                 goto err;
195         }       
196         ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
197         gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid);
198         *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out);
199         if (!size) {
200                 GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO);
201                 size=-1;
202         }
203         GOST_KEY_TRANSPORT_free(gkt);
204         DH_free(dh);
205         return 1;       
206 memerr:
207                 GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
208                                 GOST_R_MALLOC_FAILURE);
209 err:            
210                 GOST_KEY_TRANSPORT_free(gkt);
211                 DH_free(dh);
212                 return -1;
213 }
214 /* EVP_PKEY_METHOD callback encrypt for
215  * GOST R 34.10-94 cryptocom modification
216  */
217
218 int pkey_GOST94cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,  const unsigned char *   key,size_t key_len) 
219 {
220         EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx);
221         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
222         /* create DH structure filling parameters from passed pub_key */
223         DH *dh = NULL;
224         GOST_KEY_TRANSPORT *gkt = NULL;
225         gost_ctx cctx;
226         EVP_PKEY *newkey=NULL;
227         unsigned char shared_key[32],encrypted_key[32],hmac[4],
228                                   iv[8]={0,0,0,0,0,0,0,0};
229
230         if (! data->eph_seckey) {
231                 GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
232                 GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT);
233                 return -1;
234         }       
235         dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey));
236         if (!dh) goto err;
237         /* compute shared key */
238         if (!make_gost_shared_key(dh,pubk,shared_key)) 
239         {
240                 GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY);
241                 goto err;
242         }       
243         /* encrypt session key */
244         gost_init(&cctx, &GostR3411_94_CryptoProParamSet);
245         gost_key(&cctx,shared_key);
246         encrypt_cryptocom_key(key,key_len,encrypted_key,&cctx);
247         /* compute hmac of session key */
248         if (!gost_mac(&cctx,32,key,32,hmac)) 
249         {
250                 DH_free(dh);
251                 GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC);
252                 return -1;
253     }
254         gkt = GOST_KEY_TRANSPORT_new();
255         if (!gkt) 
256         {
257                 DH_free(dh);
258                 GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_NO_MEMORY);
259                 return -1;
260         }       
261         /* Store IV which is always zero in our case */
262         if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8))
263         {
264                 GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_IV);
265                 goto err;
266         }       
267         if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4)) 
268         {
269                 GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_MAC);
270                 goto err;
271         }       
272         if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32))
273         {       
274                 GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY);
275                 goto err;
276         }
277         if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) {
278                 GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
279                 goto err;
280         }       
281         ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
282         gkt->key_agreement_info->cipher = OBJ_nid2obj(NID_id_Gost28147_89_cc);
283         *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out);
284 err:
285         if (gkt) GOST_KEY_TRANSPORT_free(gkt);
286         if (dh) DH_free(dh);
287         if (newkey) EVP_PKEY_free(newkey);
288         return 1;
289 }       
290         
291 /* EVP_PLEY_METHOD callback decrypt for
292  * GOST R 34.10-94 cryptopro modification
293  */
294 int pkey_GOST94cp_decrypt (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len,const unsigned char *in, size_t in_len) {
295         DH *dh = DH_new();
296         const unsigned char *p = in;
297         GOST_KEY_TRANSPORT *gkt = NULL;
298         unsigned char wrappedKey[44];
299         unsigned char sharedKey[32];
300         gost_ctx cctx;
301         const struct gost_cipher_info *param=NULL;
302         EVP_PKEY *eph_key=NULL;
303         EVP_PKEY *priv= EVP_PKEY_CTX_get0_pkey(ctx); 
304         
305         if (!key) {
306                 *key_len = 32;
307                 return 1;
308         }       
309         
310         dh->g = BN_dup(priv->pkey.dsa->g);
311         dh->p = BN_dup(priv->pkey.dsa->p);
312         dh->priv_key = BN_dup(priv->pkey.dsa->priv_key);
313         gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
314                         in_len);
315         if (!gkt) {
316                 GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
317                 DH_free(dh);
318                 return 0;
319         }       
320         eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
321         param = get_encryption_params(gkt->key_agreement_info->cipher);
322         gost_init(&cctx,param->sblock); 
323         OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
324         memcpy(wrappedKey,gkt->key_agreement_info->eph_iv->data,8);
325         OPENSSL_assert(gkt->key_info->encrypted_key->length==32);
326         memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32);
327         OPENSSL_assert(gkt->key_info->imit->length==4);
328         memcpy(wrappedKey+40,gkt->key_info->imit->data,4);      
329         make_cp_exchange_key(dh,eph_key,sharedKey);
330         if (!keyUnwrapCryptoPro(&cctx,sharedKey,wrappedKey,key)) {
331                 GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,
332                                 GOST_R_ERROR_COMPUTING_SHARED_KEY);
333                 goto err;
334         }       
335                                 
336         EVP_PKEY_free(eph_key);
337         GOST_KEY_TRANSPORT_free(gkt);
338         DH_free(dh);
339         return 1;
340 err:
341         EVP_PKEY_free(eph_key);
342         GOST_KEY_TRANSPORT_free(gkt);
343         DH_free(dh);
344         return -1;
345         
346 }       
347 /* EVP_PKEY_METHOD callback decrypt for
348  * GOST R 34.10-94 cryptocom modification
349  */
350
351 int pkey_GOST94cc_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, const unsigned char *in, size_t in_len)
352 {
353         /* Form DH params from compute shared key */
354         GOST_KEY_TRANSPORT *gkt = NULL;
355         const unsigned char *p=in;
356         unsigned char shared_key[32];
357         unsigned char hmac[4],hmac_comp[4];
358         unsigned char iv[8];
359         int i;
360         gost_ctx ctx;
361         DH *dh = DH_new();
362         EVP_PKEY *eph_key;
363         EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
364         
365         if (!key) {
366                 *key_len = 32;
367                 return 1;
368         }
369         /* Construct DH structure from the our GOST private key */
370         dh->g = BN_dup(priv->pkey.dsa->g);
371         dh->p = BN_dup(priv->pkey.dsa->p);
372         dh->priv_key = BN_dup(priv->pkey.dsa->priv_key);
373         /* Parse passed octet string and find out public key, iv and HMAC*/
374         gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
375                         in_len);
376         if (!gkt) {
377                 GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
378                 DH_free(dh);
379                 return 0;
380         }       
381         eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
382         /* Initialization vector is really ignored here */
383         OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
384         memcpy(iv,gkt->key_agreement_info->eph_iv->data,8);
385         /* HMAC should be computed and checked */
386         OPENSSL_assert(gkt->key_info->imit->length==4);
387         memcpy(hmac,gkt->key_info->imit->data,4);       
388         /* Compute shared key */
389         i=make_gost_shared_key(dh,eph_key,shared_key);
390         EVP_PKEY_free(eph_key);
391         DH_free(dh);
392         if (!i) 
393         {
394                 GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY);
395                 GOST_KEY_TRANSPORT_free(gkt);
396                 return 0;
397         }
398         /* Decrypt session key */
399         gost_init(&ctx, &GostR3411_94_CryptoProParamSet);
400         gost_key(&ctx,shared_key);
401         
402         if (!decrypt_cryptocom_key(key,*key_len,gkt->key_info->encrypted_key->data, 
403                         gkt->key_info->encrypted_key->length, &ctx)) 
404         {
405                 GOST_KEY_TRANSPORT_free(gkt);
406                 return 0;
407         }
408         GOST_KEY_TRANSPORT_free(gkt);
409         /* check HMAC of session key*/
410         if (!gost_mac(&ctx,32,key,32,hmac_comp)) {
411                 GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_COMPUTING_MAC);
412                 return 0;
413     }
414                 /* HMAC of session key is not correct */
415     if (memcmp(hmac,hmac_comp,4)!=0) {
416                 GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH);
417                 return 0;
418         }       
419         return 1; 
420 }