1 /* ppp-crypto.c - Generic API for access to crypto/digest functions.
3 * Copyright (c) 2022 Eivind Næss. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
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.
38 #include "ppp-crypto.h"
39 #include "ppp-crypto-priv.h"
41 #ifdef PPP_WITH_OPENSSL
42 #include <openssl/opensslv.h>
45 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
46 #include <openssl/provider.h>
49 OSSL_PROVIDER *legacy;
50 OSSL_PROVIDER *provider;
54 PPP_MD_CTX *PPP_MD_CTX_new()
56 return (PPP_MD_CTX*) calloc(1, sizeof(PPP_MD_CTX));
59 void PPP_MD_CTX_free(PPP_MD_CTX* ctx)
62 if (ctx->md.clean_fn) {
63 ctx->md.clean_fn(ctx);
69 int PPP_DigestInit(PPP_MD_CTX *ctx, const PPP_MD *type)
73 if (ctx->md.init_fn) {
74 return ctx->md.init_fn(ctx);
80 int PPP_DigestUpdate(PPP_MD_CTX *ctx, const void *data, size_t length)
82 if (ctx && ctx->md.update_fn) {
83 return ctx->md.update_fn(ctx, data, length);
88 int PPP_DigestFinal(PPP_MD_CTX *ctx, unsigned char *out, unsigned int *outlen)
90 if (ctx && ctx->md.final_fn) {
91 return ctx->md.final_fn(ctx, out, outlen);
96 PPP_CIPHER_CTX *PPP_CIPHER_CTX_new(void)
98 return calloc(1, sizeof(PPP_CIPHER_CTX));
101 void PPP_CIPHER_CTX_free(PPP_CIPHER_CTX *ctx)
104 if (ctx->cipher.clean_fn) {
105 ctx->cipher.clean_fn(ctx);
107 memset(ctx->iv, 0, sizeof(ctx->iv));
108 memset(ctx->key, 0, sizeof(ctx->key));
113 int PPP_CipherInit(PPP_CIPHER_CTX *ctx, const PPP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int encr)
117 ctx->cipher = *cipher;
118 if (ctx->cipher.init_fn) {
119 ctx->cipher.init_fn(ctx, key, iv);
126 int PPP_CipherUpdate(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
128 if (ctx && ctx->cipher.update_fn) {
129 return ctx->cipher.update_fn(ctx, out, outl, in, inl);
134 int PPP_CipherFinal(PPP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
136 if (ctx && ctx->cipher.final_fn) {
137 return ctx->cipher.final_fn(ctx, out, outl);
142 void PPP_CIPHER_CTX_set_cipher_data(PPP_CIPHER_CTX *ctx, const unsigned char *key)
144 if (ctx && ctx->cipher.set_key_fn) {
145 ctx->cipher.set_key_fn(ctx, key);
150 int PPP_crypto_init()
154 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
155 g_crypto_ctx.legacy = OSSL_PROVIDER_load(NULL, "legacy");
156 if (g_crypto_ctx.legacy == NULL)
161 g_crypto_ctx.provider = OSSL_PROVIDER_load(NULL, "default");
162 if (g_crypto_ctx.provider == NULL)
174 int PPP_crypto_deinit()
176 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
177 if (g_crypto_ctx.legacy) {
178 OSSL_PROVIDER_unload(g_crypto_ctx.legacy);
179 g_crypto_ctx.legacy = NULL;
182 if (g_crypto_ctx.provider) {
183 OSSL_PROVIDER_unload(g_crypto_ctx.provider);
184 g_crypto_ctx.provider = NULL;
195 PPP_MD_CTX* ctx = NULL;
198 unsigned char data[84] = {
199 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
200 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
201 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
202 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
203 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
204 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
205 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
206 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
207 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
208 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
209 0x6b, 0x65, 0x79, 0x2e
212 unsigned int hash_len;
213 unsigned char hash[MD4_DIGEST_LENGTH];
214 unsigned char result[MD4_DIGEST_LENGTH] = {
215 0x58, 0xcb, 0x37, 0x91, 0x1d, 0x06, 0x7b, 0xdf,
216 0xfd, 0x48, 0x6d, 0x87, 0x4a, 0x35, 0x5b, 0xd4
219 ctx = PPP_MD_CTX_new();
222 if (PPP_DigestInit(ctx, PPP_md4())) {
224 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
226 hash_len = sizeof(hash);
227 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
229 if (memcmp(hash, result, MD4_DIGEST_LENGTH) == 0) {
235 PPP_MD_CTX_free(ctx);
243 PPP_MD_CTX* ctx = NULL;
246 unsigned char data[84] = {
247 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
248 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
249 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
250 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
251 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
252 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
253 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
254 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
255 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
256 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
257 0x6b, 0x65, 0x79, 0x2e
260 unsigned int hash_len;
261 unsigned char hash[MD5_DIGEST_LENGTH];
262 unsigned char result[MD5_DIGEST_LENGTH] = {
263 0x8b, 0xe3, 0x5e, 0x2c, 0x9f, 0x95, 0xbf, 0x4e,
264 0x16, 0xe4, 0x53, 0xbe, 0x52, 0xf4, 0xbc, 0x4e
267 ctx = PPP_MD_CTX_new();
270 if (PPP_DigestInit(ctx, PPP_md5())) {
272 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
274 hash_len = sizeof(hash);
275 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
277 if (memcmp(hash, result, MD5_DIGEST_LENGTH) == 0) {
283 PPP_MD_CTX_free(ctx);
291 PPP_MD_CTX* ctx = NULL;
294 unsigned char data[84] = {
295 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
296 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
297 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
298 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
299 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
300 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
301 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
302 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
303 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
304 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
305 0x6b, 0x65, 0x79, 0x2e
308 unsigned int hash_len;
309 unsigned char hash[SHA_DIGEST_LENGTH];
310 unsigned char result[SHA_DIGEST_LENGTH] = {
311 0xa8, 0x03, 0xae, 0x21, 0x30, 0xd8, 0x40, 0xbe,
312 0x27, 0xa3, 0x47, 0xc7, 0x7a, 0x90, 0xe6, 0xa3,
313 0x5b, 0xd5, 0x0e, 0x45
316 ctx = PPP_MD_CTX_new();
319 if (PPP_DigestInit(ctx, PPP_sha1())) {
321 if (PPP_DigestUpdate(ctx, &data, sizeof(data))) {
323 hash_len = sizeof(hash);
324 if (PPP_DigestFinal(ctx, hash, &hash_len)) {
326 if (memcmp(hash, result, SHA_DIGEST_LENGTH) == 0) {
332 PPP_MD_CTX_free(ctx);
338 int test_des_encrypt()
340 PPP_CIPHER_CTX* ctx = NULL;
343 unsigned char key[8] = {
344 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
347 unsigned char plain[80] = {
348 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
349 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
350 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
351 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
352 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
353 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
354 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
355 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
356 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
357 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
359 unsigned char expect[80] = {
360 0x5d, 0xa7, 0x47, 0xc5, 0x1a, 0xb1, 0x71, 0xff,
361 0xc8, 0x45, 0x7c, 0xa7, 0x07, 0xec, 0x4b, 0x13,
362 0x47, 0x55, 0x77, 0xbc, 0xcf, 0x71, 0xd9, 0x27,
363 0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
364 0x3e, 0x74, 0x38, 0x29, 0x48, 0xb0, 0xd2, 0xe2,
365 0x18, 0x45, 0xdd, 0x8a, 0x9b, 0x8d, 0x40, 0xec,
366 0x9e, 0x0c, 0x41, 0xa3, 0x36, 0x40, 0xf5, 0x91,
367 0x41, 0x44, 0xde, 0xa1, 0xb5, 0x9d, 0x39, 0x99,
368 0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
369 0xee, 0xe3, 0xbe, 0x0b, 0x83, 0x36, 0xe1, 0x25
372 unsigned char cipher[80] = {};
377 ctx = PPP_CIPHER_CTX_new();
380 if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 1)) {
382 if (PPP_CipherUpdate(ctx, cipher, &cipher_len, plain, sizeof(plain))) {
384 offset += cipher_len;
386 if (PPP_CipherFinal(ctx, cipher+offset, &cipher_len)) {
388 if (memcmp(cipher, expect, 80) == 0) {
395 PPP_CIPHER_CTX_free(ctx);
402 int test_des_decrypt()
404 PPP_CIPHER_CTX* ctx = NULL;
407 unsigned char key[8] = {
408 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
411 unsigned char cipher[80] = {
412 0x5d, 0xa7, 0x47, 0xc5, 0x1a, 0xb1, 0x71, 0xff,
413 0xc8, 0x45, 0x7c, 0xa7, 0x07, 0xec, 0x4b, 0x13,
414 0x47, 0x55, 0x77, 0xbc, 0xcf, 0x71, 0xd9, 0x27,
415 0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
416 0x3e, 0x74, 0x38, 0x29, 0x48, 0xb0, 0xd2, 0xe2,
417 0x18, 0x45, 0xdd, 0x8a, 0x9b, 0x8d, 0x40, 0xec,
418 0x9e, 0x0c, 0x41, 0xa3, 0x36, 0x40, 0xf5, 0x91,
419 0x41, 0x44, 0xde, 0xa1, 0xb5, 0x9d, 0x39, 0x99,
420 0x23, 0x12, 0x2a, 0x17, 0x20, 0xad, 0xc1, 0x19,
421 0xee, 0xe3, 0xbe, 0x0b, 0x83, 0x36, 0xe1, 0x25
424 unsigned char expect[80] = {
425 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
426 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69,
427 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
428 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
429 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
430 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,
431 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
432 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74,
433 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
434 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20
437 unsigned char plain[80] = {};
441 ctx = PPP_CIPHER_CTX_new();
444 if (PPP_CipherInit(ctx, PPP_des_ecb(), key, NULL, 0)) {
446 if (PPP_CipherUpdate(ctx, plain, &outlen, cipher, sizeof(cipher))) {
450 if (PPP_CipherFinal(ctx, plain+offset, &outlen)) {
452 if (memcmp(plain, expect, 80) == 0) {
459 PPP_CIPHER_CTX_free(ctx);
465 int main(int argc, char *argv[]) {
468 if (!PPP_crypto_init()) {
469 printf("Couldn't initialize crypto test\n");
474 printf("MD4 test failed\n");
479 printf("MD5 test failed\n");
484 printf("SHA test failed\n");
488 if (!test_des_encrypt()) {
489 printf("DES encryption test failed\n");
493 /* Bug in DES EVP decryption, TODO: file an issue
494 if (!test_des_decrypt()) {
495 printf("DES decryption test failed\n");
500 if (!PPP_crypto_deinit()) {
501 printf("Couldn't deinitialize crypto test\n");