md5.nim 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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](https://en.wikipedia.org/wiki/MD5).
  10. ##
  11. ## This module also works at compile time and in JavaScript.
  12. ##
  13. ## See also
  14. ## ========
  15. ## * `base64 module<base64.html>`_ for a Base64 encoder and decoder
  16. ## * `sha1 module <sha1.html>`_ for the SHA-1 checksum algorithm
  17. ## * `hashes module<hashes.html>`_ for efficient computations of hash values
  18. ## for diverse Nim types
  19. {.deprecated: "use command `nimble install checksums` and import `checksums/md5` instead".}
  20. when defined(nimHasStyleChecks):
  21. {.push styleChecks: off.}
  22. type
  23. MD5State = array[0..3, uint32]
  24. MD5Block = array[0..15, uint32]
  25. MD5CBits = array[0..7, uint8]
  26. MD5Digest* = array[0..15, uint8]
  27. ## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_.
  28. MD5Buffer = array[0..63, uint8]
  29. MD5Context* {.final.} = object
  30. state: MD5State
  31. count: array[0..1, uint32]
  32. buffer: MD5Buffer
  33. const
  34. padding: array[0..63, uint8] = [
  35. 0x80'u8, 0, 0, 0, 0, 0, 0, 0,
  36. 0, 0, 0, 0, 0, 0, 0, 0,
  37. 0, 0, 0, 0, 0, 0, 0, 0,
  38. 0, 0, 0, 0, 0, 0, 0, 0,
  39. 0, 0, 0, 0, 0, 0, 0, 0,
  40. 0, 0, 0, 0, 0, 0, 0, 0,
  41. 0, 0, 0, 0, 0, 0, 0, 0,
  42. 0, 0, 0, 0, 0, 0, 0, 0
  43. ]
  44. proc F(x, y, z: uint32): uint32 {.inline.} =
  45. result = (x and y) or ((not x) and z)
  46. proc G(x, y, z: uint32): uint32 {.inline.} =
  47. result = (x and z) or (y and (not z))
  48. proc H(x, y, z: uint32): uint32 {.inline.} =
  49. result = x xor y xor z
  50. proc I(x, y, z: uint32): uint32 {.inline.} =
  51. result = y xor (x or (not z))
  52. proc rot(x: var uint32, n: uint8) {.inline.} =
  53. x = (x shl n) or (x shr (32'u32 - n))
  54. proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  55. a = a + F(b, c, d) + x + ac
  56. rot(a, s)
  57. a = a + b
  58. proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  59. a = a + G(b, c, d) + x + ac
  60. rot(a, s)
  61. a = a + b
  62. proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  63. a = a + H(b, c, d) + x + ac
  64. rot(a, s)
  65. a = a + b
  66. proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
  67. a = a + I(b, c, d) + x + ac
  68. rot(a, s)
  69. a = a + b
  70. proc encode(dest: var MD5Block, src: openArray[uint8]) =
  71. var j = 0
  72. for i in 0..high(dest):
  73. dest[i] = uint32(ord(src[j])) or
  74. uint32(ord(src[j+1])) shl 8 or
  75. uint32(ord(src[j+2])) shl 16 or
  76. uint32(ord(src[j+3])) shl 24
  77. inc(j, 4)
  78. proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
  79. var i = 0
  80. for j in 0..high(src):
  81. dest[i] = uint8(src[j] and 0xff'u32)
  82. dest[i+1] = uint8(src[j] shr 8 and 0xff'u32)
  83. dest[i+2] = uint8(src[j] shr 16 and 0xff'u32)
  84. dest[i+3] = uint8(src[j] shr 24 and 0xff'u32)
  85. inc(i, 4)
  86. template slice(s: string, a, b): openArray[uint8] =
  87. when nimvm:
  88. # toOpenArray is not implemented in VM
  89. var s2 = newSeq[uint8](s.len)
  90. for i in 0 ..< s2.len:
  91. s2[i] = uint8(s[i])
  92. s2
  93. else:
  94. s.toOpenArrayByte(a, b)
  95. template slice(s: cstring, a, b): openArray[uint8] =
  96. when nimvm:
  97. # toOpenArray is not implemented in VM
  98. slice($s, a, b)
  99. else:
  100. when defined(js):
  101. # toOpenArrayByte for cstring is not implemented in JS
  102. slice($s, a, b)
  103. else:
  104. s.toOpenArrayByte(a, b)
  105. template slice(s: openArray[uint8], a, b): openArray[uint8] =
  106. when nimvm:
  107. s[a .. b]
  108. else:
  109. s.toOpenArray(a, b)
  110. const useMem = declared(copyMem)
  111. template memOrNot(withMem, withoutMem): untyped =
  112. when nimvm:
  113. withoutMem
  114. else:
  115. when useMem:
  116. withMem
  117. else:
  118. withoutMem
  119. proc transform(buffer: openArray[uint8], state: var MD5State) =
  120. var
  121. myBlock: MD5Block
  122. encode(myBlock, buffer)
  123. var a = state[0]
  124. var b = state[1]
  125. var c = state[2]
  126. var d = state[3]
  127. FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
  128. FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
  129. FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
  130. FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
  131. FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
  132. FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
  133. FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
  134. FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
  135. FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
  136. FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
  137. FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
  138. FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
  139. FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
  140. FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
  141. FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
  142. FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
  143. GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
  144. GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
  145. GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
  146. GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
  147. GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
  148. GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
  149. GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
  150. GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
  151. GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
  152. GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
  153. GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
  154. GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
  155. GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
  156. GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
  157. GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
  158. GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
  159. HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
  160. HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
  161. HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
  162. HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
  163. HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
  164. HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
  165. HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
  166. HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
  167. HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
  168. HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
  169. HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
  170. HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
  171. HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
  172. HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
  173. HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
  174. HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
  175. II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
  176. II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
  177. II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
  178. II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
  179. II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
  180. II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
  181. II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
  182. II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
  183. II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
  184. II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
  185. II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
  186. II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
  187. II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
  188. II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
  189. II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
  190. II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
  191. state[0] = state[0] + a
  192. state[1] = state[1] + b
  193. state[2] = state[2] + c
  194. state[3] = state[3] + d
  195. proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.}
  196. proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [],
  197. tags: [], gcsafe.}
  198. proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], gcsafe.}
  199. proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [],
  200. tags: [], gcsafe.} =
  201. ## Updates the `MD5Context` with the `input` data of length `len`.
  202. ##
  203. ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
  204. ## function explicitly.
  205. md5Update(c, input.slice(0, len - 1))
  206. proc toMD5*(s: string): MD5Digest =
  207. ## Computes the `MD5Digest` value for a string `s`.
  208. ##
  209. ## **See also:**
  210. ## * `getMD5 proc <#getMD5,string>`_ which returns a string representation
  211. ## of the `MD5Digest`
  212. ## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string
  213. runnableExamples:
  214. assert $toMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
  215. var c: MD5Context
  216. md5Init(c)
  217. md5Update(c, s.slice(0, s.len - 1))
  218. md5Final(c, result)
  219. proc `$`*(d: MD5Digest): string =
  220. ## Converts a `MD5Digest` value into its string representation.
  221. const digits = "0123456789abcdef"
  222. result = ""
  223. for i in 0..15:
  224. add(result, digits[(d[i].int shr 4) and 0xF])
  225. add(result, digits[d[i].int and 0xF])
  226. proc getMD5*(s: string): string =
  227. ## Computes an MD5 value of `s` and returns its string representation.
  228. ##
  229. ## **See also:**
  230. ## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string
  231. runnableExamples:
  232. assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
  233. var
  234. c: MD5Context
  235. d: MD5Digest
  236. md5Init(c)
  237. md5Update(c, s.slice(0, s.len - 1))
  238. md5Final(c, d)
  239. result = $d
  240. proc `==`*(D1, D2: MD5Digest): bool =
  241. ## Checks if two `MD5Digest` values are identical.
  242. for i in 0..15:
  243. if D1[i] != D2[i]: return false
  244. return true
  245. proc clearBuffer(c: var MD5Context) {.inline.} =
  246. memOrNot:
  247. zeroMem(addr(c.buffer), sizeof(MD5Buffer))
  248. do:
  249. reset(c.buffer)
  250. proc md5Init*(c: var MD5Context) =
  251. ## Initializes an `MD5Context`.
  252. ##
  253. ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
  254. ## function explicitly.
  255. c.state[0] = 0x67452301'u32
  256. c.state[1] = 0xEFCDAB89'u32
  257. c.state[2] = 0x98BADCFE'u32
  258. c.state[3] = 0x10325476'u32
  259. c.count[0] = 0'u32
  260. c.count[1] = 0'u32
  261. clearBuffer(c)
  262. proc writeBuffer(c: var MD5Context, index: int,
  263. input: openArray[uint8], inputIndex, len: int) {.inline.} =
  264. memOrNot:
  265. copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len)
  266. do:
  267. # cannot use system.`[]=` for arrays and openarrays as
  268. # it can raise RangeDefect which gets tracked
  269. for i in 0..<len:
  270. c.buffer[index + i] = input[inputIndex + i]
  271. proc md5Update*(c: var MD5Context, input: openArray[uint8]) =
  272. ## Updates the `MD5Context` with the `input` data.
  273. ##
  274. ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
  275. ## function explicitly.
  276. var Index = int((c.count[0] shr 3) and 0x3F)
  277. c.count[0] = c.count[0] + (uint32(input.len) shl 3)
  278. if c.count[0] < (uint32(input.len) shl 3): c.count[1] = c.count[1] + 1'u32
  279. c.count[1] = c.count[1] + (uint32(input.len) shr 29)
  280. var PartLen = 64 - Index
  281. if input.len >= PartLen:
  282. writeBuffer(c, Index, input, 0, PartLen)
  283. transform(c.buffer, c.state)
  284. var i = PartLen
  285. while i + 63 < input.len:
  286. transform(input.slice(i, i + 63), c.state)
  287. inc(i, 64)
  288. if i < input.len:
  289. writeBuffer(c, 0, input, i, input.len - i)
  290. elif input.len > 0:
  291. writeBuffer(c, Index, input, 0, input.len)
  292. proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
  293. ## Finishes the `MD5Context` and stores the result in `digest`.
  294. ##
  295. ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
  296. ## function explicitly.
  297. var
  298. Bits: MD5CBits
  299. PadLen: int
  300. decode(Bits, c.count)
  301. var Index = int((c.count[0] shr 3) and 0x3F)
  302. if Index < 56: PadLen = 56 - Index
  303. else: PadLen = 120 - Index
  304. md5Update(c, padding.slice(0, PadLen - 1))
  305. md5Update(c, Bits)
  306. decode(digest, c.state)
  307. clearBuffer(c)
  308. when defined(nimHasStyleChecks):
  309. {.pop.} #{.push styleChecks: off.}