/* * 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. * * Copyright: * 2014-2018, Danny Robson */ #include "ripemd.hpp" #include #include #include using cruft::crypto::hash::RIPEMD; /////////////////////////////////////////////////////////////////////////////// static constexpr uint32_t f1 (uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; } //----------------------------------------------------------------------------- static constexpr uint32_t f2 (uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); } //----------------------------------------------------------------------------- static constexpr uint32_t f3 (uint32_t x, uint32_t y, uint32_t z) { return (x | ~y) ^ z; } //----------------------------------------------------------------------------- static constexpr uint32_t f4 (uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); } //----------------------------------------------------------------------------- static constexpr uint32_t f5 (uint32_t x, uint32_t y, uint32_t z) { return x ^ (y | ~z); } /////////////////////////////////////////////////////////////////////////////// static void transform (uint32_t state[5], const uint32_t d32[16]) { // Use: boolean function f // state parameters a, b, c, d, e // offset value o // input data value x // shift length s #define ROUND(f,a,b,c,d,e,o,x,s) { \ a += f(b, c, d); \ a += d32[x] + o; \ a = util::rotatel (a, s); \ a += e; \ c = util::rotatel (c, 10); \ } #define R1a(a,b,c,d,e,x,s) ROUND(f1,a,b,c,d,e,0x00000000u,x,s) #define R2a(a,b,c,d,e,x,s) ROUND(f2,a,b,c,d,e,0x5A827999u,x,s) #define R3a(a,b,c,d,e,x,s) ROUND(f3,a,b,c,d,e,0x6ED9EBA1u,x,s) #define R4a(a,b,c,d,e,x,s) ROUND(f4,a,b,c,d,e,0x8F1BBCDCu,x,s) #define R5a(a,b,c,d,e,x,s) ROUND(f5,a,b,c,d,e,0xA953FD4Eu,x,s) #define R1b(a,b,c,d,e,x,s) ROUND(f5,a,b,c,d,e,0x50A28BE6u,x,s) #define R2b(a,b,c,d,e,x,s) ROUND(f4,a,b,c,d,e,0x5C4DD124u,x,s) #define R3b(a,b,c,d,e,x,s) ROUND(f3,a,b,c,d,e,0x6D703EF3u,x,s) #define R4b(a,b,c,d,e,x,s) ROUND(f2,a,b,c,d,e,0x7A6D76E9u,x,s) #define R5b(a,b,c,d,e,x,s) ROUND(f1,a,b,c,d,e,0x00000000u,x,s) uint32_t a1, b1, c1, d1, e1; uint32_t a2, b2, c2, d2, e2; a1 = a2 = state[0]; b1 = b2 = state[1]; c1 = c2 = state[2]; d1 = d2 = state[3]; e1 = e2 = state[4]; // Left round 1 R1a(a1, b1, c1, d1, e1, 0, 11); R1a(e1, a1, b1, c1, d1, 1, 14); R1a(d1, e1, a1, b1, c1, 2, 15); R1a(c1, d1, e1, a1, b1, 3, 12); R1a(b1, c1, d1, e1, a1, 4, 5); R1a(a1, b1, c1, d1, e1, 5, 8); R1a(e1, a1, b1, c1, d1, 6, 7); R1a(d1, e1, a1, b1, c1, 7, 9); R1a(c1, d1, e1, a1, b1, 8, 11); R1a(b1, c1, d1, e1, a1, 9, 13); R1a(a1, b1, c1, d1, e1, 10, 14); R1a(e1, a1, b1, c1, d1, 11, 15); R1a(d1, e1, a1, b1, c1, 12, 6); R1a(c1, d1, e1, a1, b1, 13, 7); R1a(b1, c1, d1, e1, a1, 14, 9); R1a(a1, b1, c1, d1, e1, 15, 8); // Left round 2 R2a(e1, a1, b1, c1, d1, 7, 7); R2a(d1, e1, a1, b1, c1, 4, 6); R2a(c1, d1, e1, a1, b1, 13, 8); R2a(b1, c1, d1, e1, a1, 1, 13); R2a(a1, b1, c1, d1, e1, 10, 11); R2a(e1, a1, b1, c1, d1, 6, 9); R2a(d1, e1, a1, b1, c1, 15, 7); R2a(c1, d1, e1, a1, b1, 3, 15); R2a(b1, c1, d1, e1, a1, 12, 7); R2a(a1, b1, c1, d1, e1, 0, 12); R2a(e1, a1, b1, c1, d1, 9, 15); R2a(d1, e1, a1, b1, c1, 5, 9); R2a(c1, d1, e1, a1, b1, 2, 11); R2a(b1, c1, d1, e1, a1, 14, 7); R2a(a1, b1, c1, d1, e1, 11, 13); R2a(e1, a1, b1, c1, d1, 8, 12); // Left round 3 R3a(d1, e1, a1, b1, c1, 3, 11); R3a(c1, d1, e1, a1, b1, 10, 13); R3a(b1, c1, d1, e1, a1, 14, 6); R3a(a1, b1, c1, d1, e1, 4, 7); R3a(e1, a1, b1, c1, d1, 9, 14); R3a(d1, e1, a1, b1, c1, 15, 9); R3a(c1, d1, e1, a1, b1, 8, 13); R3a(b1, c1, d1, e1, a1, 1, 15); R3a(a1, b1, c1, d1, e1, 2, 14); R3a(e1, a1, b1, c1, d1, 7, 8); R3a(d1, e1, a1, b1, c1, 0, 13); R3a(c1, d1, e1, a1, b1, 6, 6); R3a(b1, c1, d1, e1, a1, 13, 5); R3a(a1, b1, c1, d1, e1, 11, 12); R3a(e1, a1, b1, c1, d1, 5, 7); R3a(d1, e1, a1, b1, c1, 12, 5); // Left round 4 R4a(c1, d1, e1, a1, b1, 1, 11); R4a(b1, c1, d1, e1, a1, 9, 12); R4a(a1, b1, c1, d1, e1, 11, 14); R4a(e1, a1, b1, c1, d1, 10, 15); R4a(d1, e1, a1, b1, c1, 0, 14); R4a(c1, d1, e1, a1, b1, 8, 15); R4a(b1, c1, d1, e1, a1, 12, 9); R4a(a1, b1, c1, d1, e1, 4, 8); R4a(e1, a1, b1, c1, d1, 13, 9); R4a(d1, e1, a1, b1, c1, 3, 14); R4a(c1, d1, e1, a1, b1, 7, 5); R4a(b1, c1, d1, e1, a1, 15, 6); R4a(a1, b1, c1, d1, e1, 14, 8); R4a(e1, a1, b1, c1, d1, 5, 6); R4a(d1, e1, a1, b1, c1, 6, 5); R4a(c1, d1, e1, a1, b1, 2, 12); // Left round 5 R5a(b1, c1, d1, e1, a1, 4, 9); R5a(a1, b1, c1, d1, e1, 0, 15); R5a(e1, a1, b1, c1, d1, 5, 5); R5a(d1, e1, a1, b1, c1, 9, 11); R5a(c1, d1, e1, a1, b1, 7, 6); R5a(b1, c1, d1, e1, a1, 12, 8); R5a(a1, b1, c1, d1, e1, 2, 13); R5a(e1, a1, b1, c1, d1, 10, 12); R5a(d1, e1, a1, b1, c1, 14, 5); R5a(c1, d1, e1, a1, b1, 1, 12); R5a(b1, c1, d1, e1, a1, 3, 13); R5a(a1, b1, c1, d1, e1, 8, 14); R5a(e1, a1, b1, c1, d1, 11, 11); R5a(d1, e1, a1, b1, c1, 6, 8); R5a(c1, d1, e1, a1, b1, 15, 5); R5a(b1, c1, d1, e1, a1, 13, 6); // Right round 1 R1b(a2, b2, c2, d2, e2, 5, 8); R1b(e2, a2, b2, c2, d2, 14, 9); R1b(d2, e2, a2, b2, c2, 7, 9); R1b(c2, d2, e2, a2, b2, 0, 11); R1b(b2, c2, d2, e2, a2, 9, 13); R1b(a2, b2, c2, d2, e2, 2, 15); R1b(e2, a2, b2, c2, d2, 11, 15); R1b(d2, e2, a2, b2, c2, 4, 5); R1b(c2, d2, e2, a2, b2, 13, 7); R1b(b2, c2, d2, e2, a2, 6, 7); R1b(a2, b2, c2, d2, e2, 15, 8); R1b(e2, a2, b2, c2, d2, 8, 11); R1b(d2, e2, a2, b2, c2, 1, 14); R1b(c2, d2, e2, a2, b2, 10, 14); R1b(b2, c2, d2, e2, a2, 3, 12); R1b(a2, b2, c2, d2, e2, 12, 6); // Right round 2 R2b(e2, a2, b2, c2, d2, 6, 9); R2b(d2, e2, a2, b2, c2, 11, 13); R2b(c2, d2, e2, a2, b2, 3, 15); R2b(b2, c2, d2, e2, a2, 7, 7); R2b(a2, b2, c2, d2, e2, 0, 12); R2b(e2, a2, b2, c2, d2, 13, 8); R2b(d2, e2, a2, b2, c2, 5, 9); R2b(c2, d2, e2, a2, b2, 10, 11); R2b(b2, c2, d2, e2, a2, 14, 7); R2b(a2, b2, c2, d2, e2, 15, 7); R2b(e2, a2, b2, c2, d2, 8, 12); R2b(d2, e2, a2, b2, c2, 12, 7); R2b(c2, d2, e2, a2, b2, 4, 6); R2b(b2, c2, d2, e2, a2, 9, 15); R2b(a2, b2, c2, d2, e2, 1, 13); R2b(e2, a2, b2, c2, d2, 2, 11); // Right round 3 R3b(d2, e2, a2, b2, c2, 15, 9); R3b(c2, d2, e2, a2, b2, 5, 7); R3b(b2, c2, d2, e2, a2, 1, 15); R3b(a2, b2, c2, d2, e2, 3, 11); R3b(e2, a2, b2, c2, d2, 7, 8); R3b(d2, e2, a2, b2, c2, 14, 6); R3b(c2, d2, e2, a2, b2, 6, 6); R3b(b2, c2, d2, e2, a2, 9, 14); R3b(a2, b2, c2, d2, e2, 11, 12); R3b(e2, a2, b2, c2, d2, 8, 13); R3b(d2, e2, a2, b2, c2, 12, 5); R3b(c2, d2, e2, a2, b2, 2, 14); R3b(b2, c2, d2, e2, a2, 10, 13); R3b(a2, b2, c2, d2, e2, 0, 13); R3b(e2, a2, b2, c2, d2, 4, 7); R3b(d2, e2, a2, b2, c2, 13, 5); // Right round 4 R4b(c2, d2, e2, a2, b2, 8, 15); R4b(b2, c2, d2, e2, a2, 6, 5); R4b(a2, b2, c2, d2, e2, 4, 8); R4b(e2, a2, b2, c2, d2, 1, 11); R4b(d2, e2, a2, b2, c2, 3, 14); R4b(c2, d2, e2, a2, b2, 11, 14); R4b(b2, c2, d2, e2, a2, 15, 6); R4b(a2, b2, c2, d2, e2, 0, 14); R4b(e2, a2, b2, c2, d2, 5, 6); R4b(d2, e2, a2, b2, c2, 12, 9); R4b(c2, d2, e2, a2, b2, 2, 12); R4b(b2, c2, d2, e2, a2, 13, 9); R4b(a2, b2, c2, d2, e2, 9, 12); R4b(e2, a2, b2, c2, d2, 7, 5); R4b(d2, e2, a2, b2, c2, 10, 15); R4b(c2, d2, e2, a2, b2, 14, 8); // Right round 5 R5b(b2, c2, d2, e2, a2, 12 , 8); R5b(a2, b2, c2, d2, e2, 15 , 5); R5b(e2, a2, b2, c2, d2, 10 , 12); R5b(d2, e2, a2, b2, c2, 4 , 9); R5b(c2, d2, e2, a2, b2, 1 , 12); R5b(b2, c2, d2, e2, a2, 5 , 5); R5b(a2, b2, c2, d2, e2, 8 , 14); R5b(e2, a2, b2, c2, d2, 7 , 6); R5b(d2, e2, a2, b2, c2, 6 , 8); R5b(c2, d2, e2, a2, b2, 2 , 13); R5b(b2, c2, d2, e2, a2, 13 , 6); R5b(a2, b2, c2, d2, e2, 14 , 5); R5b(e2, a2, b2, c2, d2, 0 , 15); R5b(d2, e2, a2, b2, c2, 3 , 13); R5b(c2, d2, e2, a2, b2, 9 , 11); R5b(b2, c2, d2, e2, a2, 11 , 11); // Finalise state d2 = state[1] + c1 + d2; state[1] = state[2] + d1 + e2; state[2] = state[3] + e1 + a2; state[3] = state[4] + a1 + b2; state[4] = state[0] + b1 + c2; state[0] = d2; } /////////////////////////////////////////////////////////////////////////////// RIPEMD::digest_t RIPEMD::operator() (const util::view data) { struct { union { uint32_t d32[16]; uint8_t d08[64]; }; size_t size; } m_buffer; /* INIT */ uint32_t m_state[5] { 0x67452301u, 0xEFCDAB89u, 0x98BADCFEu, 0x10325476u, 0xC3D2E1F0u, }; uint64_t m_length = 0; m_buffer.size = 0; /* UPDATE */ { auto len = data.size (); auto base = data.begin (); size_t cursor = 0; while (cursor < len) { size_t width = sizeof (m_buffer.d08) - m_buffer.size; size_t chunk = util::min (width, len - cursor); memcpy (m_buffer.d08 + m_buffer.size, base + cursor, chunk); m_length += chunk; m_buffer.size += chunk; if (m_buffer.size == sizeof (m_buffer.d08)) { transform (m_state, m_buffer.d32); m_buffer.size = 0; } cursor += chunk; } if (m_length >> sizeof (m_length) * 8 - 3 != 0) panic ("exceeded maximum message length"); } /* FINISH */ { // Ensure the length wouldn't overflow if converted to bits. We need to // grab this before there's a chance it gets overwritten. CHECK_EQ (m_length >> sizeof(m_length) * 8 - 3, 0u); uint64_t length = m_length * 8; // Push a padding byte into the buffer uint8_t padding = 0x80; assert (m_buffer.size != sizeof (m_buffer.d08)); m_buffer.d08[m_buffer.size] = padding; m_buffer.size++; m_length++; if (m_buffer.size == sizeof (m_buffer.d08)) { transform (m_state, m_buffer.d32); m_buffer.size = 0; } // Pad out the line if we couldn't fit a length at the end size_t remaining = sizeof (m_buffer.d32) - m_buffer.size; if (remaining < 8) { std::fill_n (m_buffer.d08 + m_buffer.size, remaining, 0); m_buffer.size += remaining; transform (m_state, m_buffer.d32); m_buffer.size = 0; m_length += remaining; CHECK_EQ (m_buffer.size, 0u); remaining = sizeof (m_buffer.d08); } // Write the length to the end of the buffer union { uint32_t d32[16]; uint8_t d08[64]; }; std::fill (std::begin (d32), std::end (d32), 0); d32[14] = length & 0xFFFFFFFF; d32[15] = length >> 32u; // Do the final update size_t offset = sizeof(d08) - remaining; std::copy_n (d08 + offset, remaining, m_buffer.d08 + offset); m_length += remaining; m_buffer.size += remaining; transform (m_state, m_buffer.d32); m_buffer.size = 0; } /* DIGEST */ digest_t d; memcpy (d.data (), m_state, sizeof (m_state)); return d; }