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