Add get_encryption_params.

This function is used to split the links to encrypted content into
useful parts.
This commit is contained in:
Érico Rolim 2020-09-13 20:17:03 -03:00
parent 71d813af3e
commit e20d8ae124
4 changed files with 123 additions and 5 deletions

View File

@ -6,7 +6,7 @@
/*
* Set print to true to print value, otherwise returns dynamic string with the number
*/
char *print_hex(uint8_t *buf, int len, bool print)
char *print_hex(const uint8_t *buf, int len, bool print)
{
char *rv = NULL;
@ -36,6 +36,38 @@ char *print_hex(uint8_t *buf, int len, bool print)
return rv;
}
// TODO:
// buffer to base64
// base64 to buffer
static bool is_hex_char(char c)
{
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
// from https://lemire.me/blog/2019/04/17/parsing-short-hexadecimal-strings-efficiently/
static uint32_t convert_hex_char(uint8_t c) {
return (c & 0xF) + 9 * (c >> 6);
}
static uint8_t assemble_u8(const char *cs)
{
uint8_t rv = 0;
for (int i = 0; i < 2; i++) {
int index = !i;
rv |= convert_hex_char(cs[i]) << (4 * index);
}
return rv;
}
int decode_hex(const char *s, uint8_t *output, int len)
{
for (int i = 0; i < len; i++) {
int j = i * 2;
int k = j + 1;
if (is_hex_char(s[j]) && is_hex_char(s[k])) {
output[i] = assemble_u8(s + j);
} else {
return -1;
}
}
return 0;
}

4
purr.h
View File

@ -55,6 +55,7 @@ int socket_write(void *, const uint8_t *, size_t);
/* urls.c */
int clean_up_link(const char *, char *, char *, char *);
int get_encryption_params(char *, uint8_t **, uint8_t **);
int host_connect(const char *, const char *, bool);
/* files.c */
@ -68,7 +69,8 @@ size_t mmap_to_ssl(struct transmission_information);
int send_and_receive(struct connection_information *);
/* formats.c */
char *print_hex(uint8_t *, int, bool);
char *print_hex(const uint8_t *, int, bool);
int decode_hex(const char *, uint8_t *, int);
/* encrypt.c */
struct mmap_file encrypt_mmap(struct mmap_file, uint8_t **, uint8_t **);

31
tests.c
View File

@ -20,6 +20,22 @@ static int compare_strings(const char *expected, const char *result, const char
return rv;
}
static int compare_arrays(const uint8_t *expected, const uint8_t *result, size_t len, const char *function)
{
int rv = 0;
printf("%s(): ", function);
if (memcmp(expected, result, len)) {
rv = 1;
puts("failure");
printf("expected: %s\ngot: %s\n", print_hex(expected, len, false), print_hex(result, len, false));
} else {
puts("success");
}
return rv;
}
int main()
{
int rv = 0;
@ -48,6 +64,21 @@ int main()
rv = compare_strings("/", path, "clean_up_link") ? 1 : rv;
rv = compare_strings("80", port, "clean_up_link") ? 1 : rv;
assert(portn == HTTP_PORT);
dirty = "https://bsd.ac/paste.html#sieqaqk_73fe_df51";
portn = clean_up_link(dirty, clean, path, port);
rv = compare_strings("bsd.ac", clean, "clean_up_link") ? 1 : rv;
rv = compare_strings("/paste.html#sieqaqk_73fe_df51", path, "clean_up_link") ? 1 : rv;
rv = compare_strings("443", port, "clean_up_link") ? 1 : rv;
assert(portn == HTTPS_PORT);
uint8_t key_exc[KEY_LEN] = {0x73, 0xfe};
uint8_t iv_exc[IV_LEN] = {0xdf, 0x51};
uint8_t *key, *iv;
int err = get_encryption_params(path, &key, &iv);
rv = compare_strings("/sieqaqk", path, "get_encryption_params") ? 1 : rv;
rv = compare_arrays(key_exc, key, KEY_LEN, "get_encryption_params") ? 1 : rv;
rv = compare_arrays(iv_exc, iv, IV_LEN, "get_encryption_params") ? 1 : rv;
assert(err == 0);
}
return rv;

53
urls.c
View File

@ -1,5 +1,6 @@
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
@ -55,6 +56,58 @@ int clean_up_link(const char *dirty, char *clean, char *path, char *port)
return portn;
}
#define MALFORM_ERROR(p) do{if((p) == NULL || (p)[1] == 0) {fputs("get_encryption_params(): malformed URL\n", stderr); return rv;}}while(0);
int get_encryption_params(char *path, uint8_t **keyp, uint8_t **ivp)
{
int rv = -1;
// parse path in format: "/paste.html#<actual_path>_<key>[_<iv>]"
// will update path to point to the proper piece
uint8_t *key = calloc(KEY_LEN, 1);
uint8_t *iv = calloc(IV_LEN, 1);
char *path_temp = calloc(strlen(path), 1);
if (key == NULL || iv == NULL || path_temp == NULL) {
perror("calloc()");
return rv;
}
*keyp = key;
*ivp = iv;
char *hash = strchr(path, '#');
MALFORM_ERROR(hash);
char *underscore = strchr(hash + 1, '_');
MALFORM_ERROR(underscore);
underscore[0] = 0;
sprintf(path_temp, "/%s", hash + 1);
char *key_start = underscore + 1;
underscore = strchr(key_start, '_');
MALFORM_ERROR(underscore);
underscore[0] = 0;
char *iv_start = underscore + 1;
size_t key_s_len = strlen(key_start), iv_s_len = strlen(iv_start);
// odd number of chars is an error, as well as being too big
if (key_s_len & 1 || iv_s_len & 1 || key_s_len / 2 > KEY_LEN || iv_s_len / 2 > IV_LEN) {
fputs("get_encryption_params(): malformed KEY and/or IV input\n", stderr);
return rv;
}
int err = decode_hex(key_start, key, key_s_len / 2)
| decode_hex(iv_start, iv, iv_s_len / 2);
if (err) {
fputs("get_encryption_params(): malformed KEY and/or IV input\n", stderr);
return rv;
}
strcpy(path, path_temp);
free(path_temp);
rv = 0;
return rv;
}
int host_connect(const char *host, const char *port, bool debug)
{
struct addrinfo hints = { 0 }, *si = NULL;