added md5 and md4
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								manual.pdf
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								manual.pdf
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -13,6 +13,12 @@ | |||||||
| ) | ) | ||||||
| #tidy.show-module(sha-doc) | #tidy.show-module(sha-doc) | ||||||
|  |  | ||||||
|  | #let md-doc = mod( | ||||||
|  |   read("src/md.typ"), | ||||||
|  |   name: "md" | ||||||
|  | ) | ||||||
|  | #tidy.show-module(md-doc) | ||||||
|  |  | ||||||
| #let misc-doc = mod( | #let misc-doc = mod( | ||||||
|   read("src/misc.typ"), |   read("src/misc.typ"), | ||||||
|   name: "misc" |   name: "misc" | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| #import "misc.typ": * | #import "misc.typ": * | ||||||
| #import "sha.typ" | #import "sha.typ": * | ||||||
|  | #import "md.typ": * | ||||||
| #import "utils.typ": * | #import "utils.typ": * | ||||||
| #import "base.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 | /// -> bytes | ||||||
| #let sha1( | #let sha1( | ||||||
|   /// Message to hash |   /// Message to hash | ||||||
|   /// -> str |   /// -> str | bytes | ||||||
|   message, |   message, | ||||||
|   /// Initial vector |   /// Initial vector | ||||||
|   /// -> array |   /// -> array | ||||||
|   iv: sha1-default-iv |   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 |   // Complete message to multiple of 512 bits | ||||||
|   let bin-str = "" |   let bin-str = "" | ||||||
|   for char in bytes(message) { |   for char in message { | ||||||
|     bin-str += z-fill(str(char, base: 2), 8) |     bin-str += z-fill(str(char, base: 2), 8) | ||||||
|   } |   } | ||||||
|   let l = bin-str.len() |   let l = bin-str.len() | ||||||
|   | |||||||
| @@ -97,4 +97,23 @@ | |||||||
|   } |   } | ||||||
|   let high-bits = x.bit-rshift(32 - n) |   let high-bits = x.bit-rshift(32 - n) | ||||||
|   return x.bit-lshift(n).bit-or(high-bits).bit-and(mask-32) |   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) | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user