added md5 and md4
This commit is contained in:
parent
226a728e82
commit
02ee768ebb
BIN
manual.pdf
BIN
manual.pdf
Binary file not shown.
@ -13,6 +13,12 @@
|
||||
)
|
||||
#tidy.show-module(sha-doc)
|
||||
|
||||
#let md-doc = mod(
|
||||
read("src/md.typ"),
|
||||
name: "md"
|
||||
)
|
||||
#tidy.show-module(md-doc)
|
||||
|
||||
#let misc-doc = mod(
|
||||
read("src/misc.typ"),
|
||||
name: "misc"
|
||||
|
@ -1,4 +1,5 @@
|
||||
#import "misc.typ": *
|
||||
#import "sha.typ"
|
||||
#import "sha.typ": *
|
||||
#import "md.typ": *
|
||||
#import "utils.typ": *
|
||||
#import "base.typ": *
|
259
src/md.typ
Normal file
259
src/md.typ
Normal file
@ -0,0 +1,259 @@
|
||||
#import "utils.typ": *
|
||||
|
||||
#let rots = (
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
|
||||
)
|
||||
|
||||
#let _md5-const(i) = {
|
||||
return int(
|
||||
calc.floor(
|
||||
calc.abs(
|
||||
calc.sin(i + 1) * max-32
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#let md5-default-iv = (
|
||||
0x67452301,
|
||||
0xEFCDAB89,
|
||||
0x98BADCFE,
|
||||
0x10325476
|
||||
)
|
||||
#let md4-default-iv = md5-default-iv
|
||||
|
||||
/// Message Digest 5
|
||||
/// #test(
|
||||
/// `jumble.bytes-to-hex(jumble.md5("Hello World!")) == "ed076287532e86365e841e92bfc50d8c"`
|
||||
/// )
|
||||
/// ```example
|
||||
/// #bytes-to-hex(md5("Hello World!"))
|
||||
/// ```
|
||||
/// -> bytes
|
||||
#let md5(
|
||||
message,
|
||||
iv: md5-default-iv
|
||||
) = {
|
||||
let message = if type(message) == str {bytes(message)} else {message}
|
||||
assert(type(message) == bytes, message: "message must be a string or bytes, but is " + repr(type(message)))
|
||||
|
||||
// Complete message to multiple of 512 bits
|
||||
let bin-str = ""
|
||||
for char in message {
|
||||
bin-str += z-fill(str(char, base: 2), 8)
|
||||
}
|
||||
let l = bin-str.len()
|
||||
bin-str += "1"
|
||||
let padding = calc.rem-euclid(448 - bin-str.len(), 512)
|
||||
if padding != 0 {
|
||||
bin-str += "0" * padding
|
||||
}
|
||||
let len-bin = z-fill(str(l, base: 2), 64)
|
||||
// Reverse order to little-endian
|
||||
len-bin = len-bin.clusters()
|
||||
.chunks(8)
|
||||
.rev()
|
||||
.flatten()
|
||||
.join()
|
||||
bin-str += len-bin
|
||||
let bin = bin-str.clusters().map(int)
|
||||
|
||||
// Split into blocks of 16 32-bit words
|
||||
let words = bin.chunks(32).map(bin-to-int).map(switch-endianness)
|
||||
let blocks = words.chunks(16)
|
||||
|
||||
let vec = iv
|
||||
|
||||
for block in blocks {
|
||||
let (A, B, C, D) = vec
|
||||
for i in range(64) {
|
||||
let (f, g) = if i < 16 {(
|
||||
B.bit-and(C).bit-or(B.bit-not().bit-and(mask-32).bit-and(D)),
|
||||
i
|
||||
)} else if i < 32 {(
|
||||
D.bit-and(B).bit-or(D.bit-not().bit-and(mask-32).bit-and(C)),
|
||||
calc.rem(5 * i + 1, 16)
|
||||
)} else if i < 48 {(
|
||||
B.bit-xor(C).bit-xor(D),
|
||||
calc.rem(3 * i + 5, 16)
|
||||
)} else {(
|
||||
C.bit-xor(B.bit-or(D.bit-not().bit-and(mask-32))),
|
||||
calc.rem(7 * i, 16)
|
||||
)}
|
||||
let temp = circular-shift(
|
||||
calc.rem(A + f + _md5-const(i) + block.at(g), max-32),
|
||||
n: rots.at(i)
|
||||
) + B
|
||||
(A, B, C, D) = (
|
||||
D,
|
||||
calc.rem(temp, max-32),
|
||||
B,
|
||||
C
|
||||
)
|
||||
}
|
||||
|
||||
vec = vec.zip((A, B, C, D)).map(p => {
|
||||
calc.rem(p.sum(), max-32)
|
||||
})
|
||||
}
|
||||
|
||||
let digest-bytes = ()
|
||||
for n in vec {
|
||||
digest-bytes += (
|
||||
n.bit-and(0xff),
|
||||
n.bit-rshift(8).bit-and(0xff),
|
||||
n.bit-rshift(16).bit-and(0xff),
|
||||
n.bit-rshift(24)
|
||||
)
|
||||
}
|
||||
|
||||
return bytes(digest-bytes)
|
||||
}
|
||||
|
||||
#let _md4-round1-shift = (3, 7, 11, 19)
|
||||
#let _md4-round2-shift = (3, 5, 9, 13)
|
||||
#let _md4-round3-shift = (3, 9, 11, 15)
|
||||
|
||||
#let _md4-f(x, y, z) = {
|
||||
return x.bit-and(y).bit-or(x.bit-not().bit-and(mask-32).bit-and(z))
|
||||
}
|
||||
|
||||
#let _md4-g(x, y, z) = {
|
||||
let xy = x.bit-and(y)
|
||||
let xz = x.bit-and(z)
|
||||
let yz = y.bit-and(z)
|
||||
return xy.bit-or(xz).bit-or(yz)
|
||||
}
|
||||
|
||||
#let _md4-h(x, y, z) = {
|
||||
return x.bit-xor(y).bit-xor(z)
|
||||
}
|
||||
|
||||
#let _md4-round1(a, b, c, d, x, s) = {
|
||||
let temp = a + _md4-f(b, c, d) + x
|
||||
return circular-shift(
|
||||
temp.bit-and(mask-32),
|
||||
n: s
|
||||
)
|
||||
}
|
||||
|
||||
#let _md4-round2(a, b, c, d, x, s) = {
|
||||
let temp = a + _md4-g(b, c, d) + x + 0x5a827999
|
||||
return circular-shift(
|
||||
temp.bit-and(mask-32),
|
||||
n: s
|
||||
)
|
||||
}
|
||||
|
||||
#let _md4-round3(a, b, c, d, x, s) = {
|
||||
let temp = a + _md4-h(b, c, d) + x + 0x6ed9eba1
|
||||
return circular-shift(
|
||||
temp.bit-and(mask-32),
|
||||
n: s
|
||||
)
|
||||
}
|
||||
|
||||
/// Message Digest 4
|
||||
/// #test(
|
||||
/// `jumble.bytes-to-hex(jumble.md4("Hello World!")) == "b2a5cc34fc21a764ae2fad94d56fadf6"`
|
||||
/// )
|
||||
/// ```example
|
||||
/// #bytes-to-hex(md4("Hello World!"))
|
||||
/// ```
|
||||
/// -> bytes
|
||||
#let md4(
|
||||
/// -> str | bytes
|
||||
message,
|
||||
/// -> array
|
||||
iv: md4-default-iv
|
||||
) = {
|
||||
let message = if type(message) == str {bytes(message)} else {message}
|
||||
assert(type(message) == bytes, message: "message must be a string or bytes, but is " + repr(type(message)))
|
||||
|
||||
// Complete message to multiple of 512 bits
|
||||
let bin-str = ""
|
||||
for char in message {
|
||||
bin-str += z-fill(str(char, base: 2), 8)
|
||||
}
|
||||
let l = bin-str.len()
|
||||
bin-str += "1"
|
||||
let padding = calc.rem-euclid(448 - bin-str.len(), 512)
|
||||
if padding != 0 {
|
||||
bin-str += "0" * padding
|
||||
}
|
||||
let len-bin = z-fill(str(l, base: 2), 64)
|
||||
// Reverse order to little-endian
|
||||
len-bin = len-bin.clusters()
|
||||
.chunks(8)
|
||||
.rev()
|
||||
.flatten()
|
||||
.join()
|
||||
bin-str += len-bin
|
||||
let bin = bin-str.clusters().map(int)
|
||||
|
||||
// Split into blocks of 16 32-bit words
|
||||
let words = bin.chunks(32).map(bin-to-int).map(switch-endianness)
|
||||
let blocks = words.chunks(16)
|
||||
|
||||
let vec = iv
|
||||
|
||||
for block in blocks {
|
||||
let vec2 = vec
|
||||
|
||||
for i in range(16) {
|
||||
vec2.at(0) = _md4-round1(
|
||||
..vec2,
|
||||
block.at(i),
|
||||
_md4-round1-shift.at(calc.rem(i, 4))
|
||||
)
|
||||
vec2.insert(0, vec2.pop())
|
||||
}
|
||||
|
||||
for i in range(16) {
|
||||
let j = calc.rem(i * 4, 16) + calc.div-euclid(i, 4)
|
||||
vec2.at(0) = _md4-round2(
|
||||
..vec2,
|
||||
block.at(j),
|
||||
_md4-round2-shift.at(calc.rem(i, 4))
|
||||
)
|
||||
vec2.insert(0, vec2.pop())
|
||||
}
|
||||
|
||||
for i in range(16) {
|
||||
let j = bin-to-int(
|
||||
z-fill(
|
||||
str(i, base: 2),
|
||||
4
|
||||
).clusters()
|
||||
.map(int)
|
||||
.rev()
|
||||
)
|
||||
|
||||
vec2.at(0) = _md4-round3(
|
||||
..vec2,
|
||||
block.at(j),
|
||||
_md4-round3-shift.at(calc.rem(i, 4))
|
||||
)
|
||||
vec2.insert(0, vec2.pop())
|
||||
}
|
||||
|
||||
vec = vec.zip(vec2).map(p => {
|
||||
calc.rem(p.sum(), max-32)
|
||||
})
|
||||
}
|
||||
|
||||
let digest-bytes = ()
|
||||
for n in vec {
|
||||
digest-bytes += (
|
||||
n.bit-and(0xff),
|
||||
n.bit-rshift(8).bit-and(0xff),
|
||||
n.bit-rshift(16).bit-and(0xff),
|
||||
n.bit-rshift(24),
|
||||
)
|
||||
}
|
||||
|
||||
return bytes(digest-bytes)
|
||||
}
|
@ -42,15 +42,18 @@
|
||||
/// -> bytes
|
||||
#let sha1(
|
||||
/// Message to hash
|
||||
/// -> str
|
||||
/// -> str | bytes
|
||||
message,
|
||||
/// Initial vector
|
||||
/// -> array
|
||||
iv: sha1-default-iv
|
||||
) = {
|
||||
let message = if type(message) == str {bytes(message)} else {message}
|
||||
assert(type(message) == bytes, message: "message must be a string or bytes, but is " + repr(type(message)))
|
||||
|
||||
// Complete message to multiple of 512 bits
|
||||
let bin-str = ""
|
||||
for char in bytes(message) {
|
||||
for char in message {
|
||||
bin-str += z-fill(str(char, base: 2), 8)
|
||||
}
|
||||
let l = bin-str.len()
|
||||
|
@ -98,3 +98,22 @@
|
||||
let high-bits = x.bit-rshift(32 - n)
|
||||
return x.bit-lshift(n).bit-or(high-bits).bit-and(mask-32)
|
||||
}
|
||||
|
||||
/// Switches the endianness of the given value (32-bit integer)
|
||||
/// -> number
|
||||
#let switch-endianness(
|
||||
/// -> number
|
||||
value
|
||||
) = {
|
||||
let a = value.bit-rshift(24)
|
||||
let b = value.bit-rshift(16).bit-and(0xff)
|
||||
let c = value.bit-rshift(8).bit-and(0xff)
|
||||
let d = value.bit-and(0xff)
|
||||
|
||||
let a2 = d.bit-lshift(24)
|
||||
let b2 = c.bit-lshift(16)
|
||||
let c2 = b.bit-lshift(8)
|
||||
let d2 = a
|
||||
|
||||
return a2.bit-or(b2).bit-or(c2).bit-or(d2)
|
||||
}
|
Loading…
Reference in New Issue
Block a user