You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
6.5 KiB
252 lines
6.5 KiB
#include "internal.h"
|
|
#include <include/wally_crypto.h>
|
|
#include "ccan/ccan/build_assert/build_assert.h"
|
|
#include "ccan/ccan/crypto/ripemd160/ripemd160.h"
|
|
#include "ccan/ccan/crypto/sha256/sha256.h"
|
|
#include "ccan/ccan/crypto/sha512/sha512.h"
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
|
|
#undef malloc
|
|
#undef free
|
|
|
|
/* Caller is responsible for thread safety */
|
|
static secp256k1_context *global_ctx = NULL;
|
|
|
|
const secp256k1_context *secp_ctx(void)
|
|
{
|
|
const uint32_t flags = SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN;
|
|
|
|
if (!global_ctx)
|
|
global_ctx = secp256k1_context_create(flags);
|
|
|
|
return global_ctx;
|
|
}
|
|
|
|
|
|
int wally_secp_randomize(const unsigned char *bytes_in, size_t len_in)
|
|
{
|
|
secp256k1_context *ctx;
|
|
|
|
if (!bytes_in || len_in != WALLY_SECP_RANDOMISE_LEN)
|
|
return WALLY_EINVAL;
|
|
|
|
if (!(ctx = (secp256k1_context *)secp_ctx()))
|
|
return WALLY_ENOMEM;
|
|
|
|
if (!secp256k1_context_randomize(ctx, bytes_in))
|
|
return WALLY_ERROR;
|
|
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int wally_free_string(char *str)
|
|
{
|
|
if (!str)
|
|
return WALLY_EINVAL;
|
|
clear(str, strlen(str));
|
|
wally_free(str);
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int wally_bzero(void *bytes, size_t len)
|
|
{
|
|
if (!bytes)
|
|
return WALLY_EINVAL;
|
|
clear(bytes, len);
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int wally_sha256(const unsigned char *bytes_in, size_t len_in,
|
|
unsigned char *bytes_out, size_t len)
|
|
{
|
|
struct sha256 sha;
|
|
bool aligned = alignment_ok(bytes_out, sizeof(sha.u.u32));
|
|
|
|
if (!bytes_in || !bytes_out || len != SHA256_LEN)
|
|
return WALLY_EINVAL;
|
|
|
|
sha256(aligned ? (struct sha256 *)bytes_out : &sha, bytes_in, len_in);
|
|
if (!aligned) {
|
|
memcpy(bytes_out, &sha, sizeof(sha));
|
|
clear(&sha, sizeof(sha));
|
|
}
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int wally_sha256d(const unsigned char *bytes_in, size_t len_in,
|
|
unsigned char *bytes_out, size_t len)
|
|
{
|
|
struct sha256 sha_1, sha_2;
|
|
bool aligned = alignment_ok(bytes_out, sizeof(sha_1.u.u32));
|
|
|
|
if (!bytes_in || !bytes_out || len != SHA256_LEN)
|
|
return WALLY_EINVAL;
|
|
|
|
sha256(&sha_1, bytes_in, len_in);
|
|
sha256(aligned ? (struct sha256 *)bytes_out : &sha_2, &sha_1, sizeof(sha_1));
|
|
if (!aligned) {
|
|
memcpy(bytes_out, &sha_2, sizeof(sha_2));
|
|
clear(&sha_2, sizeof(sha_2));
|
|
}
|
|
clear(&sha_1, sizeof(sha_1));
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int wally_sha512(const unsigned char *bytes_in, size_t len_in,
|
|
unsigned char *bytes_out, size_t len)
|
|
{
|
|
struct sha512 sha;
|
|
bool aligned = alignment_ok(bytes_out, sizeof(sha.u.u64));
|
|
|
|
if (!bytes_in || !bytes_out || len != SHA512_LEN)
|
|
return WALLY_EINVAL;
|
|
|
|
sha512(aligned ? (struct sha512 *)bytes_out : &sha, bytes_in, len_in);
|
|
if (!aligned) {
|
|
memcpy(bytes_out, &sha, sizeof(sha));
|
|
clear(&sha, sizeof(sha));
|
|
}
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int wally_hash160(const unsigned char *bytes_in, size_t len_in,
|
|
unsigned char *bytes_out, size_t len)
|
|
{
|
|
struct sha256 sha;
|
|
struct ripemd160 ripemd;
|
|
bool aligned = alignment_ok(bytes_out, sizeof(ripemd.u.u32));
|
|
|
|
if (!bytes_in || !bytes_out || len != HASH160_LEN)
|
|
return WALLY_EINVAL;
|
|
|
|
BUILD_ASSERT(sizeof(ripemd) == HASH160_LEN);
|
|
|
|
sha256(&sha, bytes_in, len_in);
|
|
ripemd160(aligned ? (struct ripemd160 *)bytes_out : &ripemd, &sha, sizeof(sha));
|
|
if (!aligned) {
|
|
memcpy(bytes_out, &ripemd, sizeof(ripemd));
|
|
clear(&ripemd, sizeof(ripemd));
|
|
}
|
|
clear(&sha, sizeof(sha));
|
|
return WALLY_OK;
|
|
}
|
|
|
|
#if 0
|
|
/* This idea is taken from libressl's explicit_bzero.
|
|
* Use a weak symbol to force the compiler to consider dest as being read,
|
|
* since it can't know what any interposed function may read. Not ideal for
|
|
* us in case someone includes a __clear_fn symbol in a third party library,
|
|
* since it gets called with an address right in the middle of interesting
|
|
* things we are clearing out (even if the actual block is zeroed).
|
|
*/
|
|
__attribute__ ((visibility ("default"))) __attribute__((weak)) void __clear_fn(void *dest, size_t len);
|
|
#endif
|
|
|
|
/* Our implementation of secure clearing uses a variadic function.
|
|
* This appears sufficient to prevent the compiler detecting that
|
|
* the memory is not read after being zeroed and eliminating the
|
|
* call.
|
|
*/
|
|
void clear_n(unsigned int count, ...)
|
|
{
|
|
va_list args;
|
|
unsigned int i;
|
|
|
|
va_start(args, count);
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
void *dest = va_arg(args, void *);
|
|
size_t len = va_arg(args, size_t);
|
|
#ifdef HAVE_MEMSET_S
|
|
memset_s(dest, len, 0, len);
|
|
#else
|
|
memset(dest, 0, len);
|
|
#endif
|
|
#if 0
|
|
/* This is used by boringssl to prevent memset from being elided. It
|
|
* works by forcing a memory barrier and so can be slow.
|
|
*/
|
|
__asm__ __volatile__ ("" : : "r" (dest) : "memory");
|
|
#endif
|
|
#if 0
|
|
/* Continuing libressl's implementation. The check here allows the
|
|
* implementation to remain undefined and thus a buggy compiler
|
|
* cannot see that it does nothing and elide it erroneously.
|
|
*/
|
|
if (__clear_fn)
|
|
__clear_fn(dest, len);
|
|
#endif
|
|
}
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
static void *wally_internal_malloc(size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
static void wally_internal_free(void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
static int wally_internal_ec_nonce_fn(unsigned char *nonce32,
|
|
const unsigned char *msg32, const unsigned char *key32,
|
|
const unsigned char *algo16, void *data, unsigned int attempt)
|
|
{
|
|
return secp256k1_nonce_function_default(nonce32, msg32, key32, algo16, data, attempt);
|
|
}
|
|
|
|
static struct wally_operations _ops = {
|
|
wally_internal_malloc,
|
|
wally_internal_free,
|
|
wally_internal_ec_nonce_fn
|
|
};
|
|
|
|
void *wally_malloc(size_t size)
|
|
{
|
|
return _ops.malloc_fn(size);
|
|
}
|
|
|
|
void wally_free(void *ptr)
|
|
{
|
|
_ops.free_fn(ptr);
|
|
}
|
|
|
|
char *wally_strdup(const char *str)
|
|
{
|
|
size_t len = strlen(str) + 1;
|
|
char *new_str = (char *)wally_malloc(len);
|
|
if (new_str)
|
|
memcpy(new_str, str, len); /* Copies terminating nul */
|
|
return new_str;
|
|
}
|
|
|
|
const struct wally_operations *wally_ops(void)
|
|
{
|
|
return &_ops;
|
|
}
|
|
|
|
int wally_get_operations(struct wally_operations *output)
|
|
{
|
|
if (!output)
|
|
return WALLY_EINVAL;
|
|
memcpy(output, &_ops, sizeof(_ops));
|
|
return WALLY_OK;
|
|
}
|
|
|
|
int wally_set_operations(const struct wally_operations *ops)
|
|
{
|
|
if (!ops)
|
|
return WALLY_EINVAL;
|
|
memcpy(&_ops, ops, sizeof(_ops));
|
|
return WALLY_OK;
|
|
}
|
|
|
|
#ifdef __ANDROID__
|
|
#define malloc(size) wally_malloc(size)
|
|
#define free(ptr) wally_free(ptr)
|
|
#include "cpufeatures/cpu-features.c"
|
|
#endif
|
|
|