Move directory and add unit tests

This commit is contained in:
Miguel Oliveira 2022-12-14 00:00:27 -03:00
parent 5438c20bc9
commit 9d060fa581
25 changed files with 1156 additions and 35 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
out/
doc/ doc/
spec/bigvec/

View file

@ -25,13 +25,15 @@ local bor = bit32.bor
-- --
local function encrypt(key, nonce, message, aad, rounds) local function encrypt(key, nonce, message, aad, rounds)
expect(1, key, "string") expect(1, key, "string")
assert(#key == 32, "key length must be 32") if #key ~= 32 then error("key length must be 32", 2) end
expect(2, nonce, "string") expect(2, nonce, "string")
assert(#nonce == 12, "nonce length must be 12") if #nonce ~= 12 then error("nonce length must be 12", 2) end
expect(3, message, "string") expect(3, message, "string")
expect(4, aad, "string") expect(4, aad, "string")
expect(5, rounds, "number", "nil") rounds = expect(5, rounds, "number", "nil") or 20
rounds = rounds or 20 if rounds % 2 ~= 0 then error("round number must be even", 2) end
if rounds < 8 then error("round number must be no smaller than 8", 2) end
if rounds > 20 then error("round number must be no larger than 20", 2) end
-- Generate auth key and encrypt. -- Generate auth key and encrypt.
local msgLong = ("\0"):rep(64) .. message local msgLong = ("\0"):rep(64) .. message
@ -63,13 +65,17 @@ end
-- --
local function decrypt(key, nonce, tag, ciphertext, aad, rounds) local function decrypt(key, nonce, tag, ciphertext, aad, rounds)
expect(1, key, "string") expect(1, key, "string")
assert(#key == 32, "key length must be 32") if #key ~= 32 then error("key length must be 32", 2) end
expect(2, nonce, "string") expect(2, nonce, "string")
assert(#nonce == 12, "nonce length must be 12") if #nonce ~= 12 then error("nonce length must be 12", 2) end
expect(3, ciphertext, "string") expect(3, tag, "string")
expect(4, aad, "string") if #tag ~= 16 then error("tag length must be 16", 2) end
expect(5, rounds, "number", "nil") expect(4, ciphertext, "string")
rounds = rounds or 20 expect(5, aad, "string")
rounds = expect(6, rounds, "number", "nil") or 20
if rounds % 2 ~= 0 then error("round number must be even", 2) end
if rounds < 8 then error("round number must be no smaller than 8", 2) end
if rounds > 20 then error("round number must be no larger than 20", 2) end
-- Generate auth key and decrypt. -- Generate auth key and decrypt.
local ctxLong = ("\0"):rep(64) .. ciphertext local ctxLong = ("\0"):rep(64) .. ciphertext

View file

@ -125,8 +125,12 @@ end
local function expand(state, len, offset) local function expand(state, len, offset)
expect(1, state, "table") expect(1, state, "table")
expect(1, len, "number") expect(1, len, "number")
expect(2, offset, "nil", "number") if len % 1 ~= 0 then error("length must be an integer", 2) end
offset = offset or 0 if len < 1 then error("length must be positive", 2) end
offset = expect(2, offset, "nil", "number") or 0
if offset % 1 ~= 0 then error("offset must be an integer", 2) end
if offset < 0 then error("offset must be nonnegative", 2) end
if offset + len > 2 ^ 32 then error("offset is too large", 2) end
-- Expand output. -- Expand output.
local out = {} local out = {}
@ -189,6 +193,8 @@ local function update(state, message)
end end
local function finalize(state) local function finalize(state)
expect(1, state, "table")
-- Pad the last message block. -- Pad the last message block.
local lastLen = #state.m local lastLen = #state.m
local padded = state.m .. ("\0"):rep(64) local padded = state.m .. ("\0"):rep(64)
@ -270,7 +276,7 @@ end
function mod.newKeyed(key) function mod.newKeyed(key)
expect(1, key, "string") expect(1, key, "string")
assert(#key == 32, "key length must be 32") if #key ~= 32 then error("key length must be 32", 2) end
return new({u8x4(fmt8x4, key, 1)}, KEYED_HASH) return new({u8x4(fmt8x4, key, 1)}, KEYED_HASH)
end end
@ -288,9 +294,9 @@ end
-- --
function mod.digest(message, len) function mod.digest(message, len)
expect(1, message, "string") expect(1, message, "string")
expect(2, len, "number", "nil") len = expect(2, len, "number", "nil") or 32
len = len or 32 if len % 1 ~= 0 then error("length must be an integer", 2) end
assert(len % 1 == 0 and len >= 1, "length must be a positive integer") if len < 1 then error("length must be positive", 2) end
return new(IV, 0):update(message):finalize():expand(len) return new(IV, 0):update(message):finalize():expand(len)
end end
@ -303,11 +309,11 @@ end
-- --
function mod.digestKeyed(key, message, len) function mod.digestKeyed(key, message, len)
expect(1, key, "string") expect(1, key, "string")
assert(#key == 32, "key length must be 32") if #key ~= 32 then error("key length must be 32", 2) end
expect(2, message, "string") expect(2, message, "string")
expect(3, len, "number", "nil") len = expect(3, len, "number", "nil") or 32
len = len or 32 if len % 1 ~= 0 then error("length must be an integer", 2) end
assert(len % 1 == 0 and len >= 1, "length must be a positive integer") if len < 1 then error("length must be positive", 2) end
local h = new({u8x4(fmt8x4, key, 1)}, KEYED_HASH) local h = new({u8x4(fmt8x4, key, 1)}, KEYED_HASH)
return h:update(message):finalize():expand(len) return h:update(message):finalize():expand(len)
end end
@ -323,9 +329,9 @@ function mod.deriveKey(context)
return function(material, len) return function(material, len)
expect(1, material, "string") expect(1, material, "string")
expect(2, len, "number", "nil") len = expect(2, len, "number", "nil") or 32
len = len or 32 if len % 1 ~= 0 then error("length must be an integer", 2) end
assert(len % 1 == 0 and len >= 1, "length must be a positive integer") if len < 1 then error("length must be positive", 2) end
local h = new({u8x4(fmt8x4, iv, 1)}, DERIVE_KEY_MATERIAL) local h = new({u8x4(fmt8x4, iv, 1)}, DERIVE_KEY_MATERIAL)
return h:update(material):finalize():expand(len) return h:update(material):finalize():expand(len)
end end

View file

@ -26,18 +26,18 @@ local mod = {}
-- --
function mod.crypt(key, nonce, message, rounds, offset) function mod.crypt(key, nonce, message, rounds, offset)
expect(1, key, "string") expect(1, key, "string")
assert(#key == 32, "key length must be 32") if #key ~= 32 then error("key length must be 32", 2) end
expect(2, nonce, "string") expect(2, nonce, "string")
assert(#nonce == 12, "nonce length must be 12") if #nonce ~= 12 then error("nonce length must be 12", 2) end
expect(3, message, "string") expect(3, message, "string")
expect(4, rounds, "number", "nil") rounds = expect(4, rounds, "number", "nil") or 20
rounds = rounds or 20 if rounds % 2 ~= 0 then error("round number must be even", 2) end
assert(rounds % 2 == 0, "round number must be even") if rounds < 8 then error("round number must be no smaller than 8", 2) end
assert(rounds >= 8 and rounds <= 20, "round number must be in 8..20") if rounds > 20 then error("round number must be no larger than 20", 2) end
expect(5, offset, "number", "nil") offset = expect(5, offset, "number", "nil") or 1
offset = offset or 1 if offset % 1 ~= 0 then error("offset must be an integer", 2) end
assert(offset % 1 == 0 and offset >= 0, "offset must be an integer >= 0") if offset < 0 then error("offset must be nonnegative", 2) end
assert(#message + 64 * offset < 2 ^ 37, "offset too large") if #message + 64 * offset >= 2 ^ 37 then error("offset too large", 2) end
-- Build the state block. -- Build the state block.
local i0, i1, i2, i3 = 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 local i0, i1, i2, i3 = 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574

View file

@ -20,7 +20,7 @@ local mod = {}
-- --
function mod.mac(key, message) function mod.mac(key, message)
expect(1, key, "string") expect(1, key, "string")
assert(#key == 32, "key length must be 32") if #key ~= 32 then error("key length must be 32", 2) end
expect(2, message, "string") expect(2, message, "string")
-- Pad message. -- Pad message.

View file

@ -103,7 +103,7 @@ function mod.save()
end end
-- Add extra entropy. -- Add extra entropy.
mod.stir(error("TODO")) -- TODO -- mod.stir(error("TODO")) -- TODO
-- Save. -- Save.
mod.save() mod.save()

381
spec/aead_spec.lua Normal file
View file

@ -0,0 +1,381 @@
--- Test vector specification for ChaCha20Poly1305AEAD.
--
-- Derived from RFC 7539.
--
local util = require "spec.util"
local aead = require "ccryptolib.aead"
describe("aead.encrypt", function()
it("validates arguments", function()
local key = ("a"):rep(32)
local nonce = ("a"):rep(12)
local msg = ("a"):rep(179)
local aad = ("a"):rep(79)
local rounds = 20
-- Types
expect.error(aead.encrypt, nil, nonce, msg, aad, rounds)
:eq("bad argument #1 (expected string, got nil)")
expect.error(aead.encrypt, key, nil, msg, aad, rounds)
:eq("bad argument #2 (expected string, got nil)")
expect.error(aead.encrypt, key, nonce, nil, aad, rounds)
:eq("bad argument #3 (expected string, got nil)")
expect.error(aead.encrypt, key, nonce, msg, nil, rounds)
:eq("bad argument #4 (expected string, got nil)")
expect.error(aead.encrypt, key, nonce, msg, aad, {})
:eq("bad argument #5 (expected number, got table)")
-- String lengths
expect.error(aead.encrypt, key .. "a", nonce, msg, aad, rounds)
:eq("key length must be 32")
expect.error(aead.encrypt, key, nonce .. "a", msg, aad, rounds)
:eq("nonce length must be 12")
-- Rounds
expect.error(aead.encrypt, key, nonce, msg, aad, 19.5)
:eq("round number must be even")
expect.error(aead.encrypt, key, nonce, msg, aad, 19)
:eq("round number must be even")
expect.error(aead.encrypt, key, nonce, msg, aad, 6)
:eq("round number must be no smaller than 8")
expect.error(aead.encrypt, key, nonce, msg, aad, 22)
:eq("round number must be no larger than 20")
expect.error(aead.encrypt, key, nonce, msg, aad, 1 / 0)
:eq("round number must be even")
expect.error(aead.encrypt, key, nonce, msg, aad, -1 / 0)
:eq("round number must be even")
expect.error(aead.encrypt, key, nonce, msg, aad, 0 / 0)
:eq("round number must be even")
end)
it("encrypts the section 2.8.2 test vector", function()
local plaintext = table.concat {
"Ladies and Gentlemen of the class of '99: If I could offer you o",
"nly one tip for the future, sunscreen would be it.",
}
local aad = util.hexcat {
"50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7",
}
local key = util.hexcat {
"80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f",
"90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f",
}
local nonce = util.hexcat {
"07 00 00 00 40 41 42 43 44 45 46 47",
}
local ciphertext = util.hexcat {
"d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2",
"a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6",
"3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b",
"1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36",
"92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58",
"fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc",
"3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b",
"61 16 ",
}
local tag = util.hexcat {
"1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91",
}
local cCiphertext, cTag = aead.encrypt(key, nonce, plaintext, aad)
expect(cCiphertext):equals(ciphertext)
expect(cTag):equals(tag)
end)
it("encrypts the appendix A.5 test vector", function()
local plaintext = table.concat {
"Internet-Drafts are draft documents valid for a maximum of six m",
"onths and may be updated, replaced, or obsoleted by other docume",
"nts at any time. It is inappropriate to use Internet-Drafts as r",
"eference material or to cite them other than as /\xe2\x80\x9cwor",
"k in progress./\xe2\x80\x9d",
}
local aad = util.hexcat {
"f3 33 88 86 00 00 00 00 00 00 4e 91",
}
local key = util.hexcat {
"1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0",
"47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0",
}
local nonce = util.hexcat {
"00 00 00 00 01 02 03 04 05 06 07 08",
}
local ciphertext = util.hexcat {
"64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd",
"5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2",
"4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0",
"bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf",
"33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81",
"14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55",
"97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38",
"36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4",
"b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9",
"90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e",
"af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a",
"0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a",
"0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e",
"ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10",
"49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30",
"30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29",
"a6 ad 5c b4 02 2b 02 70 9b ",
}
local tag = util.hexcat {
"ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38",
}
local cCiphertext, cTag = aead.encrypt(key, nonce, plaintext, aad)
expect(cCiphertext):equals(ciphertext)
expect(cTag):equals(tag)
end)
end)
describe("aead.decrypt", function()
it("validates arguments", function()
local key = ("a"):rep(32)
local nonce = ("a"):rep(12)
local tag = ("a"):rep(16)
local ctx = ("a"):rep(179)
local aad = ("a"):rep(79)
local rounds = 20
-- Types
expect.error(aead.decrypt, nil, nonce, tag, ctx, aad, rounds)
:eq("bad argument #1 (expected string, got nil)")
expect.error(aead.decrypt, key, nil, tag, ctx, aad, rounds)
:eq("bad argument #2 (expected string, got nil)")
expect.error(aead.decrypt, key, nonce, nil, ctx, aad, rounds)
:eq("bad argument #3 (expected string, got nil)")
expect.error(aead.decrypt, key, nonce, tag, nil, aad, rounds)
:eq("bad argument #4 (expected string, got nil)")
expect.error(aead.decrypt, key, nonce, tag, ctx, nil, rounds)
:eq("bad argument #5 (expected string, got nil)")
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, {})
:eq("bad argument #6 (expected number, got table)")
-- String lengths
expect.error(aead.decrypt, key .. "a", nonce, tag, ctx, aad, rounds)
:eq("key length must be 32")
expect.error(aead.decrypt, key, nonce .. "a", tag, ctx, aad, rounds)
:eq("nonce length must be 12")
expect.error(aead.decrypt, key, nonce, tag .. "a", ctx, aad, rounds)
:eq("tag length must be 16")
-- Rounds
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, 19.5)
:eq("round number must be even")
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, 19)
:eq("round number must be even")
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, 6)
:eq("round number must be no smaller than 8")
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, 22)
:eq("round number must be no larger than 20")
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, 1 / 0)
:eq("round number must be even")
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, -1 / 0)
:eq("round number must be even")
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, 0 / 0)
:eq("round number must be even")
end)
it("decrypts the section 2.8.2 test vector", function()
local plaintext = table.concat {
"Ladies and Gentlemen of the class of '99: If I could offer you o",
"nly one tip for the future, sunscreen would be it.",
}
local aad = util.hexcat {
"50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7",
}
local key = util.hexcat {
"80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f",
"90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f",
}
local nonce = util.hexcat {
"07 00 00 00 40 41 42 43 44 45 46 47",
}
local ciphertext = util.hexcat {
"d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2",
"a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6",
"3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b",
"1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36",
"92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58",
"fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc",
"3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b",
"61 16 ",
}
local tag = util.hexcat {
"1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91",
}
expect(aead.decrypt(key, nonce, tag, ciphertext, aad))
:eq(plaintext)
end)
it("returns nil on invalid ciphertext", function()
local aad = util.hexcat {
"50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7",
}
local key = util.hexcat {
"80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f",
"90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f",
}
local nonce = util.hexcat {
"07 00 00 00 40 41 42 43 44 45 46 47",
}
local ciphertext = util.hexcat {
"d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c3", -- Bit flip
"a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6",
"3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b",
"1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36",
"92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58",
"fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc",
"3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b",
"61 16 ",
}
local tag = util.hexcat {
"1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91",
}
expect(aead.decrypt(key, nonce, tag, ciphertext, aad))
:eq(nil)
end)
it("returns nil on invalid AAD", function()
local aad = util.hexcat {
"50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c6", -- Bit flip
}
local key = util.hexcat {
"80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f",
"90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f",
}
local nonce = util.hexcat {
"07 00 00 00 40 41 42 43 44 45 46 47",
}
local ciphertext = util.hexcat {
"d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2",
"a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6",
"3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b",
"1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36",
"92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58",
"fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc",
"3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b",
"61 16 ",
}
local tag = util.hexcat {
"1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91",
}
expect(aead.decrypt(key, nonce, tag, ciphertext, aad))
:eq(nil)
end)
it("returns nil on invalid tag", function()
local aad = util.hexcat {
"50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7",
}
local key = util.hexcat {
"80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f",
"90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f",
}
local nonce = util.hexcat {
"07 00 00 00 40 41 42 43 44 45 46 47",
}
local ciphertext = util.hexcat {
"d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2",
"a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6",
"3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b",
"1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36",
"92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58",
"fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc",
"3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b",
"61 16 ",
}
local tag = util.hexcat {
"1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:90", -- Bit flip
}
expect(aead.decrypt(key, nonce, tag, ciphertext, aad))
:eq(nil)
end)
it("decrypts the appendix A.5 test vector", function()
local plaintext = table.concat {
"Internet-Drafts are draft documents valid for a maximum of six m",
"onths and may be updated, replaced, or obsoleted by other docume",
"nts at any time. It is inappropriate to use Internet-Drafts as r",
"eference material or to cite them other than as /\xe2\x80\x9cwor",
"k in progress./\xe2\x80\x9d",
}
local aad = util.hexcat {
"f3 33 88 86 00 00 00 00 00 00 4e 91",
}
local key = util.hexcat {
"1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0",
"47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0",
}
local nonce = util.hexcat {
"00 00 00 00 01 02 03 04 05 06 07 08",
}
local ciphertext = util.hexcat {
"64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd",
"5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2",
"4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0",
"bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf",
"33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81",
"14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55",
"97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38",
"36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4",
"b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9",
"90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e",
"af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a",
"0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a",
"0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e",
"ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10",
"49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30",
"30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29",
"a6 ad 5c b4 02 2b 02 70 9b ",
}
local tag = util.hexcat {
"ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38",
}
expect(aead.decrypt(key, nonce, tag, ciphertext, aad))
:eq(plaintext)
end)
end)

137
spec/blake3_spec.lua Normal file
View file

@ -0,0 +1,137 @@
--- Test vector specification for BLAKE3.
--
-- Derived from the official BLAKE3 test vectors.
--
local util = require "spec.util"
local blake3 = require "ccryptolib.blake3"
local hasVecs, vecs = pcall(require, "spec.bigvec.blake3")
local function mkInput(len)
local out = {}
for i = 1, len do out[i] = (i - 1) % 251 end
return string.char(unpack(out))
end
describe("blake3.digest", function()
it("validates arguments", function()
-- Types
expect.error(blake3.digest, nil)
:eq("bad argument #1 (expected string, got nil)")
expect.error(blake3.digest, "", {})
:eq("bad argument #2 (expected number, got table)")
-- Length
expect.error(blake3.digest, "", 0.5)
:eq("length must be an integer")
expect.error(blake3.digest, "", 0)
:eq("length must be positive")
expect.error(blake3.digest, "", 1 / 0)
:eq("length must be an integer")
expect.error(blake3.digest, "", -1 / 0)
:eq("length must be an integer")
expect.error(blake3.digest, "", 0 / 0)
:eq("length must be an integer")
end)
if not hasVecs then
pending("passes the BLAKE3 official test vectors")
else
it("passes the BLAKE3 official test vectors", function()
local cases = vecs.cases
for i = 1, #cases do
local input = mkInput(cases[i].inputLen)
local hash = util.hexcat { cases[i].hash }
expect(blake3.digest(input, #hash)):eq(hash)
expect(blake3.digest(input)):eq(hash:sub(1, 32))
end
end)
end
end)
describe("blake3.digestKeyed", function()
it("validates arguments", function()
local key = ("a"):rep(32)
-- Types
expect.error(blake3.digestKeyed, nil, "")
:eq("bad argument #1 (expected string, got nil)")
expect.error(blake3.digestKeyed, key, nil)
:eq("bad argument #2 (expected string, got nil)")
expect.error(blake3.digestKeyed, key, "", {})
:eq("bad argument #3 (expected number, got table)")
-- String lengths
expect.error(blake3.digestKeyed, key .. "a", "")
:eq("key length must be 32")
-- Length
expect.error(blake3.digestKeyed, key, "", 0.5)
:eq("length must be an integer")
expect.error(blake3.digestKeyed, key, "", 0)
:eq("length must be positive")
expect.error(blake3.digestKeyed, key, "", 1 / 0)
:eq("length must be an integer")
expect.error(blake3.digestKeyed, key, "", -1 / 0)
:eq("length must be an integer")
expect.error(blake3.digestKeyed, key, "", 0 / 0)
:eq("length must be an integer")
end)
if not hasVecs then
pending("passes the BLAKE3 official test vectors")
else
it("passes the BLAKE3 official test vectors", function()
local key = vecs.key
local cases = vecs.cases
for i = 1, #cases do
local input = mkInput(cases[i].inputLen)
local keyedHash = util.hexcat { cases[i].keyedHash }
expect(blake3.digestKeyed(key, input, #keyedHash)):eq(keyedHash)
expect(blake3.digestKeyed(key, input)):eq(keyedHash:sub(1, 32))
end
end)
end
end)
describe("blake3.deriveKey", function()
it("validates arguments", function()
-- Types
expect.error(blake3.deriveKey, nil)
:eq("bad argument #1 (expected string, got nil)")
expect.error(blake3.deriveKey(""), nil)
:eq("bad argument #1 (expected string, got nil)")
expect.error(blake3.deriveKey(""), "", {})
:eq("bad argument #2 (expected number, got table)")
-- Length
expect.error(blake3.deriveKey(""), "", 0.5)
:eq("length must be an integer")
expect.error(blake3.deriveKey(""), "", 0)
:eq("length must be positive")
expect.error(blake3.deriveKey(""), "", 1 / 0)
:eq("length must be an integer")
expect.error(blake3.deriveKey(""), "", -1 / 0)
:eq("length must be an integer")
expect.error(blake3.deriveKey(""), "", 0 / 0)
:eq("length must be an integer")
end)
if not hasVecs then
pending("passes the BLAKE3 official test vectors")
else
it("passes the BLAKE3 official test vectors", function()
local contextString = vecs.contextString
local cases = vecs.cases
for i = 1, #cases do
local input = mkInput(cases[i].inputLen)
local deriveKey = util.hexcat { cases[i].deriveKey }
expect(blake3.deriveKey(contextString)(input, #deriveKey))
:eq(deriveKey)
expect(blake3.deriveKey(contextString)(input))
:eq(deriveKey:sub(1, 32))
end
end)
end
end)

203
spec/chacha20_spec.lua Normal file
View file

@ -0,0 +1,203 @@
--- Test vector specification for ChaCha20.
--
-- Derived from RFC 7539.
--
local util = require "spec.util"
local chacha20 = require "ccryptolib.chacha20"
describe("chacha20.crypt", function()
it("validates arguments", function()
local key = ("a"):rep(32)
local nonce = ("a"):rep(12)
local msg = ("a"):rep(179)
local rounds = 20
local offset = 1
-- Types
expect.error(chacha20.crypt, nil, nonce, msg, rounds, offset)
:eq("bad argument #1 (expected string, got nil)")
expect.error(chacha20.crypt, key, nil, msg, rounds, offset)
:eq("bad argument #2 (expected string, got nil)")
expect.error(chacha20.crypt, key, nonce, nil, rounds, offset)
:eq("bad argument #3 (expected string, got nil)")
expect.error(chacha20.crypt, key, nonce, msg, {}, offset)
:eq("bad argument #4 (expected number, got table)")
expect.error(chacha20.crypt, key, nonce, msg, nil, {})
:eq("bad argument #5 (expected number, got table)")
-- String lengths
expect.error(chacha20.crypt, key .. "a", nonce, msg, rounds, offset)
:eq("key length must be 32")
expect.error(chacha20.crypt, key, nonce .. "a", msg, rounds, offset)
:eq("nonce length must be 12")
-- Rounds
expect.error(chacha20.crypt, key, nonce, msg, 19.5, offset)
:eq("round number must be even")
expect.error(chacha20.crypt, key, nonce, msg, 19, offset)
:eq("round number must be even")
expect.error(chacha20.crypt, key, nonce, msg, 6, offset)
:eq("round number must be no smaller than 8")
expect.error(chacha20.crypt, key, nonce, msg, 22, offset)
:eq("round number must be no larger than 20")
expect.error(chacha20.crypt, key, nonce, msg, 1 / 0, offset)
:eq("round number must be even")
expect.error(chacha20.crypt, key, nonce, msg, -1 / 0, offset)
:eq("round number must be even")
expect.error(chacha20.crypt, key, nonce, msg, 0 / 0, offset)
:eq("round number must be even")
-- Offset
expect.error(chacha20.crypt, key, nonce, msg, rounds, 1.1)
:eq("offset must be an integer")
expect.error(chacha20.crypt, key, nonce, msg, rounds, -1)
:eq("offset must be nonnegative")
expect.error(chacha20.crypt, key, nonce, msg, rounds, 2 ^ 32)
:eq("offset too large")
expect.error(chacha20.crypt, key, nonce, msg, rounds, 1 / 0)
:eq("offset must be an integer")
expect.error(chacha20.crypt, key, nonce, msg, rounds, -1 / 0)
:eq("offset must be an integer")
expect.error(chacha20.crypt, key, nonce, msg, rounds, 0 / 0)
:eq("offset must be an integer")
end)
it("encrypts the section 2.4.2 test vector", function()
local key = util.hexcat {
"00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f",
"10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f",
}
local nonce = util.hexcat {
"00:00:00:00:00:00:00:4a:00:00:00:00"
}
local plaintextSunscreen = table.concat {
"Ladies and Gentlemen of the class of '99: If I could offer you o",
"nly one tip for the future, sunscreen would be it.",
}
local ciphertextSunscreen = util.hexcat {
"6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81",
"e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b",
"f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57",
"16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8",
"07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e",
"52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36",
"5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42",
"87 4d ",
}
expect(chacha20.crypt(key, nonce, plaintextSunscreen))
:eq(ciphertextSunscreen)
end)
it("encrypts the appendix A.2 test vector #1", function()
local key = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local nonce = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00",
}
local plaintext = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local ciphertext = util.hexcat {
"76 b8 e0 ad a0 f1 3d 90 40 5d 6a e5 53 86 bd 28",
"bd d2 19 b8 a0 8d ed 1a a8 36 ef cc 8b 77 0d c7",
"da 41 59 7c 51 57 48 8d 77 24 e0 3f b8 d8 4a 37",
"6a 43 b8 f4 15 18 a1 1c c3 87 b6 69 b2 ee 65 86",
}
expect(chacha20.crypt(key, nonce, plaintext, 20, 0))
:eq(ciphertext)
end)
it("encrypts the appendix A.2 test vector #2", function()
local key = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01",
}
local nonce = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 02",
}
local plaintext = table.concat {
"Any submission to the IETF intended by the Contributor for publi",
"cation as all or part of an IETF Internet-Draft or RFC and any s",
"tatement made within the context of an IETF activity is consider",
'ed an "IETF Contribution". Such statements include oral statemen',
"ts in IETF sessions, as well as written and electronic communica",
"tions made at any time or place, which are addressed to",
}
local ciphertext = util.hexcat {
"a3 fb f0 7d f3 fa 2f de 4f 37 6c a2 3e 82 73 70",
"41 60 5d 9f 4f 4f 57 bd 8c ff 2c 1d 4b 79 55 ec",
"2a 97 94 8b d3 72 29 15 c8 f3 d3 37 f7 d3 70 05",
"0e 9e 96 d6 47 b7 c3 9f 56 e0 31 ca 5e b6 25 0d",
"40 42 e0 27 85 ec ec fa 4b 4b b5 e8 ea d0 44 0e",
"20 b6 e8 db 09 d8 81 a7 c6 13 2f 42 0e 52 79 50",
"42 bd fa 77 73 d8 a9 05 14 47 b3 29 1c e1 41 1c",
"68 04 65 55 2a a6 c4 05 b7 76 4d 5e 87 be a8 5a",
"d0 0f 84 49 ed 8f 72 d0 d6 62 ab 05 26 91 ca 66",
"42 4b c8 6d 2d f8 0e a4 1f 43 ab f9 37 d3 25 9d",
"c4 b2 d0 df b4 8a 6c 91 39 dd d7 f7 69 66 e9 28",
"e6 35 55 3b a7 6c 5c 87 9d 7b 35 d4 9e b2 e6 2b",
"08 71 cd ac 63 89 39 e2 5e 8a 1e 0e f9 d5 28 0f",
"a8 ca 32 8b 35 1c 3c 76 59 89 cb cf 3d aa 8b 6c",
"cc 3a af 9f 39 79 c9 2b 37 20 fc 88 dc 95 ed 84",
"a1 be 05 9c 64 99 b9 fd a2 36 e7 e8 18 b0 4b 0b",
"c3 9c 1e 87 6b 19 3b fe 55 69 75 3f 88 12 8c c0",
"8a aa 9b 63 d1 a1 6f 80 ef 25 54 d7 18 9c 41 1f",
"58 69 ca 52 c5 b8 3f a3 6f f2 16 b9 c1 d3 00 62",
"be bc fd 2d c5 bc e0 91 19 34 fd a7 9a 86 f6 e6",
"98 ce d7 59 c3 ff 9b 64 77 33 8f 3d a4 f9 cd 85",
"14 ea 99 82 cc af b3 41 b2 38 4d d9 02 f3 d1 ab",
"7a c6 1d d2 9c 6f 21 ba 5b 86 2f 37 30 e3 7c fd",
"c4 fd 80 6c 22 f2 21 ",
}
expect(chacha20.crypt(key, nonce, plaintext, 20, 1))
:eq(ciphertext)
end)
it("encrypts the appendix A.2 test vector #3", function()
local key = util.hexcat {
"1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0",
"47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0",
}
local nonce = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 02",
}
local plaintext = table.concat {
"'Twas brillig, and the slithy toves\nDid gyre and gimble in the w",
"abe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.",
}
local ciphertext = util.hexcat {
"62 e6 34 7f 95 ed 87 a4 5f fa e7 42 6f 27 a1 df",
"5f b6 91 10 04 4c 0d 73 11 8e ff a9 5b 01 e5 cf",
"16 6d 3d f2 d7 21 ca f9 b2 1e 5f b1 4c 61 68 71",
"fd 84 c5 4f 9d 65 b2 83 19 6c 7f e4 f6 05 53 eb",
"f3 9c 64 02 c4 22 34 e3 2a 35 6b 3e 76 43 12 a6",
"1a 55 32 05 57 16 ea d6 96 25 68 f8 7d 3f 3f 77",
"04 c6 a8 d1 bc d1 bf 4d 50 d6 15 4b 6d a7 31 b1",
"87 b5 8d fd 72 8a fa 36 75 7a 79 7a c1 88 d1 ",
}
expect(chacha20.crypt(key, nonce, plaintext, 20, 42))
:eq(ciphertext)
end)
end)

249
spec/poly1305_spec.lua Normal file
View file

@ -0,0 +1,249 @@
--- Test vector specification for Poly1305.
--
-- Derived from RFC 7539.
--
local util = require "spec.util"
local poly1305 = require "ccryptolib.poly1305"
describe("poly1305.mac", function()
it("validates arguments", function()
local key = ("a"):rep(32)
local msg = ("a"):rep(179)
-- Types
expect.error(poly1305.mac, nil, msg)
:eq("bad argument #1 (expected string, got nil)")
expect.error(poly1305.mac, key, nil)
:eq("bad argument #2 (expected string, got nil)")
-- Key length
expect.error(poly1305.mac, key .. "a", msg)
:eq("key length must be 32")
end)
it("derives the tag of the section 2.5.2 test vector", function()
local key = util.hexcat {
"85:d6:be:78:57:55:6d:33:7f:44:52:fe:42:d5:06:a8",
"01:03:80:8a:fb:0d:b2:fd:4a:bf:f6:af:41:49:f5:1b",
}
local message = "Cryptographic Forum Research Group"
local tag = util.hexcat {
"a8:06:1d:c1:30:51:36:c6:c2:2b:8b:af:0c:01:27:a9",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #1", function()
local key = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local tag = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #2", function()
local key = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e",
}
local message = table.concat {
"Any submission to the IETF intended by the Contributor for publi",
"cation as all or part of an IETF Internet-Draft or RFC and any s",
"tatement made within the context of an IETF activity is consider",
'ed an "IETF Contribution". Such statements include oral statemen',
"ts in IETF sessions, as well as written and electronic communica",
"tions made at any time or place, which are addressed to",
}
local tag = util.hexcat {
"36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #3", function()
local key = util.hexcat {
"36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = table.concat {
"Any submission to the IETF intended by the Contributor for publi",
"cation as all or part of an IETF Internet-Draft or RFC and any s",
"tatement made within the context of an IETF activity is consider",
'ed an "IETF Contribution". Such statements include oral statemen',
"ts in IETF sessions, as well as written and electronic communica",
"tions made at any time or place, which are addressed to",
}
local tag = util.hexcat {
"f3 47 7e 7c d9 54 17 af 89 a6 b8 79 4c 31 0c f0",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #4", function()
local key = util.hexcat {
"1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0",
"47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0",
}
local message = table.concat {
"'Twas brillig, and the slithy toves\nDid gyre and gimble in the w",
"abe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.",
}
local tag = util.hexcat {
"45 41 66 9a 7e aa ee 61 e7 08 dc 7c bc c5 eb 62",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #5", function()
local key = util.hexcat {
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = util.hexcat {
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
}
local tag = util.hexcat {
"03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #6", function()
local key = util.hexcat {
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
}
local message = util.hexcat {
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local tag = util.hexcat {
"03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #7", function()
local key = util.hexcat {
"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = util.hexcat {
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local tag = util.hexcat {
"05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #8", function()
local key = util.hexcat {
"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = util.hexcat {
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FB FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE",
"01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01",
}
local tag = util.hexcat {
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #9", function()
local key = util.hexcat {
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = util.hexcat {
"FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
}
local tag = util.hexcat {
"FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #10", function()
local key = util.hexcat {
"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = util.hexcat {
"E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00",
"33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local tag = util.hexcat {
"14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
it("derives the tag of the appendix A.2 test vector #10", function()
local key = util.hexcat {
"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local message = util.hexcat {
"E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00",
"33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
local tag = util.hexcat {
"13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
}
expect(poly1305.mac(key, message)):eq(tag)
end)
end)

64
spec/sha256_spec.lua Normal file
View file

@ -0,0 +1,64 @@
--- Test vector specification for SHA256.
--
-- Derived from the NIST SHA256 Cryptographic Algorithm Validation Program.
--
local util = require "spec.util"
local sha256 = require "ccryptolib.sha256"
local hasShort, shortMsg = pcall(require, "spec.bigvec.sha256short")
local hasLong, longMsg = pcall(require, "spec.bigvec.sha256long")
describe("sha256.digest", function()
it("validates arguments", function()
expect.error(sha256.digest, nil)
:eq("bad argument #1 (expected string, got nil)")
end)
if not hasShort then
pending("passes the NIST SHAVS byte-oriented short messages test")
else
it("passes the NIST SHAVS byte-oriented short messages test", function()
for i = 1, #shortMsg do
local msg = util.hexcat { shortMsg[i].msg }
local md = util.hexcat { shortMsg[i].md }
expect(sha256.digest(msg)):eq(md)
sleep()
end
end)
end
if not hasLong then
pending("passes the NIST SHAVS byte-oriented long messages test")
else
it("passes the NIST SHAVS byte-oriented long messages test", function()
for i = 1, #longMsg do
local msg = util.hexcat { longMsg[i].msg }
local md = util.hexcat { longMsg[i].md }
expect(sha256.digest(msg)):eq(md)
sleep()
end
end)
end
it("passes the NIST SHAVS monte carlo test (5k iterations)", function()
local seed = util.hexcat {
"6d1e72ad03ddeb5de891e572e2396f8da015d899ef0e79503152d6010a3fe691",
}
for _ = 1, 5 do
local md0, md1, md2 = seed, seed, seed
for _ = 1, 1000 do
md0, md1, md2 = md1, md2, sha256.digest(md0 .. md1 .. md2)
end
seed = md2
sleep()
end
local out = util.hexcat {
"f9eba2a4cf6263826beaf6150057849eb975a9513c0b76ecad0f1c19ebbad89b",
}
expect(seed):eq(out)
end)
end)

64
spec/sha512_spec.lua Normal file
View file

@ -0,0 +1,64 @@
--- Test vector specification for SHA512.
--
-- Derived from the NIST SHA512 Cryptographic Algorithm Validation Program.
--
local util = require "spec.util"
local sha512 = require "ccryptolib.internal.sha512"
local hasShort, shortMsg = pcall(require, "spec.bigvec.sha512short")
local hasLong, longMsg = pcall(require, "spec.bigvec.sha512long")
describe("sha256.digest", function()
it("validates arguments", function()
expect.error(sha512.digest, nil)
:eq("bad argument #1 (expected string, got nil)")
end)
if not hasShort then
pending("passes the NIST SHAVS byte-oriented short messages test")
else
it("passes the NIST SHAVS byte-oriented short messages test", function()
for i = 1, #shortMsg do
local msg = util.hexcat { shortMsg[i].msg }
local md = util.hexcat { shortMsg[i].md }
expect(sha512.digest(msg)):eq(md)
sleep()
end
end)
end
if not hasLong then
pending("passes the NIST SHAVS byte-oriented long messages test")
else
it("passes the NIST SHAVS byte-oriented long messages test", function()
for i = 1, #longMsg do
local msg = util.hexcat { longMsg[i].msg }
local md = util.hexcat { longMsg[i].md }
expect(sha512.digest(msg)):eq(md)
sleep()
end
end)
end
it("passes the NIST SHAVS monte carlo test (5k iterations)", function()
local seed = util.hexcat {
"5c337de5caf35d18ed90b5cddfce001ca1b8ee8602f367e7c24ccca6f893802fb1aca7a3dae32dcd60800a59959bc540d63237876b799229ae71a2526fbc52cd",
}
for _ = 1, 5 do
local md0, md1, md2 = seed, seed, seed
for _ = 1, 1000 do
md0, md1, md2 = md1, md2, sha512.digest(md0 .. md1 .. md2)
end
seed = md2
sleep()
end
local out = util.hexcat {
"b68f0cd2d63566b3934a50666dec6d62ca1db98e49d7733084c1f86d91a8a08c756fa7ece815e20930dd7cb66351bad8c087c2f94e8757cb98e7f4b86b21a8a8",
}
expect(seed):eq(out)
end)
end)

9
spec/util.lua Normal file
View file

@ -0,0 +1,9 @@
local function hexcat(t)
return table.concat(t):gsub("[^%x]*(%x%x)[^%x]*", function(h)
return string.char(tonumber(h, 16))
end)
end
return {
hexcat = hexcat,
}