MD5.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright (c) 2020, Ali Mohammad Pur <ali.mpfard@gmail.com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/Types.h>
  27. #include <LibCrypto/Hash/MD5.h>
  28. static constexpr inline u32 F(u32 x, u32 y, u32 z) { return (x & y) | ((~x) & z); };
  29. static constexpr inline u32 G(u32 x, u32 y, u32 z) { return (x & z) | ((~z) & y); };
  30. static constexpr inline u32 H(u32 x, u32 y, u32 z) { return x ^ y ^ z; };
  31. static constexpr inline u32 I(u32 x, u32 y, u32 z) { return y ^ (x | ~z); };
  32. static constexpr inline u32 ROTATE_LEFT(u32 x, size_t n)
  33. {
  34. return (x << n) | (x >> (32 - n));
  35. }
  36. static constexpr inline void round_1(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  37. {
  38. a += F(b, c, d) + x + ac;
  39. a = ROTATE_LEFT(a, s);
  40. a += b;
  41. }
  42. static constexpr inline void round_2(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  43. {
  44. a += G(b, c, d) + x + ac;
  45. a = ROTATE_LEFT(a, s);
  46. a += b;
  47. }
  48. static constexpr inline void round_3(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  49. {
  50. a += H(b, c, d) + x + ac;
  51. a = ROTATE_LEFT(a, s);
  52. a += b;
  53. }
  54. static constexpr inline void round_4(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  55. {
  56. a += I(b, c, d) + x + ac;
  57. a = ROTATE_LEFT(a, s);
  58. a += b;
  59. }
  60. namespace Crypto {
  61. namespace Hash {
  62. void MD5::update(const u8* input, size_t length)
  63. {
  64. auto index = (u32)(m_count[0] >> 3) & 0x3f;
  65. size_t offset { 0 };
  66. m_count[0] += (u32)length << 3;
  67. if (m_count[0] < ((u32)length << 3)) {
  68. ++m_count[1];
  69. }
  70. m_count[1] += (u32)length >> 29;
  71. auto part_length = 64 - index;
  72. if (length >= part_length) {
  73. m_buffer.overwrite(index, input, part_length);
  74. transform(m_buffer.data());
  75. for (offset = part_length; offset + 63 < length; offset += 64)
  76. transform(&input[offset]);
  77. index = 0;
  78. }
  79. ASSERT(length < part_length || length - offset <= 64);
  80. m_buffer.overwrite(index, &input[offset], length - offset);
  81. }
  82. MD5::DigestType MD5::digest()
  83. {
  84. DigestType digest;
  85. u8 bits[8];
  86. encode(m_count, bits, 8);
  87. // pad the data to 56%64
  88. u32 index = (u32)((m_count[0] >> 3) & 0x3f);
  89. u32 pad_length = index < 56 ? 56 - index : 120 - index;
  90. update(MD5Constants::PADDING, pad_length);
  91. // append length
  92. update(bits, 8);
  93. // store state (4 registers ABCD)
  94. encode(&m_A, digest.data, 4 * sizeof(m_A));
  95. reset();
  96. return digest;
  97. }
  98. void MD5::encode(const u32* from, u8* to, size_t length)
  99. {
  100. for (size_t i = 0, j = 0; j < length; ++i, j += 4) {
  101. to[j] = (u8)(from[i] & 0xff);
  102. to[j + 1] = (u8)((from[i] >> 8) & 0xff);
  103. to[j + 2] = (u8)((from[i] >> 16) & 0xff);
  104. to[j + 3] = (u8)((from[i] >> 24) & 0xff);
  105. }
  106. }
  107. void MD5::decode(const u8* from, u32* to, size_t length)
  108. {
  109. for (size_t i = 0, j = 0; j < length; ++i, j += 4)
  110. to[i] = (((u32)from[j]) | (((u32)from[j + 1]) << 8) | (((u32)from[j + 2]) << 16) | (((u32)from[j + 3]) << 24));
  111. }
  112. void MD5::transform(const u8* block)
  113. {
  114. auto a = m_A;
  115. auto b = m_B;
  116. auto c = m_C;
  117. auto d = m_D;
  118. u32 x[16];
  119. decode(block, x, 64);
  120. round_1(a, b, c, d, x[0], MD5Constants::S11, 0xd76aa478); // 1
  121. round_1(d, a, b, c, x[1], MD5Constants::S12, 0xe8c7b756); // 2
  122. round_1(c, d, a, b, x[2], MD5Constants::S13, 0x242070db); // 3
  123. round_1(b, c, d, a, x[3], MD5Constants::S14, 0xc1bdceee); // 4
  124. round_1(a, b, c, d, x[4], MD5Constants::S11, 0xf57c0faf); // 5
  125. round_1(d, a, b, c, x[5], MD5Constants::S12, 0x4787c62a); // 6
  126. round_1(c, d, a, b, x[6], MD5Constants::S13, 0xa8304613); // 7
  127. round_1(b, c, d, a, x[7], MD5Constants::S14, 0xfd469501); // 8
  128. round_1(a, b, c, d, x[8], MD5Constants::S11, 0x698098d8); // 9
  129. round_1(d, a, b, c, x[9], MD5Constants::S12, 0x8b44f7af); // 10
  130. round_1(c, d, a, b, x[10], MD5Constants::S13, 0xffff5bb1); // 11
  131. round_1(b, c, d, a, x[11], MD5Constants::S14, 0x895cd7be); // 12
  132. round_1(a, b, c, d, x[12], MD5Constants::S11, 0x6b901122); // 13
  133. round_1(d, a, b, c, x[13], MD5Constants::S12, 0xfd987193); // 14
  134. round_1(c, d, a, b, x[14], MD5Constants::S13, 0xa679438e); // 15
  135. round_1(b, c, d, a, x[15], MD5Constants::S14, 0x49b40821); // 16
  136. round_2(a, b, c, d, x[1], MD5Constants::S21, 0xf61e2562); // 17
  137. round_2(d, a, b, c, x[6], MD5Constants::S22, 0xc040b340); // 18
  138. round_2(c, d, a, b, x[11], MD5Constants::S23, 0x265e5a51); // 19
  139. round_2(b, c, d, a, x[0], MD5Constants::S24, 0xe9b6c7aa); // 20
  140. round_2(a, b, c, d, x[5], MD5Constants::S21, 0xd62f105d); // 21
  141. round_2(d, a, b, c, x[10], MD5Constants::S22, 0x2441453); // 22
  142. round_2(c, d, a, b, x[15], MD5Constants::S23, 0xd8a1e681); // 23
  143. round_2(b, c, d, a, x[4], MD5Constants::S24, 0xe7d3fbc8); // 24
  144. round_2(a, b, c, d, x[9], MD5Constants::S21, 0x21e1cde6); // 25
  145. round_2(d, a, b, c, x[14], MD5Constants::S22, 0xc33707d6); // 26
  146. round_2(c, d, a, b, x[3], MD5Constants::S23, 0xf4d50d87); // 27
  147. round_2(b, c, d, a, x[8], MD5Constants::S24, 0x455a14ed); // 28
  148. round_2(a, b, c, d, x[13], MD5Constants::S21, 0xa9e3e905); // 29
  149. round_2(d, a, b, c, x[2], MD5Constants::S22, 0xfcefa3f8); // 30
  150. round_2(c, d, a, b, x[7], MD5Constants::S23, 0x676f02d9); // 31
  151. round_2(b, c, d, a, x[12], MD5Constants::S24, 0x8d2a4c8a); // 32
  152. round_3(a, b, c, d, x[5], MD5Constants::S31, 0xfffa3942); // 33
  153. round_3(d, a, b, c, x[8], MD5Constants::S32, 0x8771f681); // 34
  154. round_3(c, d, a, b, x[11], MD5Constants::S33, 0x6d9d6122); // 35
  155. round_3(b, c, d, a, x[14], MD5Constants::S34, 0xfde5380c); // 36
  156. round_3(a, b, c, d, x[1], MD5Constants::S31, 0xa4beea44); // 37
  157. round_3(d, a, b, c, x[4], MD5Constants::S32, 0x4bdecfa9); // 38
  158. round_3(c, d, a, b, x[7], MD5Constants::S33, 0xf6bb4b60); // 39
  159. round_3(b, c, d, a, x[10], MD5Constants::S34, 0xbebfbc70); // 40
  160. round_3(a, b, c, d, x[13], MD5Constants::S31, 0x289b7ec6); // 41
  161. round_3(d, a, b, c, x[0], MD5Constants::S32, 0xeaa127fa); // 42
  162. round_3(c, d, a, b, x[3], MD5Constants::S33, 0xd4ef3085); // 43
  163. round_3(b, c, d, a, x[6], MD5Constants::S34, 0x4881d05); // 44
  164. round_3(a, b, c, d, x[9], MD5Constants::S31, 0xd9d4d039); // 45
  165. round_3(d, a, b, c, x[12], MD5Constants::S32, 0xe6db99e5); // 46
  166. round_3(c, d, a, b, x[15], MD5Constants::S33, 0x1fa27cf8); // 47
  167. round_3(b, c, d, a, x[2], MD5Constants::S34, 0xc4ac5665); // 48
  168. round_4(a, b, c, d, x[0], MD5Constants::S41, 0xf4292244); // 49
  169. round_4(d, a, b, c, x[7], MD5Constants::S42, 0x432aff97); // 50
  170. round_4(c, d, a, b, x[14], MD5Constants::S43, 0xab9423a7); // 51
  171. round_4(b, c, d, a, x[5], MD5Constants::S44, 0xfc93a039); // 52
  172. round_4(a, b, c, d, x[12], MD5Constants::S41, 0x655b59c3); // 53
  173. round_4(d, a, b, c, x[3], MD5Constants::S42, 0x8f0ccc92); // 54
  174. round_4(c, d, a, b, x[10], MD5Constants::S43, 0xffeff47d); // 55
  175. round_4(b, c, d, a, x[1], MD5Constants::S44, 0x85845dd1); // 56
  176. round_4(a, b, c, d, x[8], MD5Constants::S41, 0x6fa87e4f); // 57
  177. round_4(d, a, b, c, x[15], MD5Constants::S42, 0xfe2ce6e0); // 58
  178. round_4(c, d, a, b, x[6], MD5Constants::S43, 0xa3014314); // 59
  179. round_4(b, c, d, a, x[13], MD5Constants::S44, 0x4e0811a1); // 60
  180. round_4(a, b, c, d, x[4], MD5Constants::S41, 0xf7537e82); // 61
  181. round_4(d, a, b, c, x[11], MD5Constants::S42, 0xbd3af235); // 62
  182. round_4(c, d, a, b, x[2], MD5Constants::S43, 0x2ad7d2bb); // 63
  183. round_4(b, c, d, a, x[9], MD5Constants::S44, 0xeb86d391); // 64
  184. m_A += a;
  185. m_B += b;
  186. m_C += c;
  187. m_D += d;
  188. __builtin_memset(x, 0, sizeof(x));
  189. }
  190. void MD5::reset()
  191. {
  192. m_A = MD5Constants::init_A;
  193. m_B = MD5Constants::init_B;
  194. m_C = MD5Constants::init_C;
  195. m_D = MD5Constants::init_D;
  196. m_count[0] = 0;
  197. m_count[1] = 0;
  198. __builtin_memset(m_data_buffer, 0, sizeof(m_data_buffer));
  199. }
  200. }
  201. }