mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-12 14:09:12 +00:00
Add LuaCrypto compatible functions (plus some auxiliary functions) as per #1136
This commit is contained in:
parent
55dcce4f7d
commit
47c01b548a
2 changed files with 142 additions and 67 deletions
83
test/tool/net/lcrypto_test.lua
Normal file
83
test/tool/net/lcrypto_test.lua
Normal 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()
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue