Files
lightning/external/libwally-core/src/aes.c
Rusty Russell f42f34b82d external: new subdirectory for all external libraries and submodules.
You will want to 'make distclean' after this.

I also removed libsecp; we use the one in in libwally anyway.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2017-08-29 17:54:14 +02:00

180 lines
5.6 KiB
C

#include "internal.h"
#include <include/wally_crypto.h>
#include <stdbool.h>
#include "ctaes/ctaes.h"
#include "ctaes/ctaes.c"
#define ALL_OPS (AES_FLAG_ENCRYPT | AES_FLAG_DECRYPT)
static bool is_valid_key_len(size_t key_len)
{
return key_len == AES_KEY_LEN_128 || key_len == AES_KEY_LEN_192 ||
key_len == AES_KEY_LEN_256;
}
static bool are_valid_args(const unsigned char *key, size_t key_len,
const unsigned char *bytes_in, uint32_t flags)
{
return key && is_valid_key_len(key_len) && bytes_in &&
(flags & ALL_OPS) != ALL_OPS;
}
static void aes_enc(AES256_ctx *ctx,
const unsigned char *key, size_t key_len,
const unsigned char *bytes_in, size_t len_in,
unsigned char *bytes_out)
{
len_in /= AES_BLOCK_LEN;
switch (key_len) {
case AES_KEY_LEN_128:
AES128_init((AES128_ctx *)ctx, key);
AES128_encrypt((AES128_ctx *)ctx, len_in, bytes_out, bytes_in);
break;
case AES_KEY_LEN_192:
AES192_init((AES192_ctx *)ctx, key);
AES192_encrypt((AES192_ctx *)ctx, len_in, bytes_out, bytes_in);
break;
case AES_KEY_LEN_256:
AES256_init(ctx, key);
AES256_encrypt(ctx, len_in, bytes_out, bytes_in);
break;
}
}
static void aes_dec(AES256_ctx *ctx,
const unsigned char *key, size_t key_len,
const unsigned char *bytes_in, size_t len_in,
unsigned char *bytes_out)
{
len_in /= AES_BLOCK_LEN;
switch (key_len) {
case AES_KEY_LEN_128:
AES128_init((AES128_ctx *)ctx, key);
AES128_decrypt((AES128_ctx *)ctx, len_in, bytes_out, bytes_in);
break;
case AES_KEY_LEN_192:
AES192_init((AES192_ctx *)ctx, key);
AES192_decrypt((AES192_ctx *)ctx, len_in, bytes_out, bytes_in);
break;
case AES_KEY_LEN_256:
AES256_init(ctx, key);
AES256_decrypt(ctx, len_in, bytes_out, bytes_in);
break;
}
}
int wally_aes(const unsigned char *key, size_t key_len,
const unsigned char *bytes_in, size_t len_in,
uint32_t flags,
unsigned char *bytes_out, size_t len)
{
AES256_ctx ctx;
if (!are_valid_args(key, key_len, bytes_in, flags) ||
len % AES_BLOCK_LEN || !len_in || len_in % AES_BLOCK_LEN ||
flags & ~ALL_OPS || !bytes_out || !len)
return WALLY_EINVAL;
if (flags & AES_FLAG_ENCRYPT)
aes_enc(&ctx, key, key_len, bytes_in, len_in, bytes_out);
else
aes_dec(&ctx, key, key_len, bytes_in, len_in, bytes_out);
clear(&ctx, sizeof(ctx));
return WALLY_OK;
}
int wally_aes_cbc(const unsigned char *key, size_t key_len,
const unsigned char *iv, size_t iv_len,
const unsigned char *bytes_in, size_t len_in,
uint32_t flags,
unsigned char *bytes_out, size_t len,
size_t *written)
{
unsigned char buf[AES_BLOCK_LEN];
AES256_ctx ctx;
size_t i, n, blocks;
unsigned char remainder;
if (written)
*written = 0;
if (!are_valid_args(key, key_len, bytes_in, flags) ||
((flags & AES_FLAG_ENCRYPT) && (len % AES_BLOCK_LEN)) ||
((flags & AES_FLAG_DECRYPT) && (len_in % AES_BLOCK_LEN)) ||
!iv || iv_len != AES_BLOCK_LEN || flags & ~ALL_OPS || !written)
return WALLY_EINVAL;
blocks = len_in / AES_BLOCK_LEN;
if (flags & AES_FLAG_ENCRYPT) {
/* Determine output length from input length */
remainder = len_in % AES_BLOCK_LEN;
*written = (blocks + 1) * AES_BLOCK_LEN;
} else {
/* Determine output length from decrypted final block */
const unsigned char *last = bytes_in + len_in - AES_BLOCK_LEN;
const unsigned char *prev = last - AES_BLOCK_LEN;
if (!--blocks)
prev = iv;
aes_dec(&ctx, key, key_len, last, AES_BLOCK_LEN, buf);
for (n = 0; n < AES_BLOCK_LEN; ++n)
buf[n] = prev[n] ^ buf[n];
/* Modulo the resulting padding amount to the block size - we do
* not attempt to verify the decryption by checking the padding in
* the decrypted block. */
remainder = AES_BLOCK_LEN - (buf[AES_BLOCK_LEN - 1] % AES_BLOCK_LEN);
if (remainder == AES_BLOCK_LEN)
remainder = 0;
*written = blocks * AES_BLOCK_LEN + remainder;
}
if (len < *written || !*written)
goto finish; /* Inform caller how much space is needed */
if (!bytes_out) {
clear_n(2, buf, sizeof(buf), &ctx, sizeof(ctx));
return WALLY_EINVAL;
}
if (flags & AES_FLAG_DECRYPT)
memcpy(bytes_out + blocks * AES_BLOCK_LEN, buf, remainder);
for (i = 0; i < blocks; ++i) {
if (flags & AES_FLAG_ENCRYPT) {
for (n = 0; n < AES_BLOCK_LEN; ++n)
buf[n] = bytes_in[n] ^ iv[n];
aes_enc(&ctx, key, key_len, buf, AES_BLOCK_LEN, bytes_out);
iv = bytes_out;
} else {
aes_dec(&ctx, key, key_len, bytes_in, AES_BLOCK_LEN, bytes_out);
for (n = 0; n < AES_BLOCK_LEN; ++n)
bytes_out[n] = bytes_out[n] ^ iv[n];
iv = bytes_in;
}
bytes_in += AES_BLOCK_LEN;
bytes_out += AES_BLOCK_LEN;
}
if (flags & AES_FLAG_ENCRYPT) {
for (n = 0; n < remainder; ++n)
buf[n] = bytes_in[n] ^ iv[n];
remainder = 16 - remainder;
for (; n < AES_BLOCK_LEN; ++n)
buf[n] = remainder ^ iv[n];
aes_enc(&ctx, key, key_len, buf, AES_BLOCK_LEN, bytes_out);
}
finish:
clear_n(2, buf, sizeof(buf), &ctx, sizeof(ctx));
return WALLY_OK;
}