Add crypt module
This commit is contained in:
parent
f43bb30065
commit
6347444494
|
@ -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 */
|
Loading…
Reference in New Issue