Compare commits
3
Commits
b9e247b88f
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6347444494 | ||
|
|
f43bb30065 | ||
|
|
e00ffe6f70 |
@@ -0,0 +1,265 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file crypt.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include "crypt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_crypt__read_key_file(const char *key_file, unsigned char *key,
|
||||||
|
unsigned char *salt)
|
||||||
|
{
|
||||||
|
AislStatus result = AISL_SYSCALL_ERROR;
|
||||||
|
int i;
|
||||||
|
FILE *f;
|
||||||
|
char buff[2*(AX_CRYPT_KEY_SIZE + AX_CRYPT_SALT_SIZE) + 1], char hex[2 + 1],
|
||||||
|
*ptr = buff, *ep = NULL;
|
||||||
|
|
||||||
|
if (!(f = fopen(key_file))) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(buff, 1, sizeof (buff), f) != sizeof (buff)) {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
hex[2] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_SALT_SIZE; i++) {
|
||||||
|
memcpy(hex, ptr, 2);
|
||||||
|
salt[i] = strtol(hex, &ep, 16);
|
||||||
|
if (ep != &hex[2]) {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(ptr++) != '$') {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_KEY_SIZE; i++) {
|
||||||
|
memcpy(hex, ptr, 2);
|
||||||
|
key[i] = strtol(hex, &ep, 16);
|
||||||
|
if (ep != &hex[2]) {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = AISL_SUCCESS;
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
e_input:
|
||||||
|
result = AISL_INPUT_ERROR;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_crypt__write_key_file(const char *key_file, unsigned char *key,
|
||||||
|
unsigned char *salt)
|
||||||
|
{
|
||||||
|
AislStatus result = AISL_SYSCALL_ERROR;
|
||||||
|
int i;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (!(f = fopen(key_file))) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_SALT_SIZE; i++) {
|
||||||
|
if (fprintf(f, "%02x", salt[i] & 0xFF) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fputc('$', f) == EOF) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_KEY_SIZE; i++) {
|
||||||
|
if (fprintf(f, "%02x", key[i] & 0xFF) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = AISL_SUCCESS;
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fclose(f);
|
||||||
|
chmod(key_file, S_IRUSR);
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_crypt_init(AxSession crypt, const char *key_file)
|
||||||
|
{
|
||||||
|
AislStatus result;
|
||||||
|
unsigned char key[AX_CRYPT_KEY_SIZE], salt[AX_CRYPT_SALT_SIZE],
|
||||||
|
evp_key[AX_CRYPT_KEY_SIZE], iv[AX_CRYPT_KEY_SIZE];
|
||||||
|
|
||||||
|
if (cstuff_file_exists(key_file)) {
|
||||||
|
result = ax_crypt__read_key_file(key_file, key, salt);
|
||||||
|
} else {
|
||||||
|
RAND_bytes(key, sizeof (key));
|
||||||
|
RAND_bytes(salt, sizeof (salt));
|
||||||
|
result = ax_crypt__write_key_file(key_file, key, salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != AISL_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key, sizeof (key), 5,
|
||||||
|
key, iv)) {
|
||||||
|
return AISL_SYSCALL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((crypt->e_ctx = EVP_CIPHER_CTX_new())) {
|
||||||
|
EVP_CIPHER_CTX_init(crypt->e_ctx);
|
||||||
|
EVP_EncryptInit_ex(crypt->e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
|
||||||
|
if ((crypt->d_ctx = EVP_CIPHER_CTX_new())) {
|
||||||
|
EVP_CIPHER_CTX_init(crypt->d_ctx);
|
||||||
|
EVP_DecryptInit_ex(crypt->d_ctx, EVP_aes_256_cbc(), NULL, key, iv);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
EVP_CIPHER_CTX_free(crypt->e_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_crypt_release(AxSession crypt)
|
||||||
|
{
|
||||||
|
if (crypt->e_ctx) {
|
||||||
|
EVP_CIPHER_CTX_free(crypt->e_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypt->d_ctx) {
|
||||||
|
EVP_CIPHER_CTX_free(crypt->d_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_write(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = in_len, l;
|
||||||
|
unsigned char *out;
|
||||||
|
EVP_CIPHER_CTX *e_ctx = crypt->e_ctx;
|
||||||
|
|
||||||
|
if (!(out = calloc(result + EVP_MAX_BLOCK_LENGTH, sizeof (char)))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_EncryptInit_ex(e_ctx, NULL, NULL, NULL, NULL);
|
||||||
|
EVP_EncryptUpdate(e_ctx, out, &result, (const unsigned char *)input, in_len);
|
||||||
|
EVP_EncryptFinal_ex(e_ctx, &out[result], &l);
|
||||||
|
*p_out = (char *)out;
|
||||||
|
return result + l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_read(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = in_len, l;
|
||||||
|
unsigned char *out;
|
||||||
|
EVP_CIPHER_CTX *d_ctx = crypt->d_ctx;
|
||||||
|
|
||||||
|
if (!(out = malloc(in_len + EVP_MAX_BLOCK_LENGTH))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_DecryptInit_ex(d_ctx, NULL, NULL, NULL, NULL);
|
||||||
|
EVP_DecryptUpdate(d_ctx, out, &result, input, in_len);
|
||||||
|
EVP_DecryptFinal_ex(d_ctx, &out[result], &l);
|
||||||
|
|
||||||
|
*p_out = (char *)out;
|
||||||
|
return result + l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_encode(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
BIO *bio, *b64;
|
||||||
|
BUF_MEM *bptr;
|
||||||
|
unsigned char *out, *cipher;
|
||||||
|
|
||||||
|
if ((in_len = ax_crypt_write(crypt, &cipher, input, in_len)) != -1) {
|
||||||
|
if ((b64 = BIO_new( BIO_f_base64()))) {
|
||||||
|
if ((bio = BIO_new( BIO_s_mem()))) {
|
||||||
|
if ((b64 = BIO_push(b64, bio))) {
|
||||||
|
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
BIO_write(b64, cipher, in_len);
|
||||||
|
BIO_flush(b64);
|
||||||
|
BIO_get_mem_ptr(b64, &bptr);
|
||||||
|
result = bptr->length;
|
||||||
|
if ((out = malloc(result + 1))) {
|
||||||
|
memcpy(out, bptr->data, result);
|
||||||
|
out[result] = '\0';
|
||||||
|
*p_out = (char *)out;
|
||||||
|
} else {
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BIO_free_all(b64);
|
||||||
|
}
|
||||||
|
free(cipher);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_decode(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
BIO *bio, *b64;
|
||||||
|
BUF_MEM *bptr;
|
||||||
|
unsigned char *out, *cipher;
|
||||||
|
|
||||||
|
if ((cipher = malloc(in_len * sizeof (unsigned char)))) {
|
||||||
|
if ((bio = BIO_new_mem_buf((void*)input, in_len))) {
|
||||||
|
if ((b64 = BIO_new(BIO_f_base64()))) {
|
||||||
|
if ((bio = BIO_push(b64, bio))) {
|
||||||
|
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
in_len = BIO_read(bio, cipher, in_len);
|
||||||
|
result = ax_crypt_read(crypt, p_out, cipher, in_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BIO_free_all(bio);
|
||||||
|
}
|
||||||
|
free(cipher);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file crypt.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AX_CRYPT_H_F18E0303_66D9_4793_A902_230BA0A0A46F
|
||||||
|
#define AX_CRYPT_H_F18E0303_66D9_4793_A902_230BA0A0A46F
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <aisl/aisl.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
#define AX_CRYPT_KEY_SIZE 32
|
||||||
|
#define AX_CRYPT_SALT_SIZE 8
|
||||||
|
|
||||||
|
struct ax_crypt {
|
||||||
|
EVP_CIPHER_CTX *e_ctx;
|
||||||
|
EVP_CIPHER_CTX *d_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ax_crypt * AxCrypt;
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_crypt_init(AxSession crypt, const char *key_file);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_crypt_release(AxSession crypt);
|
||||||
|
|
||||||
|
|
||||||
|
/* encrypt */
|
||||||
|
int
|
||||||
|
ax_crypt_write(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* decrypt */
|
||||||
|
int
|
||||||
|
ax_crypt_read(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* encrypt and convert to BASE64 */
|
||||||
|
int
|
||||||
|
ax_crypt_encode(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* decrypt from BASE64 */
|
||||||
|
int
|
||||||
|
ax_crypt_decode(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
#endif /* !AX_CRYPT_H */
|
||||||
@@ -0,0 +1,465 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file html.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <cStuff/string.h>
|
||||||
|
|
||||||
|
#include "html.h"
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
ax_html_escape(char *src, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t extra = 0;
|
||||||
|
char *ptr = src;
|
||||||
|
char ch, *result;
|
||||||
|
|
||||||
|
while ((ch = *ptr) != 0) {
|
||||||
|
switch (ch) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
case '\n':
|
||||||
|
extra++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result = calloc(len + extra + 1, sizeof (char))) != NULL) {
|
||||||
|
if (extra) {
|
||||||
|
ptr = result;
|
||||||
|
while (len--) {
|
||||||
|
switch (*src) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
*(ptr++) = '\\';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
*(ptr++) = '\\';
|
||||||
|
*(ptr++) = 'n';
|
||||||
|
case '\r': /* go through */
|
||||||
|
src++;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!(*(ptr++) = *(src++)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strncpy(result, src, len);
|
||||||
|
result[len] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ax_html *
|
||||||
|
ax_html_append_new(CStuffList list, const struct ax_html *src)
|
||||||
|
{
|
||||||
|
struct ax_html *result;
|
||||||
|
|
||||||
|
if ((result = malloc(sizeof (*result))) != NULL) {
|
||||||
|
result->type = src->type;
|
||||||
|
result->offset = src->offset;
|
||||||
|
result->size = src->size;
|
||||||
|
if ((result->data = ax_html_escape(src->data, src->size)) != NULL) {
|
||||||
|
if (cstuff_list_append(list, result) != -1) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
free(result->data);
|
||||||
|
}
|
||||||
|
free(result);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_html_check_chars(char *begin, char *end)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
while (begin < end) {
|
||||||
|
char c = *begin;
|
||||||
|
if (c == '-') {
|
||||||
|
c = (*begin = '_');
|
||||||
|
}
|
||||||
|
if (isalnum(c) || c == '_') {
|
||||||
|
result++;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_html_read_line(CStuffList list, char *line)
|
||||||
|
{
|
||||||
|
const char input_open[] = "${",
|
||||||
|
input_close[] = "}",
|
||||||
|
block_open[] = "<!--@",
|
||||||
|
block_close[] = "-->";
|
||||||
|
|
||||||
|
struct ax_html node;
|
||||||
|
size_t offset;
|
||||||
|
char *cur;
|
||||||
|
|
||||||
|
offset = strspn(line, "\t ");
|
||||||
|
cur = &line[offset];
|
||||||
|
|
||||||
|
while (*cur) {
|
||||||
|
char *p1, *p2, *p;
|
||||||
|
uint16_t type = AX_HTML_PLAIN;
|
||||||
|
uint32_t close_len = 0;
|
||||||
|
|
||||||
|
p1 = strstr(cur, input_open);
|
||||||
|
p2 = strstr(cur, block_open);
|
||||||
|
|
||||||
|
if (p1 && (!p2 || p2 > p1)) {
|
||||||
|
p = &p1[sizeof (input_open) - 1];
|
||||||
|
if ((p2 = strstr(p, input_close)) && ax_html_check_chars(p, p2)) {
|
||||||
|
type = AX_HTML_INPUT;
|
||||||
|
close_len = sizeof (input_close) - 1;
|
||||||
|
}
|
||||||
|
} else if (p2 && (!p1 || p1 > p2)) {
|
||||||
|
p1 = p2;
|
||||||
|
p = &p1[sizeof (block_open) - 1];
|
||||||
|
if ((p2 = strstr(p, block_close)) && ax_html_check_chars(p, p2)) {
|
||||||
|
type = AX_HTML_BLOCK;
|
||||||
|
close_len = sizeof (block_close) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != AX_HTML_PLAIN) {
|
||||||
|
if (p1 != cur) {
|
||||||
|
node.type = AX_HTML_PLAIN;
|
||||||
|
node.offset = offset;
|
||||||
|
node.size = (uint32_t)(p1 - cur);
|
||||||
|
node.data = cur;
|
||||||
|
offset = 0;
|
||||||
|
if (ax_html_append_new(list, &node) == NULL) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.type = type;
|
||||||
|
node.offset = offset;
|
||||||
|
node.size = (uint32_t)(p2 - p);
|
||||||
|
node.data = p;
|
||||||
|
offset = 0;
|
||||||
|
if (ax_html_append_new(list, &node) == NULL) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
cur = p2 + close_len;
|
||||||
|
if (type == AX_HTML_BLOCK) {
|
||||||
|
size_t lfcr = strspn(cur, "\r\n");
|
||||||
|
if (lfcr) {
|
||||||
|
cur += lfcr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.type = type;
|
||||||
|
node.offset = offset;
|
||||||
|
node.size = strlen(cur);
|
||||||
|
node.data = cur;
|
||||||
|
if (ax_html_append_new(list, &node) == NULL) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
cur = &cur[node.size];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_import(CStuffList list, const char *html_file)
|
||||||
|
{
|
||||||
|
FILE *f = NULL;
|
||||||
|
size_t sz = 256;
|
||||||
|
char *line;
|
||||||
|
ssize_t rs;
|
||||||
|
AislStatus result = AISL_SUCCESS;
|
||||||
|
|
||||||
|
if (!(line = malloc(sz)))
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
if (!(f = fopen(html_file, "r")))
|
||||||
|
goto e_syscall;
|
||||||
|
|
||||||
|
while ((rs = getdelim(&line, &sz, '\n', f)) != -1) {
|
||||||
|
if ((result = ax_html_read_line(list, line)) != AISL_SUCCESS) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(errno) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENOMEM:
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto e_syscall;
|
||||||
|
}
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_malloc:
|
||||||
|
result = AISL_MALLOC_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_syscall:
|
||||||
|
result = AISL_SYSCALL_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if (line)
|
||||||
|
free(line);
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_export(CStuffList list, const struct ax_html_options *opts)
|
||||||
|
{
|
||||||
|
AislStatus result = AISL_SUCCESS;
|
||||||
|
FILE *out = NULL;
|
||||||
|
int i, l;
|
||||||
|
char *c_prefix = NULL, *u_prefix = NULL, *f = NULL;
|
||||||
|
const char *ofst = opts->offset;
|
||||||
|
|
||||||
|
/* Cammel case prefix */
|
||||||
|
if (cstuff_strcpy(&c_prefix, opts->name) == -1)
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
*c_prefix = toupper(*c_prefix);
|
||||||
|
|
||||||
|
/* Upper case prefix */
|
||||||
|
if ((i = cstuff_strcpy(&u_prefix, opts->name)) == -1)
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
while (i--) {
|
||||||
|
u_prefix[i] = toupper(u_prefix[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* header file */
|
||||||
|
if ((l = cstuff_sprintf(&f, "%s/%s.h", opts->path, opts->name)) == -1)
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
if (!(out = fopen(f, "w")))
|
||||||
|
goto e_syscall;
|
||||||
|
|
||||||
|
fprintf(out, "#ifndef %s_H_AISL_COMPOSED\n", u_prefix);
|
||||||
|
fprintf(out, "#define %s_H_AISL_COMPOSED\n\n", u_prefix);
|
||||||
|
fprintf(out, "#include <aisl/aisl.h>\n");
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
fprintf(out, "#include <cStuff/list.h>\n");
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
fprintf(out, "#define %s_put(STREAM, BLOCK, CB, CTX) ", opts->name);
|
||||||
|
fprintf(out, "%s_put_##BLOCK##(STREAM, CB, CTX)\n\n", opts->name);
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
fprintf(out, "typedef int\n(*%sCallback)(AislStream s, const char *input, "
|
||||||
|
"void *ctx);\n\n", c_prefix);
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
fprintf(out, "int\n%s_put(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx, const char *block);\n\n", opts->name, c_prefix);
|
||||||
|
fprintf(out, "int\n%s_set(CStuffList list);\n\n", opts->name);
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
struct ax_html *html = list->items[i];
|
||||||
|
|
||||||
|
if (html->type == AX_HTML_BLOCK) {
|
||||||
|
fprintf(out, "int\n%s_put_%s(AislStream s, %sCallback callback, void *ctx);\n\n",
|
||||||
|
opts->name, html->data, c_prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "#endif\n");
|
||||||
|
fprintf(out, "\n\n");
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
/* source file */
|
||||||
|
f[l-1] = 'c';
|
||||||
|
|
||||||
|
if (!(out = fopen(f, "w")))
|
||||||
|
goto e_syscall;
|
||||||
|
|
||||||
|
fprintf(out, "#include <stdint.h>\n");
|
||||||
|
fprintf(out, "#include \"%s.h\"\n\n", opts->name);
|
||||||
|
fprintf(out, "#define %s_PLAIN %d\n", u_prefix, AX_HTML_PLAIN);
|
||||||
|
fprintf(out, "#define %s_BLOCK %d\n", u_prefix, AX_HTML_BLOCK);
|
||||||
|
fprintf(out, "#define %s_INPUT %d\n\n", u_prefix, AX_HTML_INPUT);
|
||||||
|
fprintf(out, "struct %s {\n", opts->name);
|
||||||
|
fprintf(out, "%suint16_t type;\n", ofst);
|
||||||
|
fprintf(out, "%suint16_t offset;\n", ofst);
|
||||||
|
fprintf(out, "%suint32_t size;\n", ofst);
|
||||||
|
fprintf(out, "%sconst char *code;\n", ofst);
|
||||||
|
fprintf(out, "};\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "static struct %s *m_%s = NULL;\n\n", opts->name, opts->name);
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "static const struct %s m_%s[] = {\n", opts->name, opts->name);
|
||||||
|
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
struct ax_html *html = list->items[i];
|
||||||
|
uint32_t offset, size = html->size;
|
||||||
|
|
||||||
|
if (opts->minimize) {
|
||||||
|
offset = 0;
|
||||||
|
if (html->type == AX_HTML_PLAIN) {
|
||||||
|
int l = strlen(html->data);
|
||||||
|
|
||||||
|
if (!(l < 2) && !strcmp(&html->data[l - 2], "\\n")) {
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset = html->offset & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(out, "%s{%u, %u, %u, \"%s\"},\n", ofst, html->type, offset,
|
||||||
|
size, html->data);
|
||||||
|
}
|
||||||
|
fprintf(out, "%s{0, 0, 0, NULL}\n};\n\n", ofst);
|
||||||
|
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "static int\nput_from(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx, uint32_t from)\n{\n", c_prefix);
|
||||||
|
fprintf(out, "%sint result = 0, r;\n", ofst);
|
||||||
|
fprintf(out, "%swhile (m_%s[from]->data) {\n", ofst, opts->name);
|
||||||
|
fprintf(out, "%s%sswitch (m_%s[from]->type) {\n", ofst, ofst,
|
||||||
|
opts->name);
|
||||||
|
fprintf(out, "%s%scase %s_PLAIN:\n", ofst, ofst, u_prefix);
|
||||||
|
fprintf(out, "%s%s%sr = aisl_write(s, m_%s[from]->data, m_%s[from]->size);\n",
|
||||||
|
ofst, ofst, ofst, opts->name, opts->name);
|
||||||
|
fprintf(out, "%s%s%sbreak;\n", ofst, ofst, ofst);
|
||||||
|
|
||||||
|
fprintf(out, "%s%scase %s_INPUT:\n", ofst, ofst, u_prefix);
|
||||||
|
fprintf(out, "%s%s%sr = callback(s, m_%s[from]->data, ctx);\n",
|
||||||
|
ofst, ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s%s%sbreak;\n", ofst, ofst, ofst);
|
||||||
|
fprintf(out, "%s%scase %s_BLOCK:\n", ofst, ofst, u_prefix);
|
||||||
|
fprintf(out, "%s%s%sreturn result;\n", ofst, ofst, ofst);
|
||||||
|
fprintf(out, "%s%sdefault:\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%s%sreturn -1;\n", ofst, ofst, ofst);
|
||||||
|
fprintf(out, "%s%s}\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sif (r == -1) return r;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sresult += r;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sfrom++;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%sreturn result;\n}\n\n", ofst);
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
fprintf(out, "int\n%s_put(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx, const char *block)\n{\n", opts->name, c_prefix);
|
||||||
|
fprintf(out, "%sint i = 0;\n", ofst);
|
||||||
|
fprintf(out, "%swhile (m_%s[i]->data) {\n", ofst, opts->name);
|
||||||
|
fprintf(out, "%s%sif (m_%s[i]->type == %s_BLOCK && "
|
||||||
|
"!strcmp(m_%s[i]->data, block)) {\n", ofst, ofst, opts->name, u_prefix,
|
||||||
|
opts->name);
|
||||||
|
fprintf(out, "%s%s%sreturn put_from(s, callback, ctx, i + 1);\n", ofst, ofst,
|
||||||
|
ofst);
|
||||||
|
fprintf(out, "%s%s}\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%sreturn 0;\n}\n\n", ofst);
|
||||||
|
|
||||||
|
fprintf(out, "int\n%s_set(CStuffList list)\n{\n", opts->name);
|
||||||
|
fprintf(out, "%sint i;\n", ofst);
|
||||||
|
fprintf(out, "%sif (m_%s) {\n", ofst, opts->name);
|
||||||
|
fprintf(out, "%s%si = 0;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%swhile (m_%s[i].data) {\n", ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s%s%sfree(m_%s[i].data);\n", ofst, ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s%s}\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sfree(m_%s);\n", ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%sif (!(m_%s = malloc(list->length * sizeof (*m_%s))))\n", ofst,
|
||||||
|
opts->name, opts->name);
|
||||||
|
fprintf(out, "%s%sreturn -1;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%sfor (i = 0; i < list->length; i++) {\n", ofst);
|
||||||
|
fprintf(out, "%s%smemcpy(&m_%s[i], list->items[i], sizeof (*m_%s));\n", ofst,
|
||||||
|
ofst, opts->name, opts->name);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%smemset(&m_%s[i], 0, sizeof (m_%s[i]));\n", ofst, opts->name,
|
||||||
|
opts->name);
|
||||||
|
fprintf(out, "%sreturn i;\n", ofst);
|
||||||
|
fprintf(out, "}\n\n");
|
||||||
|
|
||||||
|
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
struct ax_html *html = list->items[i];
|
||||||
|
if (html->type == AX_HTML_BLOCK) {
|
||||||
|
fprintf(out, "int\n%s_put_%s(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx)\n", opts->name, html->data, c_prefix);
|
||||||
|
fprintf(out, "{\n");
|
||||||
|
fprintf(out, "%sreturn put_from(s, callback, ctx, %u);\n", ofst, i + 1);
|
||||||
|
fprintf(out, "}\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_syscall:
|
||||||
|
result = AISL_SYSCALL_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_malloc:
|
||||||
|
result = AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if (c_prefix)
|
||||||
|
free(c_prefix);
|
||||||
|
|
||||||
|
if (u_prefix)
|
||||||
|
free(u_prefix);
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
free(f);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_html_free(struct ax_html *html)
|
||||||
|
{
|
||||||
|
if (html->data) {
|
||||||
|
free(html->data);
|
||||||
|
}
|
||||||
|
free(html);
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file template.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AX_HTML_H_92C08532_E423_4CE4_A44C_27CF864A2C60
|
||||||
|
#define AX_HTML_H_92C08532_E423_4CE4_A44C_27CF864A2C60
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <aisl/aisl.h>
|
||||||
|
#include <cStuff/list.h>
|
||||||
|
|
||||||
|
#define AX_HTML_NULL 0
|
||||||
|
#define AX_HTML_PLAIN 1
|
||||||
|
#define AX_HTML_BLOCK 2
|
||||||
|
#define AX_HTML_INPUT 3
|
||||||
|
|
||||||
|
struct ax_html {
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t offset;
|
||||||
|
uint32_t size;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ax_html_options {
|
||||||
|
const char *offset;
|
||||||
|
const char *path;
|
||||||
|
const char *name;
|
||||||
|
bool minimize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_import(CStuffList list, const char *html_file);
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_export(CStuffList list, const struct ax_html_options *opts);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_html_free(struct ax_html *html);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !HTML_H */
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file passwd.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <cStuff/file.h>
|
||||||
|
#include "passwd.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct ax_passwd_ctx {
|
||||||
|
struct ax_passwd *items;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ax_passwd_hex2bytes(const char *hex, char *out, int max_len)
|
||||||
|
{
|
||||||
|
char s_byte[] = {'\0', '\0', '\0'}, *e_ptr = NULL;
|
||||||
|
for (i = 0; i < max_len; i++) {
|
||||||
|
if (!(*ptr)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
memcpy(s_byte, hex, 2);
|
||||||
|
*out = strtol(s_byte, &e_ptr, 16) & 0xFF;
|
||||||
|
if (e_ptr != &s_byte[2]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (!(*ptr)) ? true : flase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_hash(struct ax_passwd *entry, char *hash, int length)
|
||||||
|
{
|
||||||
|
char *ptr, *saveptr = NULL, *out, c;
|
||||||
|
int token = 0, i, cnt;
|
||||||
|
|
||||||
|
while ((ptr = strtok(hash, "$", &saveptr)) != NULL) {
|
||||||
|
switch (token++) {
|
||||||
|
case 0:
|
||||||
|
if (!(*ptr)) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if (!(strcmp(ptr, "1"))) {
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if (ax_passwd_hex2bytes(ptr, entry->salt, sizeof (entry->salt))) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
if (ax_passwd_hex2bytes(ptr, entry->hash, sizeof (entry->hash))) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_line(char *line, ssize_t len, void *p_ctx)
|
||||||
|
{
|
||||||
|
int token = 0;
|
||||||
|
struct ax_passwd_ctx *ctx = (struct ax_passwd_ctx *)p_ctx;
|
||||||
|
struct ax_passwd entry = {0};
|
||||||
|
char *ptr, *saveptr = NULL;
|
||||||
|
|
||||||
|
while ((ptr = strtok(line, ":", &saveptr)) != NULL) {
|
||||||
|
switch (token++) {
|
||||||
|
case 0:
|
||||||
|
if (!cstuff_strncpy(&entry.name, ptr, (int)(saveptr - line))) {
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return CSTUFF_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
entry.uid = strtol(ptr, NULL, 10);
|
||||||
|
continue;
|
||||||
|
case 2:
|
||||||
|
entry.gid = strtol(ptr, NULL, 10);
|
||||||
|
continue;
|
||||||
|
case 3:
|
||||||
|
return ax_passwd_get_hash(&entry, ptr, (int)(saveptr - line));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_import(struct ax_passwd **p_out, const char *file)
|
||||||
|
{
|
||||||
|
struct ax_passwd_ctx ctx = {NULL, 0};
|
||||||
|
|
||||||
|
if (!cstuff_file_get_lines(file, ax_passwd_get_line, (void *)&ctx)) {
|
||||||
|
*p_out = ctx->items;
|
||||||
|
return ctx->count;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_export(const struct ax_passwd *in, int size, const char *file)
|
||||||
|
{
|
||||||
|
int result = -1, i, j = 0;
|
||||||
|
char *swap, hash[2 * (sizeof (in->salt) + sizeof (in->hash)) + 2];
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof (in->salt); i++) {
|
||||||
|
sprintf(&hash[j], "%02x", in->salt[i] & 0xFF);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
hash[j++] = '$';
|
||||||
|
for (i = 0; i < sizeof (in->hash); i++) {
|
||||||
|
sprintf(&hash[j], "%02x", in->hash[i] & 0xFF);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cstuff_printf(&swap, "%s.swap", file)) {
|
||||||
|
if ((f = fopen(swap, "w")) != NULL) {
|
||||||
|
result = 0;
|
||||||
|
while (size--) {
|
||||||
|
if (fprintf(f, "%s:%"PRIu32":%"PRIu32":$1$%s:\n", in->name, in->uid,
|
||||||
|
in->gid, hash) < 0) {
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
if (!result) {
|
||||||
|
if (cstuff_file_move(swap, file) != CSTUFF_SUCCESS)
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(swap);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_salted(unsigned char **out, const char *password,
|
||||||
|
unsigned char *salt)
|
||||||
|
{
|
||||||
|
int l = strlen(password), result = l + AX_PASSWD_SALT_SIZE;
|
||||||
|
unsigned char *salted;
|
||||||
|
|
||||||
|
if ((salted = malloc(result)) != NULL) {
|
||||||
|
strcpy(salted, password);
|
||||||
|
memcpy(&salted[l], salt, AX_PASSWD_SALT_SIZE);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_verify(const struct ax_passwd *passwd, const char *password)
|
||||||
|
{
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
unsigned char *sltpass, hash[AX_PASSWD_HASH_SIZE];
|
||||||
|
int l;
|
||||||
|
|
||||||
|
if ((l = ax_passwd_get_salted(&sltpass, password, passwd->salt)) != -1) {
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, sltpass, l);
|
||||||
|
SHA1_Final(hash, &ctx);
|
||||||
|
free(sltpass);
|
||||||
|
return (!memcmp(passwd->hash, hash, sizeof (hash))) ? 0 : 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_set_hash(struct ax_passwd *out, const char *password)
|
||||||
|
{
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
unsigned char *sltpass;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
RAND_bytes(out->salt, (sizeof (out->salt)));
|
||||||
|
|
||||||
|
if ((l = ax_passwd_get_salted(&sltpass, password, out->salt)) != -1) {
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, sltpass, l);
|
||||||
|
SHA1_Final(out->hash, &ctx);
|
||||||
|
free(sltpass);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_free(struct ax_passwd **p_out, int size)
|
||||||
|
{
|
||||||
|
struct ax_passwd *p = *p_out;
|
||||||
|
|
||||||
|
while (size--) {
|
||||||
|
if (p->name)
|
||||||
|
free(p->name);
|
||||||
|
if (p->hash)
|
||||||
|
free(p->hash);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
free(*p_out);
|
||||||
|
*p_out = NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file passwd.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA
|
||||||
|
#define AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
#define AX_PASSWD_TOKENS 4
|
||||||
|
#define AX_PASSWD_SALT_SIZE 16
|
||||||
|
#define AX_PASSWD_HASH_SIZE SHA1_DIGEST_LENGTH
|
||||||
|
|
||||||
|
struct ax_passwd {
|
||||||
|
uint32_t uid;
|
||||||
|
uint32_t gid;
|
||||||
|
char *name;
|
||||||
|
char salt[AX_PASSWD_SALT_SIZE];
|
||||||
|
char hash[AX_PASSWD_HASH_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ax_passwd * AxPasswd;
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_import(struct ax_passwd **p_out, const char *file);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_export(const struct ax_passwd *in, int size, const char *file);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_verify(const struct ax_passwd *passwd, const char *password);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_set_hash(struct ax_passwd *out, const char *password);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_free(struct ax_passwd **p_out, int size);
|
||||||
|
|
||||||
|
#endif /* !AX_PASSWD_H */
|
||||||
Reference in New Issue
Block a user