md5.nim 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2010 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Module for computing MD5 checksums.
  10. type
  11. MD5State = array[0..3, uint32]
  12. MD5Block = array[0..15, uint32]
  13. MD5CBits = array[0..7, uint8]
  14. MD5Digest* = array[0..15, uint8]
  15. MD5Buffer = array[0..63, uint8]
  16. MD5Context* {.final.} = object
  17. state: MD5State
  18. count: array[0..1, uint32]
  19. buffer: MD5Buffer
  20. const
  21. padding: cstring = "\x80\0\0\0" &
  22. "\0\0\0\0\0\0\0\0" &
  23. "\0\0\0\0\0\0\0\0" &
  24. "\0\0\0\0\0\0\0\0" &
  25. "\0\0\0\0\0\0\0\0" &
  26. "\0\0\0\0\0\0\0\0" &
  27. "\0\0\0\0\0\0\0\0" &
  28. "\0\0\0\0\0\0\0\0" &
  29. "\0\0\0\0"
  30. proc F(x, y, z: uint32): uint32 {.inline.} =
  31. result = (x and y) or ((not x) and z)
  32. proc G(x, y, z: uint32): uint32 {.inline.} =
  33. result = (x and z) or (y and (not z))
  34. proc H(x, y, z: uint32): uint32 {.inline.} =
  35. result = x xor y xor z
  36. proc I(x, y, z: uint32): uint32 {.inline.} =
  37. result = y xor (x or (not z))
  38. proc rot(x: var uint32, n: uint8) {.inline.} =
  39. x = (x shl n) or (x shr (32'u32 - n))
  40. proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  41. a = a + F(b, c, d) + x + ac
  42. rot(a, s)
  43. a = a + b
  44. proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  45. a = a + G(b, c, d) + x + ac
  46. rot(a, s)
  47. a = a + b
  48. proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  49. a = a + H(b, c, d) + x + ac
  50. rot(a, s)
  51. a = a + b
  52. proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  53. a = a + I(b, c, d) + x + ac
  54. rot(a, s)
  55. a = a + b
  56. proc encode(dest: var MD5Block, src: cstring) =
  57. var j = 0
  58. for i in 0..high(dest):
  59. dest[i] = uint32(ord(src[j])) or
  60. uint32(ord(src[j+1])) shl 8 or
  61. uint32(ord(src[j+2])) shl 16 or
  62. uint32(ord(src[j+3])) shl 24
  63. inc(j, 4)
  64. proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
  65. var i = 0
  66. for j in 0..high(src):
  67. dest[i] = uint8(src[j] and 0xff'u32)
  68. dest[i+1] = uint8(src[j] shr 8 and 0xff'u32)
  69. dest[i+2] = uint8(src[j] shr 16 and 0xff'u32)
  70. dest[i+3] = uint8(src[j] shr 24 and 0xff'u32)
  71. inc(i, 4)
  72. proc transform(buffer: pointer, state: var MD5State) =
  73. var
  74. myBlock: MD5Block
  75. encode(myBlock, cast[cstring](buffer))
  76. var a = state[0]
  77. var b = state[1]
  78. var c = state[2]
  79. var d = state[3]
  80. FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
  81. FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
  82. FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
  83. FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
  84. FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
  85. FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
  86. FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
  87. FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
  88. FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
  89. FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
  90. FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
  91. FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
  92. FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
  93. FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
  94. FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
  95. FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
  96. GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
  97. GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
  98. GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
  99. GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
  100. GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
  101. GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
  102. GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
  103. GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
  104. GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
  105. GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
  106. GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
  107. GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
  108. GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
  109. GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
  110. GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
  111. GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
  112. HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
  113. HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
  114. HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
  115. HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
  116. HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
  117. HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
  118. HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
  119. HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
  120. HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
  121. HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
  122. HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
  123. HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
  124. HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
  125. HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
  126. HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
  127. HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
  128. II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
  129. II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
  130. II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
  131. II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
  132. II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
  133. II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
  134. II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
  135. II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
  136. II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
  137. II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
  138. II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
  139. II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
  140. II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
  141. II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
  142. II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
  143. II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
  144. state[0] = state[0] + a
  145. state[1] = state[1] + b
  146. state[2] = state[2] + c
  147. state[3] = state[3] + d
  148. proc md5Init*(c: var MD5Context) =
  149. ## initializes a MD5Context
  150. c.state[0] = 0x67452301'u32
  151. c.state[1] = 0xEFCDAB89'u32
  152. c.state[2] = 0x98BADCFE'u32
  153. c.state[3] = 0x10325476'u32
  154. c.count[0] = 0'u32
  155. c.count[1] = 0'u32
  156. zeroMem(addr(c.buffer), sizeof(MD5buffer))
  157. proc md5Update*(c: var MD5Context, input: cstring, len: int) =
  158. ## updates the MD5Context with the `input` data of length `len`
  159. var input = input
  160. var Index = int((c.count[0] shr 3) and 0x3F)
  161. c.count[0] = c.count[0] + (uint32(len) shl 3)
  162. if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32
  163. c.count[1] = c.count[1] + (uint32(len) shr 29)
  164. var PartLen = 64 - Index
  165. if len >= PartLen:
  166. copyMem(addr(c.buffer[Index]), input, PartLen)
  167. transform(addr(c.buffer), c.state)
  168. var i = PartLen
  169. while i + 63 < len:
  170. transform(addr(input[i]), c.state)
  171. inc(i, 64)
  172. copyMem(addr(c.buffer[0]), addr(input[i]), len-i)
  173. else:
  174. copyMem(addr(c.buffer[Index]), addr(input[0]), len)
  175. proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
  176. ## finishes the MD5Context and stores the result in `digest`
  177. var
  178. Bits: MD5CBits
  179. PadLen: int
  180. decode(Bits, c.count)
  181. var Index = int((c.count[0] shr 3) and 0x3F)
  182. if Index < 56: PadLen = 56 - Index
  183. else: PadLen = 120 - Index
  184. md5Update(c, padding, PadLen)
  185. md5Update(c, cast[cstring](addr(Bits)), 8)
  186. decode(digest, c.state)
  187. zeroMem(addr(c), sizeof(MD5Context))
  188. proc toMD5*(s: string): MD5Digest =
  189. ## computes the MD5Digest value for a string `s`
  190. var c: MD5Context
  191. md5Init(c)
  192. md5Update(c, cstring(s), len(s))
  193. md5Final(c, result)
  194. proc `$`*(d: MD5Digest): string =
  195. ## converts a MD5Digest value into its string representation
  196. const digits = "0123456789abcdef"
  197. result = ""
  198. for i in 0..15:
  199. add(result, digits[(d[i].int shr 4) and 0xF])
  200. add(result, digits[d[i].int and 0xF])
  201. proc getMD5*(s: string): string =
  202. ## computes an MD5 value of `s` and returns its string representation
  203. var
  204. c: MD5Context
  205. d: MD5Digest
  206. md5Init(c)
  207. md5Update(c, cstring(s), len(s))
  208. md5Final(c, d)
  209. result = $d
  210. proc `==`*(D1, D2: MD5Digest): bool =
  211. ## checks if two MD5Digest values are identical
  212. for i in 0..15:
  213. if D1[i] != D2[i]: return false
  214. return true
  215. when isMainModule:
  216. assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
  217. "a3cca2b2aa1e3b5b3b5aad99a8529074")
  218. assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
  219. "7e716d0e702df0505fc72e2b89467910")
  220. assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")