add lfcrypto, base64

This commit is contained in:
Evan Burkey 2024-03-28 15:19:05 -07:00
parent 624bd7a23b
commit 360fb91e06
6 changed files with 258 additions and 0 deletions

View File

@ -15,6 +15,7 @@ set(SOURCES
src/string.c
src/vector.c
src/utility.c
src/crypto.c
)
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin"))

24
docs/crypto.md Normal file
View File

@ -0,0 +1,24 @@
# crypto
Cryptographic library
## Functions
### b64_encode
Encodes an `unsigned char *` into base64. User is responsible for freeing the
`char *` that is returned.
```c
char *b64_encode(const unsigned char *s, size_t sz);
```
### b64_decode
Decodes a base64 encoded set of bytes into an `unsigned char *`. User is responsible
for freeing the `unsigned char *` that is returned. `decode_sz` is an optional argument
in case you need to know the size of the decoded data, otherwise you can just pass `NULL`.
```c
unsigned char *b64_decode(const char *s, size_t sz, size_t *decode_sz);
```

9
include/lfcrypto.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef LIBFLINT_CRYPTO_H
#define LIBFLINT_CRYPTO_H
#include <stddef.h>
char *b64_encode(const unsigned char *s, size_t sz);
unsigned char *b64_decode(const char *s, size_t sz, size_t *decode_sz);
#endif // LIBFLINT_CRYPTO_H

View File

@ -7,6 +7,7 @@ nav:
- 'Modules':
- 'Binary Tree': 'binarytree.md'
- 'Boolean': 'bool.md'
- 'Crypto': 'crypto.md'
- 'Input': 'input.md'
- 'Linked List': 'linkedlist.md'
- 'Math': 'math.md'

202
src/crypto.c Normal file
View File

@ -0,0 +1,202 @@
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "lfcrypto.h"
#define B64_BUF_SZ (1024 * 64)
static const char b64_table[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
typedef struct {
char *ptr;
int count;
} b64_buf;
static int new_b64_buf(b64_buf *b) {
b->ptr = malloc(B64_BUF_SZ);
if (b->ptr == NULL) {
return 1;
}
b->count = 1;
return 0;
}
static int resize_b64_buf(b64_buf *b, size_t sz) {
if (sz > b->count * B64_BUF_SZ) {
while (sz > b->count * B64_BUF_SZ) {
b->count++;
}
b->ptr = realloc(b->ptr, B64_BUF_SZ * b->count);
if (b->ptr == NULL) {
return 1;
}
}
return 0;
}
char *b64_encode(const unsigned char *s, size_t sz) {
int i = 0;
b64_buf encbuf;
size_t size = 0;
unsigned char buf[4];
unsigned char tmp[3];
if (new_b64_buf(&encbuf) != 0) {
return NULL;
}
while (sz--) {
tmp[i++] = *(s++);
if (i == 3) {
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
if (resize_b64_buf(&encbuf, size + 4) != 0) {
free(encbuf.ptr);
return NULL;
}
for (i = 0; i < 4; ++i) {
encbuf.ptr[size++] = b64_table[buf[i]];
}
i = 0;
}
}
if (i > 0) {
for (int j = i; j < 3; ++j) {
tmp[j] = '\0';
}
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
for (int j = 0; (j < i + 1); ++j) {
if (resize_b64_buf(&encbuf, size + 1) != 0) {
free(encbuf.ptr);
return NULL;
}
encbuf.ptr[size++] = b64_table[buf[j]];
}
while (i++ < 3) {
if (resize_b64_buf(&encbuf, size + 1) != 0) {
free(encbuf.ptr);
return NULL;
}
encbuf.ptr[size++] = '=';
}
}
if (resize_b64_buf(&encbuf, size + 1) != 0) {
free(encbuf.ptr);
return NULL;
}
encbuf.ptr[size] = '\0';
return encbuf.ptr;
}
unsigned char *b64_decode(const char *s, size_t sz, size_t *decode_sz) {
int i = 0, j = 0, l = 0;
size_t size = 0;
b64_buf decbuf;
unsigned char buf[3];
unsigned char tmp[4];
if (new_b64_buf(&decbuf) != 0) {
return NULL;
}
while (sz--) {
if (s[j] == '=') {
break;
}
// Not base64 characters
if (!isalnum(s[j]) || s[j] == '+' || s[j] == '/') {
break;
}
tmp[i++] = s[j++];
if (i == 4) {
for (i = 0; i < 4; ++i) {
for (l = 0; l < 64; ++l) {
if (tmp[i] == b64_table[l]) {
tmp[i] = l;
break;
}
}
}
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
if (resize_b64_buf(&decbuf, size + 3) != 0) {
free(decbuf.ptr);
return NULL;
}
for (i = 0; i < 3; ++i) {
decbuf.ptr[size++] = buf[i];
}
i = 0;
}
}
if (i > 0) {
for (j = i; j < 4; ++j) {
tmp[j] = '\0';
}
for (j = 0; j < 4; ++j) {
for (l = 0; l < 64; ++l) {
if (tmp[j] == b64_table[l]) {
tmp[j] = l;
break;
}
}
}
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
if (resize_b64_buf(&decbuf, size + (i - 1)) != 0) {
free(decbuf.ptr);
return NULL;
}
for (j = 0; (j < i - 1); ++j) {
decbuf.ptr[size++] = buf[j];
}
}
if (resize_b64_buf(&decbuf, size + 1) != 0) {
free(decbuf.ptr);
return NULL;
}
decbuf.ptr[size] = '\0';
if (decode_sz != NULL) {
*decode_sz = size;
}
return (unsigned char*)decbuf.ptr;
}

View File

@ -10,6 +10,7 @@
#include "lfvector.h"
#include "lfmath.h"
#include "lfstring.h"
#include "lfcrypto.h"
#if defined(__APPLE__) || defined(__MACH__)
#include "lfmacos.h"
@ -308,6 +309,25 @@ void test_string() {
printf("Passes all string tests\n");
}
void test_crypto() {
char *in = "BUTT";
char *s = b64_encode(in, strlen(in));
assert(strcmp(s, "QlVUVA==") == 0);
free(s);
char *in2 = "a longer base64 test, apparently";
s = b64_encode(in2, strlen(in2));
assert(strcmp(s, "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk=") == 0);
free(s);
char *out2 = "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk=";
size_t s_sz = 0;
s = (char *)b64_decode(out2, strlen(out2), &s_sz);
assert(strcmp(s, "a longer base64 test, apparently") == 0);
assert(strlen(s) == s_sz);
free(s);
}
#if defined(__APPLE__) || defined(__MACH__)
void test_macos() {
printf("\n--- macOS TEST ---\n");
@ -331,6 +351,7 @@ int main() {
test_math();
test_vector();
test_string();
test_crypto();
#if defined(__APPLE__) || defined(__MACH__)
test_macos();