chiark / gitweb /
34604676a974c26b4728bdcc74200a18a499c1af
[catacomb] / pkcs1.c
1 /* -*-c-*-
2  *
3  * $Id: pkcs1.c,v 1.4 2004/04/08 01:36:15 mdw Exp $
4  *
5  * PKCS#1 1.5 packing
6  *
7  * (c) 2000 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Catacomb.
13  *
14  * Catacomb is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * Catacomb is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with Catacomb; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Header files ------------------------------------------------------*/
31
32 #include <string.h>
33
34 #include <mLib/bits.h>
35 #include <mLib/dstr.h>
36
37 #include "grand.h"
38 #include "rsa.h"
39
40 /*----- Main code ---------------------------------------------------------*/
41
42 /* --- @pkcs1_cryptencode@ --- *
43  *
44  * Arguments:   @mp *d@ = where to put the answer
45  *              @const void *m@ = pointer to message data
46  *              @size_t msz@ = size of message data
47  *              @octet *b@ = spare buffer
48  *              @size_t sz@ = size of the buffer (big enough)
49  *              @unsigned long nbits@ = length of bits of @n@
50  *              @void *p@ = pointer to PKCS1 parameter block
51  *
52  * Returns:     The encoded result, or null.
53  *
54  * Use:         Implements the operation @EME-PKCS1-V1_5-ENCODE@, as defined
55  *              in PKCS#1 v. 2.0 (RFC2437).
56  */
57
58 mp *pkcs1_cryptencode(mp *d, const void *m, size_t msz, octet *b, size_t sz,
59                       unsigned long nbits, void *p)
60 {
61   pkcs1 *pp = p;
62   grand *r = pp->r;
63   octet *q;
64   size_t i, n;
65
66   /* --- Ensure that the buffer is sensibly sized --- */
67
68   if (pp->epsz + msz + 11 > sz)
69     return (0);
70
71   /* --- Allocate the buffer and fill it in --- */
72
73   q = b;
74   *q++ = 0x00;
75   *q++ = 0x02;
76   n = sz - msz - pp->epsz - 3;
77   GR_FILL(r, q, n);
78   for (i = 0; i < n; i++) {
79     if (*q == 0)
80       *q = r->ops->range(r, 255) + 1;
81     q++;
82   }
83   *q++ = 0;
84   if (pp->ep) {
85     memcpy(q, pp->ep, pp->epsz);
86     q += pp->epsz;
87   }
88   memcpy(q, m, msz);
89   q += msz;
90   assert(q == b + sz);
91
92   /* --- Collect the result --- */
93   
94   return (mp_loadb(d, b, sz));
95 }
96
97 /* --- @pkcs1_cryptdecode@ --- *
98  *
99  * Arguments:   @mp *m@ = the decrypted message
100  *              @octet *b@ = pointer to a buffer to work in
101  *              @size_t sz@ = the size of the buffer (big enough)
102  *              @unsigned long nbits@ = the number of bits in @n@
103  *              @void *p@ = pointer to PKCS1 parameter block
104  *
105  * Returns:     The length of the output string if successful, negative on
106  *              failure.
107  *
108  * Use:         Implements the operation @EME-PKCS1-V1_5-DECODE@, as defined
109  *              in PKCS#1 v. 2.0 (RFC2437).
110  */
111
112 static int memeq(const void *xx, const void *yy, size_t sz)
113 {
114   int eq = 1;
115   const octet *x = xx, *y = yy;
116   while (sz) {                          /* Always check every byte */
117     if (*x++ != *y++) eq = 0;
118     sz--;
119   }
120   return (eq);
121 }
122
123 int pkcs1_cryptdecode(mp *m, octet *b, size_t sz,
124                       unsigned long nbits, void *p)
125 {
126   pkcs1 *pp = p;
127   const octet *q, *qq;
128   size_t n, i;
129   int bad = 0;
130
131   /* --- Check the size of the block looks sane --- */
132
133   if (pp->epsz + 11 > sz)               /* OK: independent of ciphertext */
134     return (-1);
135   mp_storeb(m, b, sz);
136   q = b;
137   qq = q + sz;
138
139   /* --- Ensure that the block looks OK --- */
140
141   bad |= (*q++ != 0x00 || *q++ != 0x02);
142
143   /* --- Check the nonzero padding --- */
144
145   i = 0;
146   while (*q != 0 && q < qq)
147     i++, q++;
148   bad |= (i < 8 || qq - q < pp->epsz + 1);
149   q++;
150
151   /* --- Check the encoding parameters --- */
152
153   bad |= (pp->ep && !memeq(bad ? b : q, pp->ep, pp->epsz));
154   q += pp->epsz;
155
156   /* --- Done --- */
157
158   n = qq - q;
159   memmove(b, bad ? b + 1 : q, n);
160   return (bad ? -1 : n);
161 }
162
163 /* --- @pkcs1_sigencode@ --- *
164  *
165  * Arguments:   @mp *d@ = where to put the answer
166  *              @const void *m@ = pointer to message data
167  *              @size_t msz@ = size of message data
168  *              @octet *b@ = spare buffer
169  *              @size_t sz@ = size of the buffer (big enough)
170  *              @unsigned long nbits@ = length of bits of @n@
171  *              @void *p@ = pointer to PKCS1 parameter block
172  *
173  * Returns:     The encoded message representative, or null.
174  *
175  * Use:         Implements the operation @EMSA-PKCS1-V1_5-ENCODE@, as defined
176  *              in PKCS#1 v. 2.0 (RFC2437).
177  */
178
179 mp *pkcs1_sigencode(mp *d, const void *m, size_t msz, octet *b, size_t sz,
180                     unsigned long nbits, void *p)
181 {
182   pkcs1 *pp = p;
183   octet *q;
184   size_t n;
185
186   /* --- Ensure that the buffer is sensibly sized --- */
187
188   if (pp->epsz + msz + 11 > sz)
189     return (0);
190
191   /* --- Fill in the buffer --- */
192
193   q = b;
194   *q++ = 0x00;
195   *q++ = 0x01;
196   n = sz - msz - pp->epsz - 3;
197   memset(q, 0xff, n);
198   q += n;
199   *q++ = 0;
200   if (pp->ep) {
201     memcpy(q, pp->ep, pp->epsz);
202     q += pp->epsz;
203   }
204   memcpy(q, m, msz);
205   q += msz;
206   assert(q == b + sz);
207   return (mp_loadb(d, b, sz));
208 }
209
210 /* --- @pkcs1_sigdecode@ --- *
211  *
212  * Arguments:   @mp *s@ = the message representative
213  *              @const void *m@ = the original message, or null (ignored)
214  *              @size_t msz@ = the message size (ignored)
215  *              @octet *b@ = a scratch buffer
216  *              @size_t sz@ = size of the buffer (large enough)
217  *              @unsigned long nbits@ = number of bits in @n@
218  *              @void *p@ = pointer to PKCS1 parameters
219  *
220  * Returns:     The length of the output string if successful, negative on
221  *              failure.
222  *
223  * Use:         Implements the operation @EMSA-PKCS1-V1_5-DECODE@, as defined
224  *              in PKCS#1 v. 2.0 (RFC2437).
225  */
226
227 int pkcs1_sigdecode(mp *s, const void *m, size_t msz, octet *b, size_t sz,
228                     unsigned long nbits, void *p)
229 {
230   pkcs1 *pp = p;
231   const octet *q, *qq;
232   size_t i, n;
233
234   /* --- Check the size of the block looks sane --- */
235
236   if (pp->epsz + 10 > sz)
237     return (-1);
238   mp_storeb(s, b, sz);
239   q = b;
240   qq = q + sz;
241
242   /* --- Ensure that the block looks OK --- */
243
244   if (*q++ != 0x00 || *q++ != 0x01)
245     return (-1);
246
247   /* --- Check the padding --- */
248
249   i = 0;
250   while (*q == 0xff && q < qq)
251     i++, q++;
252   if (i < 8 || qq - q < pp->epsz + 1 || *q++ != 0)
253     return (-1);
254
255   /* --- Check the encoding parameters --- */
256
257   if (pp->ep && memcmp(q, pp->ep, pp->epsz) != 0)
258     return (-1);
259   q += pp->epsz;
260
261   /* --- Done --- */
262
263   n = qq - q;
264   memmove(b, q, n);
265   return (n);
266 }
267
268 /*----- That's all, folks -------------------------------------------------*/