Last active
August 24, 2023 09:08
-
-
Save liweitianux/84aa72d035e1b1a5ad4d6d629fe74455 to your computer and use it in GitHub Desktop.
Chacha20-Poly1305 AEAD with PBKDF2 key derivation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*- | |
* SPDX-License-Identifier: MIT | |
* | |
* Copyright (c) 2022-2023 Aaron LI | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining | |
* a copy of this software and associated documentation files (the | |
* "Software"), to deal in the Software without restriction, including | |
* without limitation the rights to use, copy, modify, merge, publish, | |
* distribute, sublicense, and/or sell copies of the Software, and to | |
* permit persons to whom the Software is furnished to do so, subject | |
* to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
*/ | |
/*- | |
* Simple file encryptor/decryptor. | |
*/ | |
#include <err.h> | |
#include <errno.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> /* getopt() */ | |
#include "xx_crypto.h" | |
/* | |
* Read from the given file $fp until EOF, and return the data, | |
* with data length save in $size. | |
* | |
* The returned data must be free()'d after use. | |
*/ | |
static void * | |
xx_read_file(FILE *fp, size_t *size) | |
{ | |
static size_t block_size = 4096; | |
unsigned char *buf, *tmp; | |
size_t n, sz, buf_size, tmp_size; | |
buf = tmp = NULL; | |
buf_size = sz = 0; | |
do { | |
if (sz + block_size > buf_size) { | |
tmp_size = (buf_size == 0 ? block_size : buf_size * 2); | |
tmp = calloc(1, tmp_size); | |
if (tmp == NULL) { | |
fprintf(stderr, "%s: calloc() failed: %s\n", | |
__func__, strerror(errno)); | |
goto err; | |
} | |
if (buf != NULL) { | |
memcpy(tmp, buf, buf_size); | |
free(buf); | |
} | |
buf = tmp; | |
buf_size = tmp_size; | |
} | |
n = fread(buf + sz, 1, block_size, fp); | |
sz += n; | |
if (n != block_size) { | |
if (feof(fp)) { | |
break; | |
} else { | |
fprintf(stderr, "%s: fread() failed: %s\n", | |
__func__, strerror(errno)); | |
goto err; | |
} | |
}; | |
} while (!feof(fp)); | |
*size = sz; | |
return buf; | |
err: | |
if (buf) | |
free(buf); | |
return NULL; | |
} | |
static void | |
usage(const char *progname) | |
{ | |
fprintf(stderr, | |
"Simple file encryptor/decryptor\n" | |
"\n" | |
"usage: %s [-d] [-i <infile>] [-o <outfile>]\n" | |
"\n" | |
"options:\n" | |
" -d: do decryption instead of encryption\n" | |
" -i <infile>: input file (stdin if unspecified)\n" | |
" -o <outfile>: outfile file (stdout if unspecified)\n" | |
" -v: show verbose info\n" | |
"\n", | |
progname); | |
exit(1); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
const char *progname = argv[0]; | |
const char *infile = NULL; | |
const char *outfile = NULL; | |
FILE *infp = NULL; | |
FILE *outfp = NULL; | |
bool mode_encrypt = true; | |
bool verbose = false; | |
int ch; | |
while ((ch = getopt(argc, argv, "di:ho:v")) != -1) { | |
switch (ch) { | |
case 'd': | |
mode_encrypt = false; | |
break; | |
case 'i': | |
infile = optarg; | |
break; | |
case 'o': | |
outfile = optarg; | |
break; | |
case 'v': | |
verbose = true; | |
break; | |
case 'h': | |
default: | |
usage(progname); | |
/* NOTREACH */ | |
break; | |
} | |
} | |
argc -= optind; | |
if (argc != 0) { | |
warnx("unknown extra arguments"); | |
usage(progname); | |
/* NOTREACH */ | |
} | |
infp = stdin; | |
if (infile != NULL) { | |
infp = fopen(infile, "r"); | |
if (infp == NULL) | |
err(1, "fopen(%s)", infile); | |
} | |
outfp = stdout; | |
if (outfile != NULL) { | |
outfp = fopen(outfile, "w"); | |
if (outfp == NULL) | |
err(1, "fopen(%s)", outfile); | |
} | |
if (verbose) { | |
fprintf(stderr, "Mode: %s\n", | |
mode_encrypt ? "encryption" : "decryption"); | |
fprintf(stderr, "Input file: %s\n", infile ? infile : "(stdin)"); | |
fprintf(stderr, "Output file: %s\n", outfile ? outfile : "(stdout)"); | |
} | |
unsigned char *input, *output; | |
size_t input_len; | |
int output_len; | |
input = xx_read_file(infp, &input_len); | |
if (input == NULL) { | |
errx(1, "xx_read_file(%s) failed", infile); | |
} | |
if (mode_encrypt) { | |
if (!xx_encrypt(input, input_len, &output, &output_len)) { | |
errx(1, "xx_encrypt() failed"); | |
} | |
} else { | |
if (!xx_decrypt(input, input_len, &output, &output_len)) { | |
errx(1, "xx_decrypt() failed"); | |
} | |
} | |
if (fwrite(output, 1, output_len, outfp) != (size_t)output_len) { | |
err(1, "fwrite()"); | |
} | |
free(input); | |
free(output); | |
fflush(outfp); | |
if (infile != NULL) | |
fclose(infp); | |
if (outfile != NULL) | |
fclose(outfp); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*- | |
* SPDX-License-Identifier: MIT | |
* | |
* Copyright (c) 2022-2023 Aaron LI | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining | |
* a copy of this software and associated documentation files (the | |
* "Software"), to deal in the Software without restriction, including | |
* without limitation the rights to use, copy, modify, merge, publish, | |
* distribute, sublicense, and/or sell copies of the Software, and to | |
* permit persons to whom the Software is furnished to do so, subject | |
* to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
*/ | |
/* | |
* XX crypto utilities: Chacha20-Poly1305 AEAD with PBKDF2 key derivation. | |
* | |
* Output format: | |
* <header> || <tag> || <ciphertext> | |
* | |
* Header format: | |
* <mark> || "$" || <hash> || "$" || <iteration> || "$" || <salt> || "$" | |
* | |
* Hash: "1" (SHA512) | |
* Iteration: <integer_string> | |
* Salt: <hex_string> | |
* Tag, Ciphertext: binary data | |
* | |
* NOTE: The <header> is used as the additional authenticated data (AAD). | |
* | |
* Compile: | |
* $ cc ${CFLAGS} $(pkg-config --cflags libcrypto) \ | |
* -DXX_PASSWORD='"<password-string>"' -c xx_crypto.c | |
* | |
* Reference: | |
* - https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption | |
* - https://tls13.xargs.org/ | |
* - https://datatracker.ietf.org/doc/html/rfc8439 | |
* - https://datatracker.ietf.org/doc/html/rfc7905 | |
*/ | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <openssl/evp.h> | |
#include <openssl/rand.h> | |
#include "xx_crypto.h" | |
#ifndef XX_PASSWORD | |
#error "XX_PASSWORD undefined" | |
#endif | |
#ifdef DEBUG | |
#define XX_DPRINTF(fmt, ...) \ | |
fprintf(stderr, "[DEBUG] %s: " fmt "\n", __func__, ##__VA_ARGS__) | |
#else | |
#define XX_DPRINTF(fmt, ...) /* nothing */ | |
#endif | |
#define PBKDF2_HASH_SHA512 1 | |
#define PBKDF2_ITERATION 100000 | |
/* header mark of the output */ | |
#define HEADER_MARK "XX/v1" | |
/* maximum length of the header */ | |
#define HEADER_MAX_LEN 128 | |
/* length of key (256 bits) */ | |
#define CHACHA20_POLY1305_KEY_LEN 32 | |
/* length of IV/nonce (96 bits) */ | |
#define CHACHA20_POLY1305_IV_LEN 12 | |
/* length of the authentication tag (128 bits) */ | |
#define CHACHA20_POLY1305_TAG_LEN 16 | |
typedef struct { | |
/* Chacha20-Poly1305 cipher */ | |
const EVP_CIPHER *cipher; | |
/* Passphrase */ | |
const char *password; | |
/* PBKDF2 parameters */ | |
int hash; | |
int iteration; | |
unsigned char salt[PKCS5_SALT_LEN]; | |
/* Derived key, IV/nonce */ | |
unsigned char key[CHACHA20_POLY1305_KEY_LEN]; | |
unsigned char iv[CHACHA20_POLY1305_IV_LEN]; | |
/* Authentication tag */ | |
unsigned char tag[CHACHA20_POLY1305_TAG_LEN]; | |
/* Additional authenticated data (AAD) */ | |
char aad[HEADER_MAX_LEN]; | |
int aad_len; | |
/* Plaintext and ciphertext */ | |
const unsigned char *in; | |
int in_len; | |
unsigned char *out; | |
int out_len; | |
} xx_ctx; | |
static int | |
init_ctx(xx_ctx *ctx) | |
{ | |
char *p, *endp; | |
size_t i; | |
int n; | |
ctx->cipher = EVP_chacha20_poly1305(); | |
ctx->password = XX_PASSWORD; | |
ctx->hash = PBKDF2_HASH_SHA512; | |
ctx->iteration = PBKDF2_ITERATION; | |
if (RAND_bytes(ctx->salt, sizeof(ctx->salt)) <= 0) { | |
XX_DPRINTF("RAND_bytes(salt) failed"); | |
return 0; | |
} | |
p = ctx->aad; | |
endp = ctx->aad + sizeof(ctx->aad); | |
n = snprintf(p, endp - p, "%s$%d$%d$", | |
HEADER_MARK, ctx->hash, ctx->iteration); | |
p += n; | |
for (i = 0; i < sizeof(ctx->salt); i++) { | |
n = snprintf(p, endp - p, "%02x", ctx->salt[i]); | |
p += n; | |
} | |
n = snprintf(p, endp - p, "$"); | |
p += n; | |
ctx->aad_len = p - ctx->aad; | |
XX_DPRINTF("AAD: |%s| (len=%d)", ctx->aad, ctx->aad_len); | |
return 1; | |
} | |
static int | |
derive_key_iv(xx_ctx *ctx) | |
{ | |
const EVP_MD *digest; | |
unsigned char buf[CHACHA20_POLY1305_KEY_LEN + CHACHA20_POLY1305_IV_LEN]; | |
int len; | |
if (ctx->hash == PBKDF2_HASH_SHA512) { | |
digest = EVP_sha512(); | |
} else { | |
XX_DPRINTF("invalid hash: %d", ctx->hash); | |
return 0; | |
} | |
len = CHACHA20_POLY1305_KEY_LEN + CHACHA20_POLY1305_IV_LEN; | |
if (!PKCS5_PBKDF2_HMAC(ctx->password, -1 /* pass_len */, | |
ctx->salt, sizeof(ctx->salt), ctx->iteration, | |
digest, len, buf)) { | |
XX_DPRINTF("PKCS5_PBKDF2_HMAC() failed"); | |
return 0; | |
} | |
memcpy(ctx->key, buf, sizeof(ctx->key)); | |
memcpy(ctx->iv, buf + sizeof(ctx->key), sizeof(ctx->iv)); | |
XX_DPRINTF("Derived key and IV"); | |
return 1; | |
} | |
static int | |
read_header(xx_ctx *ctx, const unsigned char *in, size_t inlen) | |
{ | |
const unsigned char *p, *endp; | |
unsigned char *salt; | |
char header[HEADER_MAX_LEN] = { 0 }; | |
char salt_str[HEADER_MAX_LEN] = { 0 }; | |
char end[2]; | |
long saltlen; | |
int hash, iteration, n; | |
n = 0; | |
endp = in + inlen; | |
for (p = in; p < endp && *p; p++) { | |
if (*p == '$') | |
n++; | |
if (n == 4) | |
break; | |
} | |
if (n != 4) { | |
XX_DPRINTF("Invalid header"); | |
return 0; | |
} | |
p++; /* include the '$' */ | |
ctx->aad_len = p - in; | |
if (ctx->aad_len + 1 > (int)sizeof(ctx->aad)) { | |
XX_DPRINTF("Header too long"); | |
return 0; | |
} | |
memcpy(ctx->aad, in, ctx->aad_len); | |
ctx->aad[ctx->aad_len] = '\0'; | |
XX_DPRINTF("AAD: |%s| (len=%d)", ctx->aad, ctx->aad_len); | |
n = sscanf(ctx->aad, "%[^$]$%d$%d$%[^$]%1[$]", | |
header, &hash, &iteration, salt_str, end); | |
if (n != 5) { | |
XX_DPRINTF("sscanf() failed"); | |
return 0; | |
} | |
if (strcmp(header, HEADER_MARK) != 0) { | |
XX_DPRINTF("Invalid mark: %s", header); | |
return 0; | |
} | |
if (hash != PBKDF2_HASH_SHA512) { | |
XX_DPRINTF("Invalid hash: %d", hash); | |
return 0; | |
} | |
ctx->hash = hash; | |
if (iteration <= 0) { | |
XX_DPRINTF("Invalid iteration: %d", iteration); | |
return 0; | |
} | |
ctx->iteration = iteration; | |
if ((salt = OPENSSL_hexstr2buf(salt_str, &saltlen)) == NULL) { | |
XX_DPRINTF("OPENSSL_hexstr2buf() failed"); | |
return 0; | |
} | |
if ((size_t)saltlen > sizeof(ctx->salt)) { | |
OPENSSL_free(salt); | |
XX_DPRINTF("Salt too long"); | |
return 0; | |
} | |
memset(ctx->salt, 0, sizeof(ctx->salt)); | |
memcpy(ctx->salt, salt, (size_t)saltlen); | |
OPENSSL_free(salt); | |
return 1; | |
} | |
static int | |
do_encrypt(xx_ctx *ctx) | |
{ | |
EVP_CIPHER_CTX *cctx = NULL; | |
unsigned char *p; | |
int len; | |
if ((cctx = EVP_CIPHER_CTX_new()) == NULL) { | |
XX_DPRINTF("EVP_CIPHER_CTX_new() failed"); | |
goto err; | |
} | |
if (!EVP_EncryptInit_ex(cctx, ctx->cipher, NULL /* engine */, | |
NULL /* key */, NULL /* IV */)) { | |
XX_DPRINTF("EVP_EncryptInit_ex(1) failed"); | |
goto err; | |
} | |
if (!EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_IVLEN, | |
sizeof(ctx->iv), NULL)) { | |
XX_DPRINTF("EVP_CIPHER_CTX_ctrl(SET_IVLEN) failed"); | |
goto err; | |
} | |
if (!EVP_EncryptInit_ex(cctx, ctx->cipher, NULL /* engine */, | |
ctx->key, ctx->iv)) { | |
XX_DPRINTF("EVP_EncryptInit_ex(2) failed"); | |
goto err; | |
} | |
len = 0; | |
if (!EVP_EncryptUpdate(cctx, NULL, &len, (unsigned char *)ctx->aad, | |
ctx->aad_len)) { | |
XX_DPRINTF("EVP_EncryptUpdate(AAD) failed"); | |
goto err; | |
} | |
p = ctx->out; | |
if (!EVP_EncryptUpdate(cctx, p, &len, ctx->in, ctx->in_len)) { | |
XX_DPRINTF("EVP_EncryptUpdate(plaintext) failed"); | |
goto err; | |
} | |
p += len; | |
ctx->out_len = len; | |
if (!EVP_EncryptFinal_ex(cctx, p, &len)) { | |
XX_DPRINTF("EVP_EncryptFinal_ex() failed"); | |
goto err; | |
} | |
ctx->out_len += len; | |
XX_DPRINTF("ciphertext length: %d", ctx->out_len); | |
if (!EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG, | |
sizeof(ctx->tag), ctx->tag)) { | |
XX_DPRINTF("EVP_CIPHER_CTX_ctrl(GET_TAG) failed"); | |
goto err; | |
} | |
EVP_CIPHER_CTX_free(cctx); | |
return 1; | |
err: | |
if (cctx) { | |
EVP_CIPHER_CTX_free(cctx); | |
} | |
return 0; | |
} | |
static int | |
do_decrypt(xx_ctx *ctx) | |
{ | |
EVP_CIPHER_CTX *cctx = NULL; | |
unsigned char *p; | |
int len; | |
if ((cctx = EVP_CIPHER_CTX_new()) == NULL) { | |
XX_DPRINTF("EVP_CIPHER_CTX_new() failed"); | |
goto err; | |
} | |
if (!EVP_DecryptInit_ex(cctx, ctx->cipher, NULL /* engine */, | |
NULL /* key */, NULL /* IV */)) { | |
XX_DPRINTF("EVP_DecryptInit_ex(1) failed"); | |
goto err; | |
} | |
if (!EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_IVLEN, | |
sizeof(ctx->iv), NULL)) { | |
XX_DPRINTF("EVP_CIPHER_CTX_ctrl(SET_IVLEN) failed"); | |
goto err; | |
} | |
if (!EVP_DecryptInit_ex(cctx, ctx->cipher, NULL /* engine */, | |
ctx->key, ctx->iv)) { | |
XX_DPRINTF("EVP_DecryptInit_ex(2) failed"); | |
goto err; | |
} | |
len = 0; | |
if (!EVP_DecryptUpdate(cctx, NULL, &len, (unsigned char *)ctx->aad, | |
ctx->aad_len)) { | |
XX_DPRINTF("EVP_DecryptUpdate(AAD) failed"); | |
goto err; | |
} | |
p = ctx->out; | |
if (!EVP_DecryptUpdate(cctx, p, &len, ctx->in, ctx->in_len)) { | |
XX_DPRINTF("EVP_DecryptUpdate(ciphertext) failed"); | |
goto err; | |
} | |
p += len; | |
ctx->out_len = len; | |
if (!EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_TAG, | |
sizeof(ctx->tag), ctx->tag)) { | |
XX_DPRINTF("EVP_CIPHER_CTX_ctrl(SET_TAG) failed"); | |
goto err; | |
} | |
if (EVP_DecryptFinal_ex(cctx, p, &len) <= 0) {; | |
XX_DPRINTF("EVP_DecryptFinal_ex() failed: tag didn't match"); | |
goto err; | |
} | |
ctx->out_len += len; | |
XX_DPRINTF("plaintext length: %d", ctx->out_len); | |
EVP_CIPHER_CTX_free(cctx); | |
return 1; | |
err: | |
if (cctx) { | |
EVP_CIPHER_CTX_free(cctx); | |
} | |
return 0; | |
} | |
/*--------------------------------------------------------------------*/ | |
int | |
xx_encrypt(const unsigned char *in, int in_len, | |
unsigned char **out, int *out_len) | |
{ | |
unsigned char *buf = NULL; | |
unsigned char *p; | |
int buf_len; | |
xx_ctx ctx = { 0 }; | |
if (!init_ctx(&ctx)) { | |
XX_DPRINTF("init_ctx() failed"); | |
goto err; | |
} | |
if (!derive_key_iv(&ctx)) { | |
XX_DPRINTF("derive_key_iv() failed"); | |
goto err; | |
} | |
ctx.in = in; | |
ctx.in_len = in_len; | |
ctx.out = calloc(1, ctx.in_len + EVP_MAX_BLOCK_LENGTH); | |
if (ctx.out == NULL) { | |
XX_DPRINTF("calloc(ctx.out)"); | |
goto err; | |
} | |
if (!do_encrypt(&ctx)) { | |
XX_DPRINTF("do_encrypt() failed"); | |
goto err; | |
} | |
buf_len = ctx.aad_len + sizeof(ctx.tag) + ctx.out_len; | |
if ((buf = calloc(1, buf_len)) == NULL) { | |
XX_DPRINTF("calloc() failed"); | |
goto err; | |
} | |
p = buf; | |
/* AAD */ | |
memcpy(p, ctx.aad, ctx.aad_len); | |
p += ctx.aad_len; | |
/* Tag */ | |
memcpy(p, ctx.tag, sizeof(ctx.tag)); | |
p += sizeof(ctx.tag); | |
/* Ciphertext */ | |
memcpy(p, ctx.out, ctx.out_len); | |
*out = buf; | |
*out_len = buf_len; | |
free(ctx.out); | |
return 1; | |
err: | |
if (ctx.out) { | |
free(ctx.out); | |
} | |
if (buf) { | |
free(buf); | |
} | |
return 0; | |
} | |
int | |
xx_decrypt(const unsigned char *in, int in_len, | |
unsigned char **out, int *out_len) | |
{ | |
xx_ctx ctx = { 0 }; | |
if (!init_ctx(&ctx)) { | |
XX_DPRINTF("init_ctx() failed"); | |
goto err; | |
} | |
ctx.in = in; | |
ctx.in_len = in_len; | |
if (!read_header(&ctx, ctx.in, ctx.in_len)) { | |
XX_DPRINTF("read_header() failed"); | |
goto err; | |
} | |
ctx.in += ctx.aad_len; | |
ctx.in_len -= ctx.aad_len; | |
if ((size_t)ctx.in_len < sizeof(ctx.tag)) { | |
XX_DPRINTF("invalid file (tag)"); | |
goto err; | |
} | |
memcpy(ctx.tag, ctx.in, sizeof(ctx.tag)); | |
ctx.in += sizeof(ctx.tag); | |
ctx.in_len -= sizeof(ctx.tag); | |
if (!derive_key_iv(&ctx)) { | |
XX_DPRINTF("derive_key_iv() failed"); | |
goto err; | |
} | |
ctx.out = calloc(1, ctx.in_len); | |
if (ctx.out == NULL) { | |
XX_DPRINTF("calloc(ctx.out)"); | |
goto err; | |
} | |
if (!do_decrypt(&ctx)) { | |
XX_DPRINTF("do_decrypt() failed"); | |
goto err; | |
} | |
*out = ctx.out; | |
*out_len = ctx.out_len; | |
return 1; | |
err: | |
if (ctx.out) { | |
free(ctx.out); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*- | |
* SPDX-License-Identifier: MIT | |
* | |
* Copyright (c) 2022-2023 Aaron LI | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining | |
* a copy of this software and associated documentation files (the | |
* "Software"), to deal in the Software without restriction, including | |
* without limitation the rights to use, copy, modify, merge, publish, | |
* distribute, sublicense, and/or sell copies of the Software, and to | |
* permit persons to whom the Software is furnished to do so, subject | |
* to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
*/ | |
/* | |
* XX crypto utilities: Chacha20-Poly1305 AEAD with PBKDF2 key derivation. | |
*/ | |
#ifndef XX_CRYPTO_H_ | |
#define XX_CRYPTO_H_ | |
/* | |
* Encrypt the data $in of length $in_len. | |
* The encrypted data is stored in $out of length $out_len, | |
* which should be free()'ed by the caller. | |
* | |
* Return 1 on success, 0 on error. | |
*/ | |
int xx_encrypt(const unsigned char *in, int in_len, | |
unsigned char **out, int *out_len); | |
/* | |
* Decrypt the data $in of length $in_len. | |
* The decrypted data is stored in $out of length $out_len, | |
* which should be free()'ed by the caller. | |
* | |
* Return 1 on success, 0 on error. | |
*/ | |
int xx_decrypt(const unsigned char *in, int in_len, | |
unsigned char **out, int *out_len); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Compile the
encryptor.c
with:(NOTE: replace the above
<your-private-password>
with yours.)Usage help:
Example: