]> git.ozlabs.org Git - ppp.git/blob - pppd/ppp-sha1.c
Makefile.am: Add explicit openssl directory to pppd include path
[ppp.git] / pppd / ppp-sha1.c
1 /* ppp-sha1.c - SHA1 Digest implementation
2  *
3  * Copyright (c) 2022 Eivind Næss. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. The name(s) of the authors of this software must not be used to
18  *    endorse or promote products derived from this software without
19  *    prior written permission.
20  *
21  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
22  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
23  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
24  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
26  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
27  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28  *
29  * Sections of this code holds different copyright information.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <stdlib.h>
37 #include <stddef.h>
38
39 #include "crypto-priv.h"
40
41
42 /* #define SHA1HANDSOFF * Copies data before messing with it. */
43 #ifdef OPENSSL_HAVE_SHA
44 #include <openssl/evp.h>
45
46 #if OPENSSL_VERSION_NUMBER < 0x10100000L
47 #define EVP_MD_CTX_free EVP_MD_CTX_destroy
48 #define EVP_MD_CTX_new EVP_MD_CTX_create
49 #endif
50
51 static int sha1_init(PPP_MD_CTX *ctx)
52 {
53     if (ctx) {
54         EVP_MD_CTX *mctx = EVP_MD_CTX_new();
55         if (mctx) {
56             if (EVP_DigestInit(mctx, EVP_sha1())) {
57                 ctx->priv = mctx;
58                 return 1;
59             }
60             EVP_MD_CTX_free(mctx);
61         }
62     }
63     return 0;
64 }
65
66 static int sha1_update(PPP_MD_CTX *ctx, const void *data, size_t len)
67 {
68     if (EVP_DigestUpdate((EVP_MD_CTX*) ctx->priv, data, len)) {
69         return 1;
70     }
71     return 0;
72 }
73
74 static int sha1_final(PPP_MD_CTX *ctx, unsigned char *out, unsigned int *len)
75 {
76     if (EVP_DigestFinal((EVP_MD_CTX*) ctx->priv, out, len)) {
77         return 1;
78     }
79     return 0;
80 }
81
82 static void sha1_clean(PPP_MD_CTX *ctx)
83 {
84     if (ctx->priv) {
85         EVP_MD_CTX_free((EVP_MD_CTX*) ctx->priv);
86         ctx->priv = NULL;
87     }
88 }
89
90
91 #else // !OPENSSL_HAVE_SHA
92
93 /*
94  * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c
95  *
96  * SHA-1 in C
97  * By Steve Reid <steve@edmweb.com>
98  * 100% Public Domain
99  *
100  * Test Vectors (from FIPS PUB 180-1)
101  * "abc"
102  * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
103  * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
104  * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
105  * A million repetitions of "a"
106  * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
107  */
108
109 #include <string.h>
110 #include <netinet/in.h> /* htonl() */
111
112 typedef struct {
113     u_int32_t state[5];
114     u_int32_t count[2];
115     unsigned char buffer[64];
116 } SHA1_CTX;
117
118
119 static void
120 SHA1_Transform(u_int32_t[5], const unsigned char[64]);
121
122 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
123
124 /* blk0() and blk() perform the initial expand. */
125 /* I got the idea of expanding during the round function from SSLeay */
126 #define blk0(i) (block->l[i] = htonl(block->l[i]))
127 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
128     ^block->l[(i+2)&15]^block->l[i&15],1))
129
130 /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
131 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
132 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
133 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
134 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
135 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
136
137
138 /* Hash a single 512-bit block. This is the core of the algorithm. */
139
140 static void
141 SHA1_Transform(u_int32_t state[5], const unsigned char buffer[64])
142 {
143     u_int32_t a, b, c, d, e;
144     typedef union {
145         unsigned char c[64];
146         u_int32_t l[16];
147     } CHAR64LONG16;
148     CHAR64LONG16 *block;
149
150 #ifdef SHA1HANDSOFF
151     static unsigned char workspace[64];
152     block = (CHAR64LONG16 *) workspace;
153     memcpy(block, buffer, 64);
154 #else
155     block = (CHAR64LONG16 *) buffer;
156 #endif
157     /* Copy context->state[] to working vars */
158     a = state[0];
159     b = state[1];
160     c = state[2];
161     d = state[3];
162     e = state[4];
163     /* 4 rounds of 20 operations each. Loop unrolled. */
164     R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
165     R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
166     R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
167     R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
168     R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
169     R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
170     R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
171     R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
172     R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
173     R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
174     R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
175     R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
176     R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
177     R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
178     R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
179     R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
180     R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
181     R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
182     R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
183     R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
184     /* Add the working vars back into context.state[] */
185     state[0] += a;
186     state[1] += b;
187     state[2] += c;
188     state[3] += d;
189     state[4] += e;
190     /* Wipe variables */
191     a = b = c = d = e = 0;
192 }
193
194
195 /* SHA1Init - Initialize new context */
196
197 static void
198 SHA1_Init(SHA1_CTX *context)
199 {
200     /* SHA1 initialization constants */
201     context->state[0] = 0x67452301;
202     context->state[1] = 0xEFCDAB89;
203     context->state[2] = 0x98BADCFE;
204     context->state[3] = 0x10325476;
205     context->state[4] = 0xC3D2E1F0;
206     context->count[0] = context->count[1] = 0;
207 }
208
209
210 /* Run your data through this. */
211
212 static void
213 SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len)
214 {
215     unsigned int i, j;
216
217     j = (context->count[0] >> 3) & 63;
218     if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
219     context->count[1] += (len >> 29);
220     i = 64 - j;
221     while (len >= i) {
222         memcpy(&context->buffer[j], data, i);
223         SHA1_Transform(context->state, context->buffer);
224         data += i;
225         len -= i;
226         i = 64;
227         j = 0;
228     }
229
230     memcpy(&context->buffer[j], data, len);
231 }
232
233
234 /* Add padding and return the message digest. */
235
236 static void
237 SHA1_Final(unsigned char digest[20], SHA1_CTX *context)
238 {
239     u_int32_t i, j;
240     unsigned char finalcount[8];
241
242     for (i = 0; i < 8; i++) {
243         finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
244          >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
245     }
246     SHA1_Update(context, (unsigned char *) "\200", 1);
247     while ((context->count[0] & 504) != 448) {
248         SHA1_Update(context, (unsigned char *) "\0", 1);
249     }
250     SHA1_Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
251     for (i = 0; i < 20; i++) {
252         digest[i] = (unsigned char)
253                      ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
254     }
255     /* Wipe variables */
256     i = j = 0;
257     memset(context->buffer, 0, 64);
258     memset(context->state, 0, 20);
259     memset(context->count, 0, 8);
260     memset(&finalcount, 0, 8);
261 #ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
262     SHA1Transform(context->state, context->buffer);
263 #endif
264 }
265
266 static int sha1_init(PPP_MD_CTX *ctx)
267 {
268     if (ctx) {
269         SHA1_CTX *mctx = calloc(1, sizeof(SHA1_CTX));
270         if (mctx) {
271             SHA1_Init(mctx);
272             ctx->priv = mctx;
273             return 1;
274         }
275     }
276     return 0;
277 }
278
279 static int sha1_update(PPP_MD_CTX* ctx, const void *data, size_t len)
280 {
281     SHA1_Update((SHA1_CTX*) ctx->priv, (void*) data, len);
282     return 1;
283 }
284
285 static int sha1_final(PPP_MD_CTX *ctx, unsigned char *out, unsigned int *len)
286 {
287     SHA1_Final(out, (SHA1_CTX*) ctx->priv);
288     return 1;
289 }
290
291 static void sha1_clean(PPP_MD_CTX *ctx)
292 {
293     if (ctx->priv) {
294         free(ctx->priv);
295         ctx->priv = NULL;
296     }
297 }
298
299 #endif
300
301 static PPP_MD ppp_sha1 = {
302     .init_fn = sha1_init,
303     .update_fn = sha1_update,
304     .final_fn = sha1_final,
305     .clean_fn = sha1_clean,
306 };
307
308 const PPP_MD *PPP_sha1(void)
309 {
310     return &ppp_sha1;
311 }
312