prosody/util-src/crypto.c
Stephen Paul Weber d477528e67 util.crypto: Add more ECC methods
pkey_meth_derive: to derive a shared symmetric key from two ECC keys
pkey_meth_public_raw: to get the raw form of the public key
import_public_ec_raw: to import the raw form of the public key
generate_p256_keypair: key generation for the P-256 curve
2024-10-29 09:15:50 -05:00

738 lines
20 KiB
C

/* Prosody IM
-- Copyright (C) 2022 Matthew Wild
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
*/
/*
* crypto.c
* Lua library for cryptographic operations using OpenSSL
*/
#include <string.h>
#include <stdlib.h>
#ifdef _MSC_VER
typedef unsigned __int32 uint32_t;
#else
#include <inttypes.h>
#endif
#include "lua.h"
#include "lauxlib.h"
#include <openssl/crypto.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/obj_mac.h>
#include <openssl/param_build.h>
#include <openssl/pem.h>
#if (LUA_VERSION_NUM == 501)
#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
#endif
/* The max size of an encoded 'R' or 'S' value. P-521 = 521 bits = 66 bytes */
#define MAX_ECDSA_SIG_INT_BYTES 66
#include "managed_pointer.h"
#define PKEY_MT_TAG "util.crypto key"
static BIO* new_memory_BIO(void) {
return BIO_new(BIO_s_mem());
}
MANAGED_POINTER_ALLOCATOR(new_managed_EVP_MD_CTX, EVP_MD_CTX*, EVP_MD_CTX_new, EVP_MD_CTX_free)
MANAGED_POINTER_ALLOCATOR(new_managed_BIO_s_mem, BIO*, new_memory_BIO, BIO_free)
MANAGED_POINTER_ALLOCATOR(new_managed_EVP_CIPHER_CTX, EVP_CIPHER_CTX*, EVP_CIPHER_CTX_new, EVP_CIPHER_CTX_free)
#define CRYPTO_KEY_TYPE_ERR "unexpected key type: got '%s', expected '%s'"
static EVP_PKEY* pkey_from_arg(lua_State *L, int idx, const int type, const int require_private) {
EVP_PKEY *pkey = *(EVP_PKEY**)luaL_checkudata(L, idx, PKEY_MT_TAG);
int got_type;
if(type || require_private) {
lua_getuservalue(L, idx);
if(type != 0) {
lua_getfield(L, -1, "type");
got_type = lua_tointeger(L, -1);
if(got_type != type) {
const char *got_key_type_name = OBJ_nid2sn(got_type);
const char *want_key_type_name = OBJ_nid2sn(type);
lua_pushfstring(L, CRYPTO_KEY_TYPE_ERR, got_key_type_name, want_key_type_name);
luaL_argerror(L, idx, lua_tostring(L, -1));
}
lua_pop(L, 1);
}
if(require_private != 0) {
lua_getfield(L, -1, "private");
if(lua_toboolean(L, -1) != 1) {
luaL_argerror(L, idx, "private key expected, got public key only");
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}
return pkey;
}
static int Lpkey_finalizer(lua_State *L) {
EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0);
EVP_PKEY_free(pkey);
return 0;
}
static int Lpkey_meth_get_type(lua_State *L) {
EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0);
int key_type = EVP_PKEY_id(pkey);
lua_pushstring(L, OBJ_nid2sn(key_type));
return 1;
}
static int Lpkey_meth_derive(lua_State *L) {
size_t outlen;
EVP_PKEY *key = pkey_from_arg(L, 1, 0, 0);
EVP_PKEY *peer = pkey_from_arg(L, 2, 0, 0);
EVP_PKEY_CTX *ctx;
BUF_MEM *buf;
BIO *bio = new_managed_BIO_s_mem(L);
BIO_get_mem_ptr(bio, &buf);
if (!(ctx = EVP_PKEY_CTX_new(key, NULL)))
goto sslerr;
if (EVP_PKEY_derive_init(ctx) <= 0)
goto sslerr;
if (EVP_PKEY_derive_set_peer(ctx, peer) <= 0)
goto sslerr;
if (EVP_PKEY_derive(ctx, NULL, &outlen) <= 0)
goto sslerr;
if (!BUF_MEM_grow_clean(buf, outlen))
goto sslerr;
if (EVP_PKEY_derive(ctx, (unsigned char*)buf->data, &outlen) <= 0)
goto sslerr;
EVP_PKEY_CTX_free(ctx);
ctx = NULL;
lua_pushlstring(L, buf->data, outlen);
BIO_reset(bio);
return 1;
sslerr:
if (ctx) {
EVP_PKEY_CTX_free(ctx);
ctx = NULL;
}
BIO_reset(bio);
return luaL_error(L, "pkey:derive failed");
}
static int base_evp_sign(lua_State *L, const int key_type, const EVP_MD *digest_type) {
EVP_PKEY *pkey = pkey_from_arg(L, 1, (key_type!=NID_rsassaPss)?key_type:NID_rsaEncryption, 1);
luaL_Buffer sigbuf;
size_t msg_len;
const unsigned char* msg = (unsigned char*)lua_tolstring(L, 2, &msg_len);
size_t sig_len;
unsigned char *sig = NULL;
EVP_MD_CTX *md_ctx = new_managed_EVP_MD_CTX(L);
if(EVP_DigestSignInit(md_ctx, NULL, digest_type, NULL, pkey) != 1) {
lua_pushnil(L);
return 1;
}
if(key_type == NID_rsassaPss) {
EVP_PKEY_CTX_set_rsa_padding(EVP_MD_CTX_pkey_ctx(md_ctx), RSA_PKCS1_PSS_PADDING);
}
if(EVP_DigestSign(md_ctx, NULL, &sig_len, msg, msg_len) != 1) {
lua_pushnil(L);
return 1;
}
// COMPAT w/ Lua 5.1
luaL_buffinit(L, &sigbuf);
sig = memset(luaL_prepbuffer(&sigbuf), 0, sig_len);
if(EVP_DigestSign(md_ctx, sig, &sig_len, msg, msg_len) != 1) {
lua_pushnil(L);
}
else {
luaL_addsize(&sigbuf, sig_len);
luaL_pushresult(&sigbuf);
return 1;
}
return 1;
}
static int base_evp_verify(lua_State *L, const int key_type, const EVP_MD *digest_type) {
EVP_PKEY *pkey = pkey_from_arg(L, 1, (key_type!=NID_rsassaPss)?key_type:NID_rsaEncryption, 0);
size_t msg_len;
const unsigned char *msg = (unsigned char*)luaL_checklstring(L, 2, &msg_len);
size_t sig_len;
const unsigned char *sig = (unsigned char*)luaL_checklstring(L, 3, &sig_len);
EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
if(EVP_DigestVerifyInit(md_ctx, NULL, digest_type, NULL, pkey) != 1) {
lua_pushnil(L);
goto cleanup;
}
if(key_type == NID_rsassaPss) {
EVP_PKEY_CTX_set_rsa_padding(EVP_MD_CTX_pkey_ctx(md_ctx), RSA_PKCS1_PSS_PADDING);
}
int result = EVP_DigestVerify(md_ctx, sig, sig_len, msg, msg_len);
if(result == 0) {
lua_pushboolean(L, 0);
} else if(result != 1) {
lua_pushnil(L);
}
else {
lua_pushboolean(L, 1);
}
cleanup:
EVP_MD_CTX_free(md_ctx);
return 1;
}
static int Lpkey_meth_public_raw(lua_State *L) {
OSSL_PARAM *params;
EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0);
if (EVP_PKEY_todata(pkey, EVP_PKEY_PUBLIC_KEY, &params)) {
OSSL_PARAM *item = params;
while (item->key) {
if (!strcmp("pub", item->key)) {
lua_pushlstring(L, item->data, item->data_size);
break;
}
item++;
}
if (!item->key) lua_pushnil(L);
OSSL_PARAM_free(params);
} else {
lua_pushnil(L);
}
return 1;
}
static int Lpkey_meth_public_pem(lua_State *L) {
char *data;
size_t bytes;
EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0);
BIO *bio = new_managed_BIO_s_mem(L);
if(PEM_write_bio_PUBKEY(bio, pkey)) {
bytes = BIO_get_mem_data(bio, &data);
if (bytes > 0) {
lua_pushlstring(L, data, bytes);
}
else {
lua_pushnil(L);
}
}
else {
lua_pushnil(L);
}
return 1;
}
static int Lpkey_meth_private_pem(lua_State *L) {
char *data;
size_t bytes;
EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 1);
BIO *bio = new_managed_BIO_s_mem(L);
if(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
bytes = BIO_get_mem_data(bio, &data);
if (bytes > 0) {
lua_pushlstring(L, data, bytes);
}
else {
lua_pushnil(L);
}
}
else {
lua_pushnil(L);
}
return 1;
}
static int push_pkey(lua_State *L, EVP_PKEY *pkey, const int type, const int privkey) {
EVP_PKEY **ud = lua_newuserdata(L, sizeof(EVP_PKEY*));
*ud = pkey;
luaL_newmetatable(L, PKEY_MT_TAG);
lua_setmetatable(L, -2);
/* Set some info about the key and attach it as a user value */
lua_newtable(L);
if(type != 0) {
lua_pushinteger(L, type);
lua_setfield(L, -2, "type");
}
if(privkey != 0) {
lua_pushboolean(L, 1);
lua_setfield(L, -2, "private");
}
lua_setuservalue(L, -2);
return 1;
}
static int Lgenerate_ed25519_keypair(lua_State *L) {
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL);
/* Generate key */
EVP_PKEY_keygen_init(pctx);
EVP_PKEY_keygen(pctx, &pkey);
EVP_PKEY_CTX_free(pctx);
push_pkey(L, pkey, NID_ED25519, 1);
return 1;
}
static int Lgenerate_p256_keypair(lua_State *L) {
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
/* Generate key */
if (EVP_PKEY_keygen_init(pctx) <= 0) goto err;
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) goto err;
if (EVP_PKEY_keygen(pctx, &pkey) <= 0) goto err;
EVP_PKEY_CTX_free(pctx);
push_pkey(L, pkey, NID_X9_62_prime256v1, 1);
return 1;
err:
if (pctx) EVP_PKEY_CTX_free(pctx);
lua_pushnil(L);
return 1;
}
static int Limport_private_pem(lua_State *L) {
EVP_PKEY *pkey = NULL;
size_t privkey_bytes;
const char* privkey_data;
BIO *bio = new_managed_BIO_s_mem(L);
privkey_data = luaL_checklstring(L, 1, &privkey_bytes);
BIO_write(bio, privkey_data, privkey_bytes);
pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
if (pkey) {
push_pkey(L, pkey, EVP_PKEY_id(pkey), 1);
}
else {
lua_pushnil(L);
}
return 1;
}
static int Limport_public_ec_raw(lua_State *L) {
OSSL_PARAM_BLD *param_bld = NULL;
OSSL_PARAM *params = NULL;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
size_t pubkey_bytes;
const char* pubkey_data = luaL_checklstring(L, 1, &pubkey_bytes);
const char* curve = luaL_checkstring(L, 2);
param_bld = OSSL_PARAM_BLD_new();
if (!param_bld) goto err;
if (!OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", curve, 0)) goto err;
if (!OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", pubkey_data, pubkey_bytes)) goto err;
params = OSSL_PARAM_BLD_to_param(param_bld);
if (!params) goto err;
ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
if (!ctx) goto err;
if (!EVP_PKEY_fromdata_init(ctx)) goto err;
if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) goto err;
push_pkey(L, pkey, EVP_PKEY_id(pkey), 0);
EVP_PKEY_CTX_free(ctx);
OSSL_PARAM_free(params);
OSSL_PARAM_BLD_free(param_bld);
return 1;
err:
if (ctx) EVP_PKEY_CTX_free(ctx);
if (params) OSSL_PARAM_free(params);
if (param_bld) OSSL_PARAM_BLD_free(param_bld);
lua_pushnil(L);
return 1;
}
static int Limport_public_pem(lua_State *L) {
EVP_PKEY *pkey = NULL;
size_t pubkey_bytes;
const char* pubkey_data;
BIO *bio = new_managed_BIO_s_mem(L);
pubkey_data = luaL_checklstring(L, 1, &pubkey_bytes);
BIO_write(bio, pubkey_data, pubkey_bytes);
pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
if (pkey) {
push_pkey(L, pkey, EVP_PKEY_id(pkey), 0);
}
else {
lua_pushnil(L);
}
return 1;
}
static int Led25519_sign(lua_State *L) {
return base_evp_sign(L, NID_ED25519, NULL);
}
static int Led25519_verify(lua_State *L) {
return base_evp_verify(L, NID_ED25519, NULL);
}
/* encrypt(key, iv, plaintext) */
static int Levp_encrypt(lua_State *L, const EVP_CIPHER *cipher, const unsigned char expected_key_len, const unsigned char expected_iv_len, const size_t tag_len) {
EVP_CIPHER_CTX *ctx;
luaL_Buffer ciphertext_buffer;
size_t key_len, iv_len, plaintext_len;
int ciphertext_len, final_len;
const unsigned char *key = (unsigned char*)luaL_checklstring(L, 1, &key_len);
const unsigned char *iv = (unsigned char*)luaL_checklstring(L, 2, &iv_len);
const unsigned char *plaintext = (unsigned char*)luaL_checklstring(L, 3, &plaintext_len);
if(key_len != expected_key_len) {
return luaL_error(L, "key must be %d bytes", expected_key_len);
}
if(iv_len != expected_iv_len) {
return luaL_error(L, "iv must be %d bytes", expected_iv_len);
}
if(lua_gettop(L) > 3) {
return luaL_error(L, "Expected 3 arguments, got %d", lua_gettop(L));
}
// Create and initialise the context
ctx = new_managed_EVP_CIPHER_CTX(L);
// Initialise the encryption operation
if(1 != EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL)) {
return luaL_error(L, "Error while initializing encryption engine");
}
// Initialise key and IV
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) {
return luaL_error(L, "Error while initializing key/iv");
}
luaL_buffinit(L, &ciphertext_buffer);
unsigned char *ciphertext = (unsigned char*)luaL_prepbuffsize(&ciphertext_buffer, plaintext_len+tag_len);
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &ciphertext_len, plaintext, plaintext_len)) {
return luaL_error(L, "Error while encrypting data");
}
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &final_len)) {
return luaL_error(L, "Error while encrypting final data");
}
if(final_len != 0) {
return luaL_error(L, "Non-zero final data");
}
if(tag_len > 0) {
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, ciphertext + ciphertext_len)) {
return luaL_error(L, "Unable to read AEAD tag of encrypted data");
}
/* Append tag */
luaL_addsize(&ciphertext_buffer, ciphertext_len + tag_len);
} else {
luaL_addsize(&ciphertext_buffer, ciphertext_len);
}
luaL_pushresult(&ciphertext_buffer);
return 1;
}
static int Laes_128_gcm_encrypt(lua_State *L) {
return Levp_encrypt(L, EVP_aes_128_gcm(), 16, 12, 16);
}
static int Laes_256_gcm_encrypt(lua_State *L) {
return Levp_encrypt(L, EVP_aes_256_gcm(), 32, 12, 16);
}
static int Laes_256_ctr_encrypt(lua_State *L) {
return Levp_encrypt(L, EVP_aes_256_ctr(), 32, 16, 0);
}
/* decrypt(key, iv, ciphertext) */
static int Levp_decrypt(lua_State *L, const EVP_CIPHER *cipher, const unsigned char expected_key_len, const unsigned char expected_iv_len, const size_t tag_len) {
EVP_CIPHER_CTX *ctx;
luaL_Buffer plaintext_buffer;
size_t key_len, iv_len, ciphertext_len;
int plaintext_len, final_len;
const unsigned char *key = (unsigned char*)luaL_checklstring(L, 1, &key_len);
const unsigned char *iv = (unsigned char*)luaL_checklstring(L, 2, &iv_len);
const unsigned char *ciphertext = (unsigned char*)luaL_checklstring(L, 3, &ciphertext_len);
if(key_len != expected_key_len) {
return luaL_error(L, "key must be %d bytes", expected_key_len);
}
if(iv_len != expected_iv_len) {
return luaL_error(L, "iv must be %d bytes", expected_iv_len);
}
if(ciphertext_len <= tag_len) {
return luaL_error(L, "ciphertext must be at least %d bytes (including tag)", tag_len);
}
if(lua_gettop(L) > 3) {
return luaL_error(L, "Expected 3 arguments, got %d", lua_gettop(L));
}
/* Create and initialise the context */
ctx = new_managed_EVP_CIPHER_CTX(L);
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL)) {
return luaL_error(L, "Error while initializing decryption engine");
}
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) {
return luaL_error(L, "Error while initializing key/iv");
}
luaL_buffinit(L, &plaintext_buffer);
unsigned char *plaintext = (unsigned char*)luaL_prepbuffsize(&plaintext_buffer, ciphertext_len);
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &plaintext_len, ciphertext, ciphertext_len-tag_len)) {
return luaL_error(L, "Error while decrypting data");
}
if(tag_len > 0) {
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, (unsigned char*)ciphertext + (ciphertext_len-tag_len))) {
return luaL_error(L, "Error while processing authentication tag");
}
}
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
int ret = EVP_DecryptFinal_ex(ctx, plaintext + plaintext_len, &final_len);
if(ret <= 0) {
/* Verify failed */
lua_pushnil(L);
lua_pushliteral(L, "verify-failed");
return 2;
}
luaL_addsize(&plaintext_buffer, plaintext_len + final_len);
luaL_pushresult(&plaintext_buffer);
return 1;
}
static int Laes_128_gcm_decrypt(lua_State *L) {
return Levp_decrypt(L, EVP_aes_128_gcm(), 16, 12, 16);
}
static int Laes_256_gcm_decrypt(lua_State *L) {
return Levp_decrypt(L, EVP_aes_256_gcm(), 32, 12, 16);
}
static int Laes_256_ctr_decrypt(lua_State *L) {
return Levp_decrypt(L, EVP_aes_256_ctr(), 32, 16, 0);
}
/* r, s = parse_ecdsa_sig(sig_der) */
static int Lparse_ecdsa_signature(lua_State *L) {
ECDSA_SIG *sig;
size_t sig_der_len;
const unsigned char *sig_der = (unsigned char*)luaL_checklstring(L, 1, &sig_der_len);
const size_t sig_int_bytes = luaL_checkinteger(L, 2);
const BIGNUM *r, *s;
int rlen, slen;
unsigned char rb[MAX_ECDSA_SIG_INT_BYTES];
unsigned char sb[MAX_ECDSA_SIG_INT_BYTES];
if(sig_int_bytes > MAX_ECDSA_SIG_INT_BYTES) {
luaL_error(L, "requested signature size exceeds supported limit");
}
sig = d2i_ECDSA_SIG(NULL, &sig_der, sig_der_len);
if(sig == NULL) {
lua_pushnil(L);
return 1;
}
ECDSA_SIG_get0(sig, &r, &s);
rlen = BN_bn2binpad(r, rb, sig_int_bytes);
slen = BN_bn2binpad(s, sb, sig_int_bytes);
if (rlen == -1 || slen == -1) {
ECDSA_SIG_free(sig);
luaL_error(L, "encoded integers exceed requested size");
}
ECDSA_SIG_free(sig);
lua_pushlstring(L, (const char*)rb, rlen);
lua_pushlstring(L, (const char*)sb, slen);
return 2;
}
/* sig_der = build_ecdsa_signature(r, s) */
static int Lbuild_ecdsa_signature(lua_State *L) {
ECDSA_SIG *sig = ECDSA_SIG_new();
BIGNUM *r, *s;
luaL_Buffer sigbuf;
size_t rlen, slen;
const unsigned char *rbin, *sbin;
rbin = (unsigned char*)luaL_checklstring(L, 1, &rlen);
sbin = (unsigned char*)luaL_checklstring(L, 2, &slen);
r = BN_bin2bn(rbin, (int)rlen, NULL);
s = BN_bin2bn(sbin, (int)slen, NULL);
ECDSA_SIG_set0(sig, r, s);
luaL_buffinit(L, &sigbuf);
/* DER structure of an ECDSA signature has 7 bytes plus the integers themselves,
which may gain an extra byte once encoded */
unsigned char *buffer = (unsigned char*)luaL_prepbuffsize(&sigbuf, (rlen+1)+(slen+1)+7);
int len = i2d_ECDSA_SIG(sig, &buffer);
luaL_addsize(&sigbuf, len);
luaL_pushresult(&sigbuf);
ECDSA_SIG_free(sig);
return 1;
}
#define REG_SIGN_VERIFY(algorithm, digest) \
{ #algorithm "_" #digest "_sign", L ## algorithm ## _ ## digest ## _sign },\
{ #algorithm "_" #digest "_verify", L ## algorithm ## _ ## digest ## _verify },
#define IMPL_SIGN_VERIFY(algorithm, key_type, digest) \
static int L ## algorithm ## _ ## digest ## _sign(lua_State *L) { \
return base_evp_sign(L, key_type, EVP_ ## digest()); \
} \
static int L ## algorithm ## _ ## digest ## _verify(lua_State *L) { \
return base_evp_verify(L, key_type, EVP_ ## digest()); \
}
IMPL_SIGN_VERIFY(ecdsa, NID_X9_62_id_ecPublicKey, sha256)
IMPL_SIGN_VERIFY(ecdsa, NID_X9_62_id_ecPublicKey, sha384)
IMPL_SIGN_VERIFY(ecdsa, NID_X9_62_id_ecPublicKey, sha512)
IMPL_SIGN_VERIFY(rsassa_pkcs1, NID_rsaEncryption, sha256)
IMPL_SIGN_VERIFY(rsassa_pkcs1, NID_rsaEncryption, sha384)
IMPL_SIGN_VERIFY(rsassa_pkcs1, NID_rsaEncryption, sha512)
IMPL_SIGN_VERIFY(rsassa_pss, NID_rsassaPss, sha256)
IMPL_SIGN_VERIFY(rsassa_pss, NID_rsassaPss, sha384)
IMPL_SIGN_VERIFY(rsassa_pss, NID_rsassaPss, sha512)
static const luaL_Reg Reg[] = {
{ "ed25519_sign", Led25519_sign },
{ "ed25519_verify", Led25519_verify },
REG_SIGN_VERIFY(ecdsa, sha256)
REG_SIGN_VERIFY(ecdsa, sha384)
REG_SIGN_VERIFY(ecdsa, sha512)
REG_SIGN_VERIFY(rsassa_pkcs1, sha256)
REG_SIGN_VERIFY(rsassa_pkcs1, sha384)
REG_SIGN_VERIFY(rsassa_pkcs1, sha512)
REG_SIGN_VERIFY(rsassa_pss, sha256)
REG_SIGN_VERIFY(rsassa_pss, sha384)
REG_SIGN_VERIFY(rsassa_pss, sha512)
{ "aes_128_gcm_encrypt", Laes_128_gcm_encrypt },
{ "aes_128_gcm_decrypt", Laes_128_gcm_decrypt },
{ "aes_256_gcm_encrypt", Laes_256_gcm_encrypt },
{ "aes_256_gcm_decrypt", Laes_256_gcm_decrypt },
{ "aes_256_ctr_encrypt", Laes_256_ctr_encrypt },
{ "aes_256_ctr_decrypt", Laes_256_ctr_decrypt },
{ "generate_ed25519_keypair", Lgenerate_ed25519_keypair },
{ "generate_p256_keypair", Lgenerate_p256_keypair },
{ "import_private_pem", Limport_private_pem },
{ "import_public_pem", Limport_public_pem },
{ "import_public_ec_raw", Limport_public_ec_raw },
{ "parse_ecdsa_signature", Lparse_ecdsa_signature },
{ "build_ecdsa_signature", Lbuild_ecdsa_signature },
{ NULL, NULL }
};
static const luaL_Reg KeyMethods[] = {
{ "private_pem", Lpkey_meth_private_pem },
{ "public_pem", Lpkey_meth_public_pem },
{ "public_raw", Lpkey_meth_public_raw },
{ "get_type", Lpkey_meth_get_type },
{ "derive", Lpkey_meth_derive },
{ NULL, NULL }
};
static const luaL_Reg KeyMetatable[] = {
{ "__gc", Lpkey_finalizer },
{ NULL, NULL }
};
LUALIB_API int luaopen_prosody_util_crypto(lua_State *L) {
#if (LUA_VERSION_NUM > 501)
luaL_checkversion(L);
#endif
/* Initialize pkey metatable */
luaL_newmetatable(L, PKEY_MT_TAG);
luaL_setfuncs(L, KeyMetatable, 0);
lua_newtable(L);
luaL_setfuncs(L, KeyMethods, 0);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
/* Initialize lib table */
lua_newtable(L);
luaL_setfuncs(L, Reg, 0);
lua_pushliteral(L, "-3.14");
lua_setfield(L, -2, "version");
#ifdef OPENSSL_VERSION
lua_pushstring(L, OpenSSL_version(OPENSSL_VERSION));
lua_setfield(L, -2, "_LIBCRYPTO_VERSION");
#endif
return 1;
}
LUALIB_API int luaopen_util_crypto(lua_State *L) {
return luaopen_prosody_util_crypto(L);
}