#include <assert.h>
#include <bare.h>
#include <js.h>
#include <openssl/bytestring.h>
#include <openssl/cipher.h>
#include <openssl/curve25519.h>
#include <openssl/digest.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/ripemd.h>
#include <stddef.h>
enum {
// Digests
bare_crypto_md5 = 1,
bare_crypto_sha1,
bare_crypto_sha256,
bare_crypto_sha384,
bare_crypto_sha512,
bare_crypto_blake2b256,
bare_crypto_ripemd160,
// Unauthenticated ciphers
bare_crypto_aes_128_ecb,
bare_crypto_aes_128_cbc,
bare_crypto_aes_128_ctr,
bare_crypto_aes_128_ofb,
bare_crypto_aes_256_ecb,
bare_crypto_aes_256_cbc,
bare_crypto_aes_256_ctr,
bare_crypto_aes_256_ofb,
// Authenticated ciphers
bare_crypto_aes_128_gcm,
bare_crypto_aes_256_gcm,
bare_crypto_chacha20_poly1305,
bare_crypto_xchacha20_poly1305,
// Signature algorithms
bare_crypto_ed25519,
};
typedef struct {
EVP_MD_CTX context;
} bare_crypto_digest_t;
typedef struct {
RIPEMD160_CTX context;
} bare_crypto_ripemd160_t;
typedef struct {
HMAC_CTX context;
} bare_crypto_hmac_t;
typedef struct {
EVP_CIPHER_CTX context;
} bare_crypto_cipher_t;
typedef struct {
EVP_AEAD_CTX context;
} bare_crypto_aead_t;
static inline const EVP_MD *
bare_crypto__to_digest(js_env_t *env, int type) {
int err;
switch (type) {
#define V(algorithm) \
case bare_crypto_##algorithm: \
return EVP_##algorithm();
V(md5)
V(sha1)
V(sha256)
V(sha384)
V(sha512)
V(blake2b256)
#undef V
default:
err = js_throw_error(env, NULL, "Unknown digest algorithm");
assert(err == 0);
return NULL;
}
}
static inline const EVP_CIPHER *
bare_crypto__to_cipher(js_env_t *env, int type) {
int err;
switch (type) {
#define V(algorithm) \
case bare_crypto_##algorithm: \
return EVP_##algorithm();
V(aes_128_ecb)
V(aes_128_cbc)
V(aes_128_ctr)
V(aes_128_ofb)
V(aes_256_ecb)
V(aes_256_cbc)
V(aes_256_ctr)
V(aes_256_ofb)
#undef V
default:
err = js_throw_error(env, NULL, "Unknown cipher algorithm");
assert(err == 0);
return NULL;
}
}
static inline const EVP_AEAD *
bare_crypto__to_aead(js_env_t *env, int type) {
int err;
switch (type) {
#define V(algorithm) \
case bare_crypto_##algorithm: \
return EVP_aead_##algorithm();
V(aes_128_gcm)
V(aes_256_gcm)
V(chacha20_poly1305)
V(xchacha20_poly1305)
#undef V
default:
err = js_throw_error(env, NULL, "Unknown cipher algorithm");
assert(err == 0);
return NULL;
}
}
static js_value_t *
bare_crypto_digest_init(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
js_value_t *handle;
bare_crypto_digest_t *digest;
err = js_create_arraybuffer(env, sizeof(bare_crypto_digest_t), (void **) &digest, &handle);
assert(err == 0);
const EVP_MD *algorithm = bare_crypto__to_digest(env, type);
if (algorithm == NULL) return NULL;
EVP_MD_CTX_init(&digest->context);
err = EVP_DigestInit(&digest->context, algorithm);
assert(err == 1);
return handle;
}
static js_value_t *
bare_crypto_digest_update(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 4);
bare_crypto_digest_t *digest;
err = js_get_arraybuffer_info(env, argv[0], (void **) &digest, NULL);
assert(err == 0);
void *data;
err = js_get_arraybuffer_info(env, argv[1], &data, NULL);
assert(err == 0);
int64_t offset;
err = js_get_value_int64(env, argv[2], &offset);
assert(err == 0);
int64_t len;
err = js_get_value_int64(env, argv[3], &len);
assert(err == 0);
err = EVP_DigestUpdate(&digest->context, &data[offset], len);
assert(err == 1);
return NULL;
}
static js_value_t *
bare_crypto_digest_final(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
bare_crypto_digest_t *digest;
err = js_get_arraybuffer_info(env, argv[0], (void **) &digest, NULL);
assert(err == 0);
js_value_t *result;
size_t len = EVP_MD_CTX_size(&digest->context);
uint8_t *out;
err = js_create_arraybuffer(env, len, (void **) &out, &result);
assert(err == 0);
err = EVP_DigestFinal(&digest->context, out, NULL);
assert(err == 1);
return result;
}
static js_value_t *
bare_crypto_ripemd160_init(js_env_t *env, js_callback_info_t *info) {
int err;
js_value_t *handle;
bare_crypto_ripemd160_t *ripemd160;
err = js_create_arraybuffer(env, sizeof(bare_crypto_ripemd160_t), (void **) &ripemd160, &handle);
assert(err == 0);
RIPEMD160_Init(&ripemd160->context);
return handle;
}
static js_value_t *
bare_crypto_ripemd160_update(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 4);
bare_crypto_ripemd160_t *ripemd160;
err = js_get_arraybuffer_info(env, argv[0], (void **) &ripemd160, NULL);
assert(err == 0);
void *data;
err = js_get_arraybuffer_info(env, argv[1], &data, NULL);
assert(err == 0);
int64_t offset;
err = js_get_value_int64(env, argv[2], &offset);
assert(err == 0);
int64_t len;
err = js_get_value_int64(env, argv[3], &len);
assert(err == 0);
err = RIPEMD160_Update(&ripemd160->context, &data[offset], len);
assert(err == 1);
return NULL;
}
static js_value_t *
bare_crypto_ripemd160_final(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
bare_crypto_ripemd160_t *ripemd160;
err = js_get_arraybuffer_info(env, argv[0], (void **) &ripemd160, NULL);
assert(err == 0);
js_value_t *result;
uint8_t *out;
err = js_create_arraybuffer(env, RIPEMD160_DIGEST_LENGTH, (void **) &out, &result);
assert(err == 0);
err = RIPEMD160_Final(out, &ripemd160->context);
assert(err == 1);
return result;
}
static js_value_t *
bare_crypto_hmac_init(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 4);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
char *key;
err = js_get_arraybuffer_info(env, argv[1], (void **) &key, NULL);
assert(err == 0);
int64_t offset;
err = js_get_value_int64(env, argv[2], &offset);
assert(err == 0);
int64_t len;
err = js_get_value_int64(env, argv[3], &len);
assert(err == 0);
js_value_t *handle;
bare_crypto_hmac_t *hmac;
err = js_create_arraybuffer(env, sizeof(bare_crypto_hmac_t), (void **) &hmac, &handle);
assert(err == 0);
const EVP_MD *algorithm = bare_crypto__to_digest(env, type);
if (algorithm == NULL) return NULL;
HMAC_CTX_init(&hmac->context);
err = HMAC_Init_ex(&hmac->context, &key[offset], len, algorithm, NULL);
assert(err == 1);
return handle;
}
static js_value_t *
bare_crypto_hmac_update(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 4);
bare_crypto_hmac_t *hmac;
err = js_get_arraybuffer_info(env, argv[0], (void **) &hmac, NULL);
assert(err == 0);
void *data;
err = js_get_arraybuffer_info(env, argv[1], &data, NULL);
assert(err == 0);
int64_t offset;
err = js_get_value_int64(env, argv[2], &offset);
assert(err == 0);
int64_t len;
err = js_get_value_int64(env, argv[3], &len);
assert(err == 0);
err = HMAC_Update(&hmac->context, &data[offset], len);
assert(err == 1);
return NULL;
}
static js_value_t *
bare_crypto_hmac_final(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
bare_crypto_hmac_t *hmac;
err = js_get_arraybuffer_info(env, argv[0], (void **) &hmac, NULL);
assert(err == 0);
js_value_t *result;
size_t len = HMAC_size(&hmac->context);
uint8_t *digest;
err = js_create_arraybuffer(env, len, (void **) &digest, &result);
assert(err == 0);
err = HMAC_Final(&hmac->context, digest, NULL);
assert(err == 1);
return result;
}
static js_value_t *
bare_crypto_cipher_key_length(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
const EVP_CIPHER *algorithm = bare_crypto__to_cipher(env, type);
if (algorithm == NULL) return NULL;
js_value_t *result;
err = js_create_uint32(env, EVP_CIPHER_key_length(algorithm), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_cipher_iv_length(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
const EVP_CIPHER *algorithm = bare_crypto__to_cipher(env, type);
if (algorithm == NULL) return NULL;
js_value_t *result;
err = js_create_uint32(env, EVP_CIPHER_iv_length(algorithm), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_cipher_block_size(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
bare_crypto_cipher_t *cipher;
err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
assert(err == 0);
js_value_t *result;
err = js_create_uint32(env, EVP_CIPHER_CTX_block_size(&cipher->context), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_cipher_init(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 8;
js_value_t *argv[8];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 8);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
uint8_t *key;
err = js_get_arraybuffer_info(env, argv[1], (void **) &key, NULL);
assert(err == 0);
int64_t key_offset;
err = js_get_value_int64(env, argv[2], &key_offset);
assert(err == 0);
int64_t key_len;
err = js_get_value_int64(env, argv[3], &key_len);
assert(err == 0);
uint8_t *iv;
err = js_get_arraybuffer_info(env, argv[4], (void **) &iv, NULL);
assert(err == 0);
int64_t iv_offset;
err = js_get_value_int64(env, argv[5], &iv_offset);
assert(err == 0);
int64_t iv_len;
err = js_get_value_int64(env, argv[6], &iv_len);
assert(err == 0);
bool encrypt;
err = js_get_value_bool(env, argv[7], &encrypt);
assert(err == 0);
js_value_t *handle;
bare_crypto_cipher_t *cipher;
err = js_create_arraybuffer(env, sizeof(bare_crypto_cipher_t), (void **) &cipher, &handle);
assert(err == 0);
const EVP_CIPHER *algorithm = bare_crypto__to_cipher(env, type);
if (algorithm == NULL) return NULL;
err = EVP_CipherInit(&cipher->context, algorithm, &key[key_offset], &iv[iv_offset], encrypt);
assert(err == 1);
return handle;
}
static js_value_t *
bare_crypto_cipher_update(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 5;
js_value_t *argv[5];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 5);
bare_crypto_cipher_t *cipher;
err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
assert(err == 0);
uint8_t *data;
err = js_get_arraybuffer_info(env, argv[1], (void **) &data, NULL);
assert(err == 0);
int64_t offset;
err = js_get_value_int64(env, argv[2], &offset);
assert(err == 0);
int64_t len;
err = js_get_value_int64(env, argv[3], &len);
assert(err == 0);
uint8_t *out;
err = js_get_arraybuffer_info(env, argv[4], (void **) &out, NULL);
assert(err == 0);
int written;
err = EVP_CipherUpdate(&cipher->context, out, &written, &data[offset], len);
if (err != 1) {
err = js_throw_error(env, NULL, "Cipher update failed");
assert(err == 0);
return NULL;
}
js_value_t *result;
err = js_create_int32(env, written, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_cipher_final(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 2;
js_value_t *argv[2];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 2);
bare_crypto_cipher_t *cipher;
err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
assert(err == 0);
uint8_t *out;
err = js_get_arraybuffer_info(env, argv[1], (void **) &out, NULL);
assert(err == 0);
int written;
err = EVP_CipherFinal(&cipher->context, out, &written);
EVP_CIPHER_CTX_cleanup(&cipher->context);
if (err != 1) {
err = js_throw_error(env, NULL, "Cipher finalisation failed");
assert(err == 0);
return NULL;
}
js_value_t *result;
err = js_create_int32(env, written, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_cipher_set_padding(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 2;
js_value_t *argv[2];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 2);
bare_crypto_cipher_t *cipher;
err = js_get_arraybuffer_info(env, argv[0], (void **) &cipher, NULL);
assert(err == 0);
bool pad;
err = js_get_value_bool(env, argv[1], &pad);
assert(err == 0);
err = EVP_CIPHER_CTX_set_padding(&cipher->context, pad);
assert(err == 1);
return NULL;
}
static js_value_t *
bare_crypto_aead_key_length(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
const EVP_AEAD *algorithm = bare_crypto__to_aead(env, type);
if (algorithm == NULL) return NULL;
js_value_t *result;
err = js_create_int64(env, EVP_AEAD_key_length(algorithm), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_aead_nonce_length(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
const EVP_AEAD *algorithm = bare_crypto__to_aead(env, type);
if (algorithm == NULL) return NULL;
js_value_t *result;
err = js_create_int64(env, EVP_AEAD_nonce_length(algorithm), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_aead_max_overhead(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
bare_crypto_aead_t *aead;
err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
assert(err == 0);
js_value_t *result;
err = js_create_int64(env, EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(&aead->context)), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_aead_max_tag_length(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
bare_crypto_aead_t *aead;
err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
assert(err == 0);
js_value_t *result;
err = js_create_int64(env, EVP_AEAD_max_tag_len(EVP_AEAD_CTX_aead(&aead->context)), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_aead_init(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 5;
js_value_t *argv[5];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 5);
uint32_t type;
err = js_get_value_uint32(env, argv[0], &type);
assert(err == 0);
uint8_t *key;
err = js_get_arraybuffer_info(env, argv[1], (void **) &key, NULL);
assert(err == 0);
int64_t key_offset;
err = js_get_value_int64(env, argv[2], &key_offset);
assert(err == 0);
int64_t key_len;
err = js_get_value_int64(env, argv[3], &key_len);
assert(err == 0);
int64_t tag_len;
err = js_get_value_int64(env, argv[4], &tag_len);
assert(err == 0);
js_value_t *handle;
bare_crypto_aead_t *aead;
err = js_create_arraybuffer(env, sizeof(bare_crypto_aead_t), (void **) &aead, &handle);
assert(err == 0);
const EVP_AEAD *algorithm = bare_crypto__to_aead(env, type);
if (algorithm == NULL) return NULL;
err = EVP_AEAD_CTX_init(&aead->context, algorithm, &key[key_offset], key_len, tag_len, NULL);
assert(err == 1);
return handle;
}
static js_value_t *
bare_crypto_aead_seal(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 11;
js_value_t *argv[11];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 11);
bare_crypto_aead_t *aead;
err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
assert(err == 0);
uint8_t *data;
err = js_get_arraybuffer_info(env, argv[1], (void **) &data, NULL);
assert(err == 0);
int64_t data_offset;
err = js_get_value_int64(env, argv[2], &data_offset);
assert(err == 0);
int64_t data_len;
err = js_get_value_int64(env, argv[3], &data_len);
assert(err == 0);
uint8_t *nonce;
err = js_get_arraybuffer_info(env, argv[4], (void **) &nonce, NULL);
assert(err == 0);
int64_t nonce_offset;
err = js_get_value_int64(env, argv[5], &nonce_offset);
assert(err == 0);
int64_t nonce_len;
err = js_get_value_int64(env, argv[6], &nonce_len);
assert(err == 0);
uint8_t *ad;
err = js_get_arraybuffer_info(env, argv[7], (void **) &ad, NULL);
assert(err == 0);
int64_t ad_offset;
err = js_get_value_int64(env, argv[8], &ad_offset);
assert(err == 0);
int64_t ad_len;
err = js_get_value_int64(env, argv[9], &ad_len);
assert(err == 0);
size_t out_len;
uint8_t *out;
err = js_get_arraybuffer_info(env, argv[10], (void **) &out, &out_len);
assert(err == 0);
size_t written;
err = EVP_AEAD_CTX_seal(
&aead->context,
out,
&written,
out_len,
&nonce[nonce_offset],
nonce_len,
&data[data_offset],
data_len,
ad_len ? &ad[ad_offset] : NULL,
ad_len
);
EVP_AEAD_CTX_cleanup(&aead->context);
if (err != 1) {
err = js_throw_error(env, NULL, "Encryption failed");
assert(err == 0);
}
js_value_t *result;
err = js_create_int32(env, written, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_aead_open(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 11;
js_value_t *argv[11];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 11);
bare_crypto_aead_t *aead;
err = js_get_arraybuffer_info(env, argv[0], (void **) &aead, NULL);
assert(err == 0);
uint8_t *data;
err = js_get_arraybuffer_info(env, argv[1], (void **) &data, NULL);
assert(err == 0);
int64_t data_offset;
err = js_get_value_int64(env, argv[2], &data_offset);
assert(err == 0);
int64_t data_len;
err = js_get_value_int64(env, argv[3], &data_len);
assert(err == 0);
uint8_t *nonce;
err = js_get_arraybuffer_info(env, argv[4], (void **) &nonce, NULL);
assert(err == 0);
int64_t nonce_offset;
err = js_get_value_int64(env, argv[5], &nonce_offset);
assert(err == 0);
int64_t nonce_len;
err = js_get_value_int64(env, argv[6], &nonce_len);
assert(err == 0);
uint8_t *ad;
err = js_get_arraybuffer_info(env, argv[7], (void **) &ad, NULL);
assert(err == 0);
int64_t ad_offset;
err = js_get_value_int64(env, argv[8], &ad_offset);
assert(err == 0);
int64_t ad_len;
err = js_get_value_int64(env, argv[9], &ad_len);
assert(err == 0);
size_t out_len;
uint8_t *out;
err = js_get_arraybuffer_info(env, argv[10], (void **) &out, &out_len);
assert(err == 0);
size_t written;
err = EVP_AEAD_CTX_open(
&aead->context,
out,
&written,
out_len,
&nonce[nonce_offset],
nonce_len,
&data[data_offset],
data_len,
ad_len ? &ad[ad_offset] : NULL,
ad_len
);
EVP_AEAD_CTX_cleanup(&aead->context);
if (err != 1) {
err = js_throw_error(env, NULL, "Decryption failed");
assert(err == 0);
}
js_value_t *result;
err = js_create_int32(env, written, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_ed25519_generate_keypair(js_env_t *env, js_callback_info_t *info) {
int err;
js_value_t *result;
err = js_create_object(env, &result);
assert(err == 0);
js_value_t *handle;
uint8_t *public_key;
err = js_create_arraybuffer(env, ED25519_PUBLIC_KEY_LEN, (void **) &public_key, &handle);
assert(err == 0);
err = js_set_named_property(env, result, "publicKey", handle);
assert(err == 0);
uint8_t *private_key;
err = js_create_arraybuffer(env, ED25519_PRIVATE_KEY_LEN, (void **) &private_key, &handle);
assert(err == 0);
err = js_set_named_property(env, result, "privateKey", handle);
assert(err == 0);
ED25519_keypair(public_key, private_key);
return result;
}
static js_value_t *
bare_crypto_ed25519_sign(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 4);
uint8_t *data;
err = js_get_arraybuffer_info(env, argv[0], (void **) &data, NULL);
assert(err == 0);
uint32_t offset;
err = js_get_value_uint32(env, argv[1], &offset);
assert(err == 0);
uint32_t len;
err = js_get_value_uint32(env, argv[2], &len);
assert(err == 0);
uint8_t *private_key;
err = js_get_arraybuffer_info(env, argv[3], (void **) &private_key, NULL);
assert(err == 0);
js_value_t *handle;
uint8_t *signature;
err = js_create_arraybuffer(env, ED25519_SIGNATURE_LEN, (void **) &signature, &handle);
assert(err == 0);
err = ED25519_sign(signature, &data[offset], len, private_key);
assert(err == 1);
return handle;
}
static js_value_t *
bare_crypto_ed25519_verify(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 6;
js_value_t *argv[6];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 6);
uint8_t *data;
err = js_get_arraybuffer_info(env, argv[0], (void **) &data, NULL);
assert(err == 0);
uint32_t data_offset;
err = js_get_value_uint32(env, argv[1], &data_offset);
assert(err == 0);
uint32_t data_len;
err = js_get_value_uint32(env, argv[2], &data_len);
assert(err == 0);
uint8_t *signature;
err = js_get_arraybuffer_info(env, argv[3], (void **) &signature, NULL);
assert(err == 0);
uint32_t signature_offset;
err = js_get_value_uint32(env, argv[4], &signature_offset);
assert(err == 0);
uint8_t *public_key;
err = js_get_arraybuffer_info(env, argv[5], (void **) &public_key, NULL);
assert(err == 0);
js_value_t *result;
err = js_get_boolean(env, ED25519_verify(&data[data_offset], data_len, &signature[signature_offset], public_key), &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_crypto_ed25519_to_spki(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
uint8_t *public_key;
err = js_get_arraybuffer_info(env, argv[0], (void **) &public_key, NULL);
assert(err == 0);
EVP_PKEY *pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, public_key, 32);
CBB bytes;
err = CBB_init(&bytes, 0);
assert(err == 1);
err = EVP_marshal_public_key(&bytes, pkey);
assert(err == 1);
EVP_PKEY_free(pkey);
uint8_t *der;
size_t len;
err = CBB_finish(&bytes, &der, &len);
assert(err == 1);
js_value_t *handle;
void *data;
err = js_create_arraybuffer(env, len, &data, &handle);
assert(err == 0);
memcpy(data, der, len);
OPENSSL_free(der);
return handle;
}
static js_value_t *
bare_crypto_ed25519_from_spki(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 3);
uint8_t *der;
err = js_get_arraybuffer_info(env, argv[0], (void **) &der, NULL);
assert(err == 0);
uint32_t offset;
err = js_get_value_uint32(env, argv[1], &offset);
assert(err == 0);
uint32_t len;
err = js_get_value_uint32(env, argv[2], &len);
assert(err == 0);
CBS bytes;
CBS_init(&bytes, &der[offset], len);
EVP_PKEY *pkey = EVP_parse_public_key(&bytes);
if (pkey == NULL) {
err = js_throw_error(env, NULL, "Invalid input");
assert(err == 0);
return NULL;
}
js_value_t *handle;
uint8_t *public_key;
err = js_create_arraybuffer(env, ED25519_PUBLIC_KEY_LEN, (void **) &public_key, &handle);
assert(err == 0);
size_t written = ED25519_PUBLIC_KEY_LEN;
err = EVP_PKEY_get_raw_public_key(pkey, public_key, &written);
EVP_PKEY_free(pkey);
if (err != 1) {
err = js_throw_error(env, NULL, "Invalid input");
assert(err == 0);
return NULL;
}
return handle;
}
static js_value_t *
bare_crypto_ed25519_to_pkcs8(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 1);
uint8_t *private_key;
err = js_get_arraybuffer_info(env, argv[0], (void **) &private_key, NULL);
assert(err == 0);
EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, private_key, 32);
CBB bytes;
err = CBB_init(&bytes, 0);
assert(err == 1);
err = EVP_marshal_private_key(&bytes, pkey);
assert(err == 1);
EVP_PKEY_free(pkey);
uint8_t *der;
size_t len;
err = CBB_finish(&bytes, &der, &len);
assert(err == 1);
js_value_t *handle;
void *data;
err = js_create_arraybuffer(env, len, &data, &handle);
assert(err == 0);
memcpy(data, der, len);
OPENSSL_free(der);
return handle;
}
static js_value_t *
bare_crypto_ed25519_from_pkcs8(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 3);
uint8_t *der;
err = js_get_arraybuffer_info(env, argv[0], (void **) &der, NULL);
assert(err == 0);
uint32_t offset;
err = js_get_value_uint32(env, argv[1], &offset);
assert(err == 0);
uint32_t len;
err = js_get_value_uint32(env, argv[2], &len);
assert(err == 0);
CBS bytes;
CBS_init(&bytes, &der[offset], len);
EVP_PKEY *pkey = EVP_parse_private_key(&bytes);
if (pkey == NULL) {
err = js_throw_error(env, NULL, "Invalid input");
assert(err == 0);
return NULL;
}
js_value_t *handle;
uint8_t *private_key;
err = js_create_arraybuffer(env, ED25519_PRIVATE_KEY_LEN, (void **) &private_key, &handle);
assert(err == 0);
size_t written = ED25519_PRIVATE_KEY_LEN;
err = EVP_PKEY_get_raw_private_key(pkey, private_key, &written);
if (err != 1) {
EVP_PKEY_free(pkey);
err = js_throw_error(env, NULL, "Invalid input");
assert(err == 0);
return NULL;
}
written = ED25519_PUBLIC_KEY_LEN;
err = EVP_PKEY_get_raw_public_key(pkey, &private_key[32], &written);
EVP_PKEY_free(pkey);
if (err != 1) {
err = js_throw_error(env, NULL, "Invalid input");
assert(err == 0);
return NULL;
}
return handle;
}
static js_value_t *
bare_crypto_random_fill(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 3);
uint8_t *data;
err = js_get_arraybuffer_info(env, argv[0], (void **) &data, NULL);
assert(err == 0);
uint32_t offset;
err = js_get_value_uint32(env, argv[1], &offset);
assert(err == 0);
uint32_t len;
err = js_get_value_uint32(env, argv[2], &len);
assert(err == 0);
err = RAND_bytes(&data[offset], len);
assert(err == 1);
return NULL;
}
static js_value_t *
bare_crypto_pbkdf2(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 9;
js_value_t *argv[9];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
assert(argc == 9);
char *password;
err = js_get_arraybuffer_info(env, argv[0], (void **) &password, NULL);
assert(err == 0);
int64_t password_offset;
err = js_get_value_int64(env, argv[1], &password_offset);
assert(err == 0);
int64_t password_len;
err = js_get_value_int64(env, argv[2], &password_len);
assert(err == 0);
uint8_t *salt;
err = js_get_arraybuffer_info(env, argv[3], (void **) &salt, NULL);
assert(err == 0);
int64_t salt_offset;
err = js_get_value_int64(env, argv[4], &salt_offset);
assert(err == 0);
int64_t salt_len;
err = js_get_value_int64(env, argv[5], &salt_len);
assert(err == 0);
uint32_t iterations;
err = js_get_value_uint32(env, argv[6], &iterations);
assert(err == 0);
uint32_t type;
err = js_get_value_uint32(env, argv[7], &type);
assert(err == 0);
int64_t key_len;
err = js_get_value_int64(env, argv[8], &key_len);
assert(err == 0);
js_value_t *handle;
uint8_t *out;
err = js_create_arraybuffer(env, key_len, (void **) &out, &handle);
assert(err == 0);
const EVP_MD *algorithm = bare_crypto__to_digest(env, type);
if (algorithm == NULL) return NULL;
err = PKCS5_PBKDF2_HMAC(&password[password_offset], password_len, &salt[salt_offset], salt_len, iterations, algorithm, key_len, out);
assert(err == 1);
return handle;
}
static js_value_t *
bare_crypto_exports(js_env_t *env, js_value_t *exports) {
int err;
#define V(name, fn) \
{ \
js_value_t *val; \
err = js_create_function(env, name, -1, fn, NULL, &val); \
assert(err == 0); \
err = js_set_named_property(env, exports, name, val); \
assert(err == 0); \
}
V("digestInit", bare_crypto_digest_init)
V("digestUpdate", bare_crypto_digest_update)
V("digestFinal", bare_crypto_digest_final)
V("ripemd160Init", bare_crypto_ripemd160_init)
V("ripemd160Update", bare_crypto_ripemd160_update)
V("ripemd160Final", bare_crypto_ripemd160_final)
V("hmacInit", bare_crypto_hmac_init)
V("hmacUpdate", bare_crypto_hmac_update)
V("hmacFinal", bare_crypto_hmac_final)
V("cipherKeyLength", bare_crypto_cipher_key_length)
V("cipherIVLength", bare_crypto_cipher_iv_length)
V("cipherBlockSize", bare_crypto_cipher_block_size)
V("cipherInit", bare_crypto_cipher_init)
V("cipherUpdate", bare_crypto_cipher_update)
V("cipherFinal", bare_crypto_cipher_final)
V("cipherSetPadding", bare_crypto_cipher_set_padding)
V("aeadKeyLength", bare_crypto_aead_key_length)
V("aeadNonceLength", bare_crypto_aead_nonce_length)
V("aeadMaxOverhead", bare_crypto_aead_max_overhead)
V("aeadMaxTagLength", bare_crypto_aead_max_tag_length)
V("aeadInit", bare_crypto_aead_init)
V("aeadSeal", bare_crypto_aead_seal)
V("aeadOpen", bare_crypto_aead_open)
V("ed25519GenerateKeypair", bare_crypto_ed25519_generate_keypair)
V("ed25519Sign", bare_crypto_ed25519_sign)
V("ed25519Verify", bare_crypto_ed25519_verify)
V("ed25519ToSPKI", bare_crypto_ed25519_to_spki)
V("ed25519FromSPKI", bare_crypto_ed25519_from_spki)
V("ed25519ToPKCS8", bare_crypto_ed25519_to_pkcs8)
V("ed25519FromPKCS8", bare_crypto_ed25519_from_pkcs8)
V("randomFill", bare_crypto_random_fill)
V("pbkdf2", bare_crypto_pbkdf2);
#undef V
#define V(name, n) \
{ \
js_value_t *val; \
err = js_create_uint32(env, n, &val); \
assert(err == 0); \
err = js_set_named_property(env, exports, name, val); \
assert(err == 0); \
}
// Digest algorithms
V("MD5", bare_crypto_md5)
V("SHA1", bare_crypto_sha1)
V("SHA256", bare_crypto_sha256)
V("SHA384", bare_crypto_sha384)
V("SHA512", bare_crypto_sha512)
V("BLAKE2B256", bare_crypto_blake2b256)
V("RIPEMD160", bare_crypto_ripemd160)
// Cipher algorithms
V("AES128ECB", bare_crypto_aes_128_ecb)
V("AES128CBC", bare_crypto_aes_128_cbc)
V("AES128CTR", bare_crypto_aes_128_ctr)
V("AES128OFB", bare_crypto_aes_128_ofb)
V("AES256ECB", bare_crypto_aes_256_ecb)
V("AES256CBC", bare_crypto_aes_256_cbc)
V("AES256CTR", bare_crypto_aes_256_ctr)
V("AES256OFB", bare_crypto_aes_256_ofb)
V("AES128GCM", bare_crypto_aes_128_gcm)
V("AES256GCM", bare_crypto_aes_256_gcm)
V("CHACHA20POLY1305", bare_crypto_chacha20_poly1305)
V("XCHACHA20POLY1305", bare_crypto_xchacha20_poly1305)
// Signature algorithms
V("ED25519", bare_crypto_ed25519)
#undef V
return exports;
}
BARE_MODULE(bare_crypto, bare_crypto_exports)