require("tests") local crypto = require("crypto") -- Test data local test_data = "Hello, World!" local test_key = "secret-key-123" -- ====================================================================== -- ENCODING/DECODING TESTS -- ====================================================================== test("Base64 Encoding/Decoding", function() local encoded = crypto.base64_encode(test_data) assert_equal(type(encoded), "string") assert(#encoded > 0, "encoded string should not be empty") local decoded = crypto.base64_decode(encoded) assert_equal(decoded, test_data) end) test("Base64 URL Encoding/Decoding", function() local encoded = crypto.base64_url_encode(test_data) assert_equal(type(encoded), "string") local decoded = crypto.base64_url_decode(encoded) assert_equal(decoded, test_data) end) test("Hex Encoding/Decoding", function() local encoded = crypto.hex_encode(test_data) assert_equal(type(encoded), "string") assert(encoded:match("^[0-9a-f]+$"), "hex should only contain hex characters") local decoded = crypto.hex_decode(encoded) assert_equal(decoded, test_data) end) test("Encoding Chain", function() local chain_encoded = crypto.encode_chain(test_data, {"hex", "base64"}) local chain_decoded = crypto.decode_chain(chain_encoded, {"hex", "base64"}) assert_equal(chain_decoded, test_data) end) -- ====================================================================== -- HASHING TESTS -- ====================================================================== test("MD5 Hash", function() local hash = crypto.md5(test_data) assert_equal(type(hash), "string") assert_equal(#hash, 32) -- MD5 is 32 hex characters assert(hash:match("^[0-9a-f]+$"), "hash should be hex") -- Same input should produce same hash assert_equal(crypto.md5(test_data), hash) end) test("SHA1 Hash", function() local hash = crypto.sha1(test_data) assert_equal(type(hash), "string") assert_equal(#hash, 40) -- SHA1 is 40 hex characters assert(hash:match("^[0-9a-f]+$"), "hash should be hex") end) test("SHA256 Hash", function() local hash = crypto.sha256(test_data) assert_equal(type(hash), "string") assert_equal(#hash, 64) -- SHA256 is 64 hex characters assert(hash:match("^[0-9a-f]+$"), "hash should be hex") end) test("SHA512 Hash", function() local hash = crypto.sha512(test_data) assert_equal(type(hash), "string") assert_equal(#hash, 128) -- SHA512 is 128 hex characters assert(hash:match("^[0-9a-f]+$"), "hash should be hex") end) test("Hash Multiple Inputs", function() local hash1 = crypto.hash_multiple({"hello", "world"}) local hash2 = crypto.hash_multiple({"hello", "world"}) local hash3 = crypto.hash_multiple({"world", "hello"}) assert_equal(hash1, hash2) assert(hash1 ~= hash3, "different order should produce different hash") end) -- ====================================================================== -- HMAC TESTS -- ====================================================================== test("HMAC SHA1", function() local hmac = crypto.hmac_sha1(test_data, test_key) assert_equal(type(hmac), "string") assert_equal(#hmac, 40) -- SHA1 HMAC is 40 hex characters assert(hmac:match("^[0-9a-f]+$"), "hmac should be hex") end) test("HMAC SHA256", function() local hmac = crypto.hmac_sha256(test_data, test_key) assert_equal(type(hmac), "string") assert_equal(#hmac, 64) -- SHA256 HMAC is 64 hex characters assert(hmac:match("^[0-9a-f]+$"), "hmac should be hex") end) test("MAC Functions", function() local mac = crypto.mac(test_data, test_key) assert_equal(type(mac), "string") assert(#mac > 0, "mac should not be empty") local valid = crypto.verify_mac(test_data, test_key, mac) assert_equal(valid, true) local invalid = crypto.verify_mac("different data", test_key, mac) assert_equal(invalid, false) end) -- ====================================================================== -- UUID TESTS -- ====================================================================== test("UUID Generation", function() local uuid1 = crypto.uuid() local uuid2 = crypto.uuid_v4() assert_equal(type(uuid1), "string") assert_equal(type(uuid2), "string") assert_equal(#uuid1, 36) -- Standard UUID length assert_equal(#uuid2, 36) assert(uuid1 ~= uuid2, "UUIDs should be unique") assert_equal(crypto.is_uuid(uuid1), true) assert_equal(crypto.is_uuid(uuid2), true) assert_equal(crypto.is_uuid("not-a-uuid"), false) end) -- ====================================================================== -- RANDOM GENERATION TESTS -- ====================================================================== test("Random Bytes", function() local bytes1 = crypto.random_bytes(16) local bytes2 = crypto.random_bytes(16) assert_equal(type(bytes1), "string") assert_equal(#bytes1, 16) assert(bytes1 ~= bytes2, "random bytes should be different") end) test("Random Hex", function() local hex1 = crypto.random_hex(8) local hex2 = crypto.random_hex(8) assert_equal(type(hex1), "string") assert_equal(#hex1, 16) -- 8 bytes = 16 hex characters assert(hex1:match("^[0-9a-f]+$"), "should be hex") assert(hex1 ~= hex2, "random hex should be different") end) test("Random String", function() local str1 = crypto.random_string(10) local str2 = crypto.random_string(10) assert_equal(type(str1), "string") assert_equal(#str1, 10) assert(str1 ~= str2, "random strings should be different") local custom = crypto.random_string(5, "abc") assert_equal(#custom, 5) assert(custom:match("^[abc]+$"), "should only contain specified characters") end) test("Random Alphanumeric", function() local str = crypto.random_alphanumeric(20) assert_equal(#str, 20) assert(str:match("^[a-zA-Z0-9]+$"), "should be alphanumeric") end) test("Random Password", function() local pass1 = crypto.random_password(12) local pass2 = crypto.random_password(12, true) -- with symbols assert_equal(#pass1, 12) assert_equal(#pass2, 12) assert(pass1 ~= pass2, "passwords should be different") end) test("Token Generation", function() local token1 = crypto.token(32) local token2 = crypto.token(32) assert_equal(#token1, 64) -- 32 bytes = 64 hex characters assert(token1:match("^[0-9a-f]+$"), "token should be hex") assert(token1 ~= token2, "tokens should be unique") end) test("Nonce Generation", function() local nonce1 = crypto.nonce() local nonce2 = crypto.nonce(32) assert_equal(#nonce1, 32) -- default 16 bytes = 32 hex assert_equal(#nonce2, 64) -- 32 bytes = 64 hex assert(nonce1 ~= nonce2, "nonces should be unique") end) -- ====================================================================== -- UTILITY TESTS -- ====================================================================== test("Secure Compare", function() local str1 = "hello" local str2 = "hello" local str3 = "world" assert_equal(crypto.secure_compare(str1, str2), true) assert_equal(crypto.secure_compare(str1, str3), false) end) test("Checksum Functions", function() local checksum = crypto.checksum(test_data) assert_equal(type(checksum), "string") local valid = crypto.verify_checksum(test_data, checksum) assert_equal(valid, true) local invalid = crypto.verify_checksum("different", checksum) assert_equal(invalid, false) end) test("XOR Encryption", function() local key = "mykey" local encrypted = crypto.xor_encrypt(test_data, key) local decrypted = crypto.xor_decrypt(encrypted, key) assert_equal(decrypted, test_data) assert(encrypted ~= test_data, "encrypted should be different") end) test("Hash Chain", function() local chain1 = crypto.hash_chain(test_data, 100) local chain2 = crypto.hash_chain(test_data, 100) local chain3 = crypto.hash_chain(test_data, 101) assert_equal(chain1, chain2) assert(chain1 ~= chain3, "different iterations should produce different results") end) test("Key Derivation", function() local derived1, salt1 = crypto.derive_key("password", "salt", 1000) local derived2, salt2 = crypto.derive_key("password", salt1, 1000) assert_equal(derived1, derived2) assert_equal(salt1, salt2) assert_equal(type(derived1), "string") assert(#derived1 > 0, "derived key should not be empty") end) test("Fingerprint", function() local data = {name = "test", value = 42} local fp1 = crypto.fingerprint(data) local fp2 = crypto.fingerprint(data) assert_equal(fp1, fp2) assert_equal(type(fp1), "string") assert(#fp1 > 0, "fingerprint should not be empty") end) test("Integrity Check", function() local check = crypto.integrity_check(test_data) assert_equal(check.data, test_data) assert_equal(type(check.hash), "string") assert_equal(type(check.timestamp), "number") assert_equal(type(check.uuid), "string") local valid = crypto.verify_integrity(check) assert_equal(valid, true) -- Tamper with data check.data = "tampered" local invalid = crypto.verify_integrity(check) assert_equal(invalid, false) end) -- ====================================================================== -- ERROR HANDLING TESTS -- ====================================================================== test("Error Handling", function() -- Invalid base64 local success, err = pcall(crypto.base64_decode, "invalid===base64") assert_equal(success, false) -- Invalid hex local success2, err2 = pcall(crypto.hex_decode, "invalid_hex") assert_equal(success2, false) -- Invalid UUID validation (returns boolean, doesn't throw) assert_equal(crypto.is_uuid("not-a-uuid"), false) assert_equal(crypto.is_uuid(""), false) assert_equal(crypto.is_uuid("12345"), false) end) -- ====================================================================== -- PERFORMANCE TESTS -- ====================================================================== test("Performance Test", function() local large_data = string.rep("test data for performance ", 1000) local start = os.clock() local hash = crypto.sha256(large_data) local hash_time = os.clock() - start start = os.clock() local encoded = crypto.base64_encode(large_data) local encode_time = os.clock() - start start = os.clock() local decoded = crypto.base64_decode(encoded) local decode_time = os.clock() - start print(string.format(" SHA256 of %d bytes: %.3fs", #large_data, hash_time)) print(string.format(" Base64 encode: %.3fs", encode_time)) print(string.format(" Base64 decode: %.3fs", decode_time)) assert_equal(decoded, large_data) assert_equal(type(hash), "string") end) summary() test_exit()