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