feat: Populate repo

This commit is contained in:
2023-03-29 14:02:05 +02:00
commit 28bec5ebb8
168 changed files with 17860 additions and 0 deletions

148
lib/array.c Normal file
View File

@@ -0,0 +1,148 @@
/* array.c */
#include <stdio.h>
#include <stdlib.h>
/** @brief Prints the values of `arr` into `STDOUT`
*
* C does not usually come with a way to print arrays,
* this function makes that possible.
*
* @param arr The array to print
* @param size The size of `arr`
*
* @returns void
*/
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("Array[%d]\t= %d\n", i, arr[i]);
}
}
/** @brief Find the key `index` of `needle` in `arr`
*
* In order to find a value's place in an array, we can
* use the following function to find `needle` in `arr`.
*
* @param arr The array to look through
* @param size The size of `arr`
* @param needle The value to search for
*
* @returns index The index of `needle` if found, else `-1`
*/
int find_index(int arr[], int size, int needle) {
for (int i = 0; i < size; i++) {
if (arr[i] == needle) return i;
}
return -1;
}
/** @brief Find the highest three numbers in `arr`
*
* In order to find the highest three values in an array,
* a loop and a set of if statements can be used.
*
* @param arr The array to look through
* @param size The size of `arr`
*
* @returns max An array with the highest three numbers in `arr`
*/
int* largest_three(int arr[], int size) {
int* max = malloc(3);
max[0] = arr[0];
max[1] = arr[1];
max[2] = arr[2];
for (int i = 0; i < size; i++) {
if (arr[i] > max[0]) {
max[2] = max[1];
max[1] = max[0];
max[0] = arr[i];
}
else if (arr[i] > max[1]) {
max[2] = max[1];
max[1] = arr[i];
}
else if (arr[i] > max[2]) {
max[2] = arr[i];
}
}
return max;
}
/** @brief Inverse the contents of `arr`
*
* This function will return the inversed version of `arr`.
* This will mean that arr[last] = inversed_array[first].
*
* @param arr The array to inverse
* @param size The size of `arr`
*
* @returns inversed_array An inversed version of `arr`
*/
int* inverse_array(int arr[], int size) {
int* inversed_array = malloc(size);
for (int i = size; i > 0; i--) {
inversed_array[size - i] = arr[i - 1];
}
return inversed_array;
}
/** @brief Sorts `arr` alphabetically using bubble sorting
*
* In order to alphabetically sort `arr` filled with `char`,
* the bubble sorting algorithm can be used.
* (THIS FUNCTION OVERWRITES `arr`.)
*
* @param arr The array to sort
* @param size The size of `arr`
*
* @returns void
*/
void sort_char_array(char arr[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i -1; j++) {
if (arr[j] > arr[j + 1]) {
char temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/** @brief Filters out any non-lowercase characters from `arr`,
* then passes it to `sort_char_array()`
*
* In order to filter out any non-lowercase characters and then
* sort the array alphabetically, the function below is used.
* It will loop through the array and check if the charcodes are inbetween
* 'a' and 'z', if not removes them.
*
* @param arr The array to filter and sort
* @param size The size of `arr`
*
* @returns void
*/
void filter_lowercase_and_sort(char arr[], int size) {
int count = 0;
for (int i = 0; i < size; i++) {
if (arr[i] >= 'a' && arr[i] <= 'z') {
arr[count++] = arr[i];
}
}
sort_char_array(arr, count);
}
// void print_array(void *arr, int size, size_t elem_size, char *format) {
// for (int i = 0; i < size; i++) {
// printf("Array[%d] = ", i);
// char *elem = (char *) arr + i * elem_size;
// printf(format, *(int *) elem);
// printf("\n");
// }
// }

155
lib/base64.c Normal file
View File

@@ -0,0 +1,155 @@
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <base64.h>
static const unsigned char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* base64_encode - Base64 encode
* @src: Data to be encoded
* @len: Length of the data to be encoded
* @out_len: Pointer to output length variable, or %NULL if not used
* Returns: Allocated buffer of out_len bytes of encoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer. Returned buffer is
* nul terminated to make it easier to use as a C string. The nul terminator is
* not included in out_len.
*/
unsigned char * base64_encode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char *out, *pos;
const unsigned char *end, *in;
size_t olen;
int line_len;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
olen += olen / 72; /* line feeds */
olen++; /* nul termination */
if (olen < len)
return NULL; /* integer overflow */
out = malloc(olen);
if (out == NULL)
return NULL;
end = src + len;
in = src;
pos = out;
line_len = 0;
while (end - in >= 3) {
*pos++ = base64_table[in[0] >> 2];
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = base64_table[in[2] & 0x3f];
in += 3;
line_len += 4;
if (line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
}
if (end - in) {
*pos++ = base64_table[in[0] >> 2];
if (end - in == 1) {
*pos++ = base64_table[(in[0] & 0x03) << 4];
*pos++ = '=';
} else {
*pos++ = base64_table[((in[0] & 0x03) << 4) |
(in[1] >> 4)];
*pos++ = base64_table[(in[1] & 0x0f) << 2];
}
*pos++ = '=';
line_len += 4;
}
if (line_len)
*pos++ = '\n';
*pos = '\0';
if (out_len)
*out_len = pos - out;
return out;
}
/**
* base64_decode - Base64 decode
* @src: Data to be decoded
* @len: Length of the data to be decoded
* @out_len: Pointer to output length variable
* Returns: Allocated buffer of out_len bytes of decoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer.
*/
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
int pad = 0;
memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++)
dtable[base64_table[i]] = (unsigned char) i;
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++) {
if (dtable[src[i]] != 0x80)
count++;
}
if (count == 0 || count % 4)
return NULL;
olen = count / 4 * 3;
pos = out = malloc(olen);
if (out == NULL)
return NULL;
count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[src[i]];
if (tmp == 0x80)
continue;
if (src[i] == '=')
pad++;
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad) {
if (pad == 1)
pos--;
else if (pad == 2)
pos -= 2;
else {
/* Invalid padding */
free(out);
return NULL;
}
break;
}
}
}
*out_len = pos - out;
return out;
}

124
lib/handshake.c Normal file
View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2016-2020 Davidson Francis <davidsondfgl@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#define _POSIX_C_SOURCE 200809L
#include <base64.h>
#include <sha1.h>
#include <ws.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @dir src/
* @brief Handshake routines directory
*
* @file handshake.c
* @brief Handshake routines.
*/
/**
* @brief Gets the field Sec-WebSocket-Accept on response, by
* an previously informed key.
*
* @param wsKey Sec-WebSocket-Key
* @param dest source to be stored the value.
*
* @return Returns 0 if success and a negative number
* otherwise.
*
* @attention This is part of the internal API and is documented just
* for completeness.
*/
int get_handshake_accept(char *wsKey, unsigned char **dest)
{
unsigned char hash[SHA1HashSize]; /* SHA-1 Hash. */
SHA1Context ctx; /* SHA-1 Context. */
char *str; /* WebSocket key + magic string. */
/* Invalid key. */
if (!wsKey)
return (-1);
str = calloc(1, sizeof(char) * (WS_KEY_LEN + WS_MS_LEN + 1));
if (!str)
return (-1);
strncpy(str, wsKey, WS_KEY_LEN);
strcat(str, MAGIC_STRING);
SHA1Reset(&ctx);
SHA1Input(&ctx, (const uint8_t *)str, WS_KEYMS_LEN);
SHA1Result(&ctx, hash);
*dest = base64_encode(hash, SHA1HashSize, NULL);
*(*dest + strlen((const char *)*dest) - 1) = '\0';
free(str);
return (0);
}
/**
* @brief Gets the complete response to accomplish a succesfully
* handshake.
*
* @param hsrequest Client request.
* @param hsresponse Server response.
*
* @return Returns 0 if success and a negative number
* otherwise.
*
* @attention This is part of the internal API and is documented just
* for completeness.
*/
int get_handshake_response(char *hsrequest, char **hsresponse)
{
unsigned char *accept; /* Accept message. */
char *saveptr; /* strtok_r() pointer. */
char *s; /* Current string. */
int ret; /* Return value. */
saveptr = NULL;
for (s = strtok_r(hsrequest, "\r\n", &saveptr); s != NULL;
s = strtok_r(NULL, "\r\n", &saveptr))
{
if (strstr(s, WS_HS_REQ) != NULL)
break;
}
/* Ensure that we have a valid pointer. */
if (s == NULL)
return (-1);
saveptr = NULL;
s = strtok_r(s, " ", &saveptr);
s = strtok_r(NULL, " ", &saveptr);
ret = get_handshake_accept(s, &accept);
if (ret < 0)
return (ret);
*hsresponse = malloc(sizeof(char) * WS_HS_ACCLEN);
if (*hsresponse == NULL)
return (-1);
strcpy(*hsresponse, WS_HS_ACCEPT);
strcat(*hsresponse, (const char *)accept);
strcat(*hsresponse, "\r\n\r\n");
free(accept);
return (0);
}

56
lib/json.c Normal file
View File

@@ -0,0 +1,56 @@
#include <string.h>
#include <json-c/json.h>
// Structs for JSON data to parse
#include "../include/json.h"
/** @brief Casts a JSON object from string to `Envelope`
*
* Iterates through the fields of `json` and casts the wanted
* fields to `Envelope`. Returns the following codes:
* 0 = Success
* 1 = Malformed json object
* 2 = Missing `payload` field
* 3 = Missing `auth` field
*
* @param json The string to cast
* @param Envelope the Envelope struct to cast into
*
* @returns The status code
*/
int parse_envelope_json(const char* json, Envelope* envelope) {
json_object* parsed = json_tokener_parse(json);
if (!parsed) return MISSING_JSON;
json_object* parsed_payload;
if (json_object_object_get_ex(parsed, "payload", &parsed_payload)) {
json_object* parsed_sensorId;
if (json_object_object_get_ex(parsed_payload, "sensorId", &parsed_sensorId)) {
envelope->payload.sensorId = strdup(json_object_get_string(parsed_sensorId));
} else {
envelope->payload.sensorId = "Nil";
}
json_object* parsed_sensorData;
if (json_object_object_get_ex(parsed_payload, "sensorData", &parsed_sensorData)) {
envelope->payload.sensorData = strdup(json_object_get_string(parsed_sensorData));
} else {
envelope->payload.sensorData = "Nil";
}
} else {
return MISSING_PAYLOAD;
}
json_object* parsed_auth;
if (json_object_object_get_ex(parsed, "auth", &parsed_auth)) {
envelope->auth = strdup(json_object_get_string(parsed_auth));
} else {
return MISSING_AUTH;
}
json_object_put(parsed);
return SUCCESS;
}

364
lib/libtap.c Normal file
View File

@@ -0,0 +1,364 @@
/*
libtap - Write tests in C
Copyright 2012 Jake Gelbman <gelbman@gmail.com>
This file is licensed under the LGPL
*/
#define _DEFAULT_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "libtap.h"
static int expected_tests = NO_PLAN;
static int failed_tests;
static int current_test;
static char *todo_mesg;
static char *
vstrdupf (const char *fmt, va_list args) {
char *str;
int size;
va_list args2;
va_copy(args2, args);
if (!fmt)
fmt = "";
size = vsnprintf(NULL, 0, fmt, args2) + 2;
str = malloc(size);
if (!str) {
perror("malloc error");
exit(1);
}
vsprintf(str, fmt, args);
va_end(args2);
return str;
}
void
tap_plan (int tests, const char *fmt, ...) {
expected_tests = tests;
if (tests == SKIP_ALL) {
char *why;
va_list args;
va_start(args, fmt);
why = vstrdupf(fmt, args);
va_end(args);
printf("1..0 ");
diag("SKIP %s\n", why);
exit(0);
}
if (tests != NO_PLAN) {
printf("1..%d\n", tests);
}
}
int
vok_at_loc (const char *file, int line, int test, const char *fmt,
va_list args)
{
char *name = vstrdupf(fmt, args);
if (!test) {
printf("not ");
}
printf("ok %d", ++current_test);
if (*name)
printf(" - %s", name);
if (todo_mesg) {
printf(" # TODO");
if (*todo_mesg)
printf(" %s", todo_mesg);
}
printf("\n");
if (!test) {
printf("# Failed ");
if (todo_mesg)
printf("(TODO) ");
printf("test ");
if (*name)
printf("'%s'\n# ", name);
printf("at %s line %d.\n", file, line);
if (!todo_mesg)
failed_tests++;
}
free(name);
return test;
}
int
ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vok_at_loc(file, line, test, fmt, args);
va_end(args);
return test;
}
static int
mystrcmp (const char *a, const char *b) {
return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
}
#define eq(a, b) (!mystrcmp(a, b))
#define ne(a, b) (mystrcmp(a, b))
int
is_at_loc (const char *file, int line, const char *got, const char *expected,
const char *fmt, ...)
{
int test = eq(got, expected);
va_list args;
va_start(args, fmt);
vok_at_loc(file, line, test, fmt, args);
va_end(args);
if (!test) {
diag(" got: '%s'", got);
diag(" expected: '%s'", expected);
}
return test;
}
int
isnt_at_loc (const char *file, int line, const char *got, const char *expected,
const char *fmt, ...)
{
int test = ne(got, expected);
va_list args;
va_start(args, fmt);
vok_at_loc(file, line, test, fmt, args);
va_end(args);
if (!test) {
diag(" got: '%s'", got);
diag(" expected: anything else");
}
return test;
}
int
cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
const char *fmt, ...)
{
int test = eq(op, "||") ? a || b
: eq(op, "&&") ? a && b
: eq(op, "|") ? a | b
: eq(op, "^") ? a ^ b
: eq(op, "&") ? a & b
: eq(op, "==") ? a == b
: eq(op, "!=") ? a != b
: eq(op, "<") ? a < b
: eq(op, ">") ? a > b
: eq(op, "<=") ? a <= b
: eq(op, ">=") ? a >= b
: eq(op, "<<") ? a << b
: eq(op, ">>") ? a >> b
: eq(op, "+") ? a + b
: eq(op, "-") ? a - b
: eq(op, "*") ? a * b
: eq(op, "/") ? a / b
: eq(op, "%") ? a % b
: diag("unrecognized operator '%s'", op);
va_list args;
va_start(args, fmt);
vok_at_loc(file, line, test, fmt, args);
va_end(args);
if (!test) {
diag(" %d", a);
diag(" %s", op);
diag(" %d", b);
}
return test;
}
static int
find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) {
size_t i;
if (a == b)
return 0;
if (!a || !b)
return 2;
for (i = 0; i < n; i++) {
if (a[i] != b[i]) {
*offset = i;
return 1;
}
}
return 0;
}
int
cmp_mem_at_loc (const char *file, int line, const void *got,
const void *expected, size_t n, const char *fmt, ...)
{
size_t offset;
int diff = find_mem_diff(got, expected, n, &offset);
va_list args;
va_start(args, fmt);
vok_at_loc(file, line, !diff, fmt, args);
va_end(args);
if (diff == 1) {
diag(" Difference starts at offset %d", offset);
diag(" got: 0x%02x", ((const unsigned char *)got)[offset]);
diag(" expected: 0x%02x", ((const unsigned char *)expected)[offset]);
}
else if (diff == 2) {
diag(" got: %s", got ? "not NULL" : "NULL");
diag(" expected: %s", expected ? "not NULL" : "NULL");
}
return !diff;
}
int
diag (const char *fmt, ...) {
va_list args;
char *mesg, *line;
int i;
va_start(args, fmt);
if (!fmt) {
va_end(args);
return 0;
}
mesg = vstrdupf(fmt, args);
line = mesg;
for (i = 0; *line; i++) {
char c = mesg[i];
if (!c || c == '\n') {
mesg[i] = '\0';
printf("# %s\n", line);
if (!c)
break;
mesg[i] = c;
line = mesg + i + 1;
}
}
free(mesg);
va_end(args);
return 0;
}
int
exit_status () {
int retval = 0;
if (expected_tests == NO_PLAN) {
printf("1..%d\n", current_test);
}
else if (current_test != expected_tests) {
diag("Looks like you planned %d test%s but ran %d.",
expected_tests, expected_tests > 1 ? "s" : "", current_test);
retval = 2;
}
if (failed_tests) {
diag("Looks like you failed %d test%s of %d run.",
failed_tests, failed_tests > 1 ? "s" : "", current_test);
retval = 1;
}
return retval;
}
int
bail_out (int ignore, const char *fmt, ...) {
va_list args;
(void) ignore;
va_start(args, fmt);
printf("Bail out! ");
vprintf(fmt, args);
printf("\n");
va_end(args);
exit(255);
return 0;
}
void
tap_skip (int n, const char *fmt, ...) {
char *why;
va_list args;
va_start(args, fmt);
why = vstrdupf(fmt, args);
va_end(args);
while (n --> 0) {
printf("ok %d ", ++current_test);
diag("skip %s\n", why);
}
free(why);
}
void
tap_todo (int ignore, const char *fmt, ...) {
va_list args;
(void) ignore;
va_start(args, fmt);
todo_mesg = vstrdupf(fmt, args);
va_end(args);
}
void
tap_end_todo () {
free(todo_mesg);
todo_mesg = NULL;
}
#ifndef _WIN32
#include <sys/mman.h>
#include <sys/param.h>
#include <regex.h>
#ifndef MAP_ANONYMOUS
#ifdef MAP_ANON
#define MAP_ANONYMOUS MAP_ANON
#else
#error "System does not support mapping anonymous pages"
#endif
#endif
/* Create a shared memory int to keep track of whether a piece of code executed
dies. to be used in the dies_ok and lives_ok macros. */
int
tap_test_died (int status) {
static int *test_died = NULL;
int prev;
if (!test_died) {
test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*test_died = 0;
}
prev = *test_died;
*test_died = status;
return prev;
}
int
like_at_loc (int for_match, const char *file, int line, const char *got,
const char *expected, const char *fmt, ...)
{
int test;
regex_t re;
va_list args;
int err = regcomp(&re, expected, REG_EXTENDED);
if (err) {
char errbuf[256];
regerror(err, &re, errbuf, sizeof errbuf);
fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
expected, errbuf, file, line);
exit(255);
}
err = regexec(&re, got, 0, NULL, 0);
regfree(&re);
test = for_match ? !err : err;
va_start(args, fmt);
vok_at_loc(file, line, test, fmt, args);
va_end(args);
if (!test) {
if (for_match) {
diag(" '%s'", got);
diag(" doesn't match: '%s'", expected);
}
else {
diag(" '%s'", got);
diag(" matches: '%s'", expected);
}
}
return test;
}
#endif

389
lib/sha1.c Normal file
View File

@@ -0,0 +1,389 @@
/*
* sha1.c
*
* Description:
* This file implements the Secure Hashing Algorithm 1 as
* defined in FIPS PUB 180-1 published April 17, 1995.
*
* The SHA-1, produces a 160-bit message digest for a given
* data stream. It should take about 2**n steps to find a
* message with the same digest as a given message and
* 2**(n/2) to find any two messages with the same digest,
* when n is the digest size in bits. Therefore, this
* algorithm can serve as a means of providing a
* "fingerprint" for a message.
*
* Portability Issues:
* SHA-1 is defined in terms of 32-bit "words". This code
* uses <stdint.h> (included via "sha1.h" to define 32 and 8
* bit unsigned integer types. If your C compiler does not
* support 32 bit unsigned integers, this code is not
* appropriate.
*
* Caveats:
* SHA-1 is designed to work with messages less than 2^64 bits
* long. Although SHA-1 allows a message digest to be generated
* for messages of any number of bits less than 2^64, this
* implementation only works with messages with a length that is
* a multiple of the size of an 8-bit character.
*
*/
#include <sha1.h>
/*
* Define the SHA1 circular left shift macro
*/
#define SHA1CircularShift(bits,word) \
(((word) << (bits)) | ((word) >> (32-(bits))))
/* Local Function Prototyptes */
void SHA1PadMessage(SHA1Context *);
void SHA1ProcessMessageBlock(SHA1Context *);
/*
* SHA1Reset
*
* Description:
* This function will initialize the SHA1Context in preparation
* for computing a new SHA1 message digest.
*
* Parameters:
* context: [in/out]
* The context to reset.
*
* Returns:
* sha Error Code.
*
*/
int SHA1Reset(SHA1Context *context)
{
if (!context)
{
return shaNull;
}
context->Length_Low = 0;
context->Length_High = 0;
context->Message_Block_Index = 0;
context->Intermediate_Hash[0] = 0x67452301;
context->Intermediate_Hash[1] = 0xEFCDAB89;
context->Intermediate_Hash[2] = 0x98BADCFE;
context->Intermediate_Hash[3] = 0x10325476;
context->Intermediate_Hash[4] = 0xC3D2E1F0;
context->Computed = 0;
context->Corrupted = 0;
return shaSuccess;
}
/*
* SHA1Result
*
* Description:
* This function will return the 160-bit message digest into the
* Message_Digest array provided by the caller.
* NOTE: The first octet of hash is stored in the 0th element,
* the last octet of hash in the 19th element.
*
* Parameters:
* context: [in/out]
* The context to use to calculate the SHA-1 hash.
* Message_Digest: [out]
* Where the digest is returned.
*
* Returns:
* sha Error Code.
*
*/
int SHA1Result( SHA1Context *context,
uint8_t Message_Digest[SHA1HashSize])
{
int i;
if (!context || !Message_Digest)
{
return shaNull;
}
if (context->Corrupted)
{
return context->Corrupted;
}
if (!context->Computed)
{
SHA1PadMessage(context);
for(i=0; i<64; ++i)
{
/* message may be sensitive, clear it out */
context->Message_Block[i] = 0;
}
context->Length_Low = 0; /* and clear length */
context->Length_High = 0;
context->Computed = 1;
}
for(i = 0; i < SHA1HashSize; ++i)
{
Message_Digest[i] = context->Intermediate_Hash[i>>2]
>> 8 * ( 3 - ( i & 0x03 ) );
}
return shaSuccess;
}
/*
* SHA1Input
*
* Description:
* This function accepts an array of octets as the next portion
* of the message.
*
* Parameters:
* context: [in/out]
* The SHA context to update
* message_array: [in]
* An array of characters representing the next portion of
* the message.
* length: [in]
* The length of the message in message_array
*
* Returns:
* sha Error Code.
*
*/
int SHA1Input( SHA1Context *context,
const uint8_t *message_array,
unsigned length)
{
if (!length)
{
return shaSuccess;
}
if (!context || !message_array)
{
return shaNull;
}
if (context->Computed)
{
context->Corrupted = shaStateError;
return shaStateError;
}
if (context->Corrupted)
{
return context->Corrupted;
}
while(length-- && !context->Corrupted)
{
context->Message_Block[context->Message_Block_Index++] =
(*message_array & 0xFF);
context->Length_Low += 8;
if (context->Length_Low == 0)
{
context->Length_High++;
if (context->Length_High == 0)
{
/* Message is too long */
context->Corrupted = 1;
}
}
if (context->Message_Block_Index == 64)
{
SHA1ProcessMessageBlock(context);
}
message_array++;
}
return shaSuccess;
}
/*
* SHA1ProcessMessageBlock
*
* Description:
* This function will process the next 512 bits of the message
* stored in the Message_Block array.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
* Many of the variable names in this code, especially the
* single character names, were used because those were the
* names used in the publication.
*
*
*/
void SHA1ProcessMessageBlock(SHA1Context *context)
{
const uint32_t K[] = { /* Constants defined in SHA-1 */
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
uint32_t temp; /* Temporary word value */
uint32_t W[80]; /* Word sequence */
uint32_t A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = context->Message_Block[t * 4] << 24;
W[t] |= context->Message_Block[t * 4 + 1] << 16;
W[t] |= context->Message_Block[t * 4 + 2] << 8;
W[t] |= context->Message_Block[t * 4 + 3];
}
for(t = 16; t < 80; t++)
{
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = context->Intermediate_Hash[0];
B = context->Intermediate_Hash[1];
C = context->Intermediate_Hash[2];
D = context->Intermediate_Hash[3];
E = context->Intermediate_Hash[4];
for(t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Intermediate_Hash[0] += A;
context->Intermediate_Hash[1] += B;
context->Intermediate_Hash[2] += C;
context->Intermediate_Hash[3] += D;
context->Intermediate_Hash[4] += E;
context->Message_Block_Index = 0;
}
/*
* SHA1PadMessage
*
* Description:
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64
* bits represent the length of the original message. All bits in
* between should be 0. This function will pad the message
* according to those rules by filling the Message_Block array
* accordingly. It will also call the ProcessMessageBlock function
* provided appropriately. When it returns, it can be assumed that
* the message digest has been computed.
*
* Parameters:
* context: [in/out]
* The context to pad
* ProcessMessageBlock: [in]
* The appropriate SHA*ProcessMessageBlock function
* Returns:
* Nothing.
*
*/
void SHA1PadMessage(SHA1Context *context)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (context->Message_Block_Index > 55)
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 64)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
SHA1ProcessMessageBlock(context);
while(context->Message_Block_Index < 56)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
}
else
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 56)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
}
/*
* Store the message length as the last 8 octets
*/
context->Message_Block[56] = context->Length_High >> 24;
context->Message_Block[57] = context->Length_High >> 16;
context->Message_Block[58] = context->Length_High >> 8;
context->Message_Block[59] = context->Length_High;
context->Message_Block[60] = context->Length_Low >> 24;
context->Message_Block[61] = context->Length_Low >> 16;
context->Message_Block[62] = context->Length_Low >> 8;
context->Message_Block[63] = context->Length_Low;
SHA1ProcessMessageBlock(context);
}

88
lib/utf8.c Normal file
View File

@@ -0,0 +1,88 @@
/**
* Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Amazing utf8 decoder & validator grabbed from:
* http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
*
* All rights goes to the original author.
*/
#include "utf8.h"
static const uint8_t utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
static
uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
uint32_t type = utf8d[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state*16 + type];
return *state;
}
int is_utf8(uint8_t *s) {
uint32_t codepoint, state = 0;
while (*s)
decode(&state, &codepoint, *s++);
return state == UTF8_ACCEPT;
}
int is_utf8_len(uint8_t *s, size_t len) {
uint32_t codepoint, state = 0;
size_t i;
for (i = 0; i < len; i++)
decode(&state, &codepoint, *s++);
return state == UTF8_ACCEPT;
}
uint32_t is_utf8_len_state(uint8_t *s, size_t len, uint32_t state) {
uint32_t codepoint;
size_t i;
for (i = 0; i < len; i++)
decode(&state, &codepoint, *s++);
return state;
}

20
lib/utils.c Normal file
View File

@@ -0,0 +1,20 @@
/* utils.c */
/** @brief Hash `str` to `hash` for use in a switch case
*
* A string needs to be hashed for it to be used
* inside of a switch statement. We want to use a switch
* statement instead of an if-else chain for it's
* simplicity and lower amount of low-level operations.
*
* @param str The string to hash
*
* @returns hash The hashed version of `str`
*/
unsigned long hash(const char *str) {
unsigned long hash = 5381;
unsigned long int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c;
return hash;
}

1759
lib/ws.c Normal file

File diff suppressed because it is too large Load Diff