99a01cb9 |
1 | /* -*-c-*- |
2 | * |
2730bf33 |
3 | * $Id: oaep.c,v 1.4 2002/01/13 13:50:21 mdw Exp $ |
99a01cb9 |
4 | * |
5 | * Optimal asymmetric encryption 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 | /*----- Revision history --------------------------------------------------* |
31 | * |
32 | * $Log: oaep.c,v $ |
2730bf33 |
33 | * Revision 1.4 2002/01/13 13:50:21 mdw |
34 | * Allow only one error return, to frustrate Manger's attack against OAEP. |
35 | * |
827a6719 |
36 | * Revision 1.3 2001/02/22 09:04:39 mdw |
37 | * Fix memory leaks. |
38 | * |
49db8dbe |
39 | * Revision 1.2 2000/07/15 10:01:48 mdw |
40 | * Test rig added, based on RIPEMD160-MGF1 test vectors. |
41 | * |
99a01cb9 |
42 | * Revision 1.1 2000/07/01 11:18:30 mdw |
43 | * Support for Optimal Asymmetric Encryption Padding. |
44 | * |
45 | */ |
46 | |
47 | /*----- Header files ------------------------------------------------------*/ |
48 | |
49 | #include <string.h> |
50 | |
51 | #include <mLib/alloc.h> |
52 | #include <mLib/bits.h> |
53 | #include <mLib/dstr.h> |
54 | |
55 | #include "gcipher.h" |
56 | #include "ghash.h" |
57 | #include "grand.h" |
58 | #include "oaep.h" |
59 | |
60 | /*----- Main code ---------------------------------------------------------*/ |
61 | |
62 | /* --- @oaep_encode@ --- * |
63 | * |
64 | * Arguments: @const void *msg@ = pointer to message data |
65 | * @size_t msz@ = size of message data |
66 | * @void *buf@ = pointer to output buffer |
67 | * @size_t sz@ = size of the output buffer |
68 | * @void *p@ = pointer to OAEP parameter block |
69 | * |
70 | * Returns: Zero if all went well, negative on failure. |
71 | * |
72 | * Use: Implements the operation @EME-OAEP-ENCODE@, as defined in |
73 | * PKCS#1 v. 2.0 (RFC2437). |
74 | */ |
75 | |
76 | int oaep_encode(const void *msg, size_t msz, void *buf, size_t sz, void *p) |
77 | { |
78 | oaep *o = p; |
79 | size_t hsz = o->ch->hashsz; |
827a6719 |
80 | ghash *h; |
99a01cb9 |
81 | octet *q, *mq, *qq; |
82 | octet *pp; |
83 | gcipher *c; |
84 | size_t n; |
85 | |
86 | /* --- Ensure that everything is sensibly sized --- */ |
87 | |
88 | if (2 * hsz + 2 + msz > sz) |
89 | return (-1); |
90 | |
91 | /* --- Make the `seed' value --- */ |
92 | |
93 | q = buf; |
94 | *q++ = 0; sz--; |
95 | mq = q + hsz; |
96 | qq = q + sz; |
97 | o->r->ops->fill(o->r, q, hsz); |
98 | |
99 | /* --- Fill in the rest of the buffer --- */ |
100 | |
827a6719 |
101 | h = o->ch->init(); |
99a01cb9 |
102 | h->ops->hash(h, o->ep, o->epsz); |
103 | h->ops->done(h, mq); |
104 | h->ops->destroy(h); |
105 | pp = mq + hsz; |
106 | n = sz - 2 * hsz - msz - 1; |
107 | memset(pp, 0, n); |
108 | pp += n; |
109 | *pp++ = 1; |
110 | memcpy(pp, msg, msz); |
111 | |
112 | /* --- Do the packing --- */ |
113 | |
114 | n = sz - hsz; |
115 | c = o->cc->init(q, hsz); |
116 | c->ops->encrypt(c, mq, mq, n); |
117 | c->ops->destroy(c); |
118 | |
119 | c = o->cc->init(mq, n); |
120 | c->ops->encrypt(c, q, q, hsz); |
121 | c->ops->destroy(c); |
122 | |
123 | /* --- Done --- */ |
124 | |
125 | return (0); |
126 | } |
127 | |
128 | /* --- @oaep_decode@ --- * |
129 | * |
130 | * Arguments: @const void *buf@ = pointer to encoded buffer |
131 | * @size_t sz@ = size of the encoded buffer |
132 | * @dstr *d@ = pointer to destination string |
133 | * @void *p@ = pointer to OAEP parameter block |
134 | * |
135 | * Returns: The length of the output string if successful, negative on |
136 | * failure. |
137 | * |
138 | * Use: Implements the operation @EME-OAEP-DECODE@, as defined in |
139 | * PKCS#1 v. 2.0 (RFC2437). |
140 | */ |
141 | |
142 | int oaep_decode(const void *buf, size_t sz, dstr *d, void *p) |
143 | { |
144 | oaep *o = p; |
145 | gcipher *c; |
146 | ghash *h; |
147 | octet *q, *mq, *qq; |
148 | octet *pp; |
149 | size_t n; |
150 | size_t hsz = o->ch->hashsz; |
151 | int rc = -1; |
152 | |
153 | /* --- Ensure that the block is large enough --- */ |
154 | |
155 | if (sz < 2 * hsz) |
156 | return (-1); |
157 | |
158 | q = x_alloc(d->a, sz); |
159 | memcpy(q, buf, sz); |
160 | |
161 | /* --- Decrypt the message --- */ |
162 | |
99a01cb9 |
163 | q++; sz--; |
164 | mq = q + hsz; |
165 | qq = q + sz; |
166 | n = sz - hsz; |
167 | c = o->cc->init(mq, n); |
168 | c->ops->decrypt(c, q, q, hsz); |
169 | c->ops->destroy(c); |
170 | |
171 | c = o->cc->init(q, hsz); |
172 | c->ops->decrypt(c, mq, mq, n); |
173 | c->ops->destroy(c); |
174 | q--; |
175 | |
176 | /* --- Check the hash on the encoding parameters --- */ |
177 | |
178 | h = o->ch->init(); |
179 | h->ops->hash(h, o->ep, o->epsz); |
180 | h->ops->done(h, q); |
827a6719 |
181 | h->ops->destroy(h); |
2730bf33 |
182 | if ((memcmp(q, mq, hsz) != 0) || (*q != 0)) |
99a01cb9 |
183 | goto fail; |
184 | |
185 | /* --- Now find the start of the actual message --- */ |
186 | |
187 | pp = mq + hsz; |
188 | while (*pp == 0 && pp < qq) |
189 | pp++; |
190 | if (pp >= qq || *pp++ != 1) |
191 | return (-1); |
192 | n = qq - pp; |
193 | dstr_putm(d, pp, n); |
194 | rc = n; |
195 | |
196 | fail: |
197 | x_free(d->a, q); |
198 | return (rc); |
199 | } |
200 | |
49db8dbe |
201 | /*----- Test rig ----------------------------------------------------------*/ |
202 | |
203 | #ifdef TEST_RIG |
204 | |
205 | #include <mLib/testrig.h> |
206 | |
207 | #include "rmd160.h" |
208 | #include "rmd160-mgf.h" |
209 | |
210 | typedef struct gctx { |
211 | grand r; |
212 | octet *buf; |
213 | } gctx; |
214 | |
215 | static void rfill(grand *r, void *buf, size_t sz) |
216 | { |
217 | gctx *g = (gctx *)r; |
218 | memcpy(buf, g->buf, sz); |
219 | } |
220 | |
221 | static const grand_ops gops = { |
222 | "const", 0, 0, |
223 | 0, 0, |
224 | 0, 0, 0, 0, rfill |
225 | }; |
226 | |
227 | static int verify(dstr *v) |
228 | { |
229 | gctx gr; |
230 | dstr d = DSTR_INIT; |
231 | oaep o; |
232 | int ok = 1; |
233 | |
234 | dstr_ensure(&d, v[3].len); |
235 | d.len = v[3].len; |
236 | gr.r.ops = &gops; |
827a6719 |
237 | gr.buf = (octet *)v[2].buf; |
49db8dbe |
238 | |
239 | o.cc = &rmd160_mgf; |
240 | o.ch = &rmd160; |
241 | o.r = &gr.r; |
242 | o.ep = v[1].buf; |
243 | o.epsz = v[1].len; |
244 | |
245 | if (oaep_encode(v[0].buf, v[0].len, d.buf, d.len, &o) || |
246 | memcmp(d.buf, v[3].buf, d.len) != 0) { |
247 | ok = 0; |
248 | fputs("\nfailure in oaep_encode", stderr); |
249 | fputs("\n message = ", stderr); type_hex.dump(&v[0], stderr); |
250 | fputs("\n params = ", stderr); type_hex.dump(&v[1], stderr); |
251 | fputs("\n salt = ", stderr); type_hex.dump(&v[2], stderr); |
252 | fputs("\nexpected = ", stderr); type_hex.dump(&v[3], stderr); |
253 | fputs("\n output = ", stderr); type_hex.dump(&d, stderr); |
254 | fputc('\n', stderr); |
255 | } |
256 | |
257 | DRESET(&d); |
258 | if (oaep_decode(v[3].buf, v[3].len, &d, &o) < 0 || |
259 | d.len != v[0].len || memcmp(d.buf, v[0].buf, d.len) != 0) { |
260 | ok = 0; |
261 | fputs("\nfailure in oaep_decode", stderr); |
262 | fputs("\n goop = ", stderr); type_hex.dump(&v[3], stderr); |
263 | fputs("\n params = ", stderr); type_hex.dump(&v[1], stderr); |
264 | fputs("\n salt = ", stderr); type_hex.dump(&v[2], stderr); |
265 | fputs("\nexpected = ", stderr); type_hex.dump(&v[0], stderr); |
266 | fputs("\n output = ", stderr); type_hex.dump(&d, stderr); |
267 | fputc('\n', stderr); |
268 | } |
269 | |
270 | dstr_destroy(&d); |
271 | return (ok); |
272 | } |
273 | |
274 | static test_chunk tests[] = { |
275 | { "oaep", verify, { &type_hex, &type_hex, &type_hex, &type_hex, 0 } }, |
276 | { 0, 0, { 0 } } |
277 | }; |
278 | |
279 | int main(int argc, char *argv[]) |
280 | { |
281 | test_run(argc, argv, tests, SRCDIR "/tests/oaep"); |
282 | return (0); |
283 | } |
284 | |
285 | #endif |
286 | |
99a01cb9 |
287 | /*----- That's all, folks -------------------------------------------------*/ |