MD5.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Memory.h>
  7. #include <AK/Types.h>
  8. #include <LibCrypto/Hash/MD5.h>
  9. static constexpr u32 F(u32 x, u32 y, u32 z) { return (x & y) | ((~x) & z); }
  10. static constexpr u32 G(u32 x, u32 y, u32 z) { return (x & z) | ((~z) & y); }
  11. static constexpr u32 H(u32 x, u32 y, u32 z) { return x ^ y ^ z; }
  12. static constexpr u32 I(u32 x, u32 y, u32 z) { return y ^ (x | ~z); }
  13. static constexpr u32 ROTATE_LEFT(u32 x, size_t n)
  14. {
  15. return (x << n) | (x >> (32 - n));
  16. }
  17. static constexpr void round_1(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  18. {
  19. a += F(b, c, d) + x + ac;
  20. a = ROTATE_LEFT(a, s);
  21. a += b;
  22. }
  23. static constexpr void round_2(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  24. {
  25. a += G(b, c, d) + x + ac;
  26. a = ROTATE_LEFT(a, s);
  27. a += b;
  28. }
  29. static constexpr void round_3(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  30. {
  31. a += H(b, c, d) + x + ac;
  32. a = ROTATE_LEFT(a, s);
  33. a += b;
  34. }
  35. static constexpr void round_4(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 ac)
  36. {
  37. a += I(b, c, d) + x + ac;
  38. a = ROTATE_LEFT(a, s);
  39. a += b;
  40. }
  41. namespace Crypto::Hash {
  42. void MD5::update(u8 const* input, size_t length)
  43. {
  44. auto index = (u32)(m_count[0] >> 3) & 0x3f;
  45. size_t offset { 0 };
  46. m_count[0] += (u32)length << 3;
  47. if (m_count[0] < ((u32)length << 3)) {
  48. ++m_count[1];
  49. }
  50. m_count[1] += (u32)length >> 29;
  51. auto part_length = 64 - index;
  52. auto buffer = Bytes { m_data_buffer, sizeof(m_data_buffer) };
  53. if (length >= part_length) {
  54. buffer.overwrite(index, input, part_length);
  55. transform(buffer.data());
  56. for (offset = part_length; offset + 63 < length; offset += 64)
  57. transform(&input[offset]);
  58. index = 0;
  59. }
  60. VERIFY(length < part_length || length - offset <= 64);
  61. buffer.overwrite(index, &input[offset], length - offset);
  62. }
  63. MD5::DigestType MD5::digest()
  64. {
  65. auto digest = peek();
  66. reset();
  67. return digest;
  68. }
  69. MD5::DigestType MD5::peek()
  70. {
  71. DigestType digest;
  72. u8 bits[8];
  73. encode(m_count, bits, 8);
  74. // pad the data to 56%64
  75. u32 index = (u32)((m_count[0] >> 3) & 0x3f);
  76. u32 pad_length = index < 56 ? 56 - index : 120 - index;
  77. update(MD5Constants::PADDING, pad_length);
  78. // append length
  79. update(bits, 8);
  80. // store state (4 registers ABCD)
  81. encode(&m_A, digest.data, 4 * sizeof(m_A));
  82. return digest;
  83. }
  84. void MD5::encode(u32 const* from, u8* to, size_t length)
  85. {
  86. for (size_t i = 0, j = 0; j < length; ++i, j += 4) {
  87. to[j] = (u8)(from[i] & 0xff);
  88. to[j + 1] = (u8)((from[i] >> 8) & 0xff);
  89. to[j + 2] = (u8)((from[i] >> 16) & 0xff);
  90. to[j + 3] = (u8)((from[i] >> 24) & 0xff);
  91. }
  92. }
  93. void MD5::decode(u8 const* from, u32* to, size_t length)
  94. {
  95. for (size_t i = 0, j = 0; j < length; ++i, j += 4)
  96. to[i] = (((u32)from[j]) | (((u32)from[j + 1]) << 8) | (((u32)from[j + 2]) << 16) | (((u32)from[j + 3]) << 24));
  97. }
  98. void MD5::transform(u8 const* block)
  99. {
  100. auto a = m_A;
  101. auto b = m_B;
  102. auto c = m_C;
  103. auto d = m_D;
  104. u32 x[16];
  105. decode(block, x, 64);
  106. round_1(a, b, c, d, x[0], MD5Constants::S11, 0xd76aa478); // 1
  107. round_1(d, a, b, c, x[1], MD5Constants::S12, 0xe8c7b756); // 2
  108. round_1(c, d, a, b, x[2], MD5Constants::S13, 0x242070db); // 3
  109. round_1(b, c, d, a, x[3], MD5Constants::S14, 0xc1bdceee); // 4
  110. round_1(a, b, c, d, x[4], MD5Constants::S11, 0xf57c0faf); // 5
  111. round_1(d, a, b, c, x[5], MD5Constants::S12, 0x4787c62a); // 6
  112. round_1(c, d, a, b, x[6], MD5Constants::S13, 0xa8304613); // 7
  113. round_1(b, c, d, a, x[7], MD5Constants::S14, 0xfd469501); // 8
  114. round_1(a, b, c, d, x[8], MD5Constants::S11, 0x698098d8); // 9
  115. round_1(d, a, b, c, x[9], MD5Constants::S12, 0x8b44f7af); // 10
  116. round_1(c, d, a, b, x[10], MD5Constants::S13, 0xffff5bb1); // 11
  117. round_1(b, c, d, a, x[11], MD5Constants::S14, 0x895cd7be); // 12
  118. round_1(a, b, c, d, x[12], MD5Constants::S11, 0x6b901122); // 13
  119. round_1(d, a, b, c, x[13], MD5Constants::S12, 0xfd987193); // 14
  120. round_1(c, d, a, b, x[14], MD5Constants::S13, 0xa679438e); // 15
  121. round_1(b, c, d, a, x[15], MD5Constants::S14, 0x49b40821); // 16
  122. round_2(a, b, c, d, x[1], MD5Constants::S21, 0xf61e2562); // 17
  123. round_2(d, a, b, c, x[6], MD5Constants::S22, 0xc040b340); // 18
  124. round_2(c, d, a, b, x[11], MD5Constants::S23, 0x265e5a51); // 19
  125. round_2(b, c, d, a, x[0], MD5Constants::S24, 0xe9b6c7aa); // 20
  126. round_2(a, b, c, d, x[5], MD5Constants::S21, 0xd62f105d); // 21
  127. round_2(d, a, b, c, x[10], MD5Constants::S22, 0x2441453); // 22
  128. round_2(c, d, a, b, x[15], MD5Constants::S23, 0xd8a1e681); // 23
  129. round_2(b, c, d, a, x[4], MD5Constants::S24, 0xe7d3fbc8); // 24
  130. round_2(a, b, c, d, x[9], MD5Constants::S21, 0x21e1cde6); // 25
  131. round_2(d, a, b, c, x[14], MD5Constants::S22, 0xc33707d6); // 26
  132. round_2(c, d, a, b, x[3], MD5Constants::S23, 0xf4d50d87); // 27
  133. round_2(b, c, d, a, x[8], MD5Constants::S24, 0x455a14ed); // 28
  134. round_2(a, b, c, d, x[13], MD5Constants::S21, 0xa9e3e905); // 29
  135. round_2(d, a, b, c, x[2], MD5Constants::S22, 0xfcefa3f8); // 30
  136. round_2(c, d, a, b, x[7], MD5Constants::S23, 0x676f02d9); // 31
  137. round_2(b, c, d, a, x[12], MD5Constants::S24, 0x8d2a4c8a); // 32
  138. round_3(a, b, c, d, x[5], MD5Constants::S31, 0xfffa3942); // 33
  139. round_3(d, a, b, c, x[8], MD5Constants::S32, 0x8771f681); // 34
  140. round_3(c, d, a, b, x[11], MD5Constants::S33, 0x6d9d6122); // 35
  141. round_3(b, c, d, a, x[14], MD5Constants::S34, 0xfde5380c); // 36
  142. round_3(a, b, c, d, x[1], MD5Constants::S31, 0xa4beea44); // 37
  143. round_3(d, a, b, c, x[4], MD5Constants::S32, 0x4bdecfa9); // 38
  144. round_3(c, d, a, b, x[7], MD5Constants::S33, 0xf6bb4b60); // 39
  145. round_3(b, c, d, a, x[10], MD5Constants::S34, 0xbebfbc70); // 40
  146. round_3(a, b, c, d, x[13], MD5Constants::S31, 0x289b7ec6); // 41
  147. round_3(d, a, b, c, x[0], MD5Constants::S32, 0xeaa127fa); // 42
  148. round_3(c, d, a, b, x[3], MD5Constants::S33, 0xd4ef3085); // 43
  149. round_3(b, c, d, a, x[6], MD5Constants::S34, 0x4881d05); // 44
  150. round_3(a, b, c, d, x[9], MD5Constants::S31, 0xd9d4d039); // 45
  151. round_3(d, a, b, c, x[12], MD5Constants::S32, 0xe6db99e5); // 46
  152. round_3(c, d, a, b, x[15], MD5Constants::S33, 0x1fa27cf8); // 47
  153. round_3(b, c, d, a, x[2], MD5Constants::S34, 0xc4ac5665); // 48
  154. round_4(a, b, c, d, x[0], MD5Constants::S41, 0xf4292244); // 49
  155. round_4(d, a, b, c, x[7], MD5Constants::S42, 0x432aff97); // 50
  156. round_4(c, d, a, b, x[14], MD5Constants::S43, 0xab9423a7); // 51
  157. round_4(b, c, d, a, x[5], MD5Constants::S44, 0xfc93a039); // 52
  158. round_4(a, b, c, d, x[12], MD5Constants::S41, 0x655b59c3); // 53
  159. round_4(d, a, b, c, x[3], MD5Constants::S42, 0x8f0ccc92); // 54
  160. round_4(c, d, a, b, x[10], MD5Constants::S43, 0xffeff47d); // 55
  161. round_4(b, c, d, a, x[1], MD5Constants::S44, 0x85845dd1); // 56
  162. round_4(a, b, c, d, x[8], MD5Constants::S41, 0x6fa87e4f); // 57
  163. round_4(d, a, b, c, x[15], MD5Constants::S42, 0xfe2ce6e0); // 58
  164. round_4(c, d, a, b, x[6], MD5Constants::S43, 0xa3014314); // 59
  165. round_4(b, c, d, a, x[13], MD5Constants::S44, 0x4e0811a1); // 60
  166. round_4(a, b, c, d, x[4], MD5Constants::S41, 0xf7537e82); // 61
  167. round_4(d, a, b, c, x[11], MD5Constants::S42, 0xbd3af235); // 62
  168. round_4(c, d, a, b, x[2], MD5Constants::S43, 0x2ad7d2bb); // 63
  169. round_4(b, c, d, a, x[9], MD5Constants::S44, 0xeb86d391); // 64
  170. m_A += a;
  171. m_B += b;
  172. m_C += c;
  173. m_D += d;
  174. secure_zero(x, sizeof(x));
  175. }
  176. }