| // Copyright 2014 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm |
| */ |
| |
| /* |
| Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All |
| rights reserved. |
| |
| License to copy and use this software is granted provided that it |
| is identified as the "RSA Data Security, Inc. MD5 Message-Digest |
| Algorithm" in all material mentioning or referencing this software |
| or this function. |
| |
| License is also granted to make and use derivative works provided |
| that such works are identified as "derived from the RSA Data |
| Security, Inc. MD5 Message-Digest Algorithm" in all material |
| mentioning or referencing the derived work. |
| |
| RSA Data Security, Inc. makes no representations concerning either |
| the merchantability of this software or the suitability of this |
| software for any particular purpose. It is provided "as is" |
| without express or implied warranty of any kind. |
| |
| These notices must be retained in any copies of any part of this |
| documentation and/or software. |
| */ |
| |
| #include "src/main/cpp/util/md5.h" |
| |
| #include <stddef.h> // for offsetof |
| #include <string.h> // for memcpy |
| |
| #include <cinttypes> |
| |
| #if !_STRING_ARCH_unaligned |
| #if defined(_LP64) || defined(_WIN64) |
| # define UNALIGNED_P(p) (reinterpret_cast<uint64_t>(p) % \ |
| __alignof__(uint32_t) != 0) // NOLINT |
| # else |
| # define UNALIGNED_P(p) (reinterpret_cast<uint32_t>(p) % \ |
| __alignof__(uint32_t) != 0) // NOLINT |
| # endif |
| #else |
| # define UNALIGNED_P(p) (0) |
| #endif |
| |
| namespace blaze_util { |
| |
| using std::string; |
| |
| static const unsigned int k8Bytes = 64; |
| static const unsigned int k8ByteMask = 63; |
| |
| static const unsigned char kPadding[64] = { |
| 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
| }; |
| |
| // Digit conversion. |
| static char hex_char[] = "0123456789abcdef"; |
| |
| // This is a templated function so that T can be either a char* |
| // or a string. This works because we use the [] operator to access |
| // individual characters at a time. |
| template <typename T> |
| static void b2a_hex_t(const unsigned char* b, T a, int num) { |
| for (int i = 0; i < num; i++) { |
| a[i * 2 + 0] = hex_char[b[i] >> 4]; |
| a[i * 2 + 1] = hex_char[b[i] & 0xf]; |
| } |
| } |
| |
| // ---------------------------------------------------------------------- |
| // b2a_hex() |
| // Description: Binary-to-Ascii hex conversion. This converts |
| // 'num' bytes of binary to a 2*'num'-character hexadecimal representation |
| // Return value: 2*'num' characters of ascii text (via the 'to' argument) |
| // ---------------------------------------------------------------------- |
| static void b2a_hex(const unsigned char* from, string* to, int num) { |
| to->resize(num << 1); |
| b2a_hex_t<string&>(from, *to, num); |
| } |
| |
| Md5Digest::Md5Digest() { |
| Reset(); |
| } |
| |
| Md5Digest::Md5Digest(const Md5Digest& original) { |
| memcpy(state, original.state, sizeof(original.state)); |
| memcpy(count, original.count, sizeof(original.count)); |
| memcpy(ctx_buffer, original.ctx_buffer, original.ctx_buffer_len); |
| ctx_buffer_len = original.ctx_buffer_len; |
| } |
| |
| void Md5Digest::Reset() { |
| count[0] = count[1] = 0; |
| ctx_buffer_len = 0; |
| // Load magic initialization constants. |
| state[0] = 0x67452301; |
| state[1] = 0xefcdab89; |
| state[2] = 0x98badcfe; |
| state[3] = 0x10325476; |
| } |
| |
| void Md5Digest::Update(const void *buf, unsigned int length) { |
| const unsigned char *input = reinterpret_cast<const unsigned char*>(buf); |
| unsigned int buffer_space_len; |
| |
| buffer_space_len = k8Bytes - ctx_buffer_len; |
| |
| // Transform as many times as possible. |
| if (length >= buffer_space_len) { |
| if (buffer_space_len != 0 && ctx_buffer_len != 0) { |
| // Copy more bytes to fill the complete buffer |
| memcpy(ctx_buffer + ctx_buffer_len, input, buffer_space_len); |
| Transform(ctx_buffer, k8Bytes); |
| input += buffer_space_len; |
| length -= buffer_space_len; |
| ctx_buffer_len = 0; |
| } |
| |
| if (UNALIGNED_P(input)) { |
| while (length >= k8Bytes) { |
| memcpy(ctx_buffer, input, k8Bytes); |
| Transform(ctx_buffer, k8Bytes); |
| input += k8Bytes; |
| length -= k8Bytes; |
| } |
| } else if (length >= k8Bytes) { |
| Transform(input, length & ~k8ByteMask); |
| input += length & ~k8ByteMask; |
| length &= k8ByteMask; |
| } |
| } |
| |
| // Buffer remaining input |
| memcpy(ctx_buffer + ctx_buffer_len, input, length); |
| ctx_buffer_len += length; |
| } |
| |
| void Md5Digest::Finish(unsigned char digest[16]) { |
| count[0] += ctx_buffer_len; |
| if (count[0] < ctx_buffer_len) { |
| ++count[1]; |
| } |
| |
| /* Put the 64-bit file length in *bits* at the end of the buffer. */ |
| unsigned int size = (ctx_buffer_len < 56 ? 64 : 128); |
| uint32_t words[2] = { count[0] << 3, (count[1] << 3) | (count[0] >> 29) }; |
| memcpy(ctx_buffer + size - 8, words, 8); |
| |
| memcpy(ctx_buffer + ctx_buffer_len, kPadding, size - 8 - ctx_buffer_len); |
| |
| Transform(ctx_buffer, size); |
| |
| uint32_t* r = reinterpret_cast<uint32_t*>(digest); |
| r[0] = state[0]; |
| r[1] = state[1]; |
| r[2] = state[2]; |
| r[3] = state[3]; |
| } |
| |
| void Md5Digest::Transform( |
| const unsigned char* buffer, unsigned int len) { |
| // Constants for transform routine. |
| #define S11 7 |
| #define S12 12 |
| #define S13 17 |
| #define S14 22 |
| #define S21 5 |
| #define S22 9 |
| #define S23 14 |
| #define S24 20 |
| #define S31 4 |
| #define S32 11 |
| #define S33 16 |
| #define S34 23 |
| #define S41 6 |
| #define S42 10 |
| #define S43 15 |
| #define S44 21 |
| |
| // F, G, H and I are basic MD5 functions. |
| /* These are the four functions used in the four steps of the MD5 algorithm |
| and defined in the RFC 1321. The first function is a little bit optimized |
| (as found in Colin Plumbs public domain implementation). */ |
| /* #define F(b, c, d) ((b & c) | (~b & d)) */ |
| #define F(x, y, z) (z ^ (x & (y ^ z))) |
| #define G(x, y, z) F (z, x, y) |
| #define H(x, y, z) ((x) ^ (y) ^ (z)) |
| #define I(x, y, z) ((y) ^ ((x) | (~z))) |
| |
| // ROTATE_LEFT rotates x left n bits. |
| #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) |
| |
| // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. |
| // Rotation is separate from addition to prevent recomputation. |
| #define FF(a, b, c, d, s, ac) { \ |
| (a) += F((b), (c), (d)) + ((*x_pos++ = *cur_word++)) + \ |
| static_cast<uint32_t>(ac); \ |
| (a) = ROTATE_LEFT((a), (s)); \ |
| (a) += (b); \ |
| } |
| |
| #define GG(a, b, c, d, x, s, ac) { \ |
| (a) += G((b), (c), (d)) + (x) + static_cast<uint32_t>(ac); \ |
| (a) = ROTATE_LEFT((a), (s)); \ |
| (a) += (b); \ |
| } |
| #define HH(a, b, c, d, x, s, ac) { \ |
| (a) += H((b), (c), (d)) + (x) + static_cast<uint32_t>(ac); \ |
| (a) = ROTATE_LEFT((a), (s)); \ |
| (a) += (b); \ |
| } |
| #define II(a, b, c, d, x, s, ac) { \ |
| (a) += I((b), (c), (d)) + (x) + static_cast<uint32_t>(ac); \ |
| (a) = ROTATE_LEFT((a), (s)); \ |
| (a) += (b); \ |
| } |
| |
| count[0] += len; |
| if (count[0] < len) { |
| ++count[1]; |
| } |
| |
| uint32_t a = state[0]; |
| uint32_t b = state[1]; |
| uint32_t c = state[2]; |
| uint32_t d = state[3]; |
| uint32_t x[16]; |
| |
| const uint32_t *cur_word = reinterpret_cast<const uint32_t*>(buffer); |
| const uint32_t *end_word = cur_word + (len / sizeof(uint32_t)); |
| |
| while (cur_word < end_word) { |
| uint32_t *x_pos = x; |
| uint32_t prev_a = a; |
| uint32_t prev_b = b; |
| uint32_t prev_c = c; |
| uint32_t prev_d = d; |
| |
| // Round 1 |
| FF(a, b, c, d, S11, 0xd76aa478); // 1 |
| FF(d, a, b, c, S12, 0xe8c7b756); // 2 |
| FF(c, d, a, b, S13, 0x242070db); // 3 |
| FF(b, c, d, a, S14, 0xc1bdceee); // 4 |
| FF(a, b, c, d, S11, 0xf57c0faf); // 5 |
| FF(d, a, b, c, S12, 0x4787c62a); // 6 |
| FF(c, d, a, b, S13, 0xa8304613); // 7 |
| FF(b, c, d, a, S14, 0xfd469501); // 8 |
| FF(a, b, c, d, S11, 0x698098d8); // 9 |
| FF(d, a, b, c, S12, 0x8b44f7af); // 10 |
| FF(c, d, a, b, S13, 0xffff5bb1); // 11 |
| FF(b, c, d, a, S14, 0x895cd7be); // 12 |
| FF(a, b, c, d, S11, 0x6b901122); // 13 |
| FF(d, a, b, c, S12, 0xfd987193); // 14 |
| FF(c, d, a, b, S13, 0xa679438e); // 15 |
| FF(b, c, d, a, S14, 0x49b40821); // 16 |
| |
| // Round 2 |
| GG(a, b, c, d, x[ 1], S21, 0xf61e2562); // 17 |
| GG(d, a, b, c, x[ 6], S22, 0xc040b340); // 18 |
| GG(c, d, a, b, x[11], S23, 0x265e5a51); // 19 |
| GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20 |
| GG(a, b, c, d, x[ 5], S21, 0xd62f105d); // 21 |
| GG(d, a, b, c, x[10], S22, 0x2441453); // 22 |
| GG(c, d, a, b, x[15], S23, 0xd8a1e681); // 23 |
| GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24 |
| GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25 |
| GG(d, a, b, c, x[14], S22, 0xc33707d6); // 26 |
| GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27 |
| GG(b, c, d, a, x[ 8], S24, 0x455a14ed); // 28 |
| GG(a, b, c, d, x[13], S21, 0xa9e3e905); // 29 |
| GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30 |
| GG(c, d, a, b, x[ 7], S23, 0x676f02d9); // 31 |
| GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32 |
| |
| // Round 3 |
| HH(a, b, c, d, x[ 5], S31, 0xfffa3942); // 33 |
| HH(d, a, b, c, x[ 8], S32, 0x8771f681); // 34 |
| HH(c, d, a, b, x[11], S33, 0x6d9d6122); // 35 |
| HH(b, c, d, a, x[14], S34, 0xfde5380c); // 36 |
| HH(a, b, c, d, x[ 1], S31, 0xa4beea44); // 37 |
| HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38 |
| HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39 |
| HH(b, c, d, a, x[10], S34, 0xbebfbc70); // 40 |
| HH(a, b, c, d, x[13], S31, 0x289b7ec6); // 41 |
| HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42 |
| HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43 |
| HH(b, c, d, a, x[ 6], S34, 0x4881d05); // 44 |
| HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45 |
| HH(d, a, b, c, x[12], S32, 0xe6db99e5); // 46 |
| HH(c, d, a, b, x[15], S33, 0x1fa27cf8); // 47 |
| HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48 |
| |
| // Round 4 |
| II(a, b, c, d, x[ 0], S41, 0xf4292244); // 49 |
| II(d, a, b, c, x[ 7], S42, 0x432aff97); // 50 |
| II(c, d, a, b, x[14], S43, 0xab9423a7); // 51 |
| II(b, c, d, a, x[ 5], S44, 0xfc93a039); // 52 |
| II(a, b, c, d, x[12], S41, 0x655b59c3); // 53 |
| II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54 |
| II(c, d, a, b, x[10], S43, 0xffeff47d); // 55 |
| II(b, c, d, a, x[ 1], S44, 0x85845dd1); // 56 |
| II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57 |
| II(d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58 |
| II(c, d, a, b, x[ 6], S43, 0xa3014314); // 59 |
| II(b, c, d, a, x[13], S44, 0x4e0811a1); // 60 |
| II(a, b, c, d, x[ 4], S41, 0xf7537e82); // 61 |
| II(d, a, b, c, x[11], S42, 0xbd3af235); // 62 |
| II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63 |
| II(b, c, d, a, x[ 9], S44, 0xeb86d391); // 64 |
| |
| a += prev_a; |
| b += prev_b; |
| c += prev_c; |
| d += prev_d; |
| } |
| |
| state[0] = a; |
| state[1] = b; |
| state[2] = c; |
| state[3] = d; |
| } |
| |
| string Md5Digest::String() const { |
| string result; |
| b2a_hex(reinterpret_cast<const uint8_t*>(state), &result, 16); |
| return result; |
| } |
| |
| } // namespace blaze_util |