Improve tests

Add definitions
Align function name
This commit is contained in:
Miguel Terron 2025-06-04 16:25:12 +12:00
parent 2d2a8a2d7d
commit 5c47674d27
3 changed files with 128 additions and 53 deletions

View file

@ -1,7 +1,7 @@
-- 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))
error("FAIL: " .. message .. ": expected " .. tostring(expected) .. ", got " .. tostring(actual))
else
print("PASS: " .. message)
end
@ -19,146 +19,153 @@ end
local function test_rsa_keypair_generation()
print('\27[1;7mTest RSA key pair generation \27[0m')
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")
assert_equal(type(priv_key), "string", "Private key type")
assert_equal(type(pub_key), "string", "Public key type")
end
-- Test ECDSA key pair generation
local function test_ecdsa_keypair_generation()
print('\n\27[1;7mTest ECDSA key pair generation \27[0m')
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")
assert_equal(type(priv_key), "string", "Private key type")
assert_equal(type(pub_key), "string", "Public key type")
end
-- Test RSA encryption and decryption
local function test_rsa_encryption_decryption()
print('\n\27[1;7mTest RSA encryption and decryption \27[0m')
local priv_key, pub_key = crypto.generatekeypair("rsa", 2048)
assert(type(priv_key) == "string", "Private key type")
assert(type(pub_key) == "string", "Public key type")
local plaintext = "Hello, RSA!"
local encrypted = crypto.encrypt("rsa", pub_key, plaintext)
assert_equal(type(encrypted), "string", "RSA encryption")
assert_equal(type(encrypted), "string", "Ciphertext type")
local decrypted = crypto.decrypt("rsa", priv_key, encrypted)
assert_equal(decrypted, plaintext, "RSA decryption")
assert_equal(decrypted, plaintext, "Decrypted ciphertext matches plaintext")
end
-- Test RSA signing and verification
local function test_rsa_signing_verification()
print('\n\27[1;7mTest RSA signing and verification \27[0m')
local priv_key, pub_key = crypto.generatekeypair("rsa", 2048)
assert(type(priv_key) == "string", "Private key type")
assert(type(pub_key) == "string", "Public key type")
local message = "Sign this message"
local signature = crypto.sign("rsa", priv_key, message, "sha256")
assert_equal(type(signature), "string", "RSA signing")
assert_equal(type(signature), "string", "Signature type")
local is_valid = crypto.verify("rsa", pub_key, message, signature, "sha256")
assert_equal(is_valid, true, "RSA signature verification")
assert_equal(is_valid, true, "Signature verification")
end
-- Test ECDSA signing and verification
local function test_ecdsa_signing_verification()
print('\n\27[1;7mTest ECDSA signing and verification \27[0m')
local priv_key, pub_key = crypto.generatekeypair("ecdsa", "secp256r1")
assert(type(priv_key) == "string", "Private key type")
assert(type(pub_key) == "string", "Public key type")
local message = "Sign this message with ECDSA"
local signature = crypto.sign("ecdsa", priv_key, message, "sha256")
assert_equal(type(signature), "string", "ECDSA signing")
assert_equal(type(signature), "string", "Signature type")
local is_valid = crypto.verify("ecdsa", pub_key, message, signature, "sha256")
assert_equal(is_valid, true, "ECDSA signature verification")
assert_equal(is_valid, true, "Signature verification")
end
-- Test AES key generation
local function test_aes_key_generation()
print('\n\27[1;7mTest AES key generation \27[0m')
local key = crypto.generatekeypair('aes', 256) -- 256-bit key
assert_equal(type(key), "string", "AES key generation")
assert_equal(#key, 32, "AES key length (256 bits)")
assert_equal(type(key), "string", "Key type")
assert_equal(#key, 32, "Key length (256 bits)")
end
-- Test AES encryption and decryption (CBC mode)
local function test_aes_encryption_decryption()
print('\n\27[1;7mTest AES encryption and decryption (CBC mode) \27[0m')
local key = crypto.generatekeypair('aes',256) -- 256-bit key
local key = crypto.generatekeypair('aes', 256) -- 256-bit key
local plaintext = "Hello, AES CBC!"
-- Encrypt without providing IV (should auto-generate IV)
print('\27[1mAES encryption (auto IV)\27[0m')
local encrypted, iv = crypto.encrypt("aes", key, plaintext, nil)
assert_equal(type(encrypted), "string", "AES encryption (CBC, auto IV)")
assert_equal(type(iv), "string", "AES IV (auto-generated)")
assert_equal(type(encrypted), "string", "Ciphertext type")
assert_equal(type(iv), "string", "IV type")
-- Decrypt
print('\n\27[1mAES decryption (auto IV)\27[0m')
local decrypted = crypto.decrypt("aes", key, encrypted, iv)
assert_equal(decrypted, plaintext, "AES decryption (CBC, auto IV)")
assert_equal(decrypted, plaintext, "Decrypted ciphertext matches plaintext")
-- Encrypt with explicit IV
print('\n\27[1mAES encryption (explicit IV)\27[0m')
local iv2 = GetRandomBytes(16)
local encrypted2, iv_used = crypto.encrypt("aes", key, plaintext, iv2)
assert_equal(type(encrypted2), "string", "AES encryption (CBC, explicit IV)")
assert_equal(iv_used, iv2, "AES IV (explicit)")
assert_equal(type(encrypted2), "string", "Ciphertext type")
assert_equal(iv_used, iv2, "IV match")
print('\n\27[1mAES decryption (explicit IV)\27[0m')
local decrypted2 = crypto.decrypt("aes", key, encrypted2, iv2)
assert_equal(decrypted2, plaintext, "AES decryption (CBC, explicit IV)")
assert_equal(decrypted2, plaintext, "Decrypted ciphertext matches plaintext")
end
-- Test AES encryption and decryption (CTR mode)
local function test_aes_encryption_decryption_ctr()
print('\n\27[1;7mTest AES encryption and decryption (CTR mode) \27[0m')
local key = crypto.generatekeypair('aes',256)
local key = crypto.generatekeypair('aes', 256)
local plaintext = "Hello, AES CTR!"
-- Encrypt without providing IV (should auto-generate IV)
print('\27[1mAES encryption (auto IV)\27[0m')
local encrypted, iv = crypto.encrypt("aes", key, plaintext, nil, "ctr")
assert_equal(type(encrypted), "string", "AES encryption (CTR, auto IV)")
assert_equal(type(iv), "string", "AES IV (auto-generated, CTR)")
assert_equal(type(encrypted), "string", "Ciphertext type")
assert_equal(type(iv), "string", "IV type")
-- Decrypt
print('\n\27[1mAES decryption (auto IV)\27[0m')
local decrypted = crypto.decrypt("aes", key, encrypted, iv, "ctr")
assert_equal(decrypted, plaintext, "AES decryption (CTR, auto IV)")
assert_equal(decrypted, plaintext, "Decrypted ciphertext matches plaintext")
-- Encrypt with explicit IV
print('\n\27[1mAES encryption (explicit IV)\27[0m')
local iv2 = GetRandomBytes(16)
local encrypted2, iv_used = crypto.encrypt("aes", key, plaintext, iv2, "ctr")
assert_equal(type(encrypted2), "string", "AES encryption (CTR, explicit IV)")
assert_equal(iv_used, iv2, "AES IV (explicit, CTR)")
assert_equal(type(encrypted2), "string", "Ciphertext type")
assert_equal(iv_used, iv2, "IV match")
print('\n\27[1mAES decryption (explicit IV)\27[0m')
local decrypted2 = crypto.decrypt("aes", key, encrypted2, iv2, "ctr")
assert_equal(decrypted2, plaintext, "AES decryption (CTR, explicit IV)")
assert_equal(decrypted2, plaintext, "Decrypted ciphertext matches plaintext")
end
-- Test AES encryption and decryption (GCM mode)
local function test_aes_encryption_decryption_gcm()
print('\n\27[1;7mTest AES encryption and decryption (GCM mode) \27[0m')
local key = crypto.generatekeypair('aes',256)
local key = crypto.generatekeypair('aes', 256)
local plaintext = "Hello, AES GCM!"
-- Encrypt without providing IV (should auto-generate IV)
print('\27[1mAES encryption (auto IV)\27[0m')
local encrypted, iv, tag = crypto.encrypt("aes", key, plaintext, nil, "gcm")
assert_equal(type(encrypted), "string", "AES encryption (GCM, auto IV)")
assert_equal(type(iv), "string", "AES IV (auto-generated, GCM)")
assert_equal(type(tag), "string", "AES GCM tag (auto IV)")
assert_equal(#plaintext, #encrypted, "Ciphertext length matches plaintext")
assert_equal(type(encrypted), "string", "Ciphertext type")
assert_equal(type(iv), "string", "IV type")
assert_equal(type(tag), "string", "Tag type")
-- Decrypt
print('\n\27[1mAES decryption (auto IV)\27[0m')
local decrypted = crypto.decrypt("aes", key, encrypted, iv, "gcm", nil, tag)
assert_equal(decrypted, plaintext, "AES decryption (GCM, auto IV)")
assert_equal(decrypted, plaintext, "Decrypted ciphertext matches plaintext")
-- Encrypt with explicit IV
print('\n\27[1mAES encryption (explicit IV)\27[0m')
local iv2 = GetRandomBytes(13) -- GCM IV/nonce can be 12-16 bytes, 12 is standard
local encrypted2, iv_used, tag2 = crypto.encrypt("aes", key, plaintext, iv2, "gcm")
assert_equal(type(encrypted2), "string", "AES encryption (GCM, explicit IV)")
assert_equal(iv_used, iv2, "AES IV (explicit, GCM)")
assert_equal(type(tag2), "string", "AES GCM tag (explicit IV)")
assert_equal(type(encrypted2), "string", "Ciphertext type")
assert_equal(iv_used, iv2, "IV match")
assert_equal(type(tag2), "string", "Tag type")
print('\n\27[1mAES decryption (explicit IV)\27[0m')
local decrypted2 = crypto.decrypt("aes", key, encrypted2, iv2, "gcm", nil, tag2)
assert_equal(decrypted2, plaintext, "AES decryption (GCM, explicit IV)")
assert_equal(decrypted2, plaintext, "Decrypted ciphertext matches plaintext")
end
-- Test PemToJwk conversion
@ -167,25 +174,25 @@ local function test_pem_to_jwk()
local priv_key, pub_key = crypto.generatekeypair()
print('\27[1mRSA Private key to JWK conversion\27[0m')
local priv_jwk = crypto.convertPemToJwk(priv_key)
assert_equal(type(priv_jwk), "table", "PEM to JWK conversion")
assert_equal(priv_jwk.kty, "RSA", "JWK key type")
assert_equal(type(priv_jwk), "table", "JWK type")
assert_equal(priv_jwk.kty, "RSA", "kty is correct")
print('\n\27[1mRSA Public key to JWK conversion\27[0m')
local pub_jwk = crypto.convertPemToJwk(pub_key)
assert_equal(type(pub_jwk), "table", "PEM to JWK conversion")
assert_equal(pub_jwk.kty, "RSA", "JWK key type")
assert_equal(type(pub_jwk), "table", "JWK type")
assert_equal(pub_jwk.kty, "RSA", "kty is correct")
-- Test ECDSA keys
local priv_key, pub_key = crypto.generatekeypair('ecdsa')
print('\n\27[1mECDSA Private key to JWK conversion\27[0m')
local priv_jwk = crypto.convertPemToJwk(priv_key)
assert_equal(type(priv_jwk), "table", "PEM to JWK conversion")
assert_equal(priv_jwk.kty, "EC", "JWK key type")
assert_equal(type(priv_jwk), "table", "JWK type")
assert_equal(priv_jwk.kty, "EC", "kty is correct")
print('\n\27[1mECDSA Public key to JWK conversion\27[0m')
local pub_jwk = crypto.convertPemToJwk(pub_key)
assert_equal(type(pub_jwk), "table", "PEM to JWK conversion")
assert_equal(pub_jwk.kty, "EC", "JWK key type")
assert_equal(type(pub_jwk), "table", "JWK type")
assert_equal(pub_jwk.kty, "EC", "kty is correct")
end
-- Test CSR generation
@ -194,24 +201,25 @@ local function test_csr_generation()
local priv_key, _ = crypto.generatekeypair()
local subject_name = "CN=example.com,O=Example Org,C=US"
local san = "DNS:example.com, DNS:www.example.com, IP:192.168.1.1"
assert(type(priv_key) == "string", "Private key type")
local csr = crypto.GenerateCsr(priv_key, subject_name)
local csr = crypto.generateCsr(priv_key, subject_name)
assert_equal(type(csr), "string", "CSR generation with subject name")
csr = crypto.GenerateCsr(priv_key, subject_name, san)
csr = crypto.generateCsr(priv_key, subject_name, san)
assert_equal(type(csr), "string", "CSR generation with subject name and san")
csr = crypto.GenerateCsr(priv_key, nil, san)
csr = crypto.generateCsr(priv_key, nil, san)
assert_equal(type(csr), "string", "CSR generation with nil subject name and san")
csr = crypto.GenerateCsr(priv_key, '', san)
csr = crypto.generateCsr(priv_key, '', san)
assert_equal(type(csr), "string", "CSR generation with empty subject name and san")
-- These should fail
csr = crypto.GenerateCsr(priv_key, '')
csr = crypto.generateCsr(priv_key, '')
assert_not_equal(type(csr), "string", "CSR generation with empty subject name and no san is rejected")
csr = crypto.GenerateCsr(priv_key)
csr = crypto.generateCsr(priv_key)
assert_not_equal(type(csr), "string", "CSR generation with nil subject name and no san is rejected")
end
@ -231,9 +239,9 @@ local function run_tests()
test_csr_generation()
print('')
print("All tests passed!")
EXIT=0
EXIT = 0
return EXIT
end
EXIT=70
EXIT = 70
os.exit(run_tests())

View file

@ -8048,6 +8048,73 @@ kUrlPlus = nil
---@type integer to transcode ISO-8859-1 input into UTF-8. See `ParseUrl`.
kUrlLatin1 = nil
--- This module provides cryptographic operations.
--- The crypto module for cryptographic operations
crypto = {}
--- Converts a PEM-encoded key to JWK format
---@param pem string PEM-encoded key
---@return table?, string? JWK table or nil on error
---@return string? error message
function crypto.convertPemToJwk(pem) end
--- Generates a Certificate Signing Request (CSR)
---@param key_pem string PEM-encoded private key
---@param subject_name string? X.509 subject name
---@param san_list string? Subject Alternative Names
---@return string?, string? CSR in PEM format or nil on error and error message
function crypto.generateCsr(key_pem, subject_name, san_list) end
--- Signs data using a private key
---@param key_type string "rsa" or "ecdsa"
---@param private_key string PEM-encoded private key
---@param message string Data to sign
---@param hash_algo string? Hash algorithm (default: SHA-256)
---@return string?, string? Signature or nil on error and error message
function crypto.sign(key_type, private_key, message, hash_algo) end
--- Verifies a signature
---@param key_type string "rsa" or "ecdsa"
---@param public_key string PEM-encoded public key
---@param message string Original message
---@param signature string Signature to verify
---@param hash_algo string? Hash algorithm (default: SHA-256)
---@return boolean?, string? True if valid or nil on error and error message
function crypto.verify(key_type, public_key, message, signature, hash_algo) end
--- Encrypts data
---@param cipher_type string "rsa" or "aes"
---@param key string Public key or symmetric key
---@param plaintext string Data to encrypt
---@param mode string? AES mode: "cbc", "gcm", "ctr" (default: "cbc")
---@param iv string? Initialization Vector for AES
---@param aad string? Additional data for AES-GCM
---@return string? Encrypted data or nil on error
---@return string? IV or error message
---@return string? Authentication tag for GCM mode
function crypto.encrypt(cipher_type, key, plaintext, mode, iv, aad) end
--- Decrypts data
---@param cipher_type string "rsa" or "aes"
---@param key string Private key or symmetric key
---@param ciphertext string Data to decrypt
---@param iv string? Initialization Vector for AES
---@param mode string? AES mode: "cbc", "gcm", "ctr" (default: "cbc")
---@param tag string? Authentication tag for AES-GCM
---@param aad string? Additional data for AES-GCM
---@return string?, string? Decrypted data or nil on error and error message
function crypto.decrypt(cipher_type, key, ciphertext, iv, mode, tag, aad) end
--- Generates cryptographic keys
---@param key_type string? "rsa", "ecdsa", or "aes"
---@param key_size_or_curve number|string? Key size or curve name
---@return string? Private key or nil on error
---@return string? Public key (nil for AES) or error message
function crypto.generatekeypair(key_type, key_size_or_curve) end
--[[
LEGAL

View file

@ -1595,7 +1595,7 @@ static const luaL_Reg kLuaCrypto[] = {
{"decrypt", LuaCryptoDecrypt}, //
{"generatekeypair", LuaCryptoGenerateKeyPair}, //
{"convertPemToJwk", LuaConvertPemToJwk}, //
{"GenerateCsr", LuaGenerateCSR}, //
{"generateCsr", LuaGenerateCSR}, //
{0}, //
};