updates.
[silc.git] / lib / silcske / silcske.c
1 /*
2
3   silcske.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "payload_internal.h"
24 #include "groups_internal.h"
25
26 /* Allocates new SKE object. */
27
28 SilcSKE silc_ske_alloc()
29 {
30   SilcSKE ske;
31
32   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
33
34   ske = silc_calloc(1, sizeof(*ske));
35   ske->status = SILC_SKE_STATUS_OK;
36
37   return ske;
38 }
39
40 /* Free's SKE object. */
41
42 void silc_ske_free(SilcSKE ske)
43 {
44   SILC_LOG_DEBUG(("Freeing Key Exchange object"));
45
46   if (ske) {
47     /* Free start payload */
48     if (ske->start_payload)
49       silc_ske_payload_start_free(ske->start_payload);
50
51     /* Free KE1 payload */
52     if (ske->ke1_payload)
53       silc_ske_payload_one_free(ske->ke1_payload);
54
55     /* Free KE2 payload */
56     if (ske->ke2_payload)
57       silc_ske_payload_two_free(ske->ke2_payload);
58
59     /* Free rest */
60     if (ske->prop) {
61       if (ske->prop->group)
62         silc_free(ske->prop->group);
63       if (ske->prop->pkcs)
64         silc_pkcs_free(ske->prop->pkcs);
65       if (ske->prop->cipher)
66         silc_cipher_free(ske->prop->cipher);
67       if (ske->prop->hash)
68         silc_hash_free(ske->prop->hash);
69       silc_free(ske->prop);
70     }
71     if (ske->start_payload_copy)
72       silc_buffer_free(ske->start_payload_copy);
73     if (ske->pk)
74       silc_free(ske->pk);
75     if (ske->x) {
76       silc_mp_clear(ske->x);
77       silc_free(ske->x);
78     }
79     if (ske->KEY) {
80       silc_mp_clear(ske->KEY);
81       silc_free(ske->KEY);
82     }
83     if (ske->hash)
84       silc_free(ske->hash);
85     silc_free(ske);
86   }
87 }
88
89 /* Starts the SILC Key Exchange protocol for initiator. The connection
90    to the remote end must be established before calling this function
91    and the connecting socket must be sent as argument. This function
92    creates the Key Exchange Start Paload which includes all our
93    configured security properties. This payload is then sent to the
94    remote end for further processing. This payload must be sent as
95    argument to the function, however, it must not be encoded
96    already, it is done by this function.
97
98    The packet sending is done by calling a callback function. Caller
99    must provide a routine to send the packet. */
100
101 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
102                                        SilcSocketConnection sock,
103                                        SilcSKEStartPayload *start_payload,
104                                        SilcSKESendPacketCb send_packet,
105                                        void *context)
106 {
107   SilcSKEStatus status = SILC_SKE_STATUS_OK;
108   SilcBuffer payload_buf;
109
110   SILC_LOG_DEBUG(("Start"));
111
112   ske->sock = sock;
113   ske->rng = rng;
114
115   /* Encode the payload */
116   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
117   if (status != SILC_SKE_STATUS_OK)
118     return status;
119
120   /* Take a copy of the payload buffer for future use. It is used to
121      compute the HASH value. */
122   ske->start_payload_copy = silc_buffer_copy(payload_buf);
123
124   /* Send the packet. */
125   if (send_packet)
126     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
127
128   silc_buffer_free(payload_buf);
129
130   return status;
131 }
132
133 /* Function called after ske_initiator_start fuction. This receives
134    the remote ends Key Exchange Start payload which includes the
135    security properties selected by the responder from our payload
136    sent in the silc_ske_initiator_start function. */
137
138 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
139                                          SilcBuffer start_payload,
140                                          SilcSKECb callback,
141                                          void *context)
142 {
143   SilcSKEStatus status = SILC_SKE_STATUS_OK;
144   SilcSKEStartPayload *payload;
145   SilcSKESecurityProperties prop;
146   SilcSKEDiffieHellmanGroup group;
147
148   SILC_LOG_DEBUG(("Start"));
149
150   /* Decode the payload */
151   status = silc_ske_payload_start_decode(ske, start_payload, &payload);
152   if (status != SILC_SKE_STATUS_OK) {
153     ske->status = status;
154     return status;
155   }
156
157   /* Take the selected security properties into use while doing
158      the key exchange. This is used only while doing the key 
159      exchange. The same data is returned to upper levels by calling
160      the callback function. */
161   ske->prop = prop = silc_calloc(1, sizeof(*prop));
162   prop->flags = payload->flags;
163   status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
164   if (status != SILC_SKE_STATUS_OK)
165     goto err;
166
167   prop->group = group;
168
169   if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
170     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
171     goto err;
172   }
173
174   if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
175     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
176     goto err;
177   }
178
179   if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
180     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
181     goto err;
182   }
183
184   ske->start_payload = payload;
185
186   /* Return the received payload by calling the callback function. */
187   if (callback)
188     (*callback)(ske, context);
189
190   return status;
191
192  err:
193   if (payload)
194     silc_ske_payload_start_free(payload);
195
196   silc_free(group);
197
198   if (prop->pkcs)
199     silc_pkcs_free(prop->pkcs);
200   if (prop->cipher)
201     silc_cipher_free(prop->cipher);
202   if (prop->hash)
203     silc_hash_free(prop->hash);
204   silc_free(prop);
205   ske->prop = NULL;
206
207   if (status == SILC_SKE_STATUS_OK)
208     return SILC_SKE_STATUS_ERROR;
209
210   ske->status = status;
211   return status;
212 }
213
214 /* This function creates random number x, such that 1 < x < q and 
215    computes e = g ^ x mod p and sends the result to the remote end in 
216    Key Exchange 1 Payload. */
217
218 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
219                                          SilcPublicKey public_key,
220                                          SilcSKESendPacketCb send_packet,
221                                          void *context)
222 {
223   SilcSKEStatus status = SILC_SKE_STATUS_OK;
224   SilcBuffer payload_buf;
225   SilcInt *x, e;
226   SilcSKEOnePayload *payload;
227   unsigned int pk_len;
228
229   SILC_LOG_DEBUG(("Start"));
230
231   /* Create the random number x, 1 < x < q. */
232   x = silc_calloc(1, sizeof(*x));
233   silc_mp_init(x);
234   status = 
235     silc_ske_create_rnd(ske, ske->prop->group->group_order,
236                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
237                         x);
238   if (status != SILC_SKE_STATUS_OK) {
239     silc_mp_clear(x);
240     silc_free(x);
241     ske->status = status;
242     return status;
243   }
244
245   SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
246
247   /* Do the Diffie Hellman computation, e = g ^ x mod p */
248   silc_mp_init(&e);
249   silc_mp_powm(&e, &ske->prop->group->generator, x, 
250                &ske->prop->group->group);
251   
252   /* Encode the result to Key Exchange 1 Payload. */
253   payload = silc_calloc(1, sizeof(*payload));
254   payload->e = e;
255   payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
256   if (!payload->pk_data) {
257     silc_mp_clear(x);
258     silc_free(x);
259     silc_mp_clear(&e);
260     silc_free(payload);
261     ske->status = SILC_SKE_STATUS_OK;
262     return ske->status;
263   }
264   payload->pk_len = pk_len;
265   payload->pk_type = SILC_SKE_PK_TYPE_SILC;
266   status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
267   if (status != SILC_SKE_STATUS_OK) {
268     silc_mp_clear(x);
269     silc_free(x);
270     silc_mp_clear(&e);
271     silc_free(payload->pk_data);
272     silc_free(payload);
273     ske->status = status;
274     return status;
275   }
276
277   ske->ke1_payload = payload;
278   ske->x = x;
279
280   /* Send the packet. */
281   if (send_packet)
282     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
283
284   silc_buffer_free(payload_buf);
285
286   return status;
287 }
288
289 /* Receives Key Exchange 2 Payload from responder consisting responders
290    public key, f, and signature. This function verifies the public key,
291    computes the secret shared key and verifies the signature. */
292
293 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
294                                         SilcBuffer ke2_payload,
295                                         SilcSKEVerifyCb verify_key,
296                                         void *verify_context,
297                                         SilcSKECb callback,
298                                         void *context)
299 {
300   SilcSKEStatus status = SILC_SKE_STATUS_OK;
301   SilcSKETwoPayload *payload;
302   SilcPublicKey public_key = NULL;
303   SilcInt *KEY;
304   unsigned char hash[32];
305   unsigned int hash_len;
306
307   SILC_LOG_DEBUG(("Start"));
308
309   /* Decode the payload */
310   status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
311   if (status != SILC_SKE_STATUS_OK) {
312     ske->status = status;
313     return status;
314   }
315   ske->ke2_payload = payload;
316
317   SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
318
319   /* Compute the shared secret key */
320   KEY = silc_calloc(1, sizeof(*KEY));
321   silc_mp_init(KEY);
322   silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group);
323   ske->KEY = KEY;
324
325   SILC_LOG_DEBUG(("Verifying public key"));
326
327   if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, 
328                                    &public_key)) {
329     status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
330     goto err;
331   }
332
333   if (verify_key) {
334     status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
335                            payload->pk_type, verify_context);
336     if (status != SILC_SKE_STATUS_OK)
337       goto err;
338   }  
339
340   SILC_LOG_DEBUG(("Public key is authentic"));
341
342   /* Compute the hash value */
343   status = silc_ske_make_hash(ske, hash, &hash_len);
344   if (status != SILC_SKE_STATUS_OK)
345     goto err;
346
347   ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
348   memcpy(ske->hash, hash, hash_len);
349   ske->hash_len = hash_len;
350
351   SILC_LOG_DEBUG(("Verifying signature"));
352
353   /* Verify signature */
354   silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, 
355                                 public_key->pk_len);
356   if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
357                                     payload->sign_data, payload->sign_len,
358                                     hash, hash_len) == FALSE) {
359
360     SILC_LOG_DEBUG(("Signature don't match"));
361
362     status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
363     goto err;
364   }
365
366   SILC_LOG_DEBUG(("Signature is Ok"));
367
368   silc_pkcs_public_key_free(public_key);
369   memset(hash, 'F', hash_len);
370
371   /* Call the callback. */
372   if (callback)
373     (*callback)(ske, context);
374
375   return status;
376
377  err:
378   memset(hash, 'F', sizeof(hash));
379   silc_ske_payload_two_free(payload);
380   ske->ke2_payload = NULL;
381
382   silc_mp_clear(ske->KEY);
383   silc_free(ske->KEY);
384   ske->KEY = NULL;
385
386   if (public_key)
387     silc_pkcs_public_key_free(public_key);
388
389   if (ske->hash) {
390     memset(ske->hash, 'F', hash_len);
391     silc_free(ske->hash);
392     ske->hash = NULL;
393   }
394
395   if (status == SILC_SKE_STATUS_OK)
396     return SILC_SKE_STATUS_ERROR;
397
398   ske->status = status;
399   return status;
400 }
401
402 /* Starts Key Exchange protocol for responder. Responder receives
403    Key Exchange Start Payload from initiator consisting of all the
404    security properties the initiator supports. This function decodes
405    the payload and parses the payload further and selects the right 
406    security properties. */
407
408 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
409                                        SilcSocketConnection sock,
410                                        char *version,
411                                        SilcBuffer start_payload,
412                                        SilcSKECb callback,
413                                        void *context)
414 {
415   SilcSKEStatus status = SILC_SKE_STATUS_OK;
416   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
417
418   SILC_LOG_DEBUG(("Start"));
419
420   ske->sock = sock;
421   ske->rng = rng;
422
423   /* Decode the payload */
424   status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
425   if (status != SILC_SKE_STATUS_OK) {
426     ske->status = status;
427     return status;
428   }
429
430   /* Take a copy of the payload buffer for future use. It is used to
431      compute the HASH value. */
432   ske->start_payload_copy = silc_buffer_copy(start_payload);
433
434   /* Parse and select the security properties from the payload */
435   payload = silc_calloc(1, sizeof(*payload));
436   status = silc_ske_select_security_properties(ske, version,
437                                                payload, remote_payload);
438   if (status != SILC_SKE_STATUS_OK)
439     goto err;
440
441   ske->start_payload = payload;
442
443   /* Call the callback function. */
444   if (callback)
445     (*callback)(ske, context);
446
447   return status;
448
449  err:
450   if (remote_payload)
451     silc_ske_payload_start_free(remote_payload);
452   if (payload)
453     silc_free(payload);
454
455   if (status == SILC_SKE_STATUS_OK)
456     return SILC_SKE_STATUS_ERROR;
457
458   ske->status = status;
459   return status;
460 }
461
462 /* The selected security properties from the initiator payload is now 
463    encoded into Key Exchange Start Payload and sent to the initiator. */
464
465 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
466                                          SilcSKEStartPayload *start_payload,
467                                          SilcSKESendPacketCb send_packet,
468                                          void *context)
469 {
470   SilcSKEStatus status = SILC_SKE_STATUS_OK;
471   SilcBuffer payload_buf;
472   SilcSKESecurityProperties prop;
473   SilcSKEDiffieHellmanGroup group = NULL;
474
475   SILC_LOG_DEBUG(("Start"));
476
477   /* Allocate security properties from the payload. These are allocated
478      only for this negotiation and will be free'd after KE is over. */
479   ske->prop = prop = silc_calloc(1, sizeof(*prop));
480   prop->flags = start_payload->flags;
481   status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
482   if (status != SILC_SKE_STATUS_OK)
483     goto err;
484
485   prop->group = group;
486
487   if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
488                       &prop->pkcs) == FALSE) {
489     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
490     goto err;
491   }
492
493   if (silc_cipher_alloc(start_payload->enc_alg_list, 
494                         &prop->cipher) == FALSE) {
495     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
496     goto err;
497   }
498
499   if (silc_hash_alloc(start_payload->hash_alg_list,
500                       &prop->hash) == FALSE) {
501     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
502     goto err;
503   }
504
505   /* Encode the payload */
506   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
507   if (status != SILC_SKE_STATUS_OK)
508     goto err;
509
510   /* Send the packet. */
511   if (send_packet)
512     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
513
514   silc_buffer_free(payload_buf);
515
516   return status;
517
518  err:
519   if (group)
520     silc_free(group);
521
522   if (prop->pkcs)
523     silc_pkcs_free(prop->pkcs);
524   if (prop->cipher)
525     silc_cipher_free(prop->cipher);
526   if (prop->hash)
527     silc_hash_free(prop->hash);
528   silc_free(prop);
529   ske->prop = NULL;
530
531   if (status == SILC_SKE_STATUS_OK)
532     return SILC_SKE_STATUS_ERROR;
533
534   ske->status = status;
535   return status;
536 }
537
538 /* This function receives the Key Exchange 1 Payload from the initiator.
539    After processing the payload this then selects random number x,
540    such that 1 < x < q and computes f = g ^ x mod p. This then puts
541    the result f to a Key Exchange 2 Payload which is later processed
542    in ske_responder_finish function. The callback function should
543    not touch the payload (it should merely call the ske_responder_finish
544    function). */
545
546 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
547                                          SilcBuffer ke1_payload,
548                                          SilcSKECb callback,
549                                          void *context)
550 {
551   SilcSKEStatus status = SILC_SKE_STATUS_OK;
552   SilcSKEOnePayload *one_payload;
553   SilcSKETwoPayload *two_payload;
554   SilcInt *x, f;
555
556   SILC_LOG_DEBUG(("Start"));
557
558   /* Decode Key Exchange 1 Payload */
559   status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
560   if (status != SILC_SKE_STATUS_OK) {
561     ske->status = status;
562     return status;
563   }
564
565   /* Create the random number x, 1 < x < q. */
566   x = silc_calloc(1, sizeof(*x));
567   silc_mp_init(x);
568   status = 
569     silc_ske_create_rnd(ske, ske->prop->group->group_order,
570                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
571                         x);
572   if (status != SILC_SKE_STATUS_OK) {
573     silc_mp_clear(x);
574     silc_free(x);
575     return status;
576   }
577
578   SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
579
580   /* Do the Diffie Hellman computation, f = g ^ x mod p */
581   silc_mp_init(&f);
582   silc_mp_powm(&f, &ske->prop->group->generator, x, 
583                &ske->prop->group->group);
584   
585   /* Save the results for later processing */
586   two_payload = silc_calloc(1, sizeof(*two_payload));
587   two_payload->f = f;
588   ske->x = x;
589   ske->ke1_payload = one_payload;
590   ske->ke2_payload = two_payload;
591
592   /* Call the callback. */
593   if (callback)
594     (*callback)(ske, context);
595
596   return status;
597 }
598
599 /* This function computes the secret shared key KEY = e ^ x mod p, and, 
600    a hash value to be signed and sent to the other end. This then
601    encodes Key Exchange 2 Payload and sends it to the other end. */
602
603 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
604                                         SilcPublicKey public_key,
605                                         SilcPrivateKey private_key,
606                                         SilcSKEPKType pk_type,
607                                         SilcSKESendPacketCb send_packet,
608                                         void *context)
609 {
610   SilcSKEStatus status = SILC_SKE_STATUS_OK;
611   SilcBuffer payload_buf;
612   SilcInt *KEY;
613   unsigned char hash[32], sign[256], *pk;
614   unsigned int hash_len, sign_len, pk_len;
615
616   SILC_LOG_DEBUG(("Start"));
617
618   if (!public_key || !private_key) {
619     status = SILC_SKE_STATUS_ERROR;
620     goto err;
621   }
622
623   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
624
625   /* Compute the shared secret key */
626   KEY = silc_calloc(1, sizeof(*KEY));
627   silc_mp_init(KEY);
628   silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x, 
629                &ske->prop->group->group);
630   ske->KEY = KEY;
631
632   SILC_LOG_DEBUG(("Getting public key"));
633
634   /* Get the public key */
635   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
636   if (!pk) {
637     status = SILC_SKE_STATUS_ERROR;
638     goto err;
639   }
640   ske->ke2_payload->pk_data = pk;
641   ske->ke2_payload->pk_len = pk_len;
642   ske->ke2_payload->pk_type = pk_type;
643
644   SILC_LOG_DEBUG(("Computing HASH value"));
645
646   /* Compute the hash value */
647   memset(hash, 0, sizeof(hash));
648   status = silc_ske_make_hash(ske, hash, &hash_len);
649   if (status != SILC_SKE_STATUS_OK)
650     goto err;
651
652   ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
653   memcpy(ske->hash, hash, hash_len);
654   ske->hash_len = hash_len;
655
656   SILC_LOG_DEBUG(("Signing HASH value"));
657
658   /* Sign the hash value */
659   silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
660                                  private_key->prv_len);
661   ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
662                               hash, hash_len,
663                               sign, &sign_len);
664   ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
665   memcpy(ske->ke2_payload->sign_data, sign, sign_len);
666   memset(sign, 0, sizeof(sign));
667   ske->ke2_payload->sign_len = sign_len;
668
669   /* Encode the Key Exchange 2 Payload */
670   status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
671                                        &payload_buf);
672   if (status != SILC_SKE_STATUS_OK)
673     goto err;
674
675   /* Send the packet. */
676   if (send_packet)
677     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
678
679   silc_buffer_free(payload_buf);
680
681   return status;
682
683  err:
684   silc_mp_clear(ske->KEY);
685   silc_free(ske->KEY);
686   ske->KEY = NULL;
687   silc_ske_payload_two_free(ske->ke2_payload);
688
689   if (status == SILC_SKE_STATUS_OK)
690     return SILC_SKE_STATUS_ERROR;
691
692   ske->status = status;
693   return status;
694 }
695
696 /* The Key Exchange protocol is ended by calling this function. This
697    must not be called until the keys are processed like the protocol
698    defines. This function is for both initiator and responder. */
699
700 SilcSKEStatus silc_ske_end(SilcSKE ske,
701                            SilcSKESendPacketCb send_packet,
702                            void *context)
703 {
704   SilcBuffer packet;
705
706   SILC_LOG_DEBUG(("Start"));
707
708   packet = silc_buffer_alloc(4);
709   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
710   silc_buffer_format(packet,
711                      SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
712                      SILC_STR_END);
713
714   if (send_packet)
715     (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
716
717   silc_buffer_free(packet);
718
719   return SILC_SKE_STATUS_OK;
720 }
721
722 /* Aborts the Key Exchange protocol. This is called if error occurs
723    while performing the protocol. The status argument is the error
724    status and it is sent to the remote end. */
725
726 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
727                              SilcSKESendPacketCb send_packet,
728                              void *context)
729 {
730   SilcBuffer packet;
731
732   SILC_LOG_DEBUG(("Start"));
733
734   packet = silc_buffer_alloc(4);
735   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
736   silc_buffer_format(packet,
737                      SILC_STR_UI_SHORT(status),
738                      SILC_STR_END);
739
740   if (send_packet)
741     (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
742
743   silc_buffer_free(packet);
744
745   return SILC_SKE_STATUS_OK;
746 }
747
748 /* Assembles security properties to Key Exchange Start Payload to be
749    sent to the remote end. This checks system wide (SILC system, that is)
750    settings and chooses from those. However, if other properties
751    should be used this function is easy to replace by another function,
752    as, this function is called by the caller of the protocol and not
753    by the protocol itself. */
754
755 SilcSKEStatus 
756 silc_ske_assemble_security_properties(SilcSKE ske,
757                                       unsigned char flags,
758                                       char *version,
759                                       SilcSKEStartPayload **return_payload)
760 {
761   SilcSKEStartPayload *rp;
762   int i;
763
764   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
765
766   rp = silc_calloc(1, sizeof(*rp));
767
768   /* Set flags */
769   rp->flags = flags;
770
771   /* Set random cookie */
772   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
773   for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
774     rp->cookie[i] = silc_rng_get_byte(ske->rng);
775   rp->cookie_len = SILC_SKE_COOKIE_LEN;
776
777   /* Put version */
778   rp->version = strdup(version);
779   rp->version_len = strlen(version);
780
781   /* Get supported Key Exhange groups */
782   rp->ke_grp_list = silc_ske_get_supported_groups();
783   rp->ke_grp_len = strlen(rp->ke_grp_list);
784
785   /* Get supported PKCS algorithms */
786   rp->pkcs_alg_list = silc_pkcs_get_supported();
787   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
788
789   /* Get supported encryption algorithms */
790   rp->enc_alg_list = silc_cipher_get_supported();
791   rp->enc_alg_len = strlen(rp->enc_alg_list);
792
793   /* Get supported hash algorithms */
794   rp->hash_alg_list = silc_hash_get_supported();
795   rp->hash_alg_len = strlen(rp->hash_alg_list);
796
797   /* XXX */
798   /* Get supported compression algorithms */
799   rp->comp_alg_list = "";
800   rp->comp_alg_len = 0;
801
802   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
803     2 + rp->version_len +
804     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
805     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
806     2 + rp->comp_alg_len;
807
808   *return_payload = rp;
809
810   return SILC_SKE_STATUS_OK;
811 }
812
813 /* Selects the supported security properties from the remote end's Key 
814    Exchange Start Payload. */
815
816 SilcSKEStatus 
817 silc_ske_select_security_properties(SilcSKE ske,
818                                     char *version,
819                                     SilcSKEStartPayload *payload,
820                                     SilcSKEStartPayload *remote_payload)
821 {
822   SilcSKEStatus status;
823   SilcSKEStartPayload *rp;
824   char *cp;
825   int len;
826
827   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
828
829   rp = remote_payload;
830
831   /* Check version string */
832   status = silc_ske_check_version(ske, rp->version, rp->version_len);
833   if (status != SILC_SKE_STATUS_OK) {
834     ske->status = status;
835     return status;
836   }
837
838   /* Flags are returned unchanged. */
839   payload->flags = rp->flags;
840
841   /* Take cookie */
842   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
843   payload->cookie_len = SILC_SKE_COOKIE_LEN;
844   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
845
846   /* Put our version to our reply */
847   payload->version = strdup(version);
848   payload->version_len = strlen(version);
849
850   /* Get supported Key Exchange groups */
851   cp = rp->ke_grp_list;
852   if (cp && strchr(cp, ',')) {
853     while(cp) {
854       char *item;
855
856       len = strcspn(cp, ",");
857       item = silc_calloc(len + 1, sizeof(char));
858       memcpy(item, cp, len);
859
860       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
861
862       if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
863         SILC_LOG_DEBUG(("Found KE group `%s'", item));
864
865         payload->ke_grp_len = len;
866         payload->ke_grp_list = item;
867         break;
868       }
869
870       cp += len;
871       if (strlen(cp) == 0)
872         cp = NULL;
873       else
874         cp++;
875
876       if (item)
877         silc_free(item);
878     }
879
880     if (!payload->ke_grp_len && !payload->ke_grp_list) {
881       SILC_LOG_DEBUG(("Could not find supported KE group"));
882       silc_free(payload);
883       return SILC_SKE_STATUS_UNKNOWN_GROUP;
884     }
885   } else {
886
887     if (!rp->ke_grp_len) {
888       SILC_LOG_DEBUG(("KE group not defined in payload"));
889       silc_free(payload);
890       return SILC_SKE_STATUS_BAD_PAYLOAD;
891     }
892
893     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
894     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
895
896     payload->ke_grp_len = rp->ke_grp_len;
897     payload->ke_grp_list = strdup(rp->ke_grp_list);
898   }
899
900   /* Get supported PKCS algorithms */
901   cp = rp->pkcs_alg_list;
902   if (cp && strchr(cp, ',')) {
903     while(cp) {
904       char *item;
905
906       len = strcspn(cp, ",");
907       item = silc_calloc(len + 1, sizeof(char));
908       memcpy(item, cp, len);
909
910       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
911
912       if (silc_pkcs_is_supported(item) == TRUE) {
913         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
914
915         payload->pkcs_alg_len = len;
916         payload->pkcs_alg_list = item;
917         break;
918       }
919
920       cp += len;
921       if (strlen(cp) == 0)
922         cp = NULL;
923       else
924         cp++;
925
926       if (item)
927         silc_free(item);
928     }
929
930     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
931       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
932       silc_free(payload->ke_grp_list);
933       silc_free(payload);
934       return SILC_SKE_STATUS_UNKNOWN_PKCS;
935     }
936   } else {
937
938     if (!rp->pkcs_alg_len) {
939       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
940       silc_free(payload->ke_grp_list);
941       silc_free(payload);
942       return SILC_SKE_STATUS_BAD_PAYLOAD;
943     }
944
945     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
946     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
947
948     payload->pkcs_alg_len = rp->pkcs_alg_len;
949     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
950   }
951
952   /* Get supported encryption algorithms */
953   cp = rp->enc_alg_list;
954   if (cp && strchr(cp, ',')) {
955     while(cp) {
956       char *item;
957
958       len = strcspn(cp, ",");
959       item = silc_calloc(len + 1, sizeof(char));
960       memcpy(item, cp, len);
961
962       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
963
964       if (silc_cipher_is_supported(item) == TRUE) {
965         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
966
967         payload->enc_alg_len = len;
968         payload->enc_alg_list = item;
969         break;
970       }
971
972       cp += len;
973       if (strlen(cp) == 0)
974         cp = NULL;
975       else
976         cp++;
977
978       if (item)
979         silc_free(item);
980     }
981
982     if (!payload->enc_alg_len && !payload->enc_alg_list) {
983       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
984       silc_free(payload->ke_grp_list);
985       silc_free(payload->pkcs_alg_list);
986       silc_free(payload);
987       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
988     }
989   } else {
990
991     if (!rp->enc_alg_len) {
992       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
993       silc_free(payload->ke_grp_list);
994       silc_free(payload->pkcs_alg_list);
995       silc_free(payload);
996       return SILC_SKE_STATUS_BAD_PAYLOAD;
997     }
998
999     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1000                     rp->enc_alg_list));
1001
1002     payload->enc_alg_len = rp->enc_alg_len;
1003     payload->enc_alg_list = strdup(rp->enc_alg_list);
1004   }
1005
1006   /* Get supported hash algorithms */
1007   cp = rp->hash_alg_list;
1008   if (cp && strchr(cp, ',')) {
1009     while(cp) {
1010       char *item;
1011
1012       len = strcspn(cp, ",");
1013       item = silc_calloc(len + 1, sizeof(char));
1014       memcpy(item, cp, len);
1015
1016       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1017
1018       if (silc_hash_is_supported(item) == TRUE) {
1019         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1020
1021         payload->hash_alg_len = len;
1022         payload->hash_alg_list = item;
1023         break;
1024       }
1025
1026       cp += len;
1027       if (strlen(cp) == 0)
1028         cp = NULL;
1029       else
1030         cp++;
1031
1032       if (item)
1033         silc_free(item);
1034     }
1035
1036     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1037       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1038       silc_free(payload->ke_grp_list);
1039       silc_free(payload->pkcs_alg_list);
1040       silc_free(payload->enc_alg_list);
1041       silc_free(payload);
1042       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1043     }
1044   } else {
1045
1046     if (!rp->hash_alg_len) {
1047       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1048       silc_free(payload->ke_grp_list);
1049       silc_free(payload->pkcs_alg_list);
1050       silc_free(payload->enc_alg_list);
1051       silc_free(payload);
1052       return SILC_SKE_STATUS_BAD_PAYLOAD;
1053     }
1054
1055     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1056                     rp->hash_alg_list));
1057
1058     payload->hash_alg_len = rp->hash_alg_len;
1059     payload->hash_alg_list = strdup(rp->hash_alg_list);
1060   }
1061
1062 #if 0
1063   /* Get supported compression algorithms */
1064   cp = rp->hash_alg_list;
1065   if (cp && strchr(cp, ',')) {
1066     while(cp) {
1067       char *item;
1068
1069       len = strcspn(cp, ",");
1070       item = silc_calloc(len + 1, sizeof(char));
1071       memcpy(item, cp, len);
1072
1073       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1074
1075       if (silc_hash_is_supported(item) == TRUE) {
1076         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1077
1078         payload->hash_alg_len = len;
1079         payload->hash_alg_list = item;
1080         break;
1081       }
1082
1083       cp += len;
1084       if (strlen(cp) == 0)
1085         cp = NULL;
1086       else
1087         cp++;
1088
1089       if (item)
1090         silc_free(item);
1091     }
1092
1093     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1094       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1095       silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1096       silc_free(payload->ke_grp_list);
1097       silc_free(payload->pkcs_alg_list);
1098       silc_free(payload->enc_alg_list);
1099       silc_free(payload);
1100       return;
1101     }
1102   } else {
1103
1104   }
1105 #endif
1106
1107   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1108     2 + payload->version_len + 
1109     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1110     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1111     2 + payload->comp_alg_len;
1112
1113   return SILC_SKE_STATUS_OK;
1114 }
1115
1116 /* Creates random number such that 1 < rnd < n and at most length
1117    of len bits. The rnd sent as argument must be initialized. */
1118
1119 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
1120                                   unsigned int len, 
1121                                   SilcInt *rnd)
1122 {
1123   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1124   unsigned char *string;
1125
1126   SILC_LOG_DEBUG(("Creating random number"));
1127
1128   /* Get the random number as string */
1129   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1130   if (!string)
1131     return SILC_SKE_STATUS_ERROR;
1132
1133   /* Decode the string into a MP integer */
1134   silc_mp_bin2mp(string, (len / 8), rnd);
1135   silc_mp_mod_2exp(rnd, rnd, len);
1136
1137   /* Checks */
1138   if (silc_mp_cmp_ui(rnd, 1) < 0)
1139     status = SILC_SKE_STATUS_ERROR;
1140
1141   if (silc_mp_cmp(rnd, &n) >= 0)
1142     status = SILC_SKE_STATUS_ERROR;
1143
1144   memset(string, 'F', (len / 8));
1145   silc_free(string);
1146
1147   return status;
1148 }
1149
1150 /* Creates a hash value HASH as defined in the SKE protocol. */
1151
1152 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1153                                  unsigned char *return_hash,
1154                                  unsigned int *return_hash_len)
1155 {
1156   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1157   SilcBuffer buf;
1158   unsigned char *e, *f, *KEY;
1159   unsigned int e_len, f_len, KEY_len;
1160   int ret;
1161
1162   SILC_LOG_DEBUG(("Start"));
1163
1164   e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len);
1165   f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len);
1166   KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1167
1168   buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1169                           ske->pk_len + e_len + f_len + KEY_len);
1170   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1171
1172   /* Format the buffer used to compute the hash value */
1173   ret = silc_buffer_format(buf,
1174                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1175                                                 ske->start_payload_copy->len),
1176                            SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1177                            SILC_STR_UI_XNSTRING(e, e_len),
1178                            SILC_STR_UI_XNSTRING(f, f_len),
1179                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
1180                            SILC_STR_END);
1181   if (ret == -1) {
1182     silc_buffer_free(buf);
1183     memset(e, 0, e_len);
1184     memset(f, 0, f_len);
1185     memset(KEY, 0, KEY_len);
1186     silc_free(e);
1187     silc_free(f);
1188     silc_free(KEY);
1189     return SILC_SKE_STATUS_ERROR;
1190   }
1191
1192   /* Make the hash */
1193   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1194   *return_hash_len = ske->prop->hash->hash->hash_len;
1195
1196   SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1197
1198   silc_buffer_free(buf);
1199   memset(e, 0, e_len);
1200   memset(f, 0, f_len);
1201   memset(KEY, 0, KEY_len);
1202   silc_free(e);
1203   silc_free(f);
1204   silc_free(KEY);
1205
1206   return status;
1207 }
1208
1209 /* Processes negotiated key material as protocol specifies. This returns
1210    the actual keys to be used in the SILC. */
1211
1212 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1213                                             unsigned int req_iv_len,
1214                                             unsigned int req_enc_key_len,
1215                                             unsigned int req_hmac_key_len,
1216                                             SilcSKEKeyMaterial *key)
1217 {
1218   int klen;
1219   SilcBuffer buf;
1220   unsigned char *tmpbuf;
1221   unsigned char hash[32];
1222   unsigned int hash_len = ske->prop->hash->hash->hash_len;
1223   unsigned int enc_key_len = req_enc_key_len / 8;
1224   int ret;
1225
1226   SILC_LOG_DEBUG(("Start"));
1227
1228   /* Encode KEY to binary data */
1229   tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1230
1231   buf = silc_buffer_alloc(1 + klen + hash_len);
1232   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1233   ret = silc_buffer_format(buf,
1234                            SILC_STR_UI_CHAR(0),
1235                            SILC_STR_UI_XNSTRING(tmpbuf, klen),
1236                            SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1237                            SILC_STR_END);
1238   if (ret == -1) {
1239     memset(tmpbuf, 0, klen);
1240     silc_free(tmpbuf);
1241     silc_buffer_free(buf);
1242     return SILC_SKE_STATUS_ERROR;
1243   }
1244
1245   /* Take IVs */
1246   memset(hash, 0, sizeof(hash));
1247   buf->data[0] = 0;
1248   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1249   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1250   memcpy(key->send_iv, hash, req_iv_len);
1251   memset(hash, 0, sizeof(hash));
1252   buf->data[0] = 1;
1253   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1254   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1255   memcpy(key->receive_iv, hash, req_iv_len);
1256   key->iv_len = req_iv_len;
1257
1258   /* Take the encryption keys. If requested key size is more than
1259      the size of hash length we will distribute more key material
1260      as protocol defines. */
1261   buf->data[0] = 2;
1262   if (enc_key_len > hash_len) {
1263     SilcBuffer dist;
1264     unsigned char k1[32], k2[32], k3[32];
1265     unsigned char *dtmp;
1266     
1267     /* XXX */
1268     if (enc_key_len > (3 * hash_len))
1269       return SILC_SKE_STATUS_ERROR;
1270     
1271     memset(k1, 0, sizeof(k1));
1272     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1273     
1274     /* XXX */
1275     dist = silc_buffer_alloc(hash_len * 3);
1276     
1277     silc_buffer_pull_tail(dist, klen + hash_len);
1278     silc_buffer_format(dist,
1279                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1280                        SILC_STR_UI_XNSTRING(k1, hash_len),
1281                        SILC_STR_END);
1282     
1283     memset(k2, 0, sizeof(k2));
1284     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1285     
1286     silc_buffer_pull(dist, klen + hash_len);
1287     silc_buffer_format(dist,
1288                        SILC_STR_UI_XNSTRING(k2, hash_len),
1289                        SILC_STR_END);
1290     silc_buffer_push(dist, klen + hash_len);
1291     
1292     memset(k3, 0, sizeof(k3));
1293     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1294     
1295     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1296     memcpy(dtmp, k1, hash_len);
1297     memcpy(dtmp + hash_len, k2, hash_len);
1298     memcpy(dtmp + hash_len, k3, hash_len);
1299
1300     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1301     memcpy(key->send_enc_key, dtmp, enc_key_len);
1302     key->enc_key_len = req_enc_key_len;
1303
1304     memset(dtmp, 0, (3 * hash_len));
1305     memset(k1, 0, sizeof(k1));
1306     memset(k2, 0, sizeof(k2));
1307     memset(k3, 0, sizeof(k3));
1308     silc_free(dtmp);
1309     silc_buffer_free(dist);
1310   } else {
1311     /* Take normal hash as key */
1312     memset(hash, 0, sizeof(hash));
1313     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1314     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1315     memcpy(key->send_enc_key, hash, enc_key_len);
1316     key->enc_key_len = req_enc_key_len;
1317   }
1318
1319   buf->data[0] = 3;
1320   if (enc_key_len > hash_len) {
1321     SilcBuffer dist;
1322     unsigned char k1[32], k2[32], k3[32];
1323     unsigned char *dtmp;
1324     
1325     /* XXX */
1326     if (enc_key_len > (3 * hash_len))
1327       return SILC_SKE_STATUS_ERROR;
1328     
1329     memset(k1, 0, sizeof(k1));
1330     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1331     
1332     /* XXX */
1333     dist = silc_buffer_alloc(hash_len * 3);
1334     
1335     silc_buffer_pull_tail(dist, klen + hash_len);
1336     silc_buffer_format(dist,
1337                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1338                        SILC_STR_UI_XNSTRING(k1, hash_len),
1339                        SILC_STR_END);
1340     
1341     memset(k2, 0, sizeof(k2));
1342     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1343     
1344     silc_buffer_pull(dist, klen + hash_len);
1345     silc_buffer_format(dist,
1346                        SILC_STR_UI_XNSTRING(k2, hash_len),
1347                        SILC_STR_END);
1348     silc_buffer_push(dist, klen + hash_len);
1349     
1350     memset(k3, 0, sizeof(k3));
1351     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1352     
1353     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1354     memcpy(dtmp, k1, hash_len);
1355     memcpy(dtmp + hash_len, k2, hash_len);
1356     memcpy(dtmp + hash_len, k3, hash_len);
1357
1358     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1359     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1360     key->enc_key_len = req_enc_key_len;
1361
1362     memset(dtmp, 0, (3 * hash_len));
1363     memset(k1, 0, sizeof(k1));
1364     memset(k2, 0, sizeof(k2));
1365     memset(k3, 0, sizeof(k3));
1366     silc_free(dtmp);
1367     silc_buffer_free(dist);
1368   } else {
1369     /* Take normal hash as key */
1370     memset(hash, 0, sizeof(hash));
1371     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1372     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1373     memcpy(key->receive_enc_key, hash, enc_key_len);
1374     key->enc_key_len = req_enc_key_len;
1375   }
1376
1377   /* Take HMAC key */
1378   memset(hash, 0, sizeof(hash));
1379   buf->data[0] = 4;
1380   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1381   key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1382   memcpy(key->hmac_key, hash, req_hmac_key_len);
1383   key->hmac_key_len = req_hmac_key_len;
1384
1385   memset(tmpbuf, 0, klen);
1386   silc_free(tmpbuf);
1387
1388   return SILC_SKE_STATUS_OK;
1389 }