72b6be1743d8deef04250dc735952e719b7ac263
[silc.git] / lib / silccrypt / silcpkcs1.c
1 /*
2
3   silcpkcs1.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2003 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
20 #include "silcincludes.h"
21 #include "silcpkcs1.h"
22
23 /* Minimum padding in block */
24 #define SILC_PKCS1_MIN_PADDING 8
25
26 /* Encodes PKCS#1 data block from the `data' according to the block type
27    indicated by `bt'.  When encoding signatures the `bt' must be
28    SILC_PKCS1_BT_PRV1 and when encoding encryption blocks the `bt' must
29    be SILC_PKCS1_BT_PUB.  The encoded data is copied into the `dest_data'
30    buffer which is size of `dest_data_size'.  If the `dest_data' is not
31    able to hold the encoded block this returns FALSE.  The `rng' must be
32    set when `bt' is SILC_PKCS1_BT_PUB.  This function returns TRUE on
33    success. */
34
35 bool silc_pkcs1_encode(SilcPkcs1BlockType bt,
36                        const unsigned char *data,
37                        SilcUInt32 data_len,
38                        unsigned char *dest_data,
39                        SilcUInt32 dest_data_size,
40                        SilcRng rng)
41 {
42   SilcInt32 padlen;
43   int i;
44
45   SILC_LOG_DEBUG(("PKCS#1 encoding, bt %d", bt));
46
47   if (!data || !dest_data ||
48       dest_data_size < 3 || dest_data_size < data_len) {
49     SILC_LOG_DEBUG(("Data to be encoded is too long"));
50     return FALSE;
51   }
52
53   /* Start of block */
54   dest_data[0] = 0x00;
55   dest_data[1] = (unsigned char)bt;
56
57   padlen = (SilcInt32)dest_data_size - (SilcInt32)data_len - 3;
58   if (padlen < SILC_PKCS1_MIN_PADDING) {
59     SILC_LOG_DEBUG(("Data to be encoded is too long"));
60     return FALSE;
61   }
62
63   /* Encode according to block type */
64   switch (bt) {
65   case SILC_PKCS1_BT_PRV0:
66   case SILC_PKCS1_BT_PRV1:
67     /* Signature */
68     memset(dest_data + 2, bt == SILC_PKCS1_BT_PRV1 ? 0xff : 0x00, padlen);
69     break;
70
71   case SILC_PKCS1_BT_PUB:
72     /* Encryption */
73
74     /* It is guaranteed this routine does not return zero byte. */
75     if (rng)
76       for (i = 2; i < padlen; i++)
77         dest_data[i] = silc_rng_get_byte_fast(rng);
78     else
79       for (i = 2; i < padlen; i++)
80         dest_data[i] = silc_rng_global_get_byte_fast();
81     break;
82   }
83
84   /* Copy the data */
85   dest_data[padlen + 2] = 0x00;
86   memcpy(dest_data + padlen + 3, data, data_len);
87
88   return TRUE;
89 }
90
91 /* Decodes the PKCS#1 encoded block according to the block type `bt'.
92    When verifying signatures the `bt' must be SILC_PKCS1_BT_PRV1 and
93    when decrypting it must be SILC_PKCS1_BT_PUB.  This copies the
94    decoded data into `dest_data' which is size of `dest_data_size'.  If
95    the deocded block does not fit to `dest_data' this returns FALSE.
96    Returns TRUE on success. */
97
98 bool silc_pkcs1_decode(SilcPkcs1BlockType bt,
99                        const unsigned char *data,
100                        SilcUInt32 data_len,
101                        unsigned char *dest_data,
102                        SilcUInt32 dest_data_size,
103                        SilcUInt32 *dest_len)
104 {
105   int i = 0;
106
107   SILC_LOG_DEBUG(("PKCS#1 decoding, bt %d", bt));
108
109   /* Sanity checks */
110   if (!data || !dest_data || dest_data_size < 3 ||
111       data[0] != 0x00 || data[1] != (unsigned char)bt) {
112     SILC_LOG_DEBUG(("Malformed block"));
113     return FALSE;
114   }
115
116   /* Decode according to block type */
117   switch (bt) {
118   case SILC_PKCS1_BT_PRV0:
119     /* Do nothing */
120     break;
121
122   case SILC_PKCS1_BT_PRV1:
123     /* Verification */
124     for (i = 2; i < data_len; i++)
125       if (data[i] != 0xff)
126         break;
127     break;
128
129   case SILC_PKCS1_BT_PUB:
130     /* Decryption */
131     for (i = 2; i < data_len; i++)
132       if (data[i] == 0x00)
133         break;
134     break;
135   }
136
137   /* Sanity checks */
138   if (data[i++] != 0x00) {
139     SILC_LOG_DEBUG(("Malformed block"));
140     return FALSE;
141   }
142   if (i - 1 < SILC_PKCS1_MIN_PADDING) {
143     SILC_LOG_DEBUG(("Malformed block"));
144     return FALSE;
145   }
146   if (dest_data_size < data_len - i) {
147     SILC_LOG_DEBUG(("Destination buffer too small"));
148     return FALSE;
149   }
150
151   /* Copy the data */
152   memcpy(dest_data, data + i, data_len - i);
153
154   /* Return data length */
155   if (dest_len)
156     *dest_len = data_len - i;
157
158   return TRUE;
159 }