]> the.earth.li Git - onak.git/blob - sha1x.c
Fix handling of other signature requirement
[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 #include <stdbool.h>
16 #include <stdint.h>
17 #include <string.h>
18
19 #include "build-config.h"
20
21 #ifdef HAVE_NETTLE
22 #include <nettle/sha.h>
23 #else
24 #include "sha1.h"
25 #endif
26 #include "sha1x.h"
27
28 #define BUFSIZE 64
29
30 void sha1x_init(struct sha1x_ctx *ctx)
31 {
32         unsigned char zeros[3];
33
34         zeros[0] = zeros[1] = zeros[2] = 0;
35         sha1_init(&ctx->a);
36         sha1_init(&ctx->b);
37         sha1_init(&ctx->c);
38         sha1_init(&ctx->d);
39
40         sha1_update(&ctx->b, 1, zeros);
41         sha1_update(&ctx->c, 2, zeros);
42         sha1_update(&ctx->d, 3, zeros);
43
44         /* We start at 0, so even */
45         ctx->odd = false;
46 }
47
48 void sha1x_update(struct sha1x_ctx *ctx, unsigned length, const uint8_t *data)
49 {
50         uint8_t evenbuf[BUFSIZE], *evenp;
51         uint8_t oddbuf[BUFSIZE], *oddp;
52         bool newodd;
53
54         oddp = oddbuf;
55         evenp = evenbuf;
56
57         /* Track whether our first byte next time round is even or odd */
58         newodd = ctx->odd ^ (length & 1);
59
60         /* If our first byte is odd this time, add it to the odd buffer */
61         if (ctx->odd && length != 0) {
62                 *oddp++ = *data++;
63                 length--;
64         }
65         ctx->odd = newodd;
66
67         while (length != 0) {
68                 while (length != 0 && oddp < oddbuf + BUFSIZE) {
69                         *evenp++ = *data++;
70                         length--;
71                         if (length == 0) {
72                                 break;
73                         }
74                         *oddp++ = *data++;
75                         length--;
76                 }
77                 sha1_update(&ctx->a, evenp - evenbuf, evenbuf);
78                 sha1_update(&ctx->b, evenp - evenbuf, evenbuf);
79                 sha1_update(&ctx->c, oddp - oddbuf, oddbuf);
80                 sha1_update(&ctx->d, oddp - oddbuf, oddbuf);
81
82                 oddp = oddbuf;
83                 evenp = evenbuf;
84         }
85 }
86
87 void sha1x_digest(struct sha1x_ctx *ctx, unsigned length, uint8_t *digest)
88 {
89         uint8_t sha1final[8][SHA1_DIGEST_SIZE];
90         uint8_t zeros[7];
91         struct sha1_ctx e, f, g, h;
92         int i;
93
94         sha1_digest(&ctx->a, SHA1_DIGEST_SIZE, sha1final[0]);
95         sha1_digest(&ctx->b, SHA1_DIGEST_SIZE, sha1final[1]);
96         sha1_digest(&ctx->c, SHA1_DIGEST_SIZE, sha1final[2]);
97         sha1_digest(&ctx->d, SHA1_DIGEST_SIZE, sha1final[3]);
98
99         /* XOR sha1-c into sha1-a & sha1-d into sha1-b */
100         for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
101                 sha1final[0][i] ^= sha1final[2][i];
102                 sha1final[1][i] ^= sha1final[3][i];
103         }
104
105         sha1_init(&e);
106         sha1_init(&f);
107         sha1_init(&g);
108         sha1_init(&h);
109
110         memset(zeros, 0, sizeof(zeros));
111         sha1_update(&e, 4, zeros);
112         sha1_update(&f, 5, zeros);
113         sha1_update(&g, 6, zeros);
114         sha1_update(&h, 7, zeros);
115
116         sha1_update(&e, SHA1_DIGEST_SIZE, sha1final[0]);
117         sha1_update(&f, SHA1_DIGEST_SIZE, sha1final[0]);
118         sha1_update(&g, SHA1_DIGEST_SIZE, sha1final[1]);
119         sha1_update(&h, SHA1_DIGEST_SIZE, sha1final[1]);
120
121         sha1_digest(&e, SHA1_DIGEST_SIZE, sha1final[4]);
122         sha1_digest(&f, SHA1_DIGEST_SIZE, sha1final[5]);
123         sha1_digest(&g, SHA1_DIGEST_SIZE, sha1final[6]);
124         sha1_digest(&h, SHA1_DIGEST_SIZE, sha1final[7]);
125
126         /* XOR sha1-g into sha1-e & sha1-h into sha1-f */
127         for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
128                 sha1final[4][i] ^= sha1final[6][i];
129                 sha1final[5][i] ^= sha1final[7][i];
130         }
131
132         if (length > SHA1X_DIGEST_SIZE) {
133                 length = SHA1X_DIGEST_SIZE;
134         }
135
136         for (i = 0; i < length; i++) {
137                 if (i < SHA1_DIGEST_SIZE) {
138                         digest[i] = sha1final[4][i];
139                 } else {
140                         digest[i] = sha1final[6][i - SHA1_DIGEST_SIZE];
141                 }
142         }
143 }