ec0dbf9c032e4f463878d948f68569795a503939
[silc.git] / lib / silccore / silcmessage.c
1 /*
2
3   silcmessage.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* Implementation of the Message Payload used as channel messages and
20    private messages. */
21 /* $Id$ */
22
23 #include "silc.h"
24 #include "silcmessage.h"
25
26 /*************************** Types and definitions **************************/
27
28 /* Calculates padding length for message payload */
29 #define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
30
31 /* Header length plus maximum padding length */
32 #define SILC_MESSAGE_HLEN 6 + 16
33
34 /* Maximum message length */
35 #define SILC_MESSAGE_MAX_LEN SILC_PACKET_MAX_LEN - SILC_MESSAGE_HLEN - 16
36
37 /* Payload encoding context */
38 typedef struct {
39   SilcBuffer buffer;
40   SilcBuffer sign;
41   SilcStack stack;
42   SilcMessagePayloadEncoded encoded;
43   void *context;
44   SilcMessageFlags flags;
45   SilcPublicKey public_key;
46   SilcPrivateKey private_key;
47   SilcRng rng;
48   SilcHash hash;
49   SilcCipher cipher;
50   SilcHmac hmac;
51   unsigned char *iv;
52   unsigned char *pk;
53   SilcUInt16 pk_len;
54   SilcUInt16 iv_len;
55   SilcUInt16 payload_len;
56   SilcID sid;
57   SilcID rid;
58 } SilcMessageEncode;
59
60
61 /************************* Static utility functions *************************/
62
63 static void
64 silc_message_payload_encode_final(SilcBuffer buffer,
65                                   SilcMessageFlags flags,
66                                   SilcCipher cipher,
67                                   SilcHmac hmac,
68                                   unsigned char *iv,
69                                   SilcUInt32 iv_len,
70                                   SilcUInt32 payload_len,
71                                   SilcID *sender_id,
72                                   SilcID *receiver_id,
73                                   SilcStack stack,
74                                   SilcBuffer signature,
75                                   SilcMessagePayloadEncoded encoded,
76                                   void *context);
77
78 /* Returns the data length that fits to the packet.  If data length is too
79    big it will be truncated to fit to the payload. */
80
81 static inline
82 SilcUInt32 silc_message_payload_datalen(SilcUInt32 data_len,
83                                         SilcUInt32 header_len,
84                                         SilcUInt32 flags,
85                                         SilcPublicKey public_key,
86                                         SilcPrivateKey private_key)
87 {
88   SilcUInt32 pklen = (flags & SILC_MESSAGE_FLAG_SIGNED && public_key ?
89                       silc_pkcs_public_key_get_len(public_key) : 0);
90   SilcUInt32 prlen = (flags & SILC_MESSAGE_FLAG_SIGNED ?
91                       silc_pkcs_private_key_get_len(private_key) / 8 : 0);
92   SilcUInt32 dlen = data_len + SILC_MESSAGE_HLEN + header_len + pklen + prlen;
93
94   if (silc_unlikely(dlen > SILC_MESSAGE_MAX_LEN))
95     data_len -= (dlen - SILC_MESSAGE_MAX_LEN);
96
97   return data_len;
98 }
99
100 /* Free signed payload */
101
102 static void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
103 {
104   if (sig->sign_data) {
105     memset(sig->sign_data, 0, sig->sign_len);
106     silc_free(sig->sign_data);
107   }
108   silc_free(sig->pk_data);
109 }
110
111 /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
112
113 static SilcBool
114 silc_message_signed_payload_parse(const unsigned char *data,
115                                   SilcUInt32 data_len,
116                                   SilcMessageSignedPayload sig)
117 {
118   SilcBufferStruct buffer;
119   int ret;
120
121   SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
122
123   SILC_LOG_HEXDUMP(("sig payload"), (unsigned char *)data, data_len);
124
125   silc_buffer_set(&buffer, (unsigned char *)data, data_len);
126
127   /* Parse the payload */
128   ret = silc_buffer_unformat(&buffer,
129                              SILC_STR_UI_SHORT(&sig->pk_len),
130                              SILC_STR_UI_SHORT(&sig->pk_type),
131                              SILC_STR_END);
132   if (ret == -1 || sig->pk_len > data_len - 4) {
133     SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED "
134                     "Payload"));
135     return FALSE;
136   }
137
138   silc_buffer_pull(&buffer, 4);
139   ret = silc_buffer_unformat(&buffer,
140                              SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
141                                                         sig->pk_len),
142                              SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
143                                                          &sig->sign_len),
144                              SILC_STR_END);
145   if (ret == -1 || sig->sign_len > silc_buffer_len(&buffer) -
146       sig->pk_len - 2) {
147     silc_message_signed_payload_free(sig);
148     SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
149     return FALSE;
150   }
151   silc_buffer_push(&buffer, 4);
152
153   /* Signature must be provided */
154   if (sig->sign_len < 1)  {
155     SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD "
156                     "Payload"));
157     silc_message_signed_payload_free(sig);
158     return FALSE;
159   }
160
161   return TRUE;
162 }
163
164 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
165
166 static SilcBuffer
167 silc_message_signed_encode_data(SilcStack stack,
168                                 const unsigned char *message_payload,
169                                 SilcUInt32 message_payload_len,
170                                 unsigned char *pk,
171                                 SilcUInt32 pk_len, SilcUInt32 pk_type)
172 {
173   SilcBuffer sign;
174
175   sign = silc_buffer_salloc_size(stack, message_payload_len + 4 + pk_len);
176   if (!sign)
177     return NULL;
178
179   silc_buffer_sformat(stack, sign,
180                       SILC_STR_DATA(message_payload, message_payload_len),
181                       SILC_STR_UI_SHORT(pk_len),
182                       SILC_STR_UI_SHORT(pk_type),
183                       SILC_STR_END);
184
185   if (pk && pk_len) {
186     silc_buffer_pull(sign, message_payload_len + 4);
187     silc_buffer_sformat(stack, sign,
188                         SILC_STR_UI_XNSTRING(pk, pk_len),
189                         SILC_STR_END);
190     silc_buffer_push(sign, message_payload_len + 4);
191   }
192
193   return sign;
194 }
195
196 /* Signature callback */
197
198 void silc_message_signed_payload_encode_cb(SilcBool success,
199                                            const unsigned char *signature,
200                                            SilcUInt32 signature_len,
201                                            void *context)
202 {
203   SilcMessageEncode *e = context;
204   SilcPKCSType pk_type;
205   SilcStack stack = e->stack;
206   SilcBuffer buffer, payload;
207   SilcMessageFlags flags;
208   SilcCipher cipher;
209   SilcHmac hmac;
210   unsigned char *iv;
211   SilcUInt32 iv_len, payload_len;
212   SilcID *sid, *rid;
213   SilcMessagePayloadEncoded encoded;
214   void *encoded_context;
215
216   if (!success) {
217     e->encoded(NULL, e->context);
218     silc_buffer_sfree(stack, e->sign);
219     silc_sfree(stack, e->pk);
220     silc_sfree(stack, e);
221     silc_stack_free(stack);
222     return;
223   }
224
225   pk_type = silc_pkcs_get_type(e->private_key);
226
227   /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
228   buffer = silc_buffer_salloc_size(stack, 4 + e->pk_len + 2 + signature_len);
229   if (!buffer) {
230     e->encoded(NULL, e->context);
231     silc_buffer_sfree(stack, e->sign);
232     silc_sfree(stack, e->pk);
233     silc_sfree(stack, e);
234     silc_stack_free(stack);
235     return;
236   }
237
238   silc_buffer_sformat(stack, buffer,
239                       SILC_STR_UI_SHORT(e->pk_len),
240                       SILC_STR_UI_SHORT(pk_type),
241                       SILC_STR_END);
242
243   if (e->pk_len && e->pk) {
244     silc_buffer_pull(buffer, 4);
245     silc_buffer_sformat(stack, buffer,
246                         SILC_STR_DATA(e->pk, e->pk_len),
247                         SILC_STR_END);
248     silc_buffer_push(buffer, 4);
249   }
250
251   silc_buffer_pull(buffer, 4 + e->pk_len);
252   silc_buffer_sformat(stack, buffer,
253                       SILC_STR_UI_SHORT(signature_len),
254                       SILC_STR_DATA(signature, signature_len),
255                       SILC_STR_END);
256   silc_buffer_push(buffer, 4 + e->pk_len);
257
258   SILC_LOG_HEXDUMP(("SIG payload"), buffer->data, silc_buffer_len(buffer));
259
260   payload = e->buffer;
261   flags = e->flags;
262   cipher = e->cipher;
263   hmac = e->hmac;
264   iv = e->iv;
265   iv_len = e->iv_len;
266   payload_len = e->payload_len;
267   sid = &e->sid;
268   rid = &e->rid;
269   encoded = e->encoded;
270   encoded_context = e->context;
271
272   silc_sfree(stack, e->pk);
273   silc_buffer_sfree(stack, e->sign);
274   silc_sfree(stack, e);
275
276   /* Finalize message payload encoding */
277   silc_message_payload_encode_final(payload, flags, cipher, hmac,
278                                     iv, iv_len, payload_len,
279                                     sid, rid, stack, buffer,
280                                     encoded, encoded_context);
281 }
282
283 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
284    signature. */
285
286 static SilcAsyncOperation
287 silc_message_signed_payload_encode(SilcBuffer payload,
288                                    SilcMessageEncode *e)
289 {
290   SilcAsyncOperation op;
291   SilcBuffer sign;
292   unsigned char *pk = NULL;
293   SilcUInt32 pk_len = 0;
294   SilcUInt16 pk_type;
295   SilcStack stack = e->stack;
296   SilcRng rng = e->rng;
297   SilcHash hash = e->hash;
298   SilcPublicKey public_key = e->public_key;
299   SilcPrivateKey private_key = e->private_key;
300   unsigned char *message_payload;
301   SilcUInt16 message_payload_len;
302
303   message_payload = payload->head;
304   message_payload_len = silc_buffer_headlen(payload);
305
306   if (!message_payload || !message_payload_len || !private_key || !hash) {
307     e->encoded(NULL, e->context);
308     silc_sfree(stack, e);
309     silc_stack_free(stack);
310     return NULL;
311   }
312
313   if (public_key) {
314     e->pk = pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
315     if (!pk) {
316       e->encoded(NULL, e->context);
317       silc_sfree(stack, e);
318       silc_stack_free(stack);
319       return NULL;
320     }
321     e->pk_len = pk_len;
322   }
323   pk_type = silc_pkcs_get_type(private_key);
324
325   /* Encode the data to be signed */
326   e->sign = sign = silc_message_signed_encode_data(stack, message_payload,
327                                                    message_payload_len,
328                                                    pk, pk_len, pk_type);
329   if (!sign) {
330     e->encoded(NULL, e->context);
331     silc_sfree(stack, pk);
332     silc_sfree(stack, e);
333     silc_stack_free(stack);
334     return NULL;
335   }
336
337   /* Compute signature */
338   op = silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
339                       TRUE, hash, rng,
340                       silc_message_signed_payload_encode_cb, e);
341
342   return op;
343 }
344
345 /***************************** Payload parsing ******************************/
346
347 /* Decrypts the Message Payload. The `data' is the actual Message Payload. */
348
349 SilcBool silc_message_payload_decrypt(unsigned char *data,
350                                       size_t data_len,
351                                       SilcBool private_message,
352                                       SilcBool static_key,
353                                       SilcCipher cipher,
354                                       SilcHmac hmac,
355                                       unsigned char *sender_id,
356                                       SilcUInt32 sender_id_len,
357                                       unsigned char *receiver_id,
358                                       SilcUInt32 receiver_id_len,
359                                       SilcBool check_mac)
360 {
361   SilcUInt32 mac_len, iv_len = 0, block_len;
362   SilcUInt16 len, totlen;
363   unsigned char mac[32], *ivp;
364
365   mac_len = silc_hmac_len(hmac);
366   block_len = silc_cipher_get_block_len(cipher);
367
368   /* IV is present for all channel messages, and private messages when
369      static key (pre-shared key) is used. */
370   if (!private_message || (private_message && static_key))
371     iv_len = block_len;
372
373   if (silc_unlikely(data_len < (mac_len + iv_len + block_len)))
374     return FALSE;
375
376   if (silc_likely(check_mac)) {
377     /* Check the MAC of the message */
378     SILC_LOG_DEBUG(("Checking message MAC"));
379     silc_hmac_init(hmac);
380     silc_hmac_update(hmac, data, data_len - mac_len);
381     silc_hmac_update(hmac, sender_id, sender_id_len);
382     silc_hmac_update(hmac, receiver_id, receiver_id_len);
383     silc_hmac_final(hmac, mac, &mac_len);
384     if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
385       /* Check for old style (version 1.2) message MAC.  Remove this check
386          at some point. */
387       silc_hmac_init(hmac);
388       silc_hmac_update(hmac, data, data_len - mac_len);
389       silc_hmac_final(hmac, mac, &mac_len);
390       if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
391         SILC_LOG_DEBUG(("Message MAC does not match"));
392         return FALSE;
393       }
394     }
395     SILC_LOG_DEBUG(("MAC is Ok"));
396   }
397
398   /* Decrypt first only one block to get the header and then rest of
399      the data.  This is done because there might be unencrypted data at
400      the end and we don't know the encrypted length yet. */
401
402   /* Get pointer to the IV */
403   ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
404          silc_cipher_get_iv(cipher));
405
406   /* Decrypt block */
407   if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len,
408                                          ivp))) {
409     SILC_ASSERT(FALSE);
410     return FALSE;
411   }
412
413   /* Get the payload length and decrypt rest */
414   totlen = 2;
415   SILC_GET16_MSB(len, data + totlen);
416   totlen += 2 + len;
417   if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len))
418     return FALSE;
419   totlen += 2;
420   if (totlen >= block_len)
421     if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len,
422                                            data + block_len,
423                                            (totlen - block_len) +
424                                            SILC_MESSAGE_PAD(totlen), ivp))) {
425       SILC_ASSERT(FALSE);
426       return FALSE;
427     }
428
429   return TRUE;
430 }
431
432 /* Parses Message Payload returning new payload structure.  This also
433    decrypts it and checks the MAC. */
434
435 SilcMessagePayload
436 silc_message_payload_parse(unsigned char *payload,
437                            SilcUInt32 payload_len,
438                            SilcBool private_message,
439                            SilcBool static_key,
440                            SilcCipher cipher,
441                            SilcHmac hmac,
442                            unsigned char *sender_id,
443                            SilcUInt32 sender_id_len,
444                            unsigned char *receiver_id,
445                            SilcUInt32 receiver_id_len,
446                            SilcStack stack,
447                            SilcBool no_allocation,
448                            SilcMessagePayload message)
449 {
450   SilcBufferStruct buffer;
451   SilcMessagePayload newp = NULL;
452   int ret;
453   SilcUInt32 mac_len = 0, iv_len = 0;
454
455   SILC_LOG_DEBUG(("Parsing Message Payload"));
456
457   silc_buffer_set(&buffer, payload, payload_len);
458
459   /* Decrypt the payload */
460   if (silc_likely(cipher)) {
461     ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer),
462                                        private_message, static_key,
463                                        cipher, hmac, sender_id,
464                                        sender_id_len, receiver_id,
465                                        receiver_id_len, TRUE);
466     if (silc_unlikely(ret == FALSE))
467       return NULL;
468   }
469
470   if (silc_likely(hmac))
471     mac_len = silc_hmac_len(hmac);
472
473   /* IV is present for all channel messages, and private messages when
474      static key (pre-shared key) is used. */
475   if (cipher && (!private_message || (private_message && static_key)))
476     iv_len = silc_cipher_get_block_len(cipher);
477
478   if (!message) {
479     newp = message = silc_calloc(1, sizeof(*newp));
480     if (silc_unlikely(!newp))
481       return NULL;
482   }
483   memset(message, 0, sizeof(*message));
484   message->allocated = (stack || no_allocation ? FALSE : TRUE);
485
486   /* Parse the Message Payload. */
487   if (!no_allocation)
488     ret = silc_buffer_sunformat(stack, &buffer,
489                           SILC_STR_UI_SHORT(&message->flags),
490                           SILC_STR_UI16_NSTRING_ALLOC(&message->data,
491                                                       &message->data_len),
492                           SILC_STR_UI16_NSTRING_ALLOC(&message->pad,
493                                                       &message->pad_len),
494                           SILC_STR_END);
495   else
496     ret = silc_buffer_unformat(&buffer,
497                                SILC_STR_UI_SHORT(&message->flags),
498                                SILC_STR_UI16_NSTRING(&message->data,
499                                                      &message->data_len),
500                                SILC_STR_UI16_NSTRING(&message->pad,
501                                                      &message->pad_len),
502                                SILC_STR_END);
503   if (silc_unlikely(ret == -1))
504     goto err;
505
506   if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) -
507                      6 - mac_len - iv_len) ||
508                     (message->pad_len + message->data_len >
509                      silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) {
510     SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
511     goto err;
512   }
513
514   /* Parse Signed Message Payload if provided */
515   if (message->flags & SILC_MESSAGE_FLAG_SIGNED &&
516       message->data_len + message->pad_len + 6 + mac_len +
517       iv_len < silc_buffer_len(&buffer)) {
518     if (!silc_message_signed_payload_parse(buffer.data + 6 +
519                                            message->data_len +
520                                            message->pad_len,
521                                            silc_buffer_len(&buffer) -
522                                            iv_len - mac_len - 6 -
523                                            message->data_len -
524                                            message->pad_len,
525                                            &message->sig))
526       goto err;
527   }
528
529   /* Parse MAC from the payload */
530   if (mac_len)
531     message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len);
532
533   return newp;
534
535  err:
536   if (newp)
537     silc_message_payload_free(newp);
538   return NULL;
539 }
540
541
542 /***************************** Payload encoding *****************************/
543
544 /* This function is used to encrypt the Messsage Payload which is
545    the `data' and `data_len'.  This is used internally by the Message
546    Payload encoding routines but application may call this too if needed.
547    The `true_len' is the data length which is used to create MAC out of. */
548
549 SilcBool silc_message_payload_encrypt(unsigned char *data,
550                                       SilcUInt32 data_len,
551                                       SilcUInt32 true_len,
552                                       unsigned char *iv,
553                                       SilcID *sender_id,
554                                       SilcID *receiver_id,
555                                       SilcCipher cipher,
556                                       SilcHmac hmac)
557 {
558   unsigned char sid[32], rid[32];
559   SilcUInt32 sid_len = 0, rid_len = 0;
560
561   /* Encrypt payload of the packet */
562   if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
563     return FALSE;
564
565   /* Encode IDs */
566   silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid),
567                  &sid_len);
568   if (receiver_id->type == SILC_ID_CLIENT)
569     silc_id_id2str(&receiver_id->u.client_id, SILC_ID_CLIENT, rid,
570                    sizeof(rid), &rid_len);
571   else if (receiver_id->type == SILC_ID_CHANNEL)
572     silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid,
573                    sizeof(rid), &rid_len);
574
575   /* Compute the MAC of the encrypted message data */
576   silc_hmac_init(hmac);
577   silc_hmac_update(hmac, data, true_len);
578   silc_hmac_update(hmac, sid, sid_len);
579   silc_hmac_update(hmac, rid, rid_len);
580   silc_hmac_final(hmac, data + true_len, NULL);
581
582   return TRUE;
583 }
584
585 /* Encrypt message payload */
586
587 static int silc_message_payload_encode_encrypt(SilcStack stack,
588                                                SilcBuffer buffer,
589                                                void *value, void *context)
590 {
591   SilcMessageEncode *e = context;
592   SilcUInt32 mac_len;
593
594   if (!e->cipher || !e->hmac)
595     return 0;
596
597   mac_len = silc_hmac_len(e->hmac);
598   if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
599     return -1;
600
601   if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
602                                                   e->payload_len,
603                                                   silc_buffer_headlen(buffer),
604                                                   e->iv, &e->sid, &e->rid,
605                                                   e->cipher, e->hmac)))
606     return -1;
607
608   return mac_len;
609 }
610
611 /* Finalize message payload encoding */
612
613 static void
614 silc_message_payload_encode_final(SilcBuffer buffer,
615                                   SilcMessageFlags flags,
616                                   SilcCipher cipher,
617                                   SilcHmac hmac,
618                                   unsigned char *iv,
619                                   SilcUInt32 iv_len,
620                                   SilcUInt32 payload_len,
621                                   SilcID *sender_id,
622                                   SilcID *receiver_id,
623                                   SilcStack stack,
624                                   SilcBuffer signature,
625                                   SilcMessagePayloadEncoded encoded,
626                                   void *context)
627 {
628   SilcMessageEncode e;
629
630   e.flags = flags;
631   e.cipher = cipher;
632   e.hmac = hmac;
633   e.sid = *sender_id;
634   e.rid = *receiver_id;
635   e.iv = iv;
636   e.payload_len = payload_len;
637
638   /* Encrypt */
639   if (silc_buffer_format(buffer,
640                          SILC_STR_DATA(signature ?
641                                        silc_buffer_data(signature) : NULL,
642                                        signature ?
643                                        silc_buffer_len(signature) : 0),
644                          SILC_STR_DATA(iv, iv_len),
645                          SILC_STR_FUNC(silc_message_payload_encode_encrypt,
646                                        NULL, &e),
647                          SILC_STR_END) < 0) {
648     silc_buffer_sfree(stack, buffer);
649     encoded(NULL, context);
650     return;
651   }
652
653   /* Deliver message payload */
654   silc_buffer_start(buffer);
655   encoded(buffer, context);
656
657   silc_buffer_sfree(stack, buffer);
658   silc_buffer_sfree(stack, signature);
659   silc_stack_free(stack);
660 }
661
662 /* Encodes Message Payload into a buffer and returns it. */
663
664 SilcAsyncOperation
665 silc_message_payload_encode(SilcMessageFlags flags,
666                             const unsigned char *data,
667                             SilcUInt32 data_len,
668                             SilcBool generate_iv,
669                             SilcBool private_message,
670                             SilcCipher cipher,
671                             SilcHmac hmac,
672                             SilcRng rng,
673                             SilcPublicKey public_key,
674                             SilcPrivateKey private_key,
675                             SilcHash hash,
676                             SilcID *sender_id,
677                             SilcID *receiver_id,
678                             SilcStack stack,
679                             SilcMessagePayloadEncoded encoded,
680                             void *context)
681 {
682   SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
683   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
684   SilcBuffer buffer;
685   int i;
686
687   SILC_LOG_DEBUG(("Encoding Message Payload"));
688
689   if (silc_unlikely(!data_len)) {
690     encoded(NULL, context);
691     return NULL;
692   }
693   if (silc_unlikely(!private_message && (!cipher || !hmac))) {
694     encoded(NULL, context);
695     return NULL;
696   }
697
698   stack = silc_stack_alloc(0, stack ? stack : silc_crypto_stack());
699
700   buffer = silc_buffer_salloc(stack, 0);
701   if (silc_unlikely(!buffer)) {
702     encoded(NULL, context);
703     silc_stack_free(stack);
704     return NULL;
705   }
706
707   /* For channel messages IV is always generated */
708   if (!private_message && !generate_iv)
709     generate_iv = TRUE;
710
711   /* Generate IV */
712   if (cipher && generate_iv) {
713     iv_len = silc_cipher_get_block_len(cipher);
714     if (rng) {
715       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
716     } else {
717       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
718     }
719   }
720
721   if (hmac)
722     mac_len = silc_hmac_len(hmac);
723   data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags,
724                                           public_key, private_key);
725
726   /* Calculate length of padding. IV is not included into the calculation
727      since it is not encrypted. */
728   pad_len = SILC_MESSAGE_PAD(6 + data_len);
729
730   /* Generate padding */
731   if (cipher) {
732     if (rng) {
733       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
734     } else {
735       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
736     }
737   }
738
739   /* Encode the Message Payload */
740   if (silc_buffer_format(buffer,
741                          SILC_STR_ADVANCE,
742                          SILC_STR_UI_SHORT(flags),
743                          SILC_STR_UI_SHORT(data_len),
744                          SILC_STR_DATA(data, data_len),
745                          SILC_STR_UI_SHORT(pad_len),
746                          SILC_STR_DATA(pad, pad_len),
747                          SILC_STR_END) < 0) {
748     silc_buffer_sfree(stack, buffer);
749     encoded(NULL, context);
750     silc_stack_free(stack);
751     return NULL;
752   }
753
754   if (flags & SILC_MESSAGE_FLAG_SIGNED) {
755     SilcMessageEncode *e = silc_scalloc(stack, 1, sizeof(*e));
756     if (!e) {
757       silc_buffer_sfree(stack, buffer);
758       encoded(NULL, context);
759       silc_stack_free(stack);
760       return NULL;
761     }
762
763     e->stack = stack;
764     e->buffer = buffer;
765     e->flags = flags;
766     e->public_key = public_key;
767     e->private_key = private_key;
768     e->rng = rng;
769     e->hash = hash;
770     e->cipher = cipher;
771     e->hmac = hmac;
772     e->sid = *sender_id;
773     e->rid = *receiver_id;
774     e->iv = iv_len ? iv : NULL;
775     e->iv_len = iv_len;
776     e->payload_len = 6 + data_len + pad_len;
777     e->encoded = encoded;
778     e->context = context;
779
780     /* Compute signature */
781     return silc_message_signed_payload_encode(buffer, e);
782   }
783
784   /* Finalize */
785   silc_message_payload_encode_final(buffer, flags, cipher, hmac,
786                                     iv_len ? iv : NULL, iv_len,
787                                     6 + data_len + pad_len,
788                                     sender_id, receiver_id, stack, NULL,
789                                     encoded, context);
790   return NULL;
791 }
792
793 /* Free's Message Payload */
794
795 void silc_message_payload_free(SilcMessagePayload payload)
796 {
797   silc_message_signed_payload_free(&payload->sig);
798   if (payload->data) {
799     memset(payload->data, 0, payload->data_len);
800     if (payload->allocated)
801       silc_free(payload->data);
802   }
803   if (payload->allocated) {
804     silc_free(payload->pad);
805     silc_free(payload);
806   }
807 }
808
809 /* Return flags */
810
811 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
812 {
813   return payload->flags;
814 }
815
816 /* Return data */
817
818 unsigned char *silc_message_get_data(SilcMessagePayload payload,
819                                      SilcUInt32 *data_len)
820 {
821   if (data_len)
822     *data_len = payload->data_len;
823   return payload->data;
824 }
825
826 /* Return MAC. The caller knows the length of the MAC */
827
828 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
829 {
830   return payload->mac;
831 }
832
833 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
834
835 SilcAsyncOperation
836 silc_message_signed_verify(SilcMessagePayload message,
837                            SilcPublicKey remote_public_key,
838                            SilcHash hash,
839                            SilcAuthResultCb result,
840                            void *context)
841 {
842   SilcAsyncOperation op;
843   SilcBuffer sign, tmp;
844   SilcStack stack = NULL;
845   SilcMessageSignedPayload sig = &message->sig;
846
847   if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
848       !sig->sign_len || !remote_public_key || !hash) {
849     result(FALSE, context);
850     return NULL;
851   }
852
853   if (silc_crypto_stack())
854     stack = silc_stack_alloc(0, silc_crypto_stack());
855
856   /* Generate the signature verification data, the Message Payload */
857   tmp = silc_buffer_salloc_size(stack,
858                                 6 + message->data_len + message->pad_len);
859   silc_buffer_sformat(stack, tmp,
860                       SILC_STR_UI_SHORT(message->flags),
861                       SILC_STR_UI_SHORT(message->data_len),
862                       SILC_STR_DATA(message->data, message->data_len),
863                       SILC_STR_UI_SHORT(message->pad_len),
864                       SILC_STR_DATA(message->pad, message->pad_len),
865                       SILC_STR_END);
866   sign = silc_message_signed_encode_data(stack, tmp->data, silc_buffer_len(tmp),
867                                          sig->pk_data, sig->pk_len,
868                                          sig->pk_type);
869   silc_buffer_clear(tmp);
870   silc_buffer_sfree(stack, tmp);
871
872   if (!sign) {
873     result(FALSE, context);
874     silc_stack_free(stack);
875     return NULL;
876   }
877
878   /* Verify the authentication data */
879   op = silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
880                         silc_buffer_data(sign), silc_buffer_len(sign),
881                         hash, result, context);
882
883   silc_buffer_clear(sign);
884   silc_buffer_sfree(stack, sign);
885   silc_stack_free(stack);
886
887   return op;
888 }
889
890 /* Return the public key from the payload */
891
892 SilcPublicKey
893 silc_message_signed_get_public_key(SilcMessagePayload payload,
894                                    const unsigned char **pk_data,
895                                    SilcUInt32 *pk_data_len)
896 {
897   SilcPublicKey pk;
898   SilcMessageSignedPayload sig = &payload->sig;
899
900   if (!sig->pk_data)
901     return NULL;
902
903   if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
904                                   sig->pk_len, &pk))
905     return NULL;
906
907   if (pk_data)
908     *pk_data = sig->pk_data;
909   if (pk_data_len)
910     *pk_data_len = sig->pk_len;
911
912   return pk;
913 }