]> the.earth.li Git - onak.git/blob - sha1x.c
Add ability to drop overly large packets
[onak.git] / sha1x.c
1 /*
2  * sha1x.c - Double width SHA-1 as per PGP 5.5
3  *
4  * Copyright 2013 Jonathan McDowell <noodles@earth.li>
5  *
6  * This is based on the description / code from PGP 5.5, where it is called
7  * "SHA Double". I have seen reference to SHA1X elsewhere, which is a more
8  * concise name, so I have used that here.
9  *
10  * I can't imagine there is a good reason to use this code other than for
11  * verifying signatures on ancient PGP keys.
12  *
13  * Placed into the public domain.
14  */
15
16 #include "config.h"
17
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <string.h>
21
22 #ifdef HAVE_NETTLE
23 #include <nettle/sha.h>
24 #else
25 #include "sha1.h"
26 #endif
27 #include "sha1x.h"
28
29 #define BUFSIZE 64
30
31 void sha1x_init(struct sha1x_ctx *ctx)
32 {
33         unsigned char zeros[3];
34
35         zeros[0] = zeros[1] = zeros[2] = 0;
36         sha1_init(&ctx->a);
37         sha1_init(&ctx->b);
38         sha1_init(&ctx->c);
39         sha1_init(&ctx->d);
40
41         sha1_update(&ctx->b, 1, zeros);
42         sha1_update(&ctx->c, 2, zeros);
43         sha1_update(&ctx->d, 3, zeros);
44
45         /* We start at 0, so even */
46         ctx->odd = false;
47 }
48
49 void sha1x_update(struct sha1x_ctx *ctx, unsigned length, const uint8_t *data)
50 {
51         uint8_t evenbuf[BUFSIZE], *evenp;
52         uint8_t oddbuf[BUFSIZE], *oddp;
53         bool newodd;
54
55         oddp = oddbuf;
56         evenp = evenbuf;
57
58         /* Track whether our first byte next time round is even or odd */
59         newodd = ctx->odd ^ (length & 1);
60
61         /* If our first byte is odd this time, add it to the odd buffer */
62         if (ctx->odd && length != 0) {
63                 *oddp++ = *data++;
64                 length--;
65         }
66         ctx->odd = newodd;
67
68         while (length != 0) {
69                 while (length != 0 && oddp < oddbuf + BUFSIZE) {
70                         *evenp++ = *data++;
71                         length--;
72                         if (length == 0) {
73                                 break;
74                         }
75                         *oddp++ = *data++;
76                         length--;
77                 }
78                 sha1_update(&ctx->a, evenp - evenbuf, evenbuf);
79                 sha1_update(&ctx->b, evenp - evenbuf, evenbuf);
80                 sha1_update(&ctx->c, oddp - oddbuf, oddbuf);
81                 sha1_update(&ctx->d, oddp - oddbuf, oddbuf);
82
83                 oddp = oddbuf;
84                 evenp = evenbuf;
85         }
86 }
87
88 void sha1x_digest(struct sha1x_ctx *ctx, unsigned length, uint8_t *digest)
89 {
90         uint8_t sha1final[8][SHA1_DIGEST_SIZE];
91         uint8_t zeros[7];
92         struct sha1_ctx e, f, g, h;
93         int i;
94
95         sha1_digest(&ctx->a, SHA1_DIGEST_SIZE, sha1final[0]);
96         sha1_digest(&ctx->b, SHA1_DIGEST_SIZE, sha1final[1]);
97         sha1_digest(&ctx->c, SHA1_DIGEST_SIZE, sha1final[2]);
98         sha1_digest(&ctx->d, SHA1_DIGEST_SIZE, sha1final[3]);
99
100         /* XOR sha1-c into sha1-a & sha1-d into sha1-b */
101         for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
102                 sha1final[0][i] ^= sha1final[2][i];
103                 sha1final[1][i] ^= sha1final[3][i];
104         }
105
106         sha1_init(&e);
107         sha1_init(&f);
108         sha1_init(&g);
109         sha1_init(&h);
110
111         memset(zeros, 0, sizeof(zeros));
112         sha1_update(&e, 4, zeros);
113         sha1_update(&f, 5, zeros);
114         sha1_update(&g, 6, zeros);
115         sha1_update(&h, 7, zeros);
116
117         sha1_update(&e, SHA1_DIGEST_SIZE, sha1final[0]);
118         sha1_update(&f, SHA1_DIGEST_SIZE, sha1final[0]);
119         sha1_update(&g, SHA1_DIGEST_SIZE, sha1final[1]);
120         sha1_update(&h, SHA1_DIGEST_SIZE, sha1final[1]);
121
122         sha1_digest(&e, SHA1_DIGEST_SIZE, sha1final[4]);
123         sha1_digest(&f, SHA1_DIGEST_SIZE, sha1final[5]);
124         sha1_digest(&g, SHA1_DIGEST_SIZE, sha1final[6]);
125         sha1_digest(&h, SHA1_DIGEST_SIZE, sha1final[7]);
126
127         /* XOR sha1-g into sha1-e & sha1-h into sha1-f */
128         for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
129                 sha1final[4][i] ^= sha1final[6][i];
130                 sha1final[5][i] ^= sha1final[7][i];
131         }
132
133         if (length > SHA1X_DIGEST_SIZE) {
134                 length = SHA1X_DIGEST_SIZE;
135         }
136
137         for (i = 0; i < length; i++) {
138                 if (i < SHA1_DIGEST_SIZE) {
139                         digest[i] = sha1final[4][i];
140                 } else {
141                         digest[i] = sha1final[6][i - SHA1_DIGEST_SIZE];
142                 }
143         }
144 }