Compare commits

..
2 Commits
Author SHA1 Message Date
elias 6347444494 Add crypt module 2019-07-19 21:19:49 +02:00
elias f43bb30065 Add passwd component 2019-07-17 22:50:08 +02:00
4 changed files with 630 additions and 0 deletions
+265
View File
@@ -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;
}
+63
View File
@@ -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 */
+245
View File
@@ -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;
}
+57
View File
@@ -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 */