Add LuaCrypto compatible functions (plus some auxiliary functions) as per #1136

This commit is contained in:
Miguel Terron 2025-06-02 14:28:19 +12:00
parent 55dcce4f7d
commit 47c01b548a
2 changed files with 142 additions and 67 deletions

View file

@ -0,0 +1,83 @@
-- Helper function to print test results
local function assert_equal(actual, expected, message)
if actual ~= expected then
error(message .. ": expected " .. tostring(expected) .. ", got " .. tostring(actual))
else
print("PASS: " .. message)
end
end
-- Test RSA key pair generation
local function test_rsa_keypair_generation()
local priv_key, pub_key = crypto.generatekeypair("rsa", 2048)
assert_equal(type(priv_key), "string", "RSA private key generation")
assert_equal(type(pub_key), "string", "RSA public key generation")
end
-- Test ECDSA key pair generation
local function test_ecdsa_keypair_generation()
local priv_key, pub_key = crypto.generatekeypair("ecdsa", "secp256r1")
assert_equal(type(priv_key), "string", "ECDSA private key generation")
assert_equal(type(pub_key), "string", "ECDSA public key generation")
end
-- Test RSA encryption and decryption
local function test_rsa_encryption_decryption()
local priv_key, pub_key = crypto.generatekeypair("rsa", 2048)
local message = "Hello, RSA!"
local encrypted = crypto.encrypt("rsa", pub_key, message)
assert_equal(type(encrypted), "string", "RSA encryption")
local decrypted = crypto.decrypt("rsa", priv_key, encrypted)
assert_equal(decrypted, message, "RSA decryption")
end
-- Test RSA signing and verification
local function test_rsa_signing_verification()
local priv_key, pub_key = crypto.generatekeypair("rsa", 2048)
local message = "Sign this message"
local signature = crypto.sign("rsa", priv_key, message, "sha256")
assert_equal(type(signature), "string", "RSA signing")
local is_valid = crypto.verify("rsa", pub_key, message, signature, "sha256")
assert_equal(is_valid, true, "RSA signature verification")
end
-- Test ECDSA signing and verification
local function test_ecdsa_signing_verification()
local priv_key, pub_key = crypto.generatekeypair("ecdsa", "secp256r1")
local message = "Sign this message with ECDSA"
local signature = crypto.sign("ecdsa", priv_key, message, "sha256")
assert_equal(type(signature), "string", "ECDSA signing")
local is_valid = crypto.verify("ecdsa", pub_key, message, signature, "sha256")
assert_equal(is_valid, true, "ECDSA signature verification")
end
-- Test CSR generation
local function test_csr_generation()
local priv_key, pub_key = crypto.generatekeypair("rsa", 2048)
local subject_name = "CN=example.com,O=Example Org,C=US"
local csr = crypto.csrGenerate(priv_key, subject_name)
assert_equal(type(csr), "string", "CSR generation")
end
-- Test PemToJwk conversion
local function test_pem_to_jwk()
local priv_key, pub_key = crypto.generatekeypair("rsa", 2048)
local jwk = crypto.PemToJwk(pub_key)
assert_equal(type(jwk), "table", "PEM to JWK conversion")
assert_equal(jwk.kty, "RSA", "JWK key type")
end
-- Run all tests
local function run_tests()
print("Running tests for lcrypto...")
test_rsa_keypair_generation()
test_ecdsa_keypair_generation()
test_rsa_encryption_decryption()
test_rsa_signing_verification()
test_ecdsa_signing_verification()
test_csr_generation()
test_pem_to_jwk()
print("All tests passed!")
end
run_tests()

View file

@ -911,76 +911,68 @@ static int LuaECDSAGenerateKeyPair(lua_State *L) {
static int ECDSASign(const char *priv_key_pem, const char *message,
hash_algorithm_t hash_alg, unsigned char **signature,
size_t *sig_len) {
mbedtls_pk_context key;
unsigned char hash[64]; // Max hash size (SHA-512)
size_t hash_size;
int ret;
mbedtls_pk_context key;
unsigned char hash[64]; // Max hash size (SHA-512)
size_t hash_size;
int ret;
*signature = NULL;
*sig_len = 0;
if (!priv_key_pem) {
WARNF("(ecdsa) Private key is NULL");
return -1;
}
// Get the length of the PEM string (excluding null terminator)
size_t key_len = strlen(priv_key_pem);
if (key_len == 0) {
WARNF("(ecdsa) Private key is empty");
return -1;
}
// Get hash size for the selected algorithm
hash_size = get_hash_size(hash_alg);
mbedtls_pk_init(&key);
// Parse the private key from PEM directly without creating a copy
ret = mbedtls_pk_parse_key(&key, (const unsigned char *)priv_key_pem,
key_len + 1, NULL, 0);
if (ret != 0) {
WARNF("(ecdsa) Failed to parse private key: -0x%04x", -ret);
goto cleanup;
}
// Compute hash of the message using the specified algorithm
ret = compute_hash(hash_alg, (const unsigned char *)message, strlen(message),
hash, sizeof(hash));
if (ret != 0) {
WARNF("(ecdsa) Failed to compute message hash");
goto cleanup;
}
// Allocate memory for signature (max size for ECDSA)
*signature = malloc(MBEDTLS_ECDSA_MAX_LEN);
if (*signature == NULL) {
WARNF("(ecdsa) Failed to allocate memory for signature");
ret = -1;
goto cleanup;
}
// Sign the hash using GenerateHardRandom
ret = mbedtls_pk_sign(&key, hash_to_md_type(hash_alg), hash, hash_size,
*signature, sig_len, GenerateHardRandom, 0);
if (ret != 0) {
WARNF("(ecdsa) Failed to sign message: -0x%04x", -ret);
free(*signature);
*signature = NULL;
*sig_len = 0;
goto cleanup;
}
cleanup:
mbedtls_pk_free(&key);
return ret;
} // Lua binding for signing a message
if (!priv_key_pem || strlen(priv_key_pem) == 0) {
WARNF("(ecdsa) Private key is NULL or empty");
return -1;
}
mbedtls_pk_init(&key);
// Parse the private key from PEM (PKCS#8 format)
ret = mbedtls_pk_parse_key(&key, (const unsigned char *)priv_key_pem,
strlen(priv_key_pem) + 1, NULL, 0);
if (ret != 0) {
WARNF("(ecdsa) Failed to parse private key: -0x%04x", -ret);
mbedtls_pk_free(&key);
return -1;
}
// Compute hash of the message
hash_size = get_hash_size(hash_alg);
ret = compute_hash(hash_alg, (const unsigned char *)message, strlen(message),
hash, sizeof(hash));
if (ret != 0) {
WARNF("(ecdsa) Failed to compute message hash");
mbedtls_pk_free(&key);
return -1;
}
// Allocate memory for the signature
*signature = malloc(MBEDTLS_PK_SIGNATURE_MAX_SIZE);
if (*signature == NULL) {
WARNF("(ecdsa) Failed to allocate memory for signature");
mbedtls_pk_free(&key);
return -1;
}
// Sign the hash
ret = mbedtls_pk_sign(&key, hash_to_md_type(hash_alg), hash, hash_size,
*signature, sig_len, GenerateHardRandom, NULL);
if (ret != 0) {
WARNF("(ecdsa) Failed to sign message: -0x%04x", -ret);
free(*signature);
*signature = NULL;
*sig_len = 0;
mbedtls_pk_free(&key);
return -1;
}
mbedtls_pk_free(&key);
return 0;
}
// Lua binding for signing a message
static int LuaECDSASign(lua_State *L) {
const char *hash_name = luaL_optstring(L, 1, "sha256"); // Default to SHA-256
const char *hash_name = luaL_optstring(L, 3, "sha256"); // Default to SHA-256
const char *message = luaL_checkstring(L, 2);
const char *priv_key_pem = luaL_checkstring(L, 3);
const char *priv_key_pem = luaL_checkstring(L, 1);
hash_algorithm_t hash_alg = string_to_hash_alg(hash_name);
@ -1054,12 +1046,12 @@ cleanup:
return ret;
}
static int LuaECDSAVerify(lua_State *L) {
const char *hash_name = luaL_optstring(L, 1, "sha256"); // Default to SHA-256
const char *pub_key_pem = luaL_checkstring(L, 1);
const char *message = luaL_checkstring(L, 2);
const char *pub_key_pem = luaL_checkstring(L, 3);
size_t sig_len;
const unsigned char *signature =
(const unsigned char *)luaL_checklstring(L, 4, &sig_len);
(const unsigned char *)luaL_checklstring(L, 3, &sig_len);
const char *hash_name = luaL_optstring(L, 4, "sha256"); // Default to SHA-256
hash_algorithm_t hash_alg = string_to_hash_alg(hash_name);