From b357cf1be1572ae4298f5ef3b43134dd00bc5895 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 Jun 2022 16:56:16 +0100 Subject: util.crypto: New wrapper for some operations in OpenSSL's libcrypto Specifically, ED25519 key generation/import/export, sign/verify operations, and AES encrypt/decrypt. --- spec/util_crypto_spec.lua | 196 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 spec/util_crypto_spec.lua (limited to 'spec/util_crypto_spec.lua') diff --git a/spec/util_crypto_spec.lua b/spec/util_crypto_spec.lua new file mode 100644 index 00000000..19af1395 --- /dev/null +++ b/spec/util_crypto_spec.lua @@ -0,0 +1,196 @@ +local test_keys = { + ecdsa_private_pem = [[ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7taVK6bPtPz4ah32 +aD9CfvOah5omBxRVtzypwQXvZeahRANCAAQpKFeNIy27+lVo6bJslO6r2ty5rlb5 +xEiCx8GrrbJ8S7b5IPZCS7OrBaO2iqgOf7NMsgO12eLCfMZRnA+gCC34 +-----END PRIVATE KEY----- +]]; + + ecdsa_public_pem = [[ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKShXjSMtu/pVaOmybJTuq9rcua5W ++cRIgsfBq62yfEu2+SD2QkuzqwWjtoqoDn+zTLIDtdniwnzGUZwPoAgt+A== +-----END PUBLIC KEY----- +]]; + + eddsa_private_pem = [[ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIOmrajEfnqdzdJzkJ4irQMCGbYRqrl0RlwPHIw+a5b7M +-----END PRIVATE KEY----- +]]; + + eddsa_public_pem = [[ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAFipbSXeGvPVK7eA4+hIOdutZTUUyXswVSbMGi0j1QKE= +-----END PUBLIC KEY----- +]]; + +}; + +describe("util.crypto", function () + local crypto = require "util.crypto"; + local random = require "util.random"; + + describe("generate_ed25519_keypair", function () + local keypair = crypto.generate_ed25519_keypair(); + assert.is_not_nil(keypair); + assert.equal("ED25519", keypair:get_type()); + end) + + describe("import_private_pem", function () + it("can import ECDSA keys", function () + local ecdsa_key = crypto.import_private_pem(test_keys.ecdsa_private_pem); + assert.equal("id-ecPublicKey", ecdsa_key:get_type()); + end); + + it("can import EdDSA (Ed25519) keys", function () + local ed25519_key = crypto.import_private_pem(crypto.generate_ed25519_keypair():private_pem()); + assert.equal("ED25519", ed25519_key:get_type()); + end); + + it("can import RSA keys", function () + -- TODO + end); + + it("rejects invalid keys", function () + assert.is_nil(crypto.import_private_pem(test_keys.eddsa_public_pem)); + assert.is_nil(crypto.import_private_pem(test_keys.ecdsa_public_pem)); + assert.is_nil(crypto.import_private_pem("foo")); + assert.is_nil(crypto.import_private_pem("")); + end); + end); + + describe("import_public_pem", function () + it("can import ECDSA public keys", function () + local ecdsa_key = crypto.import_public_pem(test_keys.ecdsa_public_pem); + assert.equal("id-ecPublicKey", ecdsa_key:get_type()); + end); + + it("can import EdDSA (Ed25519) public keys", function () + local ed25519_key = crypto.import_public_pem(test_keys.eddsa_public_pem); + assert.equal("ED25519", ed25519_key:get_type()); + end); + + it("can import RSA public keys", function () + -- TODO + end); + end); + + describe("PEM export", function () + it("works", function () + local ecdsa_key = crypto.import_public_pem(test_keys.ecdsa_public_pem); + assert.equal("id-ecPublicKey", ecdsa_key:get_type()); + assert.equal(test_keys.ecdsa_public_pem, ecdsa_key:public_pem()); + + assert.has_error(function () + -- Fails because private key is not available + ecdsa_key:private_pem(); + end); + + local ecdsa_private_key = crypto.import_private_pem(test_keys.ecdsa_private_pem); + assert.equal(test_keys.ecdsa_private_pem, ecdsa_private_key:private_pem()); + end); + end); + + describe("sign/verify with", function () + local test_cases = { + ed25519 = { + crypto.ed25519_sign, crypto.ed25519_verify; + key = crypto.import_private_pem(test_keys.eddsa_private_pem); + sig_length = 64; + }; + ecdsa = { + crypto.ecdsa_sha256_sign, crypto.ecdsa_sha256_verify; + key = crypto.import_private_pem(test_keys.ecdsa_private_pem); + }; + }; + for test_name, test in pairs(test_cases) do + local key = test.key; + describe(test_name, function () + it("works", function () + local sign, verify = test[1], test[2]; + local sig = assert(sign(key, "Hello world")); + assert.is_string(sig); + if test.sig_length then + assert.equal(test.sig_length, #sig); + end + + do + local ok = verify(key, "Hello world", sig); + assert.is_truthy(ok); + end + do -- Incorrect signature + local ok = verify(key, "Hello world", sig:sub(1, -2)..string.char((sig:byte(-1)+1)%255)); + assert.is_falsy(ok); + end + do -- Incorrect message + local ok = verify(key, "Hello earth", sig); + assert.is_falsy(ok); + end + do -- Incorrect message (embedded NUL) + local ok = verify(key, "Hello world\0foo", sig); + assert.is_falsy(ok); + end + end); + end); + end + end); + + describe("ECDSA signatures", function () + local hex = require "util.hex"; + local sig = hex.decode((([[ + 304402203e936e7b0bc62887e0e9d675afd08531a930384cfcf301 + f25d13053a2ebf141d02205a5a7c7b7ac5878d004cb79b17b39346 + 6b0cd1043718ffc31c153b971d213a8e + ]]):gsub("%s+", ""))); + it("can be parsed", function () + local r, s = crypto.parse_ecdsa_signature(sig); + assert.is_string(r); + assert.is_string(s); + assert.equal(32, #r); + assert.equal(32, #s); + end); + it("fails to parse invalid signatures", function () + local invalid_sigs = { + ""; + "\000"; + string.rep("\000", 64); + string.rep("\000", 72); + string.rep("\000", 256); + string.rep("\255", 72); + string.rep("\255", 3); + }; + for _, sig in ipairs(invalid_sigs) do + local r, s = crypto.parse_ecdsa_signature(""); + assert.is_nil(r); + assert.is_nil(s); + end + + end); + it("can be built", function () + local r, s = crypto.parse_ecdsa_signature(sig); + local rebuilt_sig = crypto.build_ecdsa_signature(r, s); + assert.equal(sig, rebuilt_sig); + end); + end); + + describe("AES-GCM encryption", function () + it("works", function () + local message = "foo\0bar"; + local key_128_bit = random.bytes(16); + local key_256_bit = random.bytes(32); + local test_cases = { + { crypto.aes_128_gcm_encrypt, crypto.aes_128_gcm_decrypt, key = key_128_bit }; + { crypto.aes_256_gcm_encrypt, crypto.aes_256_gcm_decrypt, key = key_256_bit }; + }; + for _, params in pairs(test_cases) do + local iv = params.iv or random.bytes(12); + local encrypted = params[1](params.key, iv, message); + assert.not_equal(message, encrypted); + local decrypted = params[2](params.key, iv, encrypted); + assert.equal(message, decrypted); + end + end); + end); +end); -- cgit v1.2.3 From 4d94a62f9b6f1a5e7f89a2204ffb7697d9018a9f Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 2 Jul 2022 12:36:52 +0100 Subject: spec: Move test crypto keys to a shared file for clarity and easy maintenance --- spec/util_crypto_spec.lua | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) (limited to 'spec/util_crypto_spec.lua') diff --git a/spec/util_crypto_spec.lua b/spec/util_crypto_spec.lua index 19af1395..14c35188 100644 --- a/spec/util_crypto_spec.lua +++ b/spec/util_crypto_spec.lua @@ -1,32 +1,4 @@ -local test_keys = { - ecdsa_private_pem = [[ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7taVK6bPtPz4ah32 -aD9CfvOah5omBxRVtzypwQXvZeahRANCAAQpKFeNIy27+lVo6bJslO6r2ty5rlb5 -xEiCx8GrrbJ8S7b5IPZCS7OrBaO2iqgOf7NMsgO12eLCfMZRnA+gCC34 ------END PRIVATE KEY----- -]]; - - ecdsa_public_pem = [[ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKShXjSMtu/pVaOmybJTuq9rcua5W -+cRIgsfBq62yfEu2+SD2QkuzqwWjtoqoDn+zTLIDtdniwnzGUZwPoAgt+A== ------END PUBLIC KEY----- -]]; - - eddsa_private_pem = [[ ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIOmrajEfnqdzdJzkJ4irQMCGbYRqrl0RlwPHIw+a5b7M ------END PRIVATE KEY----- -]]; - - eddsa_public_pem = [[ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEAFipbSXeGvPVK7eA4+hIOdutZTUUyXswVSbMGi0j1QKE= ------END PUBLIC KEY----- -]]; - -}; +local test_keys = require "spec.inputs.test_keys"; describe("util.crypto", function () local crypto = require "util.crypto"; -- cgit v1.2.3 From 12a9ab92de04f89aa7847eeb235180dbaa59cf02 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 2 Jul 2022 15:27:44 +0100 Subject: util.crypto: tests: fix some tests that didn't do much (thanks luacheck!) --- spec/util_crypto_spec.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'spec/util_crypto_spec.lua') diff --git a/spec/util_crypto_spec.lua b/spec/util_crypto_spec.lua index 14c35188..0d7a7ffb 100644 --- a/spec/util_crypto_spec.lua +++ b/spec/util_crypto_spec.lua @@ -133,12 +133,11 @@ describe("util.crypto", function () string.rep("\255", 72); string.rep("\255", 3); }; - for _, sig in ipairs(invalid_sigs) do - local r, s = crypto.parse_ecdsa_signature(""); + for _, invalid_sig in ipairs(invalid_sigs) do + local r, s = crypto.parse_ecdsa_signature(invalid_sig); assert.is_nil(r); assert.is_nil(s); end - end); it("can be built", function () local r, s = crypto.parse_ecdsa_signature(sig); -- cgit v1.2.3 From 70e54affa0d780922bd68bc12d411d59c4dbcf81 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 30 Sep 2022 00:27:10 +0200 Subject: util.crypto: Fix tests Found this number in a hat. Sleepy time. Good night. --- spec/util_crypto_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec/util_crypto_spec.lua') diff --git a/spec/util_crypto_spec.lua b/spec/util_crypto_spec.lua index 0d7a7ffb..152efed5 100644 --- a/spec/util_crypto_spec.lua +++ b/spec/util_crypto_spec.lua @@ -117,7 +117,7 @@ describe("util.crypto", function () 6b0cd1043718ffc31c153b971d213a8e ]]):gsub("%s+", ""))); it("can be parsed", function () - local r, s = crypto.parse_ecdsa_signature(sig); + local r, s = crypto.parse_ecdsa_signature(sig, 32); assert.is_string(r); assert.is_string(s); assert.equal(32, #r); @@ -134,13 +134,13 @@ describe("util.crypto", function () string.rep("\255", 3); }; for _, invalid_sig in ipairs(invalid_sigs) do - local r, s = crypto.parse_ecdsa_signature(invalid_sig); + local r, s = crypto.parse_ecdsa_signature(invalid_sig, 32); assert.is_nil(r); assert.is_nil(s); end end); it("can be built", function () - local r, s = crypto.parse_ecdsa_signature(sig); + local r, s = crypto.parse_ecdsa_signature(sig, 32); local rebuilt_sig = crypto.build_ecdsa_signature(r, s); assert.equal(sig, rebuilt_sig); end); -- cgit v1.2.3