From d2a3bcb744b3a23c2ba10c6366aabeee8feb47c0 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 12 Apr 2026 23:06:29 +0900 Subject: [PATCH] init --- .gitignore | 2 + LICENSE | 24 +++ Makefile | 24 +++ include/ppr.h | 15 ++ include/ppr_base.h | 230 ++++++++++++++++++++++++++ include/ppr_blake2s.h | 78 +++++++++ include/ppr_int.h | 87 ++++++++++ include/ppr_machdep.h | 100 +++++++++++ include/ppr_md5.h | 43 +++++ include/ppr_sha256.h | 8 + include/ppr_url.h | 25 +++ include/ppr_wildcard.h | 8 + src/base/arpa.c | 247 +++++++++++++++++++++++++++ src/base/dirent.c | 125 ++++++++++++++ src/base/dlfcn.c | 45 +++++ src/base/file.c | 61 +++++++ src/base/mutex.c | 62 +++++++ src/base/poll.c | 62 +++++++ src/base/process.c | 271 ++++++++++++++++++++++++++++++ src/base/socket.c | 276 +++++++++++++++++++++++++++++++ src/base/stat.c | 48 ++++++ src/base/string.c | 73 ++++++++ src/base/thread.c | 227 +++++++++++++++++++++++++ src/base/time.c | 45 +++++ src/base/unistd.c | 33 ++++ src/core.c | 22 +++ src/hash/blake2s.c | 368 +++++++++++++++++++++++++++++++++++++++++ src/hash/blake2s_int.h | 73 ++++++++ src/hash/md5.c | 254 ++++++++++++++++++++++++++++ src/hash/sha256.c | 121 ++++++++++++++ src/misc/url.c | 218 ++++++++++++++++++++++++ src/misc/wildcard.c | 23 +++ 32 files changed, 3298 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 include/ppr.h create mode 100644 include/ppr_base.h create mode 100644 include/ppr_blake2s.h create mode 100644 include/ppr_int.h create mode 100644 include/ppr_machdep.h create mode 100644 include/ppr_md5.h create mode 100644 include/ppr_sha256.h create mode 100644 include/ppr_url.h create mode 100644 include/ppr_wildcard.h create mode 100644 src/base/arpa.c create mode 100644 src/base/dirent.c create mode 100644 src/base/dlfcn.c create mode 100644 src/base/file.c create mode 100644 src/base/mutex.c create mode 100644 src/base/poll.c create mode 100644 src/base/process.c create mode 100644 src/base/socket.c create mode 100644 src/base/stat.c create mode 100644 src/base/string.c create mode 100644 src/base/thread.c create mode 100644 src/base/time.c create mode 100644 src/base/unistd.c create mode 100644 src/core.c create mode 100644 src/hash/blake2s.c create mode 100644 src/hash/blake2s_int.h create mode 100644 src/hash/md5.c create mode 100644 src/hash/sha256.c create mode 100644 src/misc/url.c create mode 100644 src/misc/wildcard.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9eca6c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.a +*.o diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3713a7b --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2026, Pyrite development team +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6572490 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +# This is jst a template... PPR can be built manually pretty easily + +CC = gcc +AR = ar + +.PHONY: all install clean +.SUFFIXES: .c .o + +OBJS = src/core.o +OBJS += src/base/poll.o src/base/file.o src/base/socket.o src/base/arpa.o src/base/string.o src/base/dlfcn.o src/base/unistd.o src/base/stat.o src/base/dirent.o src/base/time.o +OBJS += src/base/mutex.o src/base/thread.o src/base/process.o +OBJS += src/hash/md5.o src/hash/sha256.o src/hash/blake2s.o +OBJS += src/misc/url.o src/misc/wildcard.o + +all: libppr.a + +.c.o: + $(CC) -c -I include -o $@ $< + +libppr.a: $(OBJS) + $(AR) rcs $@ $(OBJS) + +clean: + rm -f *.a src/*.o src/*/*.o diff --git a/include/ppr.h b/include/ppr.h new file mode 100644 index 0000000..f4783be --- /dev/null +++ b/include/ppr.h @@ -0,0 +1,15 @@ +#ifndef __PPR_H__ +#define __PPR_H__ + +#include + +/* hash */ +#include +#include +#include + +/* misc */ +#include +#include + +#endif diff --git a/include/ppr_base.h b/include/ppr_base.h new file mode 100644 index 0000000..a678d8b --- /dev/null +++ b/include/ppr_base.h @@ -0,0 +1,230 @@ +#ifndef __PPR_BASE_H__ +#define __PPR_BASE_H__ + +#include + +/* poll.c definitions */ +#define PPR_POLLIN (1 << 0) +#define PPR_POLLPRI (1 << 1) +#define PPR_POLLOUT (1 << 2) + +struct ppr_pollfd { + int fd; + short events; + short revents; + + void* user; +}; + +/* file.c definitions */ +typedef void PPR_FILE; + +/* socket.c definitions */ +enum ppr_socket_protocol { + PPR_PF_UNSPEC = 0, + PPR_PF_INET, + PPR_PF_INET6, + PPR_PF_UNIX +}; + +enum ppr_socket_address { + PPR_AF_UNSPEC = 0, + PPR_AF_INET, + PPR_AF_INET6, + PPR_AF_UNIX +}; + +enum ppr_socket_type { + PPR_SOCK_STREAM = 0, + PPR_SOCK_DGRAM +}; + +enum ppr_socket_ip_protocol { + PPR_IPPROTO_TCP = 1, + PPR_IPPROTO_UDP +}; + +struct ppr_sockaddr { + unsigned short sa_family; + char sa_data[14]; +}; + +union ppr_in_addr_union { + ppr_uint8_t addr8[4]; + ppr_uint16_t addr16[2]; + ppr_uint32_t addr32[1]; +}; + +struct ppr_in_addr { + union ppr_in_addr_union u; +}; + +struct ppr_sockaddr_in { + unsigned short sin_family; + ppr_uint16_t sin_port; + struct ppr_in_addr sin_addr; +}; + +union ppr_in6_addr_union { + ppr_uint8_t addr8[16]; + ppr_uint16_t addr16[8]; + ppr_uint32_t addr32[4]; +}; + +struct ppr_in6_addr { + union ppr_in6_addr_union u; +}; + +struct ppr_sockaddr_in6 { + unsigned short sin6_family; + ppr_uint16_t sin6_port; + struct ppr_in6_addr sin6_addr; +}; + +struct ppr_sockaddr_storage { + unsigned short ss_family; + char ss_pad[128]; +}; + +struct ppr_sockaddr_un { + unsigned short sun_family; + char sun_path[104]; +}; + +/* stat.c definitions */ +#define PPR_S_IFREG (1 << 0) +#define PPR_S_IFDIR (1 << 1) +#define PPR_S_ISREG(x) ((x) & PPR_S_IFREG) +#define PPR_S_ISDIR(x) ((x) & PPR_S_IFDIR) + +struct ppr_stat { + ppr_size_t st_size; + ppr_time_t st_modtime; + int st_mode; +}; + +/* dirent.c definitions */ +typedef void PPR_DIR; + +struct ppr_dirent { + char d_name[512]; + char d_fullname[1024]; + struct ppr_stat d_stat; +}; + +/* time.c definitions */ +struct ppr_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +/* thread.c definitions */ +#if defined(PPR_IS_NETWARE) +struct ppr_semaphore_usage { + long sem; + ppr_bool used; +}; +#endif + +/* core.c */ +void ppr_init(void); +void ppr_uninit(void); + +/* poll.c */ +int ppr_poll(struct ppr_pollfd* fds, int nfds, int timeout); + +/* file.c */ +PPR_FILE* ppr_fopen(const char* path, const char* mode); +int ppr_fread(void* ptr, int size, int nmemb, PPR_FILE* stream); +int ppr_fwrite(const void* ptr, int size, int nmemb, PPR_FILE* stream); +void ppr_fclose(PPR_FILE* stream); + +/* socket.c */ +extern struct ppr_in_addr ppr_inaddr_any; +extern struct ppr_in6_addr ppr_in6addr_any; + +void ppr_socket_init(void); +int ppr_socket(int domain, int type, int protocol); +int ppr_recv(int s, void* buf, int len, int flags); +int ppr_send(int s, const void* msg, int len, int flags); +int ppr_bind(int s, const struct ppr_sockaddr* name, int namelen); +int ppr_connect(int s, const struct ppr_sockaddr* name, int namelen); +int ppr_listen(int s, int backlog); +int ppr_accept(int s, struct ppr_sockaddr* addr, int* addrlen); +void ppr_socket_close(int d); +void ppr_socket_uninit(void); +ppr_bool ppr_socket_has_ipv6(void); + +/* arpa.c */ +ppr_uint16_t ppr_htons(ppr_uint16_t host16); +const char* ppr_inet_ntop(struct ppr_sockaddr* src, char* dst); +struct ppr_sockaddr* ppr_inet_addr(const char* addr, int* len); + +/* string.c */ +char* ppr_strdup(const char* str); +char* ppr_strvacat(const char* a, ...); +void ppr_strappend(char** dst, const char* src); +char* ppr_strsafehtml(const char* s); + +/* dlfcn.c */ +void* ppr_dlopen(const char* path); +void* ppr_dlsym(void* handle, const char* symbol); +int ppr_dlclose(void* handle); + +/* unistd.c */ +int ppr_gethostname(char* name, int namelen); +void ppr_msleep(int ms); + +/* stat.c */ +int ppr_stat(const char* path, struct ppr_stat* s); + +/* thread.c */ +#if defined(PPR_IS_NETWARE) +extern struct ppr_semaphore_usage ppr_semaphores[]; + +long ppr_thread_open_semaphore(long initial); +void ppr_thread_close_semaphore(long sem); +#endif + +void* ppr_thread_create(void (*entry)(void* param), void* param); +void ppr_thread_join(void* handle); +void ppr_thread_destroy(void* handle); +void ppr_thread_init(void); +void ppr_thread_uninit(void); + +/* mutex.c */ +void* ppr_mutex_create(void); +void ppr_mutex_lock(void* handle); +void ppr_mutex_unlock(void* handle); +void ppr_mutex_destroy(void* handle); + +/* process.c */ +void* ppr_process_create(const char* exec, char** env); +void ppr_process_close(void* handle); +int ppr_process_write(void* handle, const void* data, int len); +int ppr_process_read(void* handle, void* data, int len); +void ppr_process_destroy(void* handle); + +/* dirent.c */ +PPR_DIR* ppr_opendir(const char* path); +struct ppr_dirent* ppr_readdir(PPR_DIR* handle); +void ppr_closedir(PPR_DIR* handle); +int ppr_scandir(const char* dirname, struct ppr_dirent*** namelist, int (*selectfn)(const struct ppr_dirent* d), int (*compar)(const struct ppr_dirent** d1, const struct ppr_dirent** d2)); +int ppr_alphasort(const struct ppr_dirent** d1, const struct ppr_dirent** d2); + +/* time.c */ +extern void* ppr_gmtime_mutex; +extern void* ppr_localtime_mutex; + +ppr_time_t ppr_time(void); +void ppr_gmtime(struct ppr_tm* tm, ppr_time_t t); +void ppr_localtime(struct ppr_tm* tm, ppr_time_t t); + +#endif diff --git a/include/ppr_blake2s.h b/include/ppr_blake2s.h new file mode 100644 index 0000000..1eaf597 --- /dev/null +++ b/include/ppr_blake2s.h @@ -0,0 +1,78 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef PPR_BLAKE2S_H +#define PPR_BLAKE2S_H + +#include + +enum ppr_blake2s_constant { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +typedef struct ppr_blake2s_state__ { + ppr_uint32_t h[8]; + ppr_uint32_t t[2]; + ppr_uint32_t f[2]; + ppr_uint8_t buf[BLAKE2S_BLOCKBYTES]; + ppr_size_t buflen; + ppr_size_t outlen; + ppr_uint8_t last_node; +} ppr_blake2s_state; + +#ifdef PPR_HAS_PACK +#pragma pack(1) +#endif +struct ppr_blake2s_param__ { + ppr_uint8_t digest_length; /* 1 */ + ppr_uint8_t key_length; /* 2 */ + ppr_uint8_t fanout; /* 3 */ + ppr_uint8_t depth; /* 4 */ + ppr_uint32_t leaf_length; /* 8 */ + ppr_uint32_t node_offset; /* 12 */ + ppr_uint16_t xof_length; /* 14 */ + ppr_uint8_t node_depth; /* 15 */ + ppr_uint8_t inner_length; /* 16 */ + /* ppr_uint8_t reserved[0]; */ + ppr_uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + ppr_uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ +}; +#ifdef PPR_HAS_PACK +#pragma pack() +#endif + +typedef struct ppr_blake2s_param__ ppr_blake2s_param; + +#if 0 + /* Padded structs result in a compile-time error */ + enum { + BLAKE2_DUMMY_1 = 1/(int)(sizeof(ppr_blake2s_param) == BLAKE2S_OUTBYTES) + }; +#endif + +/* Streaming API */ +int ppr_blake2s_init(ppr_blake2s_state* S, ppr_size_t outlen); +int ppr_blake2s_init_key(ppr_blake2s_state* S, ppr_size_t outlen, const void* key, ppr_size_t keylen); +int ppr_blake2s_init_param(ppr_blake2s_state* S, const ppr_blake2s_param* P); +int ppr_blake2s_update(ppr_blake2s_state* S, const void* in, ppr_size_t inlen); +int ppr_blake2s_final(ppr_blake2s_state* S, void* out, ppr_size_t outlen); + +/* Simple API */ +int ppr_blake2s(void* out, ppr_size_t outlen, const void* in, ppr_size_t inlen, const void* key, ppr_size_t keylen); + +#endif diff --git a/include/ppr_int.h b/include/ppr_int.h new file mode 100644 index 0000000..8ee9e58 --- /dev/null +++ b/include/ppr_int.h @@ -0,0 +1,87 @@ +#ifndef __PPR_INT_H__ +#define __PPR_INT_H__ + +/* generic section */ +#include +#include +#include +#include +#include +#include + +#if defined(PPR_IS_NETWARE) +#include + +#include +#include +#endif + +#if defined(PPR_IS_UNIX) +#include +#include +#include +#include +#endif + +#if defined(PPR_IS_UNIX) || defined(PPR_IS_PSP) || defined(PPR_IS_PS2) || defined(PPR_IS_NETWARE) +#include +#include +#endif + +/* thread section */ +#if defined(PPR_IS_WIN32) +#if !defined(PPR_USE_CREATETHREAD) +#include +#endif +#elif defined(PPR_IS_UNIX) || defined(PPR_IS_PSP) || defined(PPR_IS_PS2) +#include +#define PPR_USE_PTHREAD +#elif defined(PPR_IS_NETWARE) +#include +#include +#endif + +/* socket section */ +#if defined(PPR_IS_WIN32) +#include +#include +#include + +#ifndef IPPROTO_IPV6 +#define IPPROTO_IPV6 41 +#endif + +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif +#else +#if defined(PPR_HAS_POLL) +#include +#else + +#if !defined(PPR_IS_NETWARE) +#include +#endif +#endif + +#include +#include +#if defined(PPR_IS_NETWARE) +#include +#else +#include +#include +#include +#endif + +#if defined(PPR_HAS_UNIX_SOCKET) +#include +#endif +#endif + +/* windows.h wants to be the last one included */ +#if defined(PPR_IS_WIN32) +#include +#endif + +#endif diff --git a/include/ppr_machdep.h b/include/ppr_machdep.h new file mode 100644 index 0000000..f3b892e --- /dev/null +++ b/include/ppr_machdep.h @@ -0,0 +1,100 @@ +#ifndef __PPR_MACHDEP_H__ +#define __PPR_MACHDEP_H__ + +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__sun__) +#define PPR_IS_UNIX +#elif defined(_WIN32) +#define PPR_IS_WIN32 +#elif defined(_PSP) +#define PPR_IS_PSP +#elif defined(_EE) +#define PPR_IS_PS2 +#elif defined(__NETWARE__) +#define PPR_IS_NETWARE +#endif + +/*** Platform differences */ + +#if defined(PPR_IS_WIN32) || defined(PPR_IS_NETWARE) +#define ppr_newline "\r\n" +#else +#define ppr_newline "\n" +#endif + +#undef PPR_HAS_IPV6 +#undef PPR_HAS_POLL +#undef PPR_HAS_FORK +#undef PPR_HAS_UNIX_SOCKET +#undef PPR_USE_SOCKLEN_T + +/* Windows */ +#if defined(PPR_IS_WIN32) +#define PPR_HAS_IPV6 +#endif + +/* PSP/PS2 */ +#if defined(PPR_IS_PSP) || defined(PPR_IS_PS2) +#define PPR_USE_SOCKLEN_T +#endif + +/* NetWare */ +#if defined(PPR_IS_NETWARE) +/* Nothing */ +#endif + +/* BSD family */ +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__sun__) +#define PPR_HAS_IPV6 +#define PPR_HAS_POLL +#define PPR_HAS_FORK +#define PPR_HAS_UNIX_SOCKET +#define PPR_USE_SOCKLEN_T +#endif + +/*** Compiler differences ***/ + +#undef PPR_HAS_PACK + +#if defined(__WATCOMC__) || defined(__GNUC__) +#define PPR_HAS_PACK +#endif + +typedef unsigned char ppr_bool; +#define ppr_false 0 +#define ppr_true 1 + +#if defined(_MSC_VER) || defined(__WATCOMC__) +typedef unsigned __int8 ppr_uint8_t; +typedef unsigned __int16 ppr_uint16_t; +typedef unsigned __int32 ppr_uint32_t; + +typedef __int8 ppr_int8_t; +typedef __int16 ppr_int16_t; +typedef __int32 ppr_int32_t; + +typedef __int64 ppr_size_t; +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) || defined(__clang__)) +typedef unsigned char ppr_uint8_t; +typedef unsigned short ppr_uint16_t; +typedef unsigned int ppr_uint32_t; + +typedef signed char ppr_int8_t; +typedef short ppr_int16_t; +typedef int ppr_int32_t; + +typedef long long ppr_size_t; +#else +typedef unsigned char ppr_uint8_t; +typedef unsigned short ppr_uint16_t; +typedef unsigned int ppr_uint32_t; + +typedef signed char ppr_int8_t; +typedef short ppr_int16_t; +typedef int ppr_int32_t; + +typedef long ppr_size_t; +#endif + +typedef ppr_size_t ppr_time_t; + +#endif diff --git a/include/ppr_md5.h b/include/ppr_md5.h new file mode 100644 index 0000000..c1f855a --- /dev/null +++ b/include/ppr_md5.h @@ -0,0 +1,43 @@ +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +#ifndef __PPR_MD5_H__ +#define __PPR_MD5_H__ + +#include + +typedef struct ppr_md5_context ppr_md5_context_t; + +struct ppr_md5_context { + ppr_uint32_t i[2]; /* number of _bits_ handled mod 2^64 */ + ppr_uint32_t buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +}; + +void ppr_md5_init(ppr_md5_context_t* mdContext); +void ppr_md5_update(ppr_md5_context_t* mdContext, const void* inBuf, unsigned int inLen); +void ppr_md5_final(ppr_md5_context_t* mdContext); + +#endif diff --git a/include/ppr_sha256.h b/include/ppr_sha256.h new file mode 100644 index 0000000..5e4cf3c --- /dev/null +++ b/include/ppr_sha256.h @@ -0,0 +1,8 @@ +#ifndef __PPR_SHA256_H__ +#define __PPR_SHA256_H__ + +#include + +void ppr_sha256(void* output, const void* data, ppr_size_t len); + +#endif diff --git a/include/ppr_url.h b/include/ppr_url.h new file mode 100644 index 0000000..4e286fe --- /dev/null +++ b/include/ppr_url.h @@ -0,0 +1,25 @@ +#ifndef __PPR_URL_H__ +#define __PPR_URL_H__ + +#include + +typedef struct ppr_url ppr_url_t; + +struct ppr_url { + char* scheme; + char* userinfo; + char* host; + int port; + char* path; + char* query; + char* fragment; +}; + +ppr_bool ppr_url_decode(char* out, const char* input, int len); +ppr_bool ppr_url_encode(char* out, const char* input, int len); + +void ppr_url_init(ppr_url_t* url); +ppr_bool ppr_url_parse(ppr_url_t* url, const char* str); +void ppr_url_deinit(ppr_url_t* url); + +#endif diff --git a/include/ppr_wildcard.h b/include/ppr_wildcard.h new file mode 100644 index 0000000..075b54a --- /dev/null +++ b/include/ppr_wildcard.h @@ -0,0 +1,8 @@ +#ifndef __PPR_WILDCARD_H__ +#define __PPR_WILDCARD_H__ + +#include + +ppr_bool ppr_wildcard(const char* wildcard, const char* target); + +#endif diff --git a/src/base/arpa.c b/src/base/arpa.c new file mode 100644 index 0000000..d90240b --- /dev/null +++ b/src/base/arpa.c @@ -0,0 +1,247 @@ +#include +#include + +ppr_uint16_t ppr_htons(ppr_uint16_t host16) { +#if defined(PPR_IS_NETWARE) + unsigned char buf[2]; + + buf[0] = (host16 >> 8) & 0xff; + buf[1] = (host16 >> 0) & 0xff; + + return *(ppr_uint16_t*)buf; +#else + return htons(host16); +#endif +} + +static int sort_v6(const void* _a, const void* _b) { + int* a = (int*)_a; + int* b = (int*)_b; + + if(a[1] > b[1]) return -1; + if(a[1] < b[1]) return 1; + + return 0; +} + +const char* ppr_inet_ntop(struct ppr_sockaddr* src, char* dst) { + if(src->sa_family == PPR_AF_INET) { + struct ppr_sockaddr_in* addr = (struct ppr_sockaddr_in*)src; + int i; + + dst[0] = 0; + + for(i = 0; i < 4; i++) { + if(i > 0) strcat(dst, "."); + sprintf(dst + strlen(dst), "%d", (int)addr->sin_addr.u.addr8[i]); + } + return dst; + } else if(src->sa_family == PPR_AF_INET6) { + struct ppr_sockaddr_in6* addr = (struct ppr_sockaddr_in6*)src; + int i; + char v6[8][5]; + int l[8][2]; /* index, count */ + int c = -1; + int z = 0; + int max = 8; + + dst[0] = 0; + + for(i = 0; i < 16; i += 2) { + v6[i / 2][0] = 0; + + if(addr->sin6_addr.u.addr8[i + 0] > 0) { + sprintf(v6[i / 2], "%x", (int)addr->sin6_addr.u.addr8[i + 0]); + } + if(addr->sin6_addr.u.addr8[i + 0] > 0 && !(addr->sin6_addr.u.addr8[i + 1] & 0xf0)) strcat(v6[i / 2], "0"); + sprintf(v6[i / 2] + strlen(v6[i / 2]), "%x", (int)addr->sin6_addr.u.addr8[i + 1]); + } + + for(i = 0; i < 8; i++) l[i][0] = l[i][1] = 0; + + for(i = 7; i >= 0; i--) { + if(z && strcmp(v6[i], "0") == 0) { + l[c][0] = i; + l[c][1]++; + continue; + } else if(z) { + z = 0; + } + + if(strcmp(v6[i], "0") == 0) { + z = 1; + + c++; + + l[c][0] = i; + l[c][1] = 1; + } else { + } + } + + qsort(l, 8, sizeof(int) * 2, sort_v6); + + dst[0] = 0; + for(i = 0; i < max; i++) { + if(i > 0 || l[0][1] == 8) strcat(dst, ":"); + if(i == l[0][0] && l[0][1] > 0) { + if(i == 0 || (i + l[0][1] - 1) == (max - 1)) strcat(dst, ":"); + + i += l[0][1] - 1; + } else { + strcat(dst, v6[i]); + } + } + + if(memcmp(dst, "::ffff:", 7) == 0) { + struct ppr_sockaddr_in in; + + dst[7] = 0; + + in.sin_family = PPR_AF_INET; + memcpy(&in.sin_addr, &addr->sin6_addr.u.addr8[12], 4); + + ppr_inet_ntop((struct ppr_sockaddr*)&in, dst + 7); + } + + return dst; + } + + return NULL; +} + +struct ppr_sockaddr* ppr_inet_addr(const char* addr, int* len) { + int d = 0; + int i; + const char* v4[4]; + + v4[0] = addr; + + for(i = 0; addr[i] != 0; i++) { + if(addr[i] == '.') { + d++; + + v4[d] = &addr[i + 1]; + } else if('0' <= addr[i] && addr[i] <= '9') { + } else { + break; + } + } + + /* IPv4 */ + if(d == 3 && addr[i] == 0) { + struct ppr_sockaddr_in* in = malloc(sizeof(*in)); + + in->sin_family = PPR_AF_INET; + for(i = 0; i < 4; i++) in->sin_addr.u.addr8[i] = atoi(v4[i]); + + *len = sizeof(*in); + + return (struct ppr_sockaddr*)in; + } + + for(i = 0; addr[i] != 0; i++) { + if(addr[i] == '[' && i == 0) { + } else if(addr[i] == ']' && i == (strlen(addr) - 1)) { + } else if(addr[i] == ':') { + } else if('0' <= addr[i] && addr[i] <= '9') { + } else if('a' <= addr[i] && addr[i] <= 'f') { + } else if('A' <= addr[i] && addr[i] <= 'F') { + } else { + break; + } + } + + /* IPv6 */ + if(addr[i] == 0) { + const char* b = addr; + int e = 0; + struct ppr_sockaddr_in6* in6 = malloc(sizeof(*in6)); + int incr = 0; + + in6->sin6_family = PPR_AF_INET6; + + memset(in6->sin6_addr.u.addr8, 0, 16); + + for(i = 0;; i++) { + if(addr[i] == 0 || addr[i] == ']' || addr[i] == ':') { + char* n = malloc(&addr[i] - b + 1); + + n[&addr[i] - b] = 0; + memcpy(n, b, &addr[i] - b); + + if(strlen(n) == 0) { + e++; + } else { + int j; + int f = strlen(n) - 1; + int old = incr; + int inc = 0; + + e = 0; + + incr++; + for(j = f; j >= 0; j--) { + char byte = n[j]; + + if('0' <= byte && byte <= '9') { + byte = byte - '0'; + } else if('a' <= byte && byte <= 'f') { + byte = byte - 'a' + 10; + } else if('A' <= byte && byte <= 'F') { + byte = byte - 'A' + 10; + } + + in6->sin6_addr.u.addr8[incr] = in6->sin6_addr.u.addr8[incr] | (byte << (4 * inc)); + inc++; + + if(j == (f - 1)) { + incr--; + inc = 0; + } + } + + incr = old + 2; + + if(incr > 16) { + free(n); + free(in6); + return NULL; + } + } + + free(n); + + if(e == 2) { + int len = 16 - incr; + int c = 0; + int j; + + for(j = i + 1; addr[j] != ']' && addr[j] != 0; j++) { + if(j == (i + 1) && !(addr[j] == ']' || addr[j] == 0)) c++; + if(addr[j] == ':') c++; + } + + incr += len - c * 2; + + if(incr > 16) { + free(in6); + return NULL; + } + } + + b = &addr[i + 1]; + + if(addr[i] == 0 || addr[i] == ']') break; + } else if(addr[i] == '[') { + b = &addr[i + 1]; + } + } + + *len = sizeof(*in6); + + return (struct ppr_sockaddr*)in6; + } + + return NULL; +} diff --git a/src/base/dirent.c b/src/base/dirent.c new file mode 100644 index 0000000..fa5f4b6 --- /dev/null +++ b/src/base/dirent.c @@ -0,0 +1,125 @@ +#include +#include + +#if defined(PPR_IS_WIN32) +typedef struct dir { + ppr_bool next; + HANDLE hFind; + WIN32_FIND_DATA ffd; + + char* path; + struct ppr_dirent dirent; +} dir_t; +#else +typedef struct dir { + DIR* dir; + + char* path; + struct ppr_dirent dirent; +} dir_t; +#endif + +PPR_DIR* ppr_opendir(const char* path) { + dir_t* dir = malloc(sizeof(*dir)); +#if defined(PPR_IS_WIN32) + char* p = ppr_strvacat(path, (path[strlen(path) - 1] == '/' || path[strlen(path) - 1] == '\\') ? "" : (strchr(path, '/') != NULL ? "/" : "\\"), "*", NULL); + + if((dir->hFind = FindFirstFile(p, &dir->ffd)) == INVALID_HANDLE_VALUE) { + free(p); + free(dir); + + return NULL; + } + free(p); + + dir->next = ppr_true; +#else + if((dir->dir = opendir(path)) == NULL) { + free(dir); + + return NULL; + } +#endif + + dir->path = ppr_strdup(path); + + return (PPR_DIR*)dir; +} + +struct ppr_dirent* ppr_readdir(PPR_DIR* handle) { + dir_t* dir = handle; +#if defined(PPR_IS_WIN32) + if(!dir->next) return NULL; + + strcpy(dir->dirent.d_name, dir->ffd.cFileName); +#else + struct dirent* d; + + if((d = readdir(dir->dir)) == NULL) return NULL; + + strcpy(dir->dirent.d_name, d->d_name); +#endif + + strcpy(dir->dirent.d_fullname, dir->path); + if(dir->path[strlen(dir->path) - 1] != '/' && dir->path[strlen(dir->path) - 1] != '\\') { +#if defined(PPR_IS_WIN32) + strcat(dir->dirent.d_fullname, strchr(dir->path, '/') != NULL ? "/" : "\\"); +#else + strcat(dir->dirent.d_fullname, "/"); +#endif + } + strcat(dir->dirent.d_fullname, dir->dirent.d_name); + + memset(&dir->dirent.d_stat, 0, sizeof(dir->dirent.d_stat)); + ppr_stat(dir->dirent.d_fullname, &dir->dirent.d_stat); + + return &dir->dirent; +} + +void ppr_closedir(PPR_DIR* handle) { + dir_t* dir = handle; +#if defined(PPR_IS_WIN32) + FindClose(dir->hFind); +#else + closedir(dir->dir); +#endif + + free(dir->path); + + free(dir); +} + +int ppr_scandir(const char* dirname, struct ppr_dirent*** namelist, int (*selectfn)(const struct ppr_dirent* d), int (*compar)(const struct ppr_dirent** d1, const struct ppr_dirent** d2)) { + PPR_DIR* dir = ppr_opendir(dirname); + struct ppr_dirent* d; + int n = 0; + int n2 = 0; + if(dir == NULL) return -1; + + while((d = ppr_readdir(dir)) != NULL) n++; + + ppr_closedir(dir); + + if((dir = ppr_opendir(dirname)) == NULL) return -1; + + *namelist = malloc(sizeof(**namelist) * n); + + while(n2 < n && (d = ppr_readdir(dir)) != NULL) { + if(selectfn != NULL && !selectfn(d)) continue; + + (*namelist)[n2] = malloc(sizeof(***namelist)); + memcpy((*namelist)[n2], d, sizeof(*d)); + + n2++; + } + + ppr_closedir(dir); + + qsort(*namelist, n2, sizeof(**namelist), (int (*)(const void* d1, const void* d2))compar); + + return n2; +} + +int ppr_alphasort(const struct ppr_dirent** d1, const struct ppr_dirent** d2) { + return strcmp((*d1)->d_name, (*d2)->d_name); +} diff --git a/src/base/dlfcn.c b/src/base/dlfcn.c new file mode 100644 index 0000000..41ef1d2 --- /dev/null +++ b/src/base/dlfcn.c @@ -0,0 +1,45 @@ +#include +#include + +void* ppr_dlopen(const char* path) { +#if defined(PPR_IS_WIN32) + return LoadLibrary(path); +#elif defined(PPR_IS_UNIX) + return dlopen(path, RTLD_LAZY | RTLD_LOCAL); +#elif defined(PPR_IS_NETWARE) + unsigned int handle = FindNLMHandle(path); + + if(handle == 0) { + spawnlp(P_NOWAIT | P_SPAWN_IN_CURRENT_DOMAIN, path, NULL); + handle = FindNLMHandle(path); + } + + return (void*)handle; +#else + return NULL; +#endif +} + +void* ppr_dlsym(void* handle, const char* symbol) { +#if defined(PPR_IS_WIN32) + return GetProcAddress(handle, symbol); +#elif defined(PPR_IS_UNIX) + return dlsym(handle, symbol); +#elif defined(PPR_IS_NETWARE) + return ImportSymbol((unsigned int)handle, symbol); +#else + return NULL; +#endif +} + +int ppr_dlclose(void* handle) { +#if defined(PPR_IS_WIN32) + return FreeLibrary(handle) ? 0 : 1; +#elif defined(PPR_IS_UNIX) + return dlclose(handle); +#elif defined(PPR_IS_NETWARE) + return 0; +#else + return -1; +#endif +} diff --git a/src/base/file.c b/src/base/file.c new file mode 100644 index 0000000..05a8b6e --- /dev/null +++ b/src/base/file.c @@ -0,0 +1,61 @@ +#include +#include + +PPR_FILE* ppr_fopen(const char* path, const char* mode) { +#if defined(PPR_IS_WIN32) + DWORD ac = 0; + DWORD dis = 0; + DWORD fl = FILE_ATTRIBUTE_NORMAL; + HANDLE h; + + if(mode[0] == 'r') { + ac = GENERIC_READ; + dis = OPEN_EXISTING; + } else if(mode[0] == 'w') { + ac = GENERIC_WRITE; + dis = CREATE_ALWAYS; + } else if(mode[0] == 'a') { + ac = GENERIC_WRITE | FILE_APPEND_DATA; + dis = OPEN_ALWAYS; + } + + h = CreateFile(path, ac, FILE_SHARE_READ, NULL, dis, fl, NULL); + if(h == INVALID_HANDLE_VALUE) return NULL; + + return (PPR_FILE*)h; +#else + return (PPR_FILE*)fopen(path, mode); +#endif +} + +int ppr_fread(void* ptr, int size, int nmemb, PPR_FILE* stream) { +#if defined(PPR_IS_WIN32) + DWORD dw; + + if(!ReadFile((HANDLE)stream, ptr, size * nmemb, &dw, NULL)) return -1; + + return dw; +#else + return fread(ptr, size, nmemb, (FILE*)stream); +#endif +} + +int ppr_fwrite(const void* ptr, int size, int nmemb, PPR_FILE* stream) { +#if defined(PPR_IS_WIN32) + DWORD dw; + + if(!WriteFile((HANDLE)stream, ptr, size * nmemb, &dw, NULL)) return -1; + + return dw; +#else + return fwrite(ptr, size, nmemb, (FILE*)stream); +#endif +} + +void ppr_fclose(PPR_FILE* stream) { +#if defined(PPR_IS_WIN32) + CloseHandle((HANDLE)stream); +#else + fclose((FILE*)stream); +#endif +} diff --git a/src/base/mutex.c b/src/base/mutex.c new file mode 100644 index 0000000..01b34b4 --- /dev/null +++ b/src/base/mutex.c @@ -0,0 +1,62 @@ +#include +#include + +void* ppr_mutex_create(void) { +#if defined(PPR_IS_WIN32) + return CreateEvent(NULL, FALSE, TRUE, NULL); +#elif defined(PPR_USE_PTHREAD) + pthread_mutex_t* mutex = malloc(sizeof(*mutex)); + + pthread_mutex_init(mutex, NULL); + + return mutex; +#elif defined(PPR_IS_NETWARE) + LONG* mutex = malloc(sizeof(*mutex)); + + *mutex = ppr_thread_open_semaphore(1); + + return mutex; +#else + return NULL; +#endif +} + +void ppr_mutex_lock(void* handle) { +#if defined(PPR_IS_WIN32) + WaitForSingleObject(handle, INFINITE); +#elif defined(PPR_USE_PTHREAD) + pthread_mutex_lock(handle); +#elif defined(PPR_IS_NETWARE) + WaitOnLocalSemaphore(*(LONG*)handle); +#else + (void)handle; +#endif +} + +void ppr_mutex_unlock(void* handle) { +#if defined(PPR_IS_WIN32) + SetEvent(handle); +#elif defined(PPR_USE_PTHREAD) + pthread_mutex_unlock(handle); +#elif defined(PPR_IS_NETWARE) + SignalLocalSemaphore(*(LONG*)handle); +#else + (void)handle; +#endif +} + +void ppr_mutex_destroy(void* handle) { +#if defined(PPR_IS_WIN32) + CloseHandle(handle); +#elif defined(PPR_USE_PTHREAD) + pthread_mutex_destroy(handle); + + free(handle); +#elif defined(PPR_IS_NETWARE) + ppr_thread_close_semaphore(*(LONG*)handle); + + free(handle); +#else + (void)handle; +#endif +} diff --git a/src/base/poll.c b/src/base/poll.c new file mode 100644 index 0000000..c246ec1 --- /dev/null +++ b/src/base/poll.c @@ -0,0 +1,62 @@ +#include +#include + +int ppr_poll(struct ppr_pollfd* fds, int nfds, int timeout) { +#if defined(PPR_HAS_POLL) + struct pollfd* pfds = malloc(sizeof(*pfds) * nfds); + int i; + int st; + + for(i = 0; i < nfds; i++) { + pfds[i].fd = fds[i].fd; + pfds[i].events = 0; + fds[i].revents = 0; + + if(fds[i].events & PPR_POLLIN) pfds[i].events |= POLLIN; + if(fds[i].events & PPR_POLLPRI) pfds[i].events |= POLLPRI; + if(fds[i].events & PPR_POLLOUT) pfds[i].events |= POLLOUT; + } + + st = poll(pfds, nfds, timeout); + + if(st > 0) { + for(i = 0; i < nfds; i++) { + if(pfds[i].revents & POLLIN) fds[i].revents |= PPR_POLLIN; + if(pfds[i].revents & POLLPRI) fds[i].revents |= PPR_POLLPRI; + if(pfds[i].revents & POLLOUT) fds[i].revents |= PPR_POLLOUT; + } + } + + free(pfds); + + return st; +#else + fd_set rfds; + fd_set wfds; + int i; + struct timeval tv; + int st; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + for(i = 0; i < nfds; i++) { + if(fds[i].events & PPR_POLLIN) FD_SET(fds[i].fd, &rfds); + if(fds[i].events & PPR_POLLOUT) FD_SET(fds[i].fd, &wfds); + + fds[i].revents = 0; + } + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + st = select(FD_SETSIZE, &rfds, &wfds, NULL, &tv); + + for(i = 0; i < nfds; i++) { + if(FD_ISSET(fds[i].fd, &rfds)) fds[i].revents |= PPR_POLLIN; + if(FD_ISSET(fds[i].fd, &wfds)) fds[i].revents |= PPR_POLLOUT; + } + + return st; +#endif +} diff --git a/src/base/process.c b/src/base/process.c new file mode 100644 index 0000000..417fcb3 --- /dev/null +++ b/src/base/process.c @@ -0,0 +1,271 @@ +#include +#include + +typedef struct process { +#if defined(PPR_IS_WIN32) + HANDLE process; + HANDLE thread; + HANDLE h_stdin; + HANDLE h_stdout; + HANDLE h_stderr; +#elif defined(PPR_IS_UNIX) + pid_t pid; + int fd_stdin; + int fd_stdout; + int fd_stderr; +#else + void* reserved; +#endif +} process_t; + +static ppr_bool is_allowed_env(const char* n) { + char* p = ppr_strdup(n); + char* s; + + if((s = strchr(p, '=')) != NULL) s[0] = 0; + + if(strcmp(p, "PATH") == 0) return ppr_true; + + return ppr_false; +} + +void* ppr_process_create(const char* exec, char** env) { +#if defined(PPR_IS_WIN32) + process_t* proc = malloc(sizeof(*proc)); + SECURITY_ATTRIBUTES attr; + HANDLE pipe_stdin[2]; + HANDLE pipe_stdout[2]; + HANDLE pipe_stderr[2]; + char path[2048]; + char* envs; + PROCESS_INFORMATION pi; + STARTUPINFO si; + char* d_envs = GetEnvironmentStrings(); + char* d_envs2; + int envs_len = 0; + int i; + + d_envs2 = d_envs; + while(*d_envs2) { + if(is_allowed_env(d_envs2)) envs_len += strlen(d_envs2) + 1; + + d_envs2 += strlen(d_envs2) + 1; + } + + for(i = 0; env[i] != NULL; i++) envs_len += strlen(env[i]) + 1; + envs_len++; + + envs = malloc(envs_len); + envs_len = 0; + + d_envs2 = d_envs; + while(*d_envs2) { + if(is_allowed_env(d_envs2)) { + strcpy(envs + envs_len, d_envs2); + envs_len += strlen(d_envs2) + 1; + } + + d_envs2 += strlen(d_envs2) + 1; + } + + for(i = 0; env[i] != NULL; i++) { + strcpy(envs + envs_len, env[i]); + envs_len += strlen(env[i]) + 1; + } + FreeEnvironmentStrings(d_envs); + + envs[envs_len] = 0; + + memset(&pi, 0, sizeof(pi)); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + + sprintf(path, "\"%s\"", exec); + + memset(&attr, 0, sizeof(attr)); + attr.nLength = sizeof(attr); + attr.bInheritHandle = TRUE; + + CreatePipe(&pipe_stdin[0], &pipe_stdin[1], &attr, 0); + SetHandleInformation(pipe_stdin[1], HANDLE_FLAG_INHERIT, 0); + + CreatePipe(&pipe_stdout[0], &pipe_stdout[1], &attr, 0); + SetHandleInformation(pipe_stdout[0], HANDLE_FLAG_INHERIT, 0); + + CreatePipe(&pipe_stderr[0], &pipe_stderr[1], &attr, 0); + SetHandleInformation(pipe_stderr[0], HANDLE_FLAG_INHERIT, 0); + + si.hStdInput = pipe_stdin[0]; + si.hStdOutput = pipe_stdout[1]; + si.hStdError = pipe_stderr[1]; + + if(!CreateProcess(NULL, path, NULL, NULL, TRUE, 0, envs, NULL, &si, &pi)) { + int i; + + free(proc); + free(envs); + + for(i = 0; i < 2; i++) { + CloseHandle(pipe_stdin[i]); + CloseHandle(pipe_stdout[i]); + CloseHandle(pipe_stderr[i]); + } + + return NULL; + } else { + CloseHandle(pipe_stdin[0]); + CloseHandle(pipe_stdout[1]); + CloseHandle(pipe_stderr[1]); + + proc->process = pi.hProcess; + proc->thread = pi.hThread; + proc->h_stdin = pipe_stdin[1]; + proc->h_stdout = pipe_stdout[0]; + proc->h_stderr = pipe_stderr[0]; + } + + free(envs); + + return proc; +#elif defined(PPR_IS_UNIX) + process_t* proc = malloc(sizeof(*proc)); + int pipe_stdin[2]; + int pipe_stdout[2]; + int pipe_stderr[2]; + char** envs = NULL; + int i; + int c = 0; + + extern char** environ; + + for(i = 0; environ[i] != NULL; i++) { + if(is_allowed_env(environ[i])) c++; + } + for(i = 0; env != NULL && env[i] != NULL; i++) c++; + + envs = malloc(sizeof(*envs) * (c + 1)); + + c = 0; + for(i = 0; environ[i] != NULL; i++) { + if(is_allowed_env(environ[i])) envs[c++] = environ[i]; + } + for(i = 0; env != NULL && env[i] != NULL; i++) envs[c++] = env[i]; + envs[c] = 0; + + pipe(pipe_stdin); + pipe(pipe_stdout); + pipe(pipe_stderr); + + if((proc->pid = fork()) == 0) { + int basefd = pipe_stdout[1] > pipe_stderr[1] ? pipe_stdout[1] : pipe_stderr[1]; + int infd = basefd + 3; + int outfd = basefd + 4; + int errfd = basefd + 5; + + free(proc); + + close(pipe_stdin[1]); + close(pipe_stdout[0]); + close(pipe_stderr[0]); + + dup2(pipe_stdin[0], infd); + dup2(pipe_stdout[1], outfd); + dup2(pipe_stderr[1], errfd); + close(pipe_stdin[0]); + close(pipe_stdout[1]); + close(pipe_stderr[1]); + dup2(infd, 0); + dup2(outfd, 1); + dup2(errfd, 2); + close(infd); + close(outfd); + close(errfd); + + execle(exec, exec, NULL, envs); + + _exit(-1); + } else { + close(pipe_stdin[0]); + close(pipe_stdout[1]); + close(pipe_stderr[1]); + + proc->fd_stdin = pipe_stdin[1]; + proc->fd_stdout = pipe_stdout[0]; + proc->fd_stderr = pipe_stderr[0]; + } + + free(envs); + + return proc; +#else + return NULL; +#endif +} + +void ppr_process_close(void* handle) { + process_t* proc = handle; +#if defined(PPR_IS_WIN32) + CloseHandle(proc->h_stdin); + proc->h_stdin = NULL; +#elif defined(PPR_IS_UNIX) + close(proc->fd_stdin); + proc->fd_stdin = -1; +#endif +} + +int ppr_process_write(void* handle, const void* data, int len) { + process_t* proc = handle; +#if defined(PPR_IS_WIN32) + DWORD r; + + if(!WriteFile(proc->h_stdin, data, len, &r, NULL)) return -1; + + return r; +#elif defined(PPR_IS_UNIX) + return write(proc->fd_stdin, data, len); +#else + return -1; +#endif +} + +int ppr_process_read(void* handle, void* data, int len) { + process_t* proc = handle; +#if defined(PPR_IS_WIN32) + DWORD r; + + if(!ReadFile(proc->h_stdout, data, len, &r, NULL)) return -1; + + return r; +#elif defined(PPR_IS_UNIX) + return read(proc->fd_stdout, data, len); +#else + return -1; +#endif +} + +void ppr_process_destroy(void* handle) { + process_t* proc = handle; +#if defined(PPR_IS_WIN32) + if(proc->h_stdin != NULL) CloseHandle(proc->h_stdin); + CloseHandle(proc->h_stdout); + CloseHandle(proc->h_stderr); + + WaitForSingleObject(proc->process, INFINITE); + + CloseHandle(proc->process); + CloseHandle(proc->thread); +#elif defined(PPR_IS_UNIX) + int st; + + if(proc->fd_stdin >= 0) close(proc->fd_stdin); + close(proc->fd_stdout); + close(proc->fd_stderr); + + do { + waitpid(proc->pid, &st, 0); + } while(!WIFEXITED(st)); +#endif + free(proc); +} diff --git a/src/base/socket.c b/src/base/socket.c new file mode 100644 index 0000000..556bb7f --- /dev/null +++ b/src/base/socket.c @@ -0,0 +1,276 @@ +#include +#include + +#if !defined(IPPROTO_TCP) +#define IPPROTO_TCP 0 +#endif + +#if !defined(IPPROTO_UDP) +#define IPPROTO_UDP 0 +#endif + +#if defined(PPR_IS_NETWARE) +struct in_addr { + ppr_uint32_t s_addr; +}; +struct sockaddr_in { + ppr_uint16_t sin_family; + ppr_uint16_t sin_port; + struct in_addr sin_addr; + ppr_uint8_t sin_zero[8]; +}; +#endif + +void ppr_socket_init(void) { +#if defined(PPR_IS_WIN32) + WSADATA wsa; + + WSAStartup(MAKEWORD(2, 0), &wsa); +#elif defined(PPR_IS_UNIX) + signal(SIGPIPE, SIG_IGN); +#endif +} + +void ppr_socket_uninit(void) { +#if defined(PPR_IS_WIN32) + WSACleanup(); +#elif defined(PPR_IS_UNIX) +#endif +} + +int ppr_socket(int domain, int type, int protocol) { + int d = PF_UNSPEC, t = 0, p = 0; + int s; + int nbyt; + + if(domain == PPR_PF_INET) { + d = PF_INET; +#if defined(PPR_HAS_IPV6) + } else if(domain == PPR_PF_INET6) { + d = PF_INET6; +#endif +#if defined(PPR_HAS_UNIX_SOCKET) + } else if(domain == PPR_PF_UNIX) { + d = PF_UNIX; +#endif + } + + if(type == PPR_SOCK_STREAM) { + t = SOCK_STREAM; + } else if(type == PPR_SOCK_DGRAM) { + t = SOCK_DGRAM; + } + + if(protocol == PPR_IPPROTO_TCP) { + p = IPPROTO_TCP; + } else if(protocol == PPR_IPPROTO_UDP) { + p = IPPROTO_UDP; + } + + s = socket(d, t, p); + +#if defined(PPR_IS_WIN32) + if(s == INVALID_SOCKET) s = -1; +#endif + + if(s >= 0 && t == SOCK_STREAM && p == IPPROTO_TCP) { + int yes = 1; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(yes)); + } + +#if defined(PPR_HAS_IPV6) + if(s >= 0 && d == PF_INET6) { + int yes = 1; + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(yes)); + } +#endif + + if(s >= 0) { + nbyt = 65535; + setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&nbyt, sizeof(nbyt)); + nbyt = 65535; + setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&nbyt, sizeof(nbyt)); + } + + return s; +} + +/* we ignore flags for now */ +int ppr_recv(int s, void* buf, int len, int flags) { + (void)flags; + + return recv(s, buf, len, 0); +} + +int ppr_send(int s, const void* msg, int len, int flags) { + (void)flags; + + return send(s, (void*)msg, len, 0); +} + +static struct sockaddr* conv_to_sa(int* outlen, const struct ppr_sockaddr* input, int namelen) { + struct sockaddr* out = NULL; + + if(input->sa_family == PPR_AF_INET && namelen == sizeof(struct ppr_sockaddr_in)) { + struct ppr_sockaddr_in* addr = (struct ppr_sockaddr_in*)input; + struct sockaddr_in addr4; + + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = addr->sin_addr.u.addr32[0]; + addr4.sin_port = addr->sin_port; + + out = malloc(sizeof(addr4)); + memcpy(out, &addr4, sizeof(addr4)); + *outlen = sizeof(addr4); +#if defined(PPR_HAS_IPV6) + } else if(input->sa_family == PPR_AF_INET6 && namelen == sizeof(struct ppr_sockaddr_in6)) { + struct ppr_sockaddr_in6* addr = (struct ppr_sockaddr_in6*)input; + struct sockaddr_in6 addr6; + + addr6.sin6_family = AF_INET6; + memcpy(addr6.sin6_addr.s6_addr, &addr->sin6_addr.u.addr8, 16); + addr6.sin6_port = addr->sin6_port; + + out = malloc(sizeof(addr6)); + memcpy(out, &addr6, sizeof(addr6)); + *outlen = sizeof(addr6); +#endif +#if defined(PPR_HAS_UNIX_SOCKET) + } else if(input->sa_family == PPR_AF_UNIX && namelen == sizeof(struct ppr_sockaddr_un)) { + struct ppr_sockaddr_un* addr = (struct ppr_sockaddr_un*)input; + struct sockaddr_un addru; + + addru.sun_family = AF_UNIX; + strcpy(addru.sun_path, addr->sun_path); + + out = malloc(sizeof(addru)); + memcpy(out, &addru, sizeof(addru)); + *outlen = sizeof(addru); +#endif + } + + return out; +} + +int ppr_bind(int s, const struct ppr_sockaddr* name, int namelen) { + int st = -1; + int yes = 1; + struct sockaddr* sa; + int len; + + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)); + if((sa = conv_to_sa(&len, name, namelen)) != NULL) { + st = bind(s, sa, len); + free(sa); + } + + return st; +} + +int ppr_connect(int s, const struct ppr_sockaddr* name, int namelen) { + int st = -1; + struct sockaddr* sa; + int len; + + if((sa = conv_to_sa(&len, name, namelen)) != NULL) { + st = connect(s, sa, len); + free(sa); + } + + return st; +} + +int ppr_listen(int s, int backlog) { + return listen(s, backlog); +} + +int ppr_accept(int s, struct ppr_sockaddr* addr, int* addrlen) { + unsigned char buffer[256]; + struct sockaddr* sa = (struct sockaddr*)buffer; + int r; +#if defined(PPR_USE_SOCKLEN_T) + socklen_t l +#else + int l +#endif + = *addrlen; + + r = accept(s, sa, &l); + *addrlen = l; + +#if defined(PPR_IS_WIN32) + if(r == INVALID_SOCKET) r = -1; +#endif + + if(r < 0) return r; + + if(sa->sa_family == AF_INET) { + struct ppr_sockaddr_in* taddr = (struct ppr_sockaddr_in*)addr; + struct sockaddr_in* addr4 = (struct sockaddr_in*)buffer; + + taddr->sin_family = PPR_AF_INET; + taddr->sin_addr.u.addr32[0] = addr4->sin_addr.s_addr; + taddr->sin_port = addr4->sin_port; + + *addrlen = sizeof(*taddr); +#if defined(PPR_HAS_IPV6) + } else if(sa->sa_family == AF_INET6) { + struct ppr_sockaddr_in6* taddr = (struct ppr_sockaddr_in6*)addr; + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)buffer; + + taddr->sin6_family = PPR_AF_INET6; + memcpy(taddr->sin6_addr.u.addr32, addr6->sin6_addr.s6_addr, 16); + taddr->sin6_port = addr6->sin6_port; + + *addrlen = sizeof(*taddr); +#endif +#if defined(PPR_HAS_UNIX_SOCKET) + } else if(sa->sa_family == AF_UNIX) { + struct ppr_sockaddr_un* taddr = (struct ppr_sockaddr_un*)addr; + struct sockaddr_un* addru = (struct sockaddr_un*)buffer; + + taddr->sun_family = PPR_AF_UNIX; + strcpy(taddr->sun_path, addru->sun_path); + + *addrlen = sizeof(*taddr); +#endif + } + + return r; +} + +void ppr_socket_close(int d) { +#if defined(PPR_IS_WIN32) + shutdown(d, SD_BOTH); + closesocket(d); +#elif defined(PPR_IS_UNIX) + shutdown(d, SHUT_RD); + close(d); +#endif +} + +ppr_bool ppr_socket_has_ipv6(void) { +#if defined(PPR_HAS_IPV6) +#if defined(PPR_IS_WIN32) + DWORD v = GetVersion(); + DWORD majorv, minorv; + + majorv = LOBYTE(LOWORD(v)); + minorv = HIBYTE(LOWORD(v)); + + if(majorv > 5 && (majorv == 5 && minorv >= 1)) return ppr_true; + + return ppr_false; +#else + return ppr_true; +#endif +#else + return ppr_false; +#endif +} + +struct ppr_in_addr ppr_inaddr_any = { + {{0, 0, 0, 0}}}; + +struct ppr_in6_addr ppr_in6addr_any = { + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}; diff --git a/src/base/stat.c b/src/base/stat.c new file mode 100644 index 0000000..43f1dc6 --- /dev/null +++ b/src/base/stat.c @@ -0,0 +1,48 @@ +#include +#include + +int ppr_stat(const char* path, struct ppr_stat* s) { +#if defined(PPR_IS_WIN32) + WIN32_FILE_ATTRIBUTE_DATA fad; + ULARGE_INTEGER mtime; + + if(!GetFileAttributesEx(path, GetFileExInfoStandard, &fad)) return -1; + + memcpy(&mtime, &fad.ftLastWriteTime, sizeof(mtime)); + + s->st_size = 0; + s->st_modtime = (mtime.QuadPart / 10000000) / 11644473600; + s->st_mode = 0; + + s->st_mode |= PPR_S_IFREG; + if(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + s->st_mode &= ~PPR_S_IFREG; + s->st_mode |= PPR_S_IFDIR; + } + + if(PPR_S_ISREG(s->st_mode)) { + PPR_FILE* f = ppr_fopen(path, "r"); /* :))))))) */ + s->st_size = GetFileSize((HANDLE)f, NULL); + ppr_fclose(f); + } + + return 0; +#elif defined(PPR_IS_UNIX) || defined(PPR_IS_NETWARE) + struct stat st; + int sc; + + sc = stat(path, &st); + if(sc != 0) return sc; + + s->st_size = st.st_size; + s->st_modtime = st.st_mtime; + s->st_mode = 0; + + if(S_ISREG(st.st_mode)) s->st_mode |= PPR_S_IFREG; + if(S_ISDIR(st.st_mode)) s->st_mode |= PPR_S_IFDIR; + + return sc; +#else + return -1; +#endif +} diff --git a/src/base/string.c b/src/base/string.c new file mode 100644 index 0000000..fd5252a --- /dev/null +++ b/src/base/string.c @@ -0,0 +1,73 @@ +#include +#include + +char* ppr_strdup(const char* str) { + char* r = malloc(strlen(str) + 1); + + strcpy(r, str); + + return r; +} + +char* ppr_strvacat(const char* a, ...) { + int l = 1 + strlen(a); + va_list va; + char* s; + char* r; + + va_start(va, a); + while((s = va_arg(va, char*)) != NULL) { + l += strlen(s); + } + va_end(va); + + r = malloc(l); + + strcpy(r, a); + + va_start(va, a); + while((s = va_arg(va, char*)) != NULL) { + strcat(r, s); + } + va_end(va); + + return r; +} + +void ppr_strappend(char** dst, const char* src) { + char* n = ppr_strvacat(*dst, src, NULL); + + free(*dst); + *dst = n; +} + +char* ppr_strsafehtml(const char* s) { + char* r = malloc(strlen(s) * 5 + 1); + int i; + int n = 0; + + for(i = 0; s[i] != 0; i++) { + if(s[i] == '&') { + r[n++] = '&'; + r[n++] = 'a'; + r[n++] = 'm'; + r[n++] = 'p'; + r[n++] = ';'; + } else if(s[i] == '<') { + r[n++] = '&'; + r[n++] = 'l'; + r[n++] = 't'; + r[n++] = ';'; + } else if(s[i] == '>') { + r[n++] = '&'; + r[n++] = 'g'; + r[n++] = 't'; + r[n++] = ';'; + } else { + r[n++] = s[i]; + } + } + r[n] = 0; + + return r; +} diff --git a/src/base/thread.c b/src/base/thread.c new file mode 100644 index 0000000..13c65b2 --- /dev/null +++ b/src/base/thread.c @@ -0,0 +1,227 @@ +#include +#include + +typedef struct arg { + void (*entry)(void* param); + void* param; +#if defined(PPR_IS_NETWARE) + LONG waitsem; +#endif +} arg_t; + +#if defined(PPR_IS_NETWARE) +typedef struct thread { + int thread; + LONG waitsem; +} thread_t; + +struct ppr_thread_usage { + ppr_bool used; + thread_t* thread; +}; + +struct ppr_semaphore_usage ppr_semaphores[1024]; +struct ppr_thread_usage ppr_threads[1024]; +#endif + +#if defined(PPR_IS_NETWARE) +long ppr_thread_open_semaphore(long initial) { + long sem = OpenLocalSemaphore(initial); + int i; + + for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) { + if(!ppr_semaphores[i].used) { + ppr_semaphores[i].used = ppr_true; + ppr_semaphores[i].sem = sem; + break; + } + } + + return sem; +} + +void ppr_thread_close_semaphore(long sem) { + int i; + + for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) { + if(ppr_semaphores[i].used && ppr_semaphores[i].sem == sem) { + ppr_semaphores[i].used = ppr_false; + break; + } + } + + CloseLocalSemaphore(sem); +} +#endif + +void ppr_thread_init(void) { +#if defined(PPR_IS_NETWARE) + int i; + + for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) { + ppr_semaphores[i].used = ppr_false; + } + for(i = 0; i < sizeof(ppr_threads) / sizeof(ppr_threads[0]); i++) { + ppr_threads[i].used = ppr_false; + } +#endif +} + +void ppr_thread_uninit(void) { +#if defined(PPR_IS_NETWARE) + int i; + + for(i = 0; i < sizeof(ppr_threads) / sizeof(ppr_threads[0]); i++) { + if(ppr_threads[i].used) { + ppr_thread_join(ppr_threads[i].thread); + ppr_thread_destroy(ppr_threads[i].thread); + } + } + for(i = 0; i < sizeof(ppr_semaphores) / sizeof(ppr_semaphores[0]); i++) { + if(ppr_semaphores[i].used) { + ppr_thread_close_semaphore(ppr_semaphores[i].sem); + } + } +#endif +} + +#if defined(PPR_IS_WIN32) +#if defined(PPR_USE_CREATETHREAD) +static DWORD WINAPI thread_entry(void* _param) { +#else +static unsigned int WINAPI thread_entry(void* _param) { +#endif + arg_t* arg = _param; + void (*entry)(void* param) = arg->entry; + void* param = arg->param; + + free(arg); + + entry(param); + +#if defined(PPR_USE_CREATETHREAD) + ExitThread(0); +#else + _endthreadex(0); +#endif + + return 0; +} +#elif defined(PPR_USE_PTHREAD) +static void* thread_entry(void* _param) { + arg_t* arg = _param; + void (*entry)(void* param) = arg->entry; + void* param = arg->param; + + free(arg); + + entry(param); + + pthread_exit(NULL); + + return NULL; +} +#elif defined(PPR_IS_NETWARE) +static void thread_entry(void* _param) { + arg_t* arg = _param; + void (*entry)(void* param) = arg->entry; + void* param = arg->param; + LONG waitsem = arg->waitsem; + + free(arg); + + entry(param); + + SignalLocalSemaphore(waitsem); + ExitThread(EXIT_THREAD, 0); +} +#endif + +void* ppr_thread_create(void (*entry)(void* param), void* param) { +#if defined(PPR_IS_WIN32) + arg_t* arg = malloc(sizeof(*arg)); +#if defined(PPR_USE_CREATETHREAD) + DWORD id; +#else + unsigned int id; +#endif + + arg->entry = entry; + arg->param = param; + + return (void*) +#if defined(PPR_USE_CREATETHREAD) + CreateThread +#else + _beginthreadex +#endif + (NULL, 0, thread_entry, arg, 0, &id); +#elif defined(PPR_USE_PTHREAD) + pthread_t* t = malloc(sizeof(*t)); + arg_t* arg = malloc(sizeof(*arg)); + + arg->entry = entry; + arg->param = param; + + pthread_create(t, NULL, thread_entry, arg); + + return t; +#elif defined(PPR_IS_NETWARE) + thread_t* t = malloc(sizeof(*t)); + arg_t* arg = malloc(sizeof(*arg)); + + arg->entry = entry; + arg->param = param; + arg->waitsem = ppr_thread_open_semaphore(0); + + t->waitsem = arg->waitsem; + t->thread = BeginThread(thread_entry, NULL, 8192, arg); + + return t; +#else + (void)entry; + (void)param; + + return NULL; +#endif +} + +void ppr_thread_join(void* handle) { +#if defined(PPR_IS_WIN32) + WaitForSingleObject(handle, INFINITE); +#elif defined(PPR_USE_PTHREAD) + void* ret; + + pthread_join(*(pthread_t*)handle, &ret); +#elif defined(PPR_IS_NETWARE) + thread_t* t = handle; + + WaitOnLocalSemaphore(t->waitsem); +#else + (void)handle; +#endif +} + +void ppr_thread_destroy(void* handle) { +#if defined(PPR_IS_WIN32) + CloseHandle(handle); +#elif defined(PPR_USE_PTHREAD) + free(handle); +#elif defined(PPR_IS_NETWARE) + thread_t* t = handle; + int i; + + ppr_thread_close_semaphore(t->waitsem); + + for(i = 0; i < sizeof(ppr_threads) / sizeof(ppr_threads[0]); i++) { + if(ppr_threads[i].used && ppr_threads[i].thread == handle) { + ppr_threads[i].used = ppr_false; + break; + } + } + + free(handle); +#else + (void)handle; +#endif +} diff --git a/src/base/time.c b/src/base/time.c new file mode 100644 index 0000000..171854b --- /dev/null +++ b/src/base/time.c @@ -0,0 +1,45 @@ +#include +#include + +void* ppr_gmtime_mutex; +void* ppr_localtime_mutex; + +ppr_time_t ppr_time(void) { + time_t t = time(NULL); + + return t; +} + +static void tm_to_ppr(struct ppr_tm* to, struct tm* from) { + to->tm_sec = from->tm_sec; + to->tm_min = from->tm_min; + to->tm_hour = from->tm_hour; + to->tm_mday = from->tm_mday; + to->tm_mon = from->tm_mon; + to->tm_year = from->tm_year; + to->tm_wday = from->tm_wday; + to->tm_yday = from->tm_yday; + to->tm_isdst = from->tm_isdst; +} + +void ppr_gmtime(struct ppr_tm* tm, ppr_time_t t) { + struct tm from_tm; + time_t from = t; + + ppr_mutex_lock(ppr_gmtime_mutex); + from_tm = *gmtime(&from); + ppr_mutex_unlock(ppr_gmtime_mutex); + + tm_to_ppr(tm, &from_tm); +} + +void ppr_localtime(struct ppr_tm* tm, ppr_time_t t) { + struct tm from_tm; + time_t from = t; + + ppr_mutex_lock(ppr_localtime_mutex); + from_tm = *localtime(&from); + ppr_mutex_unlock(ppr_localtime_mutex); + + tm_to_ppr(tm, &from_tm); +} diff --git a/src/base/unistd.c b/src/base/unistd.c new file mode 100644 index 0000000..4ffc531 --- /dev/null +++ b/src/base/unistd.c @@ -0,0 +1,33 @@ +#include +#include + +int ppr_gethostname(char* name, int namelen) { +#if defined(PPR_IS_PS2) + if(namelen < 4) return -1; + + strcpy(name, "PS2"); + return 0; +#elif defined(PPR_IS_NETWARE) + if(namelen < 8) return -1; + + strcpy(name, "netware"); + return 0; +#else + return gethostname(name, namelen); +#endif +} + +void ppr_msleep(int ms) { +#if defined(PPR_IS_WIN32) + Sleep(ms); +#elif defined(PPR_IS_NETWARE) + delay(ms); +#else + struct timespec ts; + + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; + + nanosleep(&ts, NULL); +#endif +} diff --git a/src/core.c b/src/core.c new file mode 100644 index 0000000..bcb721f --- /dev/null +++ b/src/core.c @@ -0,0 +1,22 @@ +#include +#include + +void ppr_init(void) { + ppr_socket_init(); + ppr_thread_init(); + +#if defined(PPR_IS_NETWARE) + SetCurrentNameSpace(NW_NS_LONG); +#endif + + ppr_gmtime_mutex = ppr_mutex_create(); + ppr_localtime_mutex = ppr_mutex_create(); +} + +void ppr_uninit(void) { + ppr_mutex_destroy(ppr_localtime_mutex); + ppr_mutex_destroy(ppr_gmtime_mutex); + + ppr_thread_uninit(); + ppr_socket_uninit(); +} diff --git a/src/hash/blake2s.c b/src/hash/blake2s.c new file mode 100644 index 0000000..b21f25e --- /dev/null +++ b/src/hash/blake2s.c @@ -0,0 +1,368 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include + +#include "blake2s_int.h" + +static const ppr_uint32_t ppr_blake2s_IV[8] = + { + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL}; + +static const ppr_uint8_t ppr_blake2s_sigma[10][16] = + { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, +}; + +static void ppr_blake2s_set_lastnode(ppr_blake2s_state* S) { + S->f[1] = (ppr_uint32_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int ppr_blake2s_is_lastblock(const ppr_blake2s_state* S) { + return S->f[0] != 0; +} + +static void ppr_blake2s_set_lastblock(ppr_blake2s_state* S) { + if(S->last_node) ppr_blake2s_set_lastnode(S); + + S->f[0] = (ppr_uint32_t)-1; +} + +static void ppr_blake2s_increment_counter(ppr_blake2s_state* S, const ppr_uint32_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static void ppr_blake2s_init0(ppr_blake2s_state* S) { + ppr_size_t i; + memset(S, 0, sizeof(ppr_blake2s_state)); + + for(i = 0; i < 8; ++i) S->h[i] = ppr_blake2s_IV[i]; +} + +/* init2 xors IV with input parameter block */ +int ppr_blake2s_init_param(ppr_blake2s_state* S, const ppr_blake2s_param* P) { + ppr_size_t i; +#ifdef PPR_HAS_PACK + unsigned char* p = (unsigned char*)P; +#else + unsigned char p[32]; + unsigned char* ptr = &p[0]; +#endif + + ppr_blake2s_init0(S); + +#ifndef PPR_HAS_PACK +#define COPY(x) \ + { \ + memcpy(ptr, &(x), sizeof((x))); \ + ptr += sizeof((x)); \ + } + COPY(P->digest_length); + COPY(P->key_length); + COPY(P->fanout); + COPY(P->depth); + COPY(P->leaf_length); + COPY(P->node_offset); + COPY(P->xof_length); + COPY(P->node_depth); + COPY(P->inner_length); + COPY(P->salt); + COPY(P->personal); +#undef COPY +#endif + + /* IV XOR ParamBlock */ + for(i = 0; i < 8; ++i) + S->h[i] ^= load32(&p[i * 4]); + + S->outlen = P->digest_length; + return 0; +} + +/* Sequential ppr_blake2s initialization */ +int ppr_blake2s_init(ppr_blake2s_state* S, ppr_size_t outlen) { + ppr_blake2s_param P[1]; + + /* Move interval verification here? */ + if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1; + + P->digest_length = (ppr_uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store16(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset(P->salt, 0, sizeof(P->salt)); + memset(P->personal, 0, sizeof(P->personal)); + return ppr_blake2s_init_param(S, P); +} + +int ppr_blake2s_init_key(ppr_blake2s_state* S, ppr_size_t outlen, const void* key, ppr_size_t keylen) { + ppr_blake2s_param P[1]; + + if((!outlen) || (outlen > BLAKE2S_OUTBYTES)) return -1; + + if(!key || !keylen || keylen > BLAKE2S_KEYBYTES) return -1; + + P->digest_length = (ppr_uint8_t)outlen; + P->key_length = (ppr_uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32(&P->leaf_length, 0); + store32(&P->node_offset, 0); + store16(&P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset(P->salt, 0, sizeof(P->salt)); + memset(P->personal, 0, sizeof(P->personal)); + + if(ppr_blake2s_init_param(S, P) < 0) return -1; + + { + ppr_uint8_t block[BLAKE2S_BLOCKBYTES]; + memset(block, 0, BLAKE2S_BLOCKBYTES); + memcpy(block, key, keylen); + ppr_blake2s_update(S, block, BLAKE2S_BLOCKBYTES); + secure_zero_memory(block, BLAKE2S_BLOCKBYTES); /* Burn the key from stack */ + } + return 0; +} + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[ppr_blake2s_sigma[r][2 * i + 0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[ppr_blake2s_sigma[r][2 * i + 1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while(0) + +static void ppr_blake2s_compress(ppr_blake2s_state* S, const ppr_uint8_t in[BLAKE2S_BLOCKBYTES]) { + ppr_uint32_t m[16]; + ppr_uint32_t v[16]; + ppr_size_t i; + + for(i = 0; i < 16; ++i) { + m[i] = load32(in + i * sizeof(m[i])); + } + + for(i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = ppr_blake2s_IV[0]; + v[9] = ppr_blake2s_IV[1]; + v[10] = ppr_blake2s_IV[2]; + v[11] = ppr_blake2s_IV[3]; + v[12] = S->t[0] ^ ppr_blake2s_IV[4]; + v[13] = S->t[1] ^ ppr_blake2s_IV[5]; + v[14] = S->f[0] ^ ppr_blake2s_IV[6]; + v[15] = S->f[1] ^ ppr_blake2s_IV[7]; + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + + for(i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int ppr_blake2s_update(ppr_blake2s_state* S, const void* pin, ppr_size_t inlen) { + const unsigned char* in = (const unsigned char*)pin; + if(inlen > 0) { + ppr_size_t left = S->buflen; + ppr_size_t fill = BLAKE2S_BLOCKBYTES - left; + if(inlen > fill) { + S->buflen = 0; + memcpy(S->buf + left, in, fill); /* Fill buffer */ + ppr_blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + ppr_blake2s_compress(S, S->buf); /* Compress */ + in += fill; + inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + ppr_blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + ppr_blake2s_compress(S, in); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy(S->buf + S->buflen, in, inlen); + S->buflen += inlen; + } + return 0; +} + +int ppr_blake2s_final(ppr_blake2s_state* S, void* out, ppr_size_t outlen) { + ppr_uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + ppr_size_t i; + + if(out == NULL || outlen < S->outlen) + return -1; + + if(ppr_blake2s_is_lastblock(S)) + return -1; + + ppr_blake2s_increment_counter(S, (ppr_uint32_t)S->buflen); + ppr_blake2s_set_lastblock(S); + memset(S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen); /* Padding */ + ppr_blake2s_compress(S, S->buf); + + for(i = 0; i < 8; ++i) /* Output full hash to temp buffer */ + store32(buffer + sizeof(S->h[i]) * i, S->h[i]); + + memcpy(out, buffer, outlen); + secure_zero_memory(buffer, sizeof(buffer)); + return 0; +} + +int ppr_blake2s(void* out, ppr_size_t outlen, const void* in, ppr_size_t inlen, const void* key, ppr_size_t keylen) { + ppr_blake2s_state S[1]; + + /* Verify parameters */ + if(NULL == in && inlen > 0) return -1; + + if(NULL == out) return -1; + + if(NULL == key && keylen > 0) return -1; + + if(!outlen || outlen > BLAKE2S_OUTBYTES) return -1; + + if(keylen > BLAKE2S_KEYBYTES) return -1; + + if(keylen > 0) { + if(ppr_blake2s_init_key(S, outlen, key, keylen) < 0) return -1; + } else { + if(ppr_blake2s_init(S, outlen) < 0) return -1; + } + + ppr_blake2s_update(S, (const ppr_uint8_t*)in, inlen); + ppr_blake2s_final(S, out, outlen); + return 0; +} + +#if defined(SUPERCOP) +int crypto_hash(unsigned char* out, unsigned char* in, unsigned long long inlen) { + return ppr_blake2s(out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0); +} +#endif + +#if defined(BLAKE2S_SELFTEST) +#include +#include "blake2-kat.h" +int main(void) { + ppr_uint8_t key[BLAKE2S_KEYBYTES]; + ppr_uint8_t buf[BLAKE2_KAT_LENGTH]; + ppr_size_t i, step; + + for(i = 0; i < BLAKE2S_KEYBYTES; ++i) + key[i] = (ppr_uint8_t)i; + + for(i = 0; i < BLAKE2_KAT_LENGTH; ++i) + buf[i] = (ppr_uint8_t)i; + + /* Test simple API */ + for(i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + ppr_uint8_t hash[BLAKE2S_OUTBYTES]; + ppr_blake2s(hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES); + + if(0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for(i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + ppr_uint8_t hash[BLAKE2S_OUTBYTES]; + ppr_blake2s_state S; + ppr_uint8_t* p = buf; + ppr_size_t mlen = i; + int err = 0; + + if((err = ppr_blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0) { + goto fail; + } + + while(mlen >= step) { + if((err = ppr_blake2s_update(&S, p, step)) < 0) { + goto fail; + } + mlen -= step; + p += step; + } + if((err = ppr_blake2s_update(&S, p, mlen)) < 0) { + goto fail; + } + if((err = ppr_blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) { + goto fail; + } + + if(0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) { + goto fail; + } + } + } + + puts("ok"); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/hash/blake2s_int.h b/src/hash/blake2s_int.h new file mode 100644 index 0000000..27ebbd8 --- /dev/null +++ b/src/hash/blake2s_int.h @@ -0,0 +1,73 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2S_INT_H +#define BLAKE2S_INT_H + +#include + +#include + +#define BLAKE2S_INLINE static __inline + +BLAKE2S_INLINE ppr_uint32_t load32(const void* src) { +#if defined(NATIVE_LITTLE_ENDIAN) + ppr_uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const ppr_uint8_t* p = (const ppr_uint8_t*)src; + return ((ppr_uint32_t)(p[0]) << 0) | + ((ppr_uint32_t)(p[1]) << 8) | + ((ppr_uint32_t)(p[2]) << 16) | + ((ppr_uint32_t)(p[3]) << 24); +#endif +} + +BLAKE2S_INLINE void store16(void* dst, ppr_uint16_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + ppr_uint8_t* p = (ppr_uint8_t*)dst; + *p++ = (ppr_uint8_t)w; + w >>= 8; + *p++ = (ppr_uint8_t)w; +#endif +} + +BLAKE2S_INLINE void store32(void* dst, ppr_uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + ppr_uint8_t* p = (ppr_uint8_t*)dst; + p[0] = (ppr_uint8_t)(w >> 0); + p[1] = (ppr_uint8_t)(w >> 8); + p[2] = (ppr_uint8_t)(w >> 16); + p[3] = (ppr_uint8_t)(w >> 24); +#endif +} + +BLAKE2S_INLINE ppr_uint32_t rotr32(const ppr_uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +#include + +/* prevents compiler optimizing out memset() */ +BLAKE2S_INLINE void secure_zero_memory(void* v, ppr_size_t n) { + static void* (*const volatile memset_v)(void*, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/src/hash/md5.c b/src/hash/md5.c new file mode 100644 index 0000000..44ab492 --- /dev/null +++ b/src/hash/md5.c @@ -0,0 +1,254 @@ +#include +#include + +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +/* forward declaration */ +static void Transform(ppr_uint32_t* buf, ppr_uint32_t* in); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* F, G and H are basic MD5 functions: selection, majority, parity */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + { \ + (a) += F((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + { \ + (a) += G((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + { \ + (a) += H((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + { \ + (a) += I((b), (c), (d)) + (x) + (ppr_uint32_t)(ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +void ppr_md5_init(ppr_md5_context_t* mdContext) { + mdContext->i[0] = mdContext->i[1] = (ppr_uint32_t)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (ppr_uint32_t)0x67452301; + mdContext->buf[1] = (ppr_uint32_t)0xefcdab89; + mdContext->buf[2] = (ppr_uint32_t)0x98badcfe; + mdContext->buf[3] = (ppr_uint32_t)0x10325476; +} + +void ppr_md5_update(ppr_md5_context_t* mdContext, const void* inBuf, unsigned int inLen) { + ppr_uint32_t in[16]; + int mdi; + unsigned int i, ii; + const unsigned char* buf = inBuf; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if((mdContext->i[0] + ((ppr_uint32_t)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((ppr_uint32_t)inLen << 3); + mdContext->i[1] += ((ppr_uint32_t)inLen >> 29); + + while(inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *buf++; + + /* transform if necessary */ + if(mdi == 0x40) { + for(i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((ppr_uint32_t)mdContext->in[ii + 3]) << 24) | + (((ppr_uint32_t)mdContext->in[ii + 2]) << 16) | + (((ppr_uint32_t)mdContext->in[ii + 1]) << 8) | + ((ppr_uint32_t)mdContext->in[ii]); + Transform(mdContext->buf, in); + mdi = 0; + } + } +} + +void ppr_md5_final(ppr_md5_context_t* mdContext) { + ppr_uint32_t in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + ppr_md5_update(mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for(i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((ppr_uint32_t)mdContext->in[ii + 3]) << 24) | + (((ppr_uint32_t)mdContext->in[ii + 2]) << 16) | + (((ppr_uint32_t)mdContext->in[ii + 1]) << 8) | + ((ppr_uint32_t)mdContext->in[ii]); + Transform(mdContext->buf, in); + + /* store buffer in digest */ + for(i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii + 1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii + 2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii + 3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } +} + +/* Basic MD5 step. Transform buf based on in. + */ +static void Transform(ppr_uint32_t* buf, ppr_uint32_t* in) { + ppr_uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF(a, b, c, d, in[0], S11, 3614090360); /* 1 */ + FF(d, a, b, c, in[1], S12, 3905402710); /* 2 */ + FF(c, d, a, b, in[2], S13, 606105819); /* 3 */ + FF(b, c, d, a, in[3], S14, 3250441966); /* 4 */ + FF(a, b, c, d, in[4], S11, 4118548399); /* 5 */ + FF(d, a, b, c, in[5], S12, 1200080426); /* 6 */ + FF(c, d, a, b, in[6], S13, 2821735955); /* 7 */ + FF(b, c, d, a, in[7], S14, 4249261313); /* 8 */ + FF(a, b, c, d, in[8], S11, 1770035416); /* 9 */ + FF(d, a, b, c, in[9], S12, 2336552879); /* 10 */ + FF(c, d, a, b, in[10], S13, 4294925233); /* 11 */ + FF(b, c, d, a, in[11], S14, 2304563134); /* 12 */ + FF(a, b, c, d, in[12], S11, 1804603682); /* 13 */ + FF(d, a, b, c, in[13], S12, 4254626195); /* 14 */ + FF(c, d, a, b, in[14], S13, 2792965006); /* 15 */ + FF(b, c, d, a, in[15], S14, 1236535329); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG(a, b, c, d, in[1], S21, 4129170786); /* 17 */ + GG(d, a, b, c, in[6], S22, 3225465664); /* 18 */ + GG(c, d, a, b, in[11], S23, 643717713); /* 19 */ + GG(b, c, d, a, in[0], S24, 3921069994); /* 20 */ + GG(a, b, c, d, in[5], S21, 3593408605); /* 21 */ + GG(d, a, b, c, in[10], S22, 38016083); /* 22 */ + GG(c, d, a, b, in[15], S23, 3634488961); /* 23 */ + GG(b, c, d, a, in[4], S24, 3889429448); /* 24 */ + GG(a, b, c, d, in[9], S21, 568446438); /* 25 */ + GG(d, a, b, c, in[14], S22, 3275163606); /* 26 */ + GG(c, d, a, b, in[3], S23, 4107603335); /* 27 */ + GG(b, c, d, a, in[8], S24, 1163531501); /* 28 */ + GG(a, b, c, d, in[13], S21, 2850285829); /* 29 */ + GG(d, a, b, c, in[2], S22, 4243563512); /* 30 */ + GG(c, d, a, b, in[7], S23, 1735328473); /* 31 */ + GG(b, c, d, a, in[12], S24, 2368359562); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH(a, b, c, d, in[5], S31, 4294588738); /* 33 */ + HH(d, a, b, c, in[8], S32, 2272392833); /* 34 */ + HH(c, d, a, b, in[11], S33, 1839030562); /* 35 */ + HH(b, c, d, a, in[14], S34, 4259657740); /* 36 */ + HH(a, b, c, d, in[1], S31, 2763975236); /* 37 */ + HH(d, a, b, c, in[4], S32, 1272893353); /* 38 */ + HH(c, d, a, b, in[7], S33, 4139469664); /* 39 */ + HH(b, c, d, a, in[10], S34, 3200236656); /* 40 */ + HH(a, b, c, d, in[13], S31, 681279174); /* 41 */ + HH(d, a, b, c, in[0], S32, 3936430074); /* 42 */ + HH(c, d, a, b, in[3], S33, 3572445317); /* 43 */ + HH(b, c, d, a, in[6], S34, 76029189); /* 44 */ + HH(a, b, c, d, in[9], S31, 3654602809); /* 45 */ + HH(d, a, b, c, in[12], S32, 3873151461); /* 46 */ + HH(c, d, a, b, in[15], S33, 530742520); /* 47 */ + HH(b, c, d, a, in[2], S34, 3299628645); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II(a, b, c, d, in[0], S41, 4096336452); /* 49 */ + II(d, a, b, c, in[7], S42, 1126891415); /* 50 */ + II(c, d, a, b, in[14], S43, 2878612391); /* 51 */ + II(b, c, d, a, in[5], S44, 4237533241); /* 52 */ + II(a, b, c, d, in[12], S41, 1700485571); /* 53 */ + II(d, a, b, c, in[3], S42, 2399980690); /* 54 */ + II(c, d, a, b, in[10], S43, 4293915773); /* 55 */ + II(b, c, d, a, in[1], S44, 2240044497); /* 56 */ + II(a, b, c, d, in[8], S41, 1873313359); /* 57 */ + II(d, a, b, c, in[15], S42, 4264355552); /* 58 */ + II(c, d, a, b, in[6], S43, 2734768916); /* 59 */ + II(b, c, d, a, in[13], S44, 1309151649); /* 60 */ + II(a, b, c, d, in[4], S41, 4149444226); /* 61 */ + II(d, a, b, c, in[11], S42, 3174756917); /* 62 */ + II(c, d, a, b, in[2], S43, 718787259); /* 63 */ + II(b, c, d, a, in[9], S44, 3951481745); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/src/hash/sha256.c b/src/hash/sha256.c new file mode 100644 index 0000000..755d848 --- /dev/null +++ b/src/hash/sha256.c @@ -0,0 +1,121 @@ +#include +#include + +const ppr_uint32_t sha256_initial_h[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + +const ppr_uint32_t sha256_round_k[64] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +static ppr_uint32_t sha256_endian_read32(ppr_uint8_t* input) { + ppr_uint32_t output = 0; + output |= (input[0] << 24); + output |= (input[1] << 16); + output |= (input[2] << 8); + output |= (input[3] << 0); + + return output; +} + +static ppr_uint32_t sha256_ror(ppr_uint32_t input, ppr_uint32_t by) { + return (input >> by) | (((input & ((1 << by) - 1))) << (32 - by)); +} + +void ppr_sha256(void* output, const void* data, ppr_size_t len) { + ppr_uint8_t padding[80]; + ppr_size_t current = (len + 1) % 64; + /* want to be == 56 % 64. */ + ppr_size_t needed = (64 + 56 - current) % 64; + ppr_size_t extra = needed + 9; + ppr_size_t total = len + extra; + int i, j; + ppr_size_t cursor; + ppr_uint32_t v[8]; + ppr_size_t l; + + for(i = 1; i < 80; i++) + padding[i] = 0; + padding[0] = 0x80; + + l = len * 8; + for(i = 7; i >= 0; i--) { + padding[total - len - 8 + i] = l & 0xff; + l = l >> 8; + } + + for(i = 0; i < 8; i++) + v[i] = sha256_initial_h[i]; + + for(cursor = 0; cursor * 64 < total; cursor++) { + ppr_uint32_t t[8]; + ppr_uint32_t w[64]; + for(i = 0; i < 8; i++) + t[i] = v[i]; + + if(cursor * 64 + 64 <= len) { + for(j = 0; j < 16; j++) { + w[j] = sha256_endian_read32( + (ppr_uint8_t*)data + cursor * 64 + j * 4); + } + } else { + if(cursor * 64 < len) { + ppr_size_t size = len - cursor * 64; + if(size > 0) memcpy(w, (ppr_uint8_t*)data + cursor * 64, size); + memcpy((ppr_uint8_t*)w + size, padding, 64 - size); + } else { + ppr_size_t off = (cursor * 64 - len) % 64; + memcpy((ppr_uint8_t*)w, padding + off, 64); + } + + for(j = 0; j < 16; j++) { + w[j] = sha256_endian_read32((ppr_uint8_t*)&w[j]); + } + } + + for(j = 16; j < 64; j++) { + ppr_uint32_t s1 = sha256_ror(w[j - 2], 17) ^ sha256_ror(w[j - 2], 19) ^ (w[j - 2] >> 10); + ppr_uint32_t s0 = sha256_ror(w[j - 15], 7) ^ sha256_ror(w[j - 15], 18) ^ (w[j - 15] >> 3); + w[j] = s1 + w[j - 7] + s0 + w[j - 16]; + } + + for(j = 0; j < 64; j++) { + ppr_uint32_t ch = (t[4] & t[5]) ^ (~t[4] & t[6]); + ppr_uint32_t maj = (t[0] & t[1]) ^ (t[0] & t[2]) ^ (t[1] & t[2]); + ppr_uint32_t S0 = sha256_ror(t[0], 2) ^ sha256_ror(t[0], 13) ^ sha256_ror(t[0], 22); + ppr_uint32_t S1 = sha256_ror(t[4], 6) ^ sha256_ror(t[4], 11) ^ sha256_ror(t[4], 25); + + ppr_uint32_t t1 = t[7] + S1 + ch + sha256_round_k[j] + w[j]; + ppr_uint32_t t2 = S0 + maj; + + t[7] = t[6]; + t[6] = t[5]; + t[5] = t[4]; + t[4] = t[3] + t1; + t[3] = t[2]; + t[2] = t[1]; + t[1] = t[0]; + t[0] = t1 + t2; + } + + for(i = 0; i < 8; i++) v[i] += t[i]; + } + + for(i = 0; i < 8; i++) { + ppr_uint8_t* out = (ppr_uint8_t*)output + i * 4; + ppr_uint32_t val = v[i]; + + for(j = 3; j >= 0; j--) { + out[j] = val & 0xff; + val = val >> 8; + } + } +} diff --git a/src/misc/url.c b/src/misc/url.c new file mode 100644 index 0000000..ea03712 --- /dev/null +++ b/src/misc/url.c @@ -0,0 +1,218 @@ +#include +#include + +static int hex(const char in) { + if('0' <= in && in <= '9') return in - '0'; + if('a' <= in && in <= 'f') return in - 'a' + 10; + if('A' <= in && in <= 'F') return in - 'A' + 10; + + return 0; +} + +ppr_bool ppr_url_decode(char* out, const char* input, int len) { + int i; + + for(i = 0; input[i] != 0; i++) { + if((int)strlen(out) == len) { + return ppr_false; + } else if(input[i] == '%') { + if(strlen(input + i) >= 3) { + int n = strlen(out); + out[n] = (hex(input[i + 1]) << 4) | (hex(input[i + 2])); + out[n + 1] = 0; + + i += 2; + } + } else { + int n = strlen(out); + out[n] = input[i]; + out[n + 1] = 0; + } + } + + return ppr_true; +} + +ppr_bool ppr_url_encode(char* out, const char* input, int len) { + int i; + + for(i = 0; input[i] != 0; i++) { + if(strlen(out) == len) { + return ppr_false; + } else if(input[i] == '%') { + if(strlen(input + i) >= 3 && strlen(out) <= (len - 3)) { + int n = strlen(out); + + out[n] = '%'; + out[n + 1] = '2'; + out[n + 2] = '5'; + out[n + 3] = 0; + } + } else { + int n = strlen(out); + out[n] = input[i]; + out[n + 1] = 0; + } + } + + return ppr_true; +} + +void ppr_url_init(ppr_url_t* url) { + memset(url, 0, sizeof(*url)); +} + +enum STATE { + USERINFO = 0, + HOST, + PORT, + PATH, + QUERY, + FRAGMENT +}; + +ppr_bool ppr_url_parse(ppr_url_t* url, const char* str) { + const char* st; /* tmp */ + const char* sp; /* pointer */ + ppr_bool has_userinfo = ppr_false; + int state = 0; + ppr_bool br = ppr_false; + + if((st = strstr(str, "://")) == NULL) return ppr_false; + + for(sp = str; sp != st; sp++) { + char c = *sp; + + if('A' <= c && c <= 'Z') continue; + if('a' <= c && c <= 'z') continue; + if(sp == str) { + ppr_url_deinit(url); + return ppr_false; + } + + if('0' <= c && c <= '9') continue; + if(c == '+' || c == '-' || c == '.') continue; + + ppr_url_deinit(url); + return ppr_false; + } + + url->scheme = malloc(sp - str + 1); + memcpy(url->scheme, str, sp - str); + url->scheme[sp - str] = 0; + + str = st + 3; + + if((st = strchr(str, '/')) == NULL) st = str + strlen(str); + + for(sp = str; sp != st; sp++) { + if((*sp) == '@') { + has_userinfo = ppr_true; + break; + } + } + + if(has_userinfo) { + state = USERINFO; + } else { + state = HOST; + } + + for(sp = str;; sp++) { + char c = *sp; + + if(state == USERINFO && c == '@') { + url->userinfo = malloc(sp - str + 1); + memcpy(url->userinfo, str, sp - str); + url->userinfo[sp - str] = 0; + + str = sp + 1; + + state = HOST; + } else if(state == HOST && !br && c == '[') { + br = ppr_true; + } else if(state == HOST && br && c == ']') { + br = ppr_false; + } else if(state == HOST && !br && (c == 0 || c == ':' || c == '/')) { + url->host = malloc(sp - str + 1); + memcpy(url->host, str, sp - str); + url->host[sp - str] = 0; + + if(c == 0) { + break; + } else if(c == ':') { + str = sp + 1; + + state = PORT; + } else { + str = sp; + + state = PATH; + } + } else if(state == PORT && (c == 0 || c == '/')) { + char* p = malloc(sp - str + 1); + memcpy(p, str, sp - str); + p[sp - str] = 0; + + url->port = atoi(p); + + free(p); + + if(c == 0) { + break; + } else { + str = sp; /* intended */ + + state = PATH; + } + } else if(state == PATH && (c == 0 || c == '?' || c == '#')) { + url->path = malloc(sp - str + 1); + memcpy(url->path, str, sp - str); + url->path[sp - str] = 0; + + str = sp + 1; + + if(c == 0) { + break; + } else if(c == '?') { + state = QUERY; + } else { + state = FRAGMENT; + } + } else if(state == QUERY && (c == 0 || c == '#')) { + url->query = malloc(sp - str + 1); + memcpy(url->query, str, sp - str); + url->query[sp - str] = 0; + + str = sp + 1; + + if(c == 0) { + break; + } else { + state = FRAGMENT; + } + } else if(state == FRAGMENT && c == 0) { + url->fragment = malloc(sp - str + 1); + memcpy(url->fragment, str, sp - str); + url->fragment[sp - str] = 0; + + break; + } else if(c == 0) { + ppr_url_deinit(url); + return ppr_false; + } + } + + return ppr_true; +} + +void ppr_url_deinit(ppr_url_t* url) { + if(url->scheme != NULL) free(url->scheme); + if(url->userinfo != NULL) free(url->userinfo); + if(url->host != NULL) free(url->host); + if(url->path != NULL) free(url->path); + if(url->query != NULL) free(url->query); + if(url->fragment != NULL) free(url->fragment); + + memset(url, 0, sizeof(*url)); +} diff --git a/src/misc/wildcard.c b/src/misc/wildcard.c new file mode 100644 index 0000000..d4e22f2 --- /dev/null +++ b/src/misc/wildcard.c @@ -0,0 +1,23 @@ +#include +#include + +ppr_bool ppr_wildcard(const char* wildcard, const char* target) { + const char *pw = wildcard, *pt = target; + + while(1) { + if(*pt == 0) { + while(*pw == '*') pw++; + return *pw == 0; + } else if(*pw == 0) { + return 0; + } else if(*pw == '*') { + return *(pw + 1) == 0 || ppr_wildcard(pw, pt + 1) || ppr_wildcard(pw + 1, pt); + } else if(*pw == '?' || (tolower((int)*pw) == tolower((int)*pt))) { + pw++; + pt++; + continue; + } else { + return 0; + } + } +}