Add an internal-representation no-op function.
[u/mdw/catacomb] / sslprf.c
CommitLineData
51a0f805 1/* -*-c-*-
2 *
3 * $Id: sslprf.c,v 1.1 2001/04/06 22:05:10 mdw Exp $
4 *
5 * The SSL pseudo-random function
6 *
7 * (c) 2001 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: sslprf.c,v $
33 * Revision 1.1 2001/04/06 22:05:10 mdw
34 * Add support for SSL pseudo-random function.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include <mLib/alloc.h>
41#include <mLib/dstr.h>
42#include <mLib/sub.h>
43
44#include "arena.h"
45#include "ghash.h"
46#include "grand.h"
47#include "paranoia.h"
48#include "sslprf.h"
49
50/*----- Main code ---------------------------------------------------------*/
51
52/* --- @step@ --- *
53 *
54 * Arguments: @sslprf_ctx *c@ = pointer to context structure
55 *
56 * Returns: ---
57 *
58 * Use: Steps the generator.
59 */
60
61static void step(sslprf_ctx *c)
62{
63 octet buf[64];
64 size_t n, sz;
65 octet x;
66 ghash *h, *hh;
67 octet *p;
68
69 h = c->ci->init();
70 x = 'A' + c->i - 1;
71 for (sz = c->i++; sz > 0; sz -= n) {
72 n = sz;
73 if (n > sizeof(buf))
74 n = sizeof(buf);
75 memset(buf, x, n);
76 h->ops->hash(h, buf, n);
77 }
78 h->ops->hash(h, c->k, c->ksz);
79 h->ops->hash(h, c->sd, c->sdsz);
80 p = h->ops->done(h, 0);
81
82 hh = c->co->init();
83 hh->ops->hash(hh, c->k, c->ksz);
84 hh->ops->hash(hh, p, c->ihashsz);
85 c->p = hh->ops->done(hh, 0);
86 h->ops->destroy(h);
87
88 c->h = hh;
89 c->sz = c->ohashsz;
90}
91
92/* --- @sslprf_init@ --- *
93 *
94 * Arguments: @sslprf_ctx *c@ = pointer to a context structure
95 * @const gchash *hco, *hci@ = outer and inner hash functions
96 * @const void *k@ = pointer to secret buffer
97 * @size_t ksz@ = size of the secret
98 * @const void *sd@ = pointer to seed buffer
99 * @size_t sdsz@ = size of the seed
100 *
101 * Returns: ---
102 *
103 * Use: Initializes an SSL generator context.
104 */
105
106void sslprf_init(sslprf_ctx *c, const gchash *hco, const gchash *hci,
107 const void *k, size_t ksz,
108 const void *sd, size_t sdsz)
109{
110 c->co = hco; c->ci = hci;
111 c->ohashsz = hco->hashsz; c->ihashsz = hci->hashsz;
112 c->k = k; c->ksz = ksz; c->sd = sd; c->sdsz = sdsz;
113 c->i = 1;
114 step(c);
115}
116
117/* --- @sslprf_encrypt@ --- *
118 *
119 * Arguments: @sslprf_ctx *c@ = pointer to a context structure
120 * @const void *src@ = pointer to source buffer
121 * @void *dest@ = pointer to destination buffer
122 * @size_t sz@ = size of the buffers
123 *
124 * Returns: ---
125 *
126 * Use: Encrypts data using the SSL pseudo-random function. If the
127 * destination pointer is null, the generator is spun and no
128 * output is produced; if the source pointer is null, raw output
129 * from the generator is written; otherwise, the source data is
130 * XORed with the generator output.
131 */
132
133void sslprf_encrypt(sslprf_ctx *c, const void *src, void *dest, size_t sz)
134{
135 const octet *s = src;
136 octet *d = dest;
137 size_t i, n;
138
139 while (sz) {
140 if (!c->sz) {
141 c->h->ops->destroy(c->h);
142 step(c);
143 }
144 n = c->sz;
145 if (n > sz)
146 n = sz;
147 if (d) {
148 if (!s)
149 memcpy(d, c->p, n);
150 else {
151 for (i = 0; i < n; i++) d[i] = s[i] ^ c->p[i];
152 s += n;
153 }
154 d += n;
155 }
156 c->p += n;
157 c->sz -= n;
158 sz -= n;
159 }
160}
161
162/* --- @sslprf_free@ --- *
163 *
164 * Arguments: @sslprf_ctx@ = pointer to a context
165 *
166 * Returns: ---
167 *
168 * Use: Frees resources held in an SSL generator context.
169 */
170
171void sslprf_free(sslprf_ctx *c)
172{
173 c->h->ops->destroy(c->h);
174}
175
176/* --- Generic random number generator --- */
177
178typedef struct grctx {
179 grand r;
180 grand_ops ops;
181 sslprf_ctx prf;
182} grctx;
183
184static void grdestroy(grand *r)
185{
186 grctx *g = (grctx *)r;
187 xfree((char *)g->ops.name);
188 xfree((octet *)g->prf.sd);
189 sslprf_free(&g->prf);
190 BURN(*g);
191 S_DESTROY(g);
192}
193
194static void seed(grctx *g, const void *p, size_t sz)
195{
196 octet *q;
197 xfree((octet *)g->prf.sd);
198 g->prf.sd = q = xmalloc(sz);
199 memcpy(q, p, sz);
200 g->prf.sdsz = sz;
201}
202
203static int grmisc(grand *r, unsigned op, ...)
204{
205 grctx *g = (grctx *)r;
206 va_list ap;
207 int rc = 0;
208 uint32 i;
209 octet buf[4];
210 va_start(ap, op);
211
212 switch (op) {
213 case GRAND_CHECK:
214 switch (va_arg(ap, unsigned)) {
215 case GRAND_CHECK:
216 case GRAND_SEEDINT:
217 case GRAND_SEEDUINT32:
218 case GRAND_SEEDBLOCK:
219 case GRAND_SEEDRAND:
220 rc = 1;
221 break;
222 default:
223 rc = 0;
224 break;
225 }
226 break;
227 case GRAND_SEEDINT:
228 i = va_arg(ap, unsigned);
229 STORE32(buf, i);
230 seed(g, buf, sizeof(buf));
231 break;
232 case GRAND_SEEDUINT32:
233 i = va_arg(ap, uint32);
234 STORE32(buf, i);
235 seed(g, buf, sizeof(buf));
236 break;
237 case GRAND_SEEDBLOCK: {
238 const void *p = va_arg(ap, const void *);
239 size_t sz = va_arg(ap, size_t);
240 seed(g, p, sz);
241 } break;
242 case GRAND_SEEDRAND: {
243 grand *rr = va_arg(ap, grand *);
244 octet buf[16];
245 rr->ops->fill(rr, buf, sizeof(buf));
246 seed(g, buf, sizeof(buf));
247 } break;
248 default:
249 GRAND_BADOP;
250 break;
251 }
252
253 va_end(ap);
254 return (rc);
255}
256
257static octet grbyte(grand *r)
258{
259 grctx *g = (grctx *)r;
260 octet o;
261 sslprf_encrypt(&g->prf, 0, &o, 1);
262 return (o);
263}
264
265static uint32 grword(grand *r)
266{
267 grctx *g = (grctx *)r;
268 octet b[4];
269 sslprf_encrypt(&g->prf, 0, &b, sizeof(b));
270 return (LOAD32(b));
271}
272
273static void grfill(grand *r, void *p, size_t sz)
274{
275 grctx *g = (grctx *)r;
276 sslprf_encrypt(&g->prf, 0, p, sz);
277}
278
279static const grand_ops grops = {
280 "<sslprf-dummy>",
281 GRAND_CRYPTO, 0,
282 grmisc, grdestroy,
283 grword, grbyte, grword, grand_range, grfill
284};
285
286/* ---@sslprf_rand@ --- *
287 *
288 * Arguments: @const gchash *hco, const gchash *hci@ = hash functions
289 * @const void *k@ = pointer to the key material
290 * @size_t ksz@ = size of the key material
291 * @const void *sd@ = pointer to the seed material
292 * @size_t sdsz@ = size of the seed material
293 *
294 * Returns: Pointer to generic random number generator interface.
295 *
296 * Use: Creates a generic generator which does TLS data expansion.
297 */
298
299grand *sslprf_rand(const gchash *hco, const gchash *hci,
300 const void *k, size_t ksz,
301 const void *sd, size_t sdsz)
302{
303 grctx *g = S_CREATE(grctx);
304 dstr d = DSTR_INIT;
305 octet *q = xmalloc(sdsz);
306 memcpy(q, sd, sdsz);
307 dstr_putf(&d, "sslprf(%s,%s)", hco->name, hci->name);
308 g->ops = grops;
309 g->ops.name = xstrdup(d.buf);
310 g->r.ops = &g->ops;
311 dstr_destroy(&d);
312 sslprf_init(&g->prf, hco, hci, k, ksz, q, sdsz);
313 return (&g->r);
314}
315
316/*----- Test rig ----------------------------------------------------------*/
317
318#ifdef TEST_RIG
319
320#include <stdio.h>
321#include <string.h>
322
323#include <mLib/quis.h>
324#include <mLib/testrig.h>
325
326#include "sha.h"
327#include "md5.h"
328
329static int v_generate(dstr *v)
330{
331 grand *g;
332 dstr d = DSTR_INIT;
333 int ok = 1;
334
335 g = sslprf_rand(&md5, &sha, v[0].buf, v[0].len, v[1].buf, v[1].len);
336 dstr_ensure(&d, v[2].len);
337 d.len = v[2].len;
338 g->ops->fill(g, d.buf, d.len);
339 g->ops->destroy(g);
340 if (memcmp(v[2].buf, d.buf, d.len) != 0) {
341 ok = 0;
342 printf("\nfail sslprf:"
343 "\n\tkey = ");
344 type_hex.dump(&v[0], stdout);
345 printf("\n\tseed = "); type_hex.dump(&v[1], stdout);
346 printf("\n\texpected = "); type_hex.dump(&v[2], stdout);
347 printf("\n\tcalculated = "); type_hex.dump(&d, stdout);
348 putchar('\n');
349 }
350 return (ok);
351}
352
353static test_chunk defs[] = {
354 { "sslprf", v_generate, { &type_hex, &type_hex, &type_hex, 0 } },
355 { 0, 0, { 0 } }
356};
357
358int main(int argc, char *argv[])
359{
360 test_run(argc, argv, defs, SRCDIR"/tests/sslprf");
361 return (0);
362}
363
364#endif
365
366/*----- That's all, folks -------------------------------------------------*/