From 226a728e82f73c65db7c8e0dd13b4c7cfe409439 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Sat, 21 Dec 2024 14:17:09 +0100 Subject: [PATCH] initial commit (b32, sha1, hmac) --- manual.pdf | Bin 0 -> 48642 bytes manual.typ | 34 +++++++++++++++ src/base.typ | 62 +++++++++++++++++++++++++++ src/lib.typ | 4 ++ src/misc.typ | 48 +++++++++++++++++++++ src/sha.typ | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils.typ | 100 +++++++++++++++++++++++++++++++++++++++++++ typst.toml | 14 ++++++ 8 files changed, 377 insertions(+) create mode 100644 manual.pdf create mode 100644 manual.typ create mode 100644 src/base.typ create mode 100644 src/lib.typ create mode 100644 src/misc.typ create mode 100644 src/sha.typ create mode 100644 src/utils.typ create mode 100644 typst.toml diff --git a/manual.pdf b/manual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f7ad06ab7e2eb861eff0006ab8a44a8d5258256f GIT binary patch literal 48642 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 Bv9bUF literal 0 HcmV?d00001 diff --git a/manual.typ b/manual.typ new file mode 100644 index 0000000..e052c0a --- /dev/null +++ b/manual.typ @@ -0,0 +1,34 @@ +#import "@preview/tidy:0.4.0" + +#import "src/lib.typ" + +#let mod = tidy.parse-module.with( + scope: (jumble: lib), + preamble: "#import jumble: *;" +) + +#let sha-doc = mod( + read("src/sha.typ"), + name: "sha" +) +#tidy.show-module(sha-doc) + +#let misc-doc = mod( + read("src/misc.typ"), + name: "misc" +) +#tidy.show-module(misc-doc) + +#let base-doc = mod( + read("src/base.typ"), + name: "base" +) +#tidy.show-module(base-doc) + +#pagebreak() + +#let utils-doc = mod( + read("src/utils.typ"), + name: "utils" +) +#tidy.show-module(utils-doc) \ No newline at end of file diff --git a/src/base.typ b/src/base.typ new file mode 100644 index 0000000..8aaedf2 --- /dev/null +++ b/src/base.typ @@ -0,0 +1,62 @@ +#import "utils.typ": z-fill, bin-to-int +#let b32-alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" + +/// Decodes a base32-encoded value +/// #test( +/// `jumble.b32-decode("LFHVKUCJ") == bytes("YOUPI")` +/// ) +/// ```example +/// #str(b32-decode("LFHVKUCJ")) +/// ``` +/// -> bytes +#let b32-decode( + /// -> str + encoded +) = { + let decoded-bin = () + for char in encoded { + if char == "=" { + break + } + let i = b32-alphabet.position(char) + decoded-bin += z-fill(str(i, base: 2), 5).clusters().map(int) + } + decoded-bin = decoded-bin.slice( + 0, + calc.div-euclid(decoded-bin.len(), 8) * 8 + ) + let decoded-bytes = decoded-bin.chunks(8).map(bin-to-int) + return bytes(decoded-bytes) +} + +/// Encodes a value in base32 +/// #test( +/// `jumble.b32-encode(bytes("YOUPI")) == "LFHVKUCJ"` +/// ) +/// ```example +/// #b32-encode(bytes("YOUPI")) +/// ``` +/// -> str +#let b32-encode( + /// -> bytes + decoded +) = { + let encoded = "" + let decoded-bin = array(decoded).map(b => z-fill(str(b, base: 2), 8)).join() + decoded-bin = decoded-bin.clusters().map(int) + let groups = decoded-bin.chunks(40) + for group in groups { + let chars = group.chunks(5) + if chars.last().len() != 5 { + chars.last() += (0,) * (5 - chars.last().len()) + } + let chars = chars.map(bin-to-int) + .map(c => b32-alphabet.at(c)) + encoded += chars.join() + let pad = 8 - chars.len() + if pad != 0 { + encoded += "=" * pad + } + } + return encoded +} \ No newline at end of file diff --git a/src/lib.typ b/src/lib.typ new file mode 100644 index 0000000..2a16f0b --- /dev/null +++ b/src/lib.typ @@ -0,0 +1,4 @@ +#import "misc.typ": * +#import "sha.typ" +#import "utils.typ": * +#import "base.typ": * \ No newline at end of file diff --git a/src/misc.typ b/src/misc.typ new file mode 100644 index 0000000..e38a3c3 --- /dev/null +++ b/src/misc.typ @@ -0,0 +1,48 @@ +#import "utils.typ": xor-bytes +#import "sha.typ": sha1 + +#let _compute-block-sized-key(key, hash-func: sha1, block-size: 64) = { + if key.len() > block-size { + key = hash-func(key) + } + + if key.len() < block-size { + key = bytes((0,) * (block-size - key.len())) + key + } + + return key +} + +/// Hash-based Message Authentication Code +/// ```example +/// #bytes-to-hex(hmac("Key", "Hello World!")) +/// ``` +/// -> bytes +#let hmac( + /// Hashing key + /// -> str | bytes + key, + /// Message to hash + /// -> str | bytes + message, + /// Hashing function + /// -> function + hash-func: sha1, + /// Block size + /// -> number + block-size: 64 +) = { + let key = if type(key) == str {bytes(key)} else {key} + let message = if type(message) == str {bytes(message)} else {message} + assert(type(key) == bytes, message: "key must be a string or bytes, but is " + repr(type(key))) + assert(type(message) == bytes, message: "message must be a string or bytes, but is " + repr(type(message))) + + let block-sized-key = _compute-block-sized-key(key, hash-func: hash-func, block-size: block-size) + + let i-pad = bytes((0x36,) * block-size) + let o-pad = bytes((0x5c,) * block-size) + let i-key-pad = xor-bytes(key, i-pad) + let o-key-pad = xor-bytes(key, o-pad) + + return hash-func(o-key-pad + hash-func(i-key-pad + message)) +} \ No newline at end of file diff --git a/src/sha.typ b/src/sha.typ new file mode 100644 index 0000000..ec09ff4 --- /dev/null +++ b/src/sha.typ @@ -0,0 +1,115 @@ +#import "utils.typ": * + +#let sha1-default-iv = ( + 0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476, + 0xc3d2e1f0 +) + +#let _sha1-const(i) = { + if i < 20 { + return 0x5a827999 + } else if i < 40 { + return 0x6ed9eba1 + } else if i < 60 { + return 0x8f1bbcdc + } else { + return 0xca62c1d6 + } +} + +#let _sha1-func(i, b, c, d) = { + if i < 20 { + return b.bit-and(c).bit-or(b.bit-not().bit-and(mask-32).bit-and(d)) + } else if i < 40 { + return b.bit-xor(c).bit-xor(d) + } else if i < 60 { + let bc = b.bit-and(c) + let bd = b.bit-and(d) + let cd = c.bit-and(d) + return bc.bit-or(bd).bit-or(cd) + } else { + return b.bit-xor(c).bit-xor(d) + } +} + +/// Secure Hash Algorithm 1 +/// ```example +/// #bytes-to-hex(sha1("Hello World!")) +/// ``` +/// -> bytes +#let sha1( + /// Message to hash + /// -> str + message, + /// Initial vector + /// -> array + iv: sha1-default-iv +) = { + // Complete message to multiple of 512 bits + let bin-str = "" + for char in bytes(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 + } + bin-str += z-fill(str(l, base: 2), 64) + let bin = bin-str.clusters().map(int) + + // Split into blocks of 16 32-bit words + let words = bin.chunks(32).map(bin-to-int) + let blocks = words.chunks(16) + + let vec = iv + + for block in blocks { + // Expand + for i in range(16, 80) { + let chosen-words = ( + block.at(i - 3), + block.at(i - 8), + block.at(i - 14), + block.at(i - 16) + ) + let word = circular-shift( + chosen-words.fold(0, (a, b) => a.bit-xor(b)) + ) + block.push(word) + } + + // Compress + let (A, B, C, D, E) = vec + for i in range(80) { + let temp = ( + circular-shift(A, n: 5) + + _sha1-func(i, B, C, D) + + E + + block.at(i) + + _sha1-const(i) + ) + temp = calc.rem(temp, max-32) + (A, B, C, D, E) = (temp, A, circular-shift(B, n: 30), C, D) + } + vec = vec.zip((A, B, C, D, E)).map(p => { + calc.rem(p.sum(), max-32) + }) + } + + let digest-bytes = () + for n in vec { + digest-bytes += ( + n.bit-rshift(24), + n.bit-rshift(16).bit-and(0xff), + n.bit-rshift(8).bit-and(0xff), + n.bit-and(0xff) + ) + } + + return bytes(digest-bytes) +} \ No newline at end of file diff --git a/src/utils.typ b/src/utils.typ new file mode 100644 index 0000000..3b7cd2f --- /dev/null +++ b/src/utils.typ @@ -0,0 +1,100 @@ +/// Applies the XOR operation between two byte arrays +/// ```example +/// #let a = bytes((0b010, 0b0111)) +/// #let b = bytes((0b011, 0b0101)) +/// #array(xor-bytes(a, b)).map( +/// b => z-fill(str(b, base: 2), 3) +/// ) +/// ``` +/// -> bytes +#let xor-bytes( + /// First byte array + /// -> bytes + bytes-a, + /// Second byte array + /// -> bytes + bytes-b +) = { + let length = calc.max(bytes-a.len(), bytes-b.len()) + let bytes-c = () + for i in range(length) { + bytes-c.push( + bytes-a.at(i, default: 0).bit-xor(bytes-b.at(i, default: 0)) + ) + } + return bytes(bytes-c) +} + +/// Pads a string with 0s on the left to reach a certain length +/// ```example +/// #z-fill("1011", 8) +/// ``` +/// -> str +#let z-fill( + /// -> str + string, + /// -> number + length +) = { + return "0" * (length - string.len()) + string +} + +/// Converts a byte array to a hexadecimal string +/// ```example +/// #let b = bytes((0xfa, 0xca, 0xde)) +/// #bytes-to-hex(b) +/// ``` +/// -> str +#let bytes-to-hex( + /// -> bytes + bytes +) = { + let res = "" + for byte in bytes { + res += z-fill(str(byte, base: 16), 2) + } + return res +} + +/// Converts an array of bits into an integer +/// ```example +/// #let bits = (0, 0, 1, 0, 1, 0, 1, 0) +/// #bin-to-int(bits) +/// ``` +/// -> number +#let bin-to-int( + /// Bit array + /// -> array + bin +) = { + return bin.fold( + 0, + (v, b) => v.bit-lshift(1).bit-or(b) + ) +} + +#let max-32 = 1.bit-lshift(32) +#let mask-32 = max-32 - 1 + +/// Rotates a number to the left (wrapping the leftmost bits to the right) +/// ```example +/// #let a = 42 +/// #let b = circular-shift(a, n: 20) +/// #let c = circular-shift(b, n: 11) +/// #b, #c +/// ``` +/// -> number +#let circular-shift( + /// Number to rotate + /// -> number + x, + /// Shift amount + /// -> number + n: 1 +) = { + if n < 0 { + return circular-shift(x, n: 32 + n) + } + let high-bits = x.bit-rshift(32 - n) + return x.bit-lshift(n).bit-or(high-bits).bit-and(mask-32) +} \ No newline at end of file diff --git a/typst.toml b/typst.toml new file mode 100644 index 0000000..131d1e2 --- /dev/null +++ b/typst.toml @@ -0,0 +1,14 @@ +[package] +name = "jumble" +version = "0.0.1" +compiler = "0.12.0" +repository = "https://git.kb28.ch/HEL/jumble" +entrypoint = "src/lib.typ" +authors = [ + "Louis Heredero " +] +categories = ["scripting", "utility"] +license = "Apache-2.0" +description = "A package to hash " +keywords = ["hash", "algorithm", "cryptography", "md5", "sha1"] +exclude = [ "gallery", "gallery.bash", "docs" ] \ No newline at end of file