tests/gdsa: Test from P1363.
[u/mdw/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 -------------------------------------------------*/