Move directory and add unit tests
This commit is contained in:
parent
5438c20bc9
commit
9d060fa581
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
out/
|
||||
doc/
|
||||
spec/bigvec/
|
||||
|
|
|
@ -25,13 +25,15 @@ local bor = bit32.bor
|
|||
--
|
||||
local function encrypt(key, nonce, message, aad, rounds)
|
||||
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")
|
||||
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(4, aad, "string")
|
||||
expect(5, rounds, "number", "nil")
|
||||
rounds = rounds or 20
|
||||
rounds = expect(5, 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 encrypt.
|
||||
local msgLong = ("\0"):rep(64) .. message
|
||||
|
@ -63,13 +65,17 @@ end
|
|||
--
|
||||
local function decrypt(key, nonce, tag, ciphertext, aad, rounds)
|
||||
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")
|
||||
assert(#nonce == 12, "nonce length must be 12")
|
||||
expect(3, ciphertext, "string")
|
||||
expect(4, aad, "string")
|
||||
expect(5, rounds, "number", "nil")
|
||||
rounds = rounds or 20
|
||||
if #nonce ~= 12 then error("nonce length must be 12", 2) end
|
||||
expect(3, tag, "string")
|
||||
if #tag ~= 16 then error("tag length must be 16", 2) end
|
||||
expect(4, ciphertext, "string")
|
||||
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.
|
||||
local ctxLong = ("\0"):rep(64) .. ciphertext
|
|
@ -125,8 +125,12 @@ end
|
|||
local function expand(state, len, offset)
|
||||
expect(1, state, "table")
|
||||
expect(1, len, "number")
|
||||
expect(2, offset, "nil", "number")
|
||||
offset = offset or 0
|
||||
if len % 1 ~= 0 then error("length must be an integer", 2) end
|
||||
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.
|
||||
local out = {}
|
||||
|
@ -189,6 +193,8 @@ local function update(state, message)
|
|||
end
|
||||
|
||||
local function finalize(state)
|
||||
expect(1, state, "table")
|
||||
|
||||
-- Pad the last message block.
|
||||
local lastLen = #state.m
|
||||
local padded = state.m .. ("\0"):rep(64)
|
||||
|
@ -270,7 +276,7 @@ end
|
|||
|
||||
function mod.newKeyed(key)
|
||||
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)
|
||||
end
|
||||
|
||||
|
@ -288,9 +294,9 @@ end
|
|||
--
|
||||
function mod.digest(message, len)
|
||||
expect(1, message, "string")
|
||||
expect(2, len, "number", "nil")
|
||||
len = len or 32
|
||||
assert(len % 1 == 0 and len >= 1, "length must be a positive integer")
|
||||
len = expect(2, len, "number", "nil") or 32
|
||||
if len % 1 ~= 0 then error("length must be an integer", 2) end
|
||||
if len < 1 then error("length must be positive", 2) end
|
||||
return new(IV, 0):update(message):finalize():expand(len)
|
||||
end
|
||||
|
||||
|
@ -303,11 +309,11 @@ end
|
|||
--
|
||||
function mod.digestKeyed(key, message, len)
|
||||
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(3, len, "number", "nil")
|
||||
len = len or 32
|
||||
assert(len % 1 == 0 and len >= 1, "length must be a positive integer")
|
||||
len = expect(3, len, "number", "nil") or 32
|
||||
if len % 1 ~= 0 then error("length must be an integer", 2) end
|
||||
if len < 1 then error("length must be positive", 2) end
|
||||
local h = new({u8x4(fmt8x4, key, 1)}, KEYED_HASH)
|
||||
return h:update(message):finalize():expand(len)
|
||||
end
|
||||
|
@ -323,9 +329,9 @@ function mod.deriveKey(context)
|
|||
|
||||
return function(material, len)
|
||||
expect(1, material, "string")
|
||||
expect(2, len, "number", "nil")
|
||||
len = len or 32
|
||||
assert(len % 1 == 0 and len >= 1, "length must be a positive integer")
|
||||
len = expect(2, len, "number", "nil") or 32
|
||||
if len % 1 ~= 0 then error("length must be an integer", 2) end
|
||||
if len < 1 then error("length must be positive", 2) end
|
||||
local h = new({u8x4(fmt8x4, iv, 1)}, DERIVE_KEY_MATERIAL)
|
||||
return h:update(material):finalize():expand(len)
|
||||
end
|
|
@ -26,18 +26,18 @@ local mod = {}
|
|||
--
|
||||
function mod.crypt(key, nonce, message, rounds, offset)
|
||||
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")
|
||||
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(4, rounds, "number", "nil")
|
||||
rounds = rounds or 20
|
||||
assert(rounds % 2 == 0, "round number must be even")
|
||||
assert(rounds >= 8 and rounds <= 20, "round number must be in 8..20")
|
||||
expect(5, offset, "number", "nil")
|
||||
offset = offset or 1
|
||||
assert(offset % 1 == 0 and offset >= 0, "offset must be an integer >= 0")
|
||||
assert(#message + 64 * offset < 2 ^ 37, "offset too large")
|
||||
rounds = expect(4, 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
|
||||
offset = expect(5, offset, "number", "nil") or 1
|
||||
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 #message + 64 * offset >= 2 ^ 37 then error("offset too large", 2) end
|
||||
|
||||
-- Build the state block.
|
||||
local i0, i1, i2, i3 = 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
|
|
@ -20,7 +20,7 @@ local mod = {}
|
|||
--
|
||||
function mod.mac(key, message)
|
||||
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")
|
||||
|
||||
-- Pad message.
|
|
@ -103,7 +103,7 @@ function mod.save()
|
|||
end
|
||||
|
||||
-- Add extra entropy.
|
||||
mod.stir(error("TODO")) -- TODO
|
||||
-- mod.stir(error("TODO")) -- TODO
|
||||
|
||||
-- Save.
|
||||
mod.save()
|
381
spec/aead_spec.lua
Normal file
381
spec/aead_spec.lua
Normal 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
137
spec/blake3_spec.lua
Normal 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
203
spec/chacha20_spec.lua
Normal 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
249
spec/poly1305_spec.lua
Normal 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
64
spec/sha256_spec.lua
Normal 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
64
spec/sha512_spec.lua
Normal 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
9
spec/util.lua
Normal 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,
|
||||
}
|
Loading…
Reference in a new issue