cd6c3eeb |
1 | /* -*-c-*- |
2 | * |
b817bfc6 |
3 | * $Id: pkcs1.c,v 1.4 2004/04/08 01:36:15 mdw Exp $ |
cd6c3eeb |
4 | * |
5 | * PKCS#1 1.5 packing |
6 | * |
7 | * (c) 2000 Straylight/Edgeware |
8 | */ |
9 | |
45c0fd36 |
10 | /*----- Licensing notice --------------------------------------------------* |
cd6c3eeb |
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. |
45c0fd36 |
18 | * |
cd6c3eeb |
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. |
45c0fd36 |
23 | * |
cd6c3eeb |
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 | |
cd6c3eeb |
30 | /*----- Header files ------------------------------------------------------*/ |
31 | |
32 | #include <string.h> |
33 | |
34 | #include <mLib/bits.h> |
35 | #include <mLib/dstr.h> |
36 | |
37 | #include "grand.h" |
b817bfc6 |
38 | #include "rsa.h" |
cd6c3eeb |
39 | |
40 | /*----- Main code ---------------------------------------------------------*/ |
41 | |
42 | /* --- @pkcs1_cryptencode@ --- * |
43 | * |
b817bfc6 |
44 | * Arguments: @mp *d@ = where to put the answer |
45 | * @const void *m@ = pointer to message data |
cd6c3eeb |
46 | * @size_t msz@ = size of message data |
b817bfc6 |
47 | * @octet *b@ = spare buffer |
48 | * @size_t sz@ = size of the buffer (big enough) |
49 | * @unsigned long nbits@ = length of bits of @n@ |
cd6c3eeb |
50 | * @void *p@ = pointer to PKCS1 parameter block |
51 | * |
b817bfc6 |
52 | * Returns: The encoded result, or null. |
cd6c3eeb |
53 | * |
54 | * Use: Implements the operation @EME-PKCS1-V1_5-ENCODE@, as defined |
55 | * in PKCS#1 v. 2.0 (RFC2437). |
56 | */ |
57 | |
b817bfc6 |
58 | mp *pkcs1_cryptencode(mp *d, const void *m, size_t msz, octet *b, size_t sz, |
59 | unsigned long nbits, void *p) |
cd6c3eeb |
60 | { |
61 | pkcs1 *pp = p; |
62 | grand *r = pp->r; |
b817bfc6 |
63 | octet *q; |
cd6c3eeb |
64 | size_t i, n; |
65 | |
66 | /* --- Ensure that the buffer is sensibly sized --- */ |
67 | |
68 | if (pp->epsz + msz + 11 > sz) |
b817bfc6 |
69 | return (0); |
cd6c3eeb |
70 | |
b817bfc6 |
71 | /* --- Allocate the buffer and fill it in --- */ |
cd6c3eeb |
72 | |
b817bfc6 |
73 | q = b; |
74 | *q++ = 0x00; |
75 | *q++ = 0x02; |
cd6c3eeb |
76 | n = sz - msz - pp->epsz - 3; |
b817bfc6 |
77 | GR_FILL(r, q, n); |
cd6c3eeb |
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; |
b817bfc6 |
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 --- */ |
45c0fd36 |
93 | |
b817bfc6 |
94 | return (mp_loadb(d, b, sz)); |
cd6c3eeb |
95 | } |
96 | |
97 | /* --- @pkcs1_cryptdecode@ --- * |
98 | * |
b817bfc6 |
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@ |
cd6c3eeb |
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 | |
b817bfc6 |
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) |
cd6c3eeb |
125 | { |
126 | pkcs1 *pp = p; |
127 | const octet *q, *qq; |
128 | size_t n, i; |
b817bfc6 |
129 | int bad = 0; |
cd6c3eeb |
130 | |
131 | /* --- Check the size of the block looks sane --- */ |
132 | |
b817bfc6 |
133 | if (pp->epsz + 11 > sz) /* OK: independent of ciphertext */ |
cd6c3eeb |
134 | return (-1); |
b817bfc6 |
135 | mp_storeb(m, b, sz); |
136 | q = b; |
7629bca8 |
137 | qq = q + sz; |
cd6c3eeb |
138 | |
139 | /* --- Ensure that the block looks OK --- */ |
140 | |
b817bfc6 |
141 | bad |= (*q++ != 0x00 || *q++ != 0x02); |
cd6c3eeb |
142 | |
143 | /* --- Check the nonzero padding --- */ |
144 | |
145 | i = 0; |
146 | while (*q != 0 && q < qq) |
147 | i++, q++; |
b817bfc6 |
148 | bad |= (i < 8 || qq - q < pp->epsz + 1); |
cd6c3eeb |
149 | q++; |
150 | |
151 | /* --- Check the encoding parameters --- */ |
152 | |
b817bfc6 |
153 | bad |= (pp->ep && !memeq(bad ? b : q, pp->ep, pp->epsz)); |
cd6c3eeb |
154 | q += pp->epsz; |
155 | |
156 | /* --- Done --- */ |
157 | |
158 | n = qq - q; |
b817bfc6 |
159 | memmove(b, bad ? b + 1 : q, n); |
160 | return (bad ? -1 : n); |
cd6c3eeb |
161 | } |
162 | |
163 | /* --- @pkcs1_sigencode@ --- * |
164 | * |
b817bfc6 |
165 | * Arguments: @mp *d@ = where to put the answer |
166 | * @const void *m@ = pointer to message data |
cd6c3eeb |
167 | * @size_t msz@ = size of message data |
b817bfc6 |
168 | * @octet *b@ = spare buffer |
169 | * @size_t sz@ = size of the buffer (big enough) |
170 | * @unsigned long nbits@ = length of bits of @n@ |
cd6c3eeb |
171 | * @void *p@ = pointer to PKCS1 parameter block |
172 | * |
b817bfc6 |
173 | * Returns: The encoded message representative, or null. |
cd6c3eeb |
174 | * |
175 | * Use: Implements the operation @EMSA-PKCS1-V1_5-ENCODE@, as defined |
176 | * in PKCS#1 v. 2.0 (RFC2437). |
177 | */ |
178 | |
b817bfc6 |
179 | mp *pkcs1_sigencode(mp *d, const void *m, size_t msz, octet *b, size_t sz, |
180 | unsigned long nbits, void *p) |
cd6c3eeb |
181 | { |
182 | pkcs1 *pp = p; |
b817bfc6 |
183 | octet *q; |
cd6c3eeb |
184 | size_t n; |
185 | |
186 | /* --- Ensure that the buffer is sensibly sized --- */ |
187 | |
188 | if (pp->epsz + msz + 11 > sz) |
b817bfc6 |
189 | return (0); |
cd6c3eeb |
190 | |
191 | /* --- Fill in the buffer --- */ |
192 | |
b817bfc6 |
193 | q = b; |
194 | *q++ = 0x00; |
195 | *q++ = 0x01; |
cd6c3eeb |
196 | n = sz - msz - pp->epsz - 3; |
197 | memset(q, 0xff, n); |
198 | q += n; |
199 | *q++ = 0; |
b817bfc6 |
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)); |
cd6c3eeb |
208 | } |
209 | |
210 | /* --- @pkcs1_sigdecode@ --- * |
211 | * |
b817bfc6 |
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 |
cd6c3eeb |
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 | |
b817bfc6 |
227 | int pkcs1_sigdecode(mp *s, const void *m, size_t msz, octet *b, size_t sz, |
228 | unsigned long nbits, void *p) |
cd6c3eeb |
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); |
b817bfc6 |
238 | mp_storeb(s, b, sz); |
239 | q = b; |
7629bca8 |
240 | qq = q + sz; |
cd6c3eeb |
241 | |
242 | /* --- Ensure that the block looks OK --- */ |
243 | |
b817bfc6 |
244 | if (*q++ != 0x00 || *q++ != 0x01) |
cd6c3eeb |
245 | return (-1); |
246 | |
247 | /* --- Check the padding --- */ |
248 | |
249 | i = 0; |
250 | while (*q == 0xff && q < qq) |
251 | i++, q++; |
0586d2a1 |
252 | if (i < 8 || qq - q < pp->epsz + 1 || *q++ != 0) |
cd6c3eeb |
253 | return (-1); |
cd6c3eeb |
254 | |
255 | /* --- Check the encoding parameters --- */ |
256 | |
b817bfc6 |
257 | if (pp->ep && memcmp(q, pp->ep, pp->epsz) != 0) |
cd6c3eeb |
258 | return (-1); |
259 | q += pp->epsz; |
260 | |
261 | /* --- Done --- */ |
262 | |
263 | n = qq - q; |
b817bfc6 |
264 | memmove(b, q, n); |
cd6c3eeb |
265 | return (n); |
266 | } |
267 | |
268 | /*----- That's all, folks -------------------------------------------------*/ |