Skip to content

Commit

Permalink
Correctly hash messages where the input length was 55 + (64*n) or 111…
Browse files Browse the repository at this point in the history
… + (128*n) (#9)

* Test for buggy case

* Fix buggy case in all SHA modules + update changelog
  • Loading branch information
Dekkonot authored Apr 23, 2024
1 parent a986dc8 commit d126993
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 6 deletions.
1 change: 1 addition & 0 deletions modules/sha1/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Several performance improvements
- Add `--!native` directive to module to support native codegen in Roblox
- Fixed incorrect hashing result when input had a length of `55 + 64 * n` where `n` was any integer

## Version 1.0.2

Expand Down
8 changes: 6 additions & 2 deletions modules/sha1/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,15 @@ local function sha1(message: string): (string, { number })
processBlocks(digest, message, 1, messageLen - leftover)
end

-- TODO find a way to do this more eloquently
-- Raise `leftover` to next multiple of 64 so that we can calculate
-- how much padding we need without a branch or loop.
-- The number here is just masking off the last 6 bits.
local nextMultipleOf64 = bit32.band(leftover + 32, 0xffffffc0)

local finalMessage = {
if leftover ~= 0 then string.sub(message, -leftover) else "",
"\x80",
string.rep("\0", 64 - (messageLen + 9) % 64),
string.rep("\0", (nextMultipleOf64 - leftover - 9) % 64),
string.pack(">L", messageLen * 8),
}
local finalBlock = table.concat(finalMessage)
Expand Down
1 change: 1 addition & 0 deletions modules/sha224/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Several performance improvements
- Add `--!native` directive to module to support native codegen in Roblox
- Fixed incorrect hashing result when input had a length of `55 + 64 * n` where `n` was any integer

## Version 1.0.0

Expand Down
7 changes: 6 additions & 1 deletion modules/sha224/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,15 @@ local function sha224(message: string): (string, { number })
processBlocks(digest, message, 1, messageLen - leftover)
end

-- Raise `leftover` to next multiple of 64 so that we can calculate
-- how much padding we need without a branch or loop.
-- The number here is just masking off the last 6 bits.
local nextMultipleOf64 = bit32.band(leftover + 32, 0xffffffc0)

local finalMessage = {
if leftover ~= 0 then string.sub(message, -leftover) else "",
"\x80",
string.rep("\0", 64 - (messageLen + 9) % 64),
string.rep("\0", (nextMultipleOf64 - leftover - 9) % 64),
string.pack(">L", messageLen * 8),
}
local finalBlock = table.concat(finalMessage)
Expand Down
1 change: 1 addition & 0 deletions modules/sha256/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Several performance improvements
- Add `--!native` directive to module to support native codegen in Roblox
- Fixed incorrect hashing result when input had a length where `length % 55` was `0`

## Version 1.0.0

Expand Down
7 changes: 6 additions & 1 deletion modules/sha256/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,15 @@ local function sha256(message: string): (string, { number })
processBlocks(digest, message, 1, messageLen - leftover)
end

-- Raise `leftover` to next multiple of 64 so that we can calculate
-- how much padding we need without a branch or loop.
-- The number here is just masking off the last 6 bits.
local nextMultipleOf64 = bit32.band(leftover + 32, 0xffff_ffc0)

local finalMessage = {
if leftover ~= 0 then string.sub(message, -leftover) else "",
"\x80",
string.rep("\0", 64 - (messageLen + 9) % 64),
string.rep("\0", (nextMultipleOf64 - leftover - 9) % 64),
string.pack(">L", messageLen * 8),
}
local finalBlock = table.concat(finalMessage)
Expand Down
1 change: 1 addition & 0 deletions modules/sha384/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Several performance improvements
- Add `--!native` directive to module to support native codegen in Roblox
- Fixed incorrect hashing result when input had a length of `111 + 128 * n` where `n` was any integer

## Version 1.0.0

Expand Down
8 changes: 7 additions & 1 deletion modules/sha384/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,16 @@ local function sha384(message: string): string
if messageLen >= 128 then
processBlocks(digest_front, digest_back, message, 1, messageLen - leftover)
end

-- Raise `leftover` to next multiple of 128 so that we can calculate
-- how much padding we need without a branch or loop.
-- The number here is just masking off the last 6 bits.
local nextMultipleOf128 = bit32.band(leftover + 64, 0xfffff000)

local finalMessage = {
if leftover ~= 0 then string.sub(message, -leftover) else "",
"\x80",
string.rep("\0", 128 - (messageLen + 17) % 128),
string.rep("\0", (nextMultipleOf128 - leftover - 17) % 128),
string.pack(">L", messageLen * 8 / 2 ^ 32),
string.pack(">L", bit32.bor(messageLen * 8)),
}
Expand Down
1 change: 1 addition & 0 deletions modules/sha512/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Several performance improvements
- Add `--!native` directive to module to support native codegen in Roblox
- Fixed incorrect hashing result when input had a length of `111 + 128 * n` where `n` was any integer

## Version 1.0.0

Expand Down
8 changes: 7 additions & 1 deletion modules/sha512/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,16 @@ local function sha512(message: string): string
if messageLen >= 128 then
processBlocks(digest_front, digest_back, message, 1, messageLen - leftover)
end

-- Raise `leftover` to next multiple of 128 so that we can calculate
-- how much padding we need without a branch or loop.
-- The number here is just masking off the last 6 bits.
local nextMultipleOf128 = bit32.band(leftover + 64, 0xfffff000)

local finalMessage = {
if leftover ~= 0 then string.sub(message, -leftover) else "",
"\x80",
string.rep("\0", 128 - (messageLen + 17) % 128),
string.rep("\0", (nextMultipleOf128 - leftover - 17) % 128),
string.pack(">L", messageLen * 8 / 2 ^ 32),
string.pack(">L", messageLen * 8 % 2 ^ 32),
}
Expand Down
1 change: 1 addition & 0 deletions testfiles/111-a.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 change: 1 addition & 0 deletions testfiles/119-a.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 change: 1 addition & 0 deletions testfiles/239-a.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 change: 1 addition & 0 deletions testfiles/55-a.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
27 changes: 27 additions & 0 deletions tests/sha1.luau
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,33 @@ assert(
== "fe32af74bc982dc5da23e54055f5515e948a10bd",
"(SHA-1) Fitness-Gram hash does not match"
)

assert(
sha1("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") == "c1c8bbdc22796e28c0e15163d20899b65621d65a",
"(SHA-1) 55 character a hash does not match"
)

assert(
sha1(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "ee971065aaa017e0632a8ca6c77bb3bf8b1dfc56",
"(SHA-1) 119 character a hash does not match"
)

assert(
sha1(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "ac877859d427d9192054eea8feb3b8a403ef83a5",
"(SHA-1) 111 character a hash does not match"
)

assert(
sha1(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "fdc30857cf7b957f47ebd8288d5e5d7426f44394",
"(SHA-1) 239 character a hash does not match"
)

if true then
local e = string.rep("e", 199999)
local a = string.rep("a", 1e6)
Expand Down
27 changes: 27 additions & 0 deletions tests/sha224.luau
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,33 @@ assert(
"(SHA-224) Fitness-Gram hash does not match"
)

assert(
sha224("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
== "fb0bd626a70c28541dfa781bb5cc4d7d7f56622a58f01a0b1ddd646f",
"(SHA-224) 55 character a hash does not match"
)

assert(
sha224(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "e000e6709d26667b631faa7fc1bd404eb4774003c5fb4f51a0184875",
"(SHA-224) 119 character a hash does not match"
)

assert(
sha224(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "4aeec1a49b2c1bc663abf2809b36faaa64359523d4f26d02dbc2cba3",
"(SHA-224) 111 character a hash does not match"
)

assert(
sha224(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "9da4e535cdffdbb7ee783ef7c6b61cbda7bcd4b15ce59d6ce5c2f099",
"(SHA-224) 239 character a hash does not match"
)

if true then
local e = string.rep("e", 199999)
local a = string.rep("a", 1e6)
Expand Down
27 changes: 27 additions & 0 deletions tests/sha256.luau
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,33 @@ assert(
"(SHA-256) Fitness-Gram hash does not match"
)

assert(
sha256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
== "9f4390f8d30c2dd92ec9f095b65e2b9ae9b0a925a5258e241c9f1e910f734318",
"(SHA-256) 55 character a hash does not match"
)

assert(
sha256(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "31eba51c313a5c08226adf18d4a359cfdfd8d2e816b13f4af952f7ea6584dcfb",
"(SHA-256) 119 character a hash does not match"
)

assert(
sha256(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "6374f73208854473827f6f6a3f43b1f53eaa3b82c21c1a6d69a2110b2a79baad",
"(SHA-256) 111 character a hash does not match"
)

assert(
sha256(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "064b3d122abe25c36265f79fc794b0adf28a6c5e4fe8ed3661f2287e8cecadcc",
"(SHA-256) 239 character a hash does not match"
)

if true then
local e = string.rep("e", 199999)
local a = string.rep("a", 1e6)
Expand Down
27 changes: 27 additions & 0 deletions tests/sha384.luau
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,33 @@ assert(
"(SHA-384) Fitness-Gram hash does not match"
)

assert(
sha384("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
== "5d91ac7e74e62b5c728904b40f10784d66b7af9cb6302123e48c92f0432ceb8d2a92c02de77dcb29ed75c4b42bde46f4",
"(SHA-384) 55 character a hash does not match"
)

assert(
sha384(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "c2fbb1911d6889e3db556b482236ab82f3c736f00a22c088641a09fdbbca27e3f1e3b6235bad20aee1ca083c76ac590c",
"(SHA-384) 119 character a hash does not match"
)

assert(
sha384(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "3c37955051cb5c3026f94d551d5b5e2ac38d572ae4e07172085fed81f8466b8f90dc23a8ffcdea0b8d8e58e8fdacc80a",
"(SHA-384) 111 character a hash does not match"
)

assert(
sha384(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
) == "e247c35f4bc1aa38026f8880c8c97305545d00d3f859e00c57d1c1f0a176b3c6b749c4eb081f08bd0fba500969cd056a",
"(SHA-384) 239 character a hash does not match"
)

if true then
local e = string.rep("e", 199999)
local a = string.rep("a", 1e6)
Expand Down
30 changes: 30 additions & 0 deletions tests/sha512.luau
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,36 @@ assert(
"(SHA-512) Fitness-Gram hash does not match"
)

assert(
sha512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
== "b0220c772cbf6c1822e2cb38a437d0e1d58772417a4bbb21c961364f8b6143e05aa6316dca8d1d7b19e16448419076395f6086cb55101fbd6d5497b148e1745f",
"(SHA-512) 55 character a hash does not match"
)

assert(
sha512(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
)
== "130396a75cb483f2eee8c56d8a668bb3d2641f5243212c0bee2bd33da096ad9eb8179fe18f9eaacf76e09fae9de4c3f14ba13341e345be05bf76c182cc3468cb",
"(SHA-512) 119 character a hash does not match"
)

assert(
sha512(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
)
== "fa9121c7b32b9e01733d034cfc78cbf67f926c7ed83e82200ef86818196921760b4beff48404df811b953828274461673c68d04e297b0eb7b2b4d60fc6b566a2",
"(SHA-512) 111 character a hash does not match"
)

assert(
sha512(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
)
== "52c853cb8d907f3d4d6b889beb027985d7c273486d75f8baf26f80d24e90c74c6c3de3e22131582380a7d14d43f2941a31385439cd6ddc469f628015e50bf286",
"(SHA-512) 239 character a hash does not match"
)

if true then
local e = string.rep("e", 199999)
local a = string.rep("a", 1e6)
Expand Down

0 comments on commit d126993

Please sign in to comment.