blob: 905f11d9bc16fbd68ddb6d7e686e14256b5ae5f2 [file] [log] [blame]
xf.li84027492024-04-09 00:17:51 -07001/* ppp-crypto.c - Generic API for access to crypto/digest functions.
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
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include <stdlib.h>
36#include <string.h>
37
38#include "crypto.h"
39#include "crypto-priv.h"
40
41#ifdef PPP_WITH_OPENSSL
42#include <openssl/opensslv.h>
43#endif
44
45#if OPENSSL_VERSION_NUMBER >= 0x30000000L
46#include <openssl/provider.h>
47struct crypto_ctx {
48
49 OSSL_PROVIDER *legacy;
50 OSSL_PROVIDER *provider;
51} g_crypto_ctx;
52#endif
53
54PPP_MD_CTX *PPP_MD_CTX_new()
55{
56 return (PPP_MD_CTX*) calloc(1, sizeof(PPP_MD_CTX));
57}
58
59void PPP_MD_CTX_free(PPP_MD_CTX* ctx)
60{
61 if (ctx) {
62 if (ctx->md.clean_fn) {
63 ctx->md.clean_fn(ctx);
64 }
65 free(ctx);
66 }
67}
68
69int PPP_DigestInit(PPP_MD_CTX *ctx, const PPP_MD *type)
70{
71 if (ctx) {
72 ctx->md = *type;
73 if (ctx->md.init_fn) {
74 return ctx->md.init_fn(ctx);
75 }
76 }
77 return 0;
78}
79
80int PPP_DigestUpdate(PPP_MD_CTX *ctx, const void *data, size_t length)
81{
82 if (ctx && ctx->md.update_fn) {
83 return ctx->md.update_fn(ctx, data, length);
84 }
85 return 0;
86}
87
88int PPP_DigestFinal(PPP_MD_CTX *ctx, unsigned char *out, unsigned int *outlen)
89{
90 if (ctx && ctx->md.final_fn) {
91 return ctx->md.final_fn(ctx, out, outlen);
92 }
93 return 0;
94}
95
96PPP_CIPHER_CTX *PPP_CIPHER_CTX_new(void)
97{
98 return calloc(1, sizeof(PPP_CIPHER_CTX));
99}
100
101void PPP_CIPHER_CTX_free(PPP_CIPHER_CTX *ctx)
102{
103 if (ctx) {
104 if (ctx->cipher.clean_fn) {
105 ctx->cipher.clean_fn(ctx);
106 }
107 memset(ctx->iv, 0, sizeof(ctx->iv));
108 memset(ctx->key, 0, sizeof(ctx->key));
109 free(ctx);
110 }
111}
112
113int PPP_CipherInit(PPP_CIPHER_CTX *ctx, const PPP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int encr)
114{
115 if (ctx && cipher) {
116 ctx->is_encr = encr;
117 ctx->cipher = *cipher;
118 if (ctx->cipher.init_fn) {
119 ctx->cipher.init_fn(ctx, key, iv);
120 }
121 return 1;
122 }
123 return 0;
124}
125
126int PPP_CipherUpdate(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
127{
128 if (ctx && ctx->cipher.update_fn) {
129 return ctx->cipher.update_fn(ctx, out, outl, in, inl);
130 }
131 return 0;
132}
133
134int PPP_CipherFinal(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
135{
136 if (ctx && ctx->cipher.final_fn) {
137 return ctx->cipher.final_fn(ctx, out, outl);
138 }
139 return 0;
140}
141
142int PPP_crypto_init()
143{
144 int retval = 0;
145
146#if OPENSSL_VERSION_NUMBER >= 0x30000000L
147 g_crypto_ctx.legacy = OSSL_PROVIDER_load(NULL, "legacy");
148 if (g_crypto_ctx.legacy == NULL)
149 {
150 goto done;
151 }
152
153 g_crypto_ctx.provider = OSSL_PROVIDER_load(NULL, "default");
154 if (g_crypto_ctx.provider == NULL)
155 {
156 goto done;
157 }
158#endif
159 retval = 1;
160
161done:
162
163 return retval;
164}
165
166int PPP_crypto_deinit()
167{
168#if OPENSSL_VERSION_NUMBER >= 0x30000000L
169 if (g_crypto_ctx.legacy) {
170 OSSL_PROVIDER_unload(g_crypto_ctx.legacy);
171 g_crypto_ctx.legacy = NULL;
172 }
173
174 if (g_crypto_ctx.provider) {
175 OSSL_PROVIDER_unload(g_crypto_ctx.provider);
176 g_crypto_ctx.provider = NULL;
177 }
178#endif
179 return 1;
180}
181
182#ifdef UNIT_TEST
183#include <stdio.h>
184
185int test_md4()
186{
187 PPP_MD_CTX* ctx = NULL;
188 int success = 0;
189
190 unsigned char data[84] = {
191 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
192 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
193 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
194 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
195 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
196 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
197 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
198 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
199 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
200 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
201 0x6b, 0x65, 0x79, 0x2e
202 };
203
204 unsigned int hash_len;
205 unsigned char hash[MD4_DIGEST_LENGTH];
206 unsigned char result[MD4_DIGEST_LENGTH] = {
207 0x58, 0xcb, 0x37, 0x91, 0x1d, 0x06, 0x7b, 0xdf,
208 0xfd, 0x48, 0x6d, 0x87, 0x4a, 0x35, 0x5b, 0xd4
209 };
210
211 ctx = PPP_MD_CTX_new();
212 if (ctx) {
213
214 if (PPP_DigestInit(ctx, PPP_md4())) {
215
216 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
217
218 hash_len = sizeof(hash);
219 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
220
221 if (memcmp(hash, result, MD4_DIGEST_LENGTH) == 0) {
222 success = 1;
223 }
224 }
225 }
226 }
227 PPP_MD_CTX_free(ctx);
228 }
229
230 return success;
231}
232
233int test_md5()
234{
235 PPP_MD_CTX* ctx = NULL;
236 int success = 0;
237
238 unsigned char data[84] = {
239 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
240 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
241 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
242 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
243 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
244 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
245 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
246 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
247 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
248 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
249 0x6b, 0x65, 0x79, 0x2e
250 };
251
252 unsigned int hash_len;
253 unsigned char hash[MD5_DIGEST_LENGTH];
254 unsigned char result[MD5_DIGEST_LENGTH] = {
255 0x8b, 0xe3, 0x5e, 0x2c, 0x9f, 0x95, 0xbf, 0x4e,
256 0x16, 0xe4, 0x53, 0xbe, 0x52, 0xf4, 0xbc, 0x4e
257 };
258
259 ctx = PPP_MD_CTX_new();
260 if (ctx) {
261
262 if (PPP_DigestInit(ctx, PPP_md5())) {
263
264 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
265
266 hash_len = sizeof(hash);
267 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
268
269 if (memcmp(hash, result, MD5_DIGEST_LENGTH) == 0) {
270 success = 1;
271 }
272 }
273 }
274 }
275 PPP_MD_CTX_free(ctx);
276 }
277
278 return success;
279}
280
281int test_sha()
282{
283 PPP_MD_CTX* ctx = NULL;
284 int success = 0;
285
286 unsigned char data[84] = {
287 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
288 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
289 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
290 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
291 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
292 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
293 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
294 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
295 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
296 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
297 0x6b, 0x65, 0x79, 0x2e
298 };
299
300 unsigned int hash_len;
301 unsigned char hash[SHA_DIGEST_LENGTH];
302 unsigned char result[SHA_DIGEST_LENGTH] = {
303 0xa8, 0x03, 0xae, 0x21, 0x30, 0xd8, 0x40, 0xbe,
304 0x27, 0xa3, 0x47, 0xc7, 0x7a, 0x90, 0xe6, 0xa3,
305 0x5b, 0xd5, 0x0e, 0x45
306 };
307
308 ctx = PPP_MD_CTX_new();
309 if (ctx) {
310
311 if (PPP_DigestInit(ctx, PPP_sha1())) {
312
313 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
314
315 hash_len = sizeof(hash);
316 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
317
318 if (memcmp(hash, result, SHA_DIGEST_LENGTH) == 0) {
319 success = 1;
320 }
321 }
322 }
323 }
324 PPP_MD_CTX_free(ctx);
325 }
326
327 return success;
328}
329
330int test_des_encrypt()
331{
332 PPP_CIPHER_CTX* ctx = NULL;
333 int success = 0;
334
335 unsigned char key[8] = {
336 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
337 };
338
339 unsigned char plain[80] = {
340 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
341 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
342 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
343 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
344 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
345 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
346 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
347 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
348 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
349 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
350 };
351 unsigned char expect[80] = {
352 0x45, 0xdb, 0x80, 0x45, 0x16, 0xd0, 0x6d, 0x60,
353 0x92, 0x23, 0x4b, 0xd3, 0x9d, 0x36, 0xb8, 0x1a,
354 0xa4, 0x1a, 0xf7, 0xb1, 0x60, 0xfb, 0x74, 0x16,
355 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
356 0x2b, 0xed, 0x68, 0x9d, 0x19, 0xd6, 0xb1, 0xb8,
357 0x91, 0xff, 0xea, 0x62, 0xac, 0xe7, 0x49, 0xdd,
358 0xfa, 0x4d, 0xa4, 0x01, 0x3f, 0xea, 0xca, 0xb4,
359 0xb6, 0xdc, 0xd3, 0x04, 0x45, 0x07, 0x74, 0xed,
360 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
361 0xbb, 0x9b, 0x13, 0x31, 0xf4, 0xa9, 0x32, 0x49
362 };
363
364 unsigned char cipher[80] = {};
365 int cipher_len = 0;
366 int offset = 0;
367
368
369 ctx = PPP_CIPHER_CTX_new();
370 if (ctx) {
371
372 if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 1)) {
373
374 if (PPP_CipherUpdate(ctx, cipher, &cipher_len, plain, sizeof(plain))) {
375
376 offset += cipher_len;
377
378 if (PPP_CipherFinal(ctx, cipher+offset, &cipher_len)) {
379
380 if (memcmp(cipher, expect, 80) == 0) {
381
382 success = 1;
383 }
384 }
385 }
386 }
387 PPP_CIPHER_CTX_free(ctx);
388 }
389
390 return success;
391}
392
393
394int test_des_decrypt()
395{
396 PPP_CIPHER_CTX* ctx = NULL;
397 int success = 0;
398
399 unsigned char key[8] = {
400 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
401 };
402
403 unsigned char cipher[80] = {
404 0x45, 0xdb, 0x80, 0x45, 0x16, 0xd0, 0x6d, 0x60,
405 0x92, 0x23, 0x4b, 0xd3, 0x9d, 0x36, 0xb8, 0x1a,
406 0xa4, 0x1a, 0xf7, 0xb1, 0x60, 0xfb, 0x74, 0x16,
407 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
408 0x2b, 0xed, 0x68, 0x9d, 0x19, 0xd6, 0xb1, 0xb8,
409 0x91, 0xff, 0xea, 0x62, 0xac, 0xe7, 0x49, 0xdd,
410 0xfa, 0x4d, 0xa4, 0x01, 0x3f, 0xea, 0xca, 0xb4,
411 0xb6, 0xdc, 0xd3, 0x04, 0x45, 0x07, 0x74, 0xed,
412 0xa6, 0xdc, 0xe1, 0x14, 0xb7, 0xed, 0x48, 0x5a,
413 0xbb, 0x9b, 0x13, 0x31, 0xf4, 0xa9, 0x32, 0x49
414 };
415
416 unsigned char expect[80] = {
417 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
418 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
419 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
420 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
421 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
422 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
423 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
424 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
425 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
426 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
427 };
428
429 unsigned char plain[80] = {};
430 int outlen = 0;
431 int offset = 0;
432
433 ctx = PPP_CIPHER_CTX_new();
434 if (ctx) {
435
436 if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 0)) {
437
438 if (PPP_CipherUpdate(ctx, plain, &outlen, cipher, sizeof(cipher))) {
439
440 offset += outlen;
441
442 if (PPP_CipherFinal(ctx, plain+offset, &outlen)) {
443
444 if (memcmp(plain, expect, 80) == 0) {
445
446 success = 1;
447 }
448 }
449 }
450 }
451 PPP_CIPHER_CTX_free(ctx);
452 }
453
454 return success;
455}
456
457int main(int argc, char *argv[])
458{
459 int failure = 0;
460
461 if (!PPP_crypto_init()) {
462 printf("Couldn't initialize crypto test\n");
463 return -1;
464 }
465
466 if (!test_md4()) {
467 printf("MD4 test failed\n");
468 failure++;
469 }
470
471 if (!test_md5()) {
472 printf("MD5 test failed\n");
473 failure++;
474 }
475
476 if (!test_sha()) {
477 printf("SHA test failed\n");
478 failure++;
479 }
480
481 if (!test_des_encrypt()) {
482 printf("DES encryption test failed\n");
483 failure++;
484 }
485
486 if (!test_des_decrypt()) {
487 printf("DES decryption test failed\n");
488 failure++;
489 }
490
491 if (!PPP_crypto_deinit()) {
492 printf("Couldn't deinitialize crypto test\n");
493 return -1;
494 }
495
496 return failure;
497}
498
499#endif