| 1 | // |
| 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
| 3 | // |
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | // |
| 7 | // Official repository: https://github.com/boostorg/beast |
| 8 | // |
| 9 | |
| 10 | #ifndef BOOST_BEAST_DETAIL_SHA1_IPP |
| 11 | #define BOOST_BEAST_DETAIL_SHA1_IPP |
| 12 | |
| 13 | #include <boost/beast/core/detail/sha1.hpp> |
| 14 | |
| 15 | #include <algorithm> |
| 16 | #include <cstdint> |
| 17 | #include <cstring> |
| 18 | |
| 19 | // Based on https://github.com/vog/sha1 |
| 20 | /* |
| 21 | Original authors: |
| 22 | Steve Reid (Original C Code) |
| 23 | Bruce Guenter (Small changes to fit into bglibs) |
| 24 | Volker Grabsch (Translation to simpler C++ Code) |
| 25 | Eugene Hopkinson (Safety improvements) |
| 26 | Vincent Falco (beast adaptation) |
| 27 | */ |
| 28 | |
| 29 | namespace boost { |
| 30 | namespace beast { |
| 31 | namespace detail { |
| 32 | |
| 33 | namespace sha1 { |
| 34 | |
| 35 | inline |
| 36 | std::uint32_t |
| 37 | rol(std::uint32_t value, std::size_t bits) |
| 38 | { |
| 39 | return (value << bits) | (value >> (32 - bits)); |
| 40 | } |
| 41 | |
| 42 | inline |
| 43 | std::uint32_t |
| 44 | blk(std::uint32_t block[BLOCK_INTS], std::size_t i) |
| 45 | { |
| 46 | return rol( |
| 47 | value: block[(i+13)&15] ^ block[(i+8)&15] ^ |
| 48 | block[(i+2)&15] ^ block[i], bits: 1); |
| 49 | } |
| 50 | |
| 51 | inline |
| 52 | void |
| 53 | R0(std::uint32_t block[BLOCK_INTS], std::uint32_t v, |
| 54 | std::uint32_t &w, std::uint32_t x, std::uint32_t y, |
| 55 | std::uint32_t &z, std::size_t i) |
| 56 | { |
| 57 | z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(value: v, bits: 5); |
| 58 | w = rol(value: w, bits: 30); |
| 59 | } |
| 60 | |
| 61 | |
| 62 | inline |
| 63 | void |
| 64 | R1(std::uint32_t block[BLOCK_INTS], std::uint32_t v, |
| 65 | std::uint32_t &w, std::uint32_t x, std::uint32_t y, |
| 66 | std::uint32_t &z, std::size_t i) |
| 67 | { |
| 68 | block[i] = blk(block, i); |
| 69 | z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(value: v, bits: 5); |
| 70 | w = rol(value: w, bits: 30); |
| 71 | } |
| 72 | |
| 73 | inline |
| 74 | void |
| 75 | R2(std::uint32_t block[BLOCK_INTS], std::uint32_t v, |
| 76 | std::uint32_t &w, std::uint32_t x, std::uint32_t y, |
| 77 | std::uint32_t &z, std::size_t i) |
| 78 | { |
| 79 | block[i] = blk(block, i); |
| 80 | z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(value: v, bits: 5); |
| 81 | w = rol(value: w, bits: 30); |
| 82 | } |
| 83 | |
| 84 | inline |
| 85 | void |
| 86 | R3(std::uint32_t block[BLOCK_INTS], std::uint32_t v, |
| 87 | std::uint32_t &w, std::uint32_t x, std::uint32_t y, |
| 88 | std::uint32_t &z, std::size_t i) |
| 89 | { |
| 90 | block[i] = blk(block, i); |
| 91 | z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rol(value: v, bits: 5); |
| 92 | w = rol(value: w, bits: 30); |
| 93 | } |
| 94 | |
| 95 | inline |
| 96 | void |
| 97 | R4(std::uint32_t block[BLOCK_INTS], std::uint32_t v, |
| 98 | std::uint32_t &w, std::uint32_t x, std::uint32_t y, |
| 99 | std::uint32_t &z, std::size_t i) |
| 100 | { |
| 101 | block[i] = blk(block, i); |
| 102 | z += (w^x^y) + block[i] + 0xca62c1d6 + rol(value: v, bits: 5); |
| 103 | w = rol(value: w, bits: 30); |
| 104 | } |
| 105 | |
| 106 | inline |
| 107 | void |
| 108 | make_block(std::uint8_t const* p, |
| 109 | std::uint32_t block[BLOCK_INTS]) |
| 110 | { |
| 111 | for(std::size_t i = 0; i < BLOCK_INTS; i++) |
| 112 | block[i] = |
| 113 | (static_cast<std::uint32_t>(p[4*i+3])) | |
| 114 | (static_cast<std::uint32_t>(p[4*i+2]))<< 8 | |
| 115 | (static_cast<std::uint32_t>(p[4*i+1]))<<16 | |
| 116 | (static_cast<std::uint32_t>(p[4*i+0]))<<24; |
| 117 | } |
| 118 | |
| 119 | inline |
| 120 | void |
| 121 | transform( |
| 122 | std::uint32_t digest[], std::uint32_t block[BLOCK_INTS]) |
| 123 | { |
| 124 | std::uint32_t a = digest[0]; |
| 125 | std::uint32_t b = digest[1]; |
| 126 | std::uint32_t c = digest[2]; |
| 127 | std::uint32_t d = digest[3]; |
| 128 | std::uint32_t e = digest[4]; |
| 129 | |
| 130 | R0(block, v: a, w&: b, x: c, y: d, z&: e, i: 0); |
| 131 | R0(block, v: e, w&: a, x: b, y: c, z&: d, i: 1); |
| 132 | R0(block, v: d, w&: e, x: a, y: b, z&: c, i: 2); |
| 133 | R0(block, v: c, w&: d, x: e, y: a, z&: b, i: 3); |
| 134 | R0(block, v: b, w&: c, x: d, y: e, z&: a, i: 4); |
| 135 | R0(block, v: a, w&: b, x: c, y: d, z&: e, i: 5); |
| 136 | R0(block, v: e, w&: a, x: b, y: c, z&: d, i: 6); |
| 137 | R0(block, v: d, w&: e, x: a, y: b, z&: c, i: 7); |
| 138 | R0(block, v: c, w&: d, x: e, y: a, z&: b, i: 8); |
| 139 | R0(block, v: b, w&: c, x: d, y: e, z&: a, i: 9); |
| 140 | R0(block, v: a, w&: b, x: c, y: d, z&: e, i: 10); |
| 141 | R0(block, v: e, w&: a, x: b, y: c, z&: d, i: 11); |
| 142 | R0(block, v: d, w&: e, x: a, y: b, z&: c, i: 12); |
| 143 | R0(block, v: c, w&: d, x: e, y: a, z&: b, i: 13); |
| 144 | R0(block, v: b, w&: c, x: d, y: e, z&: a, i: 14); |
| 145 | R0(block, v: a, w&: b, x: c, y: d, z&: e, i: 15); |
| 146 | R1(block, v: e, w&: a, x: b, y: c, z&: d, i: 0); |
| 147 | R1(block, v: d, w&: e, x: a, y: b, z&: c, i: 1); |
| 148 | R1(block, v: c, w&: d, x: e, y: a, z&: b, i: 2); |
| 149 | R1(block, v: b, w&: c, x: d, y: e, z&: a, i: 3); |
| 150 | R2(block, v: a, w&: b, x: c, y: d, z&: e, i: 4); |
| 151 | R2(block, v: e, w&: a, x: b, y: c, z&: d, i: 5); |
| 152 | R2(block, v: d, w&: e, x: a, y: b, z&: c, i: 6); |
| 153 | R2(block, v: c, w&: d, x: e, y: a, z&: b, i: 7); |
| 154 | R2(block, v: b, w&: c, x: d, y: e, z&: a, i: 8); |
| 155 | R2(block, v: a, w&: b, x: c, y: d, z&: e, i: 9); |
| 156 | R2(block, v: e, w&: a, x: b, y: c, z&: d, i: 10); |
| 157 | R2(block, v: d, w&: e, x: a, y: b, z&: c, i: 11); |
| 158 | R2(block, v: c, w&: d, x: e, y: a, z&: b, i: 12); |
| 159 | R2(block, v: b, w&: c, x: d, y: e, z&: a, i: 13); |
| 160 | R2(block, v: a, w&: b, x: c, y: d, z&: e, i: 14); |
| 161 | R2(block, v: e, w&: a, x: b, y: c, z&: d, i: 15); |
| 162 | R2(block, v: d, w&: e, x: a, y: b, z&: c, i: 0); |
| 163 | R2(block, v: c, w&: d, x: e, y: a, z&: b, i: 1); |
| 164 | R2(block, v: b, w&: c, x: d, y: e, z&: a, i: 2); |
| 165 | R2(block, v: a, w&: b, x: c, y: d, z&: e, i: 3); |
| 166 | R2(block, v: e, w&: a, x: b, y: c, z&: d, i: 4); |
| 167 | R2(block, v: d, w&: e, x: a, y: b, z&: c, i: 5); |
| 168 | R2(block, v: c, w&: d, x: e, y: a, z&: b, i: 6); |
| 169 | R2(block, v: b, w&: c, x: d, y: e, z&: a, i: 7); |
| 170 | R3(block, v: a, w&: b, x: c, y: d, z&: e, i: 8); |
| 171 | R3(block, v: e, w&: a, x: b, y: c, z&: d, i: 9); |
| 172 | R3(block, v: d, w&: e, x: a, y: b, z&: c, i: 10); |
| 173 | R3(block, v: c, w&: d, x: e, y: a, z&: b, i: 11); |
| 174 | R3(block, v: b, w&: c, x: d, y: e, z&: a, i: 12); |
| 175 | R3(block, v: a, w&: b, x: c, y: d, z&: e, i: 13); |
| 176 | R3(block, v: e, w&: a, x: b, y: c, z&: d, i: 14); |
| 177 | R3(block, v: d, w&: e, x: a, y: b, z&: c, i: 15); |
| 178 | R3(block, v: c, w&: d, x: e, y: a, z&: b, i: 0); |
| 179 | R3(block, v: b, w&: c, x: d, y: e, z&: a, i: 1); |
| 180 | R3(block, v: a, w&: b, x: c, y: d, z&: e, i: 2); |
| 181 | R3(block, v: e, w&: a, x: b, y: c, z&: d, i: 3); |
| 182 | R3(block, v: d, w&: e, x: a, y: b, z&: c, i: 4); |
| 183 | R3(block, v: c, w&: d, x: e, y: a, z&: b, i: 5); |
| 184 | R3(block, v: b, w&: c, x: d, y: e, z&: a, i: 6); |
| 185 | R3(block, v: a, w&: b, x: c, y: d, z&: e, i: 7); |
| 186 | R3(block, v: e, w&: a, x: b, y: c, z&: d, i: 8); |
| 187 | R3(block, v: d, w&: e, x: a, y: b, z&: c, i: 9); |
| 188 | R3(block, v: c, w&: d, x: e, y: a, z&: b, i: 10); |
| 189 | R3(block, v: b, w&: c, x: d, y: e, z&: a, i: 11); |
| 190 | R4(block, v: a, w&: b, x: c, y: d, z&: e, i: 12); |
| 191 | R4(block, v: e, w&: a, x: b, y: c, z&: d, i: 13); |
| 192 | R4(block, v: d, w&: e, x: a, y: b, z&: c, i: 14); |
| 193 | R4(block, v: c, w&: d, x: e, y: a, z&: b, i: 15); |
| 194 | R4(block, v: b, w&: c, x: d, y: e, z&: a, i: 0); |
| 195 | R4(block, v: a, w&: b, x: c, y: d, z&: e, i: 1); |
| 196 | R4(block, v: e, w&: a, x: b, y: c, z&: d, i: 2); |
| 197 | R4(block, v: d, w&: e, x: a, y: b, z&: c, i: 3); |
| 198 | R4(block, v: c, w&: d, x: e, y: a, z&: b, i: 4); |
| 199 | R4(block, v: b, w&: c, x: d, y: e, z&: a, i: 5); |
| 200 | R4(block, v: a, w&: b, x: c, y: d, z&: e, i: 6); |
| 201 | R4(block, v: e, w&: a, x: b, y: c, z&: d, i: 7); |
| 202 | R4(block, v: d, w&: e, x: a, y: b, z&: c, i: 8); |
| 203 | R4(block, v: c, w&: d, x: e, y: a, z&: b, i: 9); |
| 204 | R4(block, v: b, w&: c, x: d, y: e, z&: a, i: 10); |
| 205 | R4(block, v: a, w&: b, x: c, y: d, z&: e, i: 11); |
| 206 | R4(block, v: e, w&: a, x: b, y: c, z&: d, i: 12); |
| 207 | R4(block, v: d, w&: e, x: a, y: b, z&: c, i: 13); |
| 208 | R4(block, v: c, w&: d, x: e, y: a, z&: b, i: 14); |
| 209 | R4(block, v: b, w&: c, x: d, y: e, z&: a, i: 15); |
| 210 | |
| 211 | digest[0] += a; |
| 212 | digest[1] += b; |
| 213 | digest[2] += c; |
| 214 | digest[3] += d; |
| 215 | digest[4] += e; |
| 216 | } |
| 217 | |
| 218 | } // sha1 |
| 219 | |
| 220 | void |
| 221 | init(sha1_context& ctx) noexcept |
| 222 | { |
| 223 | ctx.buflen = 0; |
| 224 | ctx.blocks = 0; |
| 225 | ctx.digest[0] = 0x67452301; |
| 226 | ctx.digest[1] = 0xefcdab89; |
| 227 | ctx.digest[2] = 0x98badcfe; |
| 228 | ctx.digest[3] = 0x10325476; |
| 229 | ctx.digest[4] = 0xc3d2e1f0; |
| 230 | } |
| 231 | |
| 232 | void |
| 233 | update( |
| 234 | sha1_context& ctx, |
| 235 | void const* message, |
| 236 | std::size_t size) noexcept |
| 237 | { |
| 238 | auto p = static_cast< |
| 239 | std::uint8_t const*>(message); |
| 240 | for(;;) |
| 241 | { |
| 242 | auto const n = (std::min)( |
| 243 | a: size, b: sizeof(ctx.buf) - ctx.buflen); |
| 244 | std::memcpy(dest: ctx.buf + ctx.buflen, src: p, n: n); |
| 245 | ctx.buflen += n; |
| 246 | if(ctx.buflen != 64) |
| 247 | return; |
| 248 | p += n; |
| 249 | size -= n; |
| 250 | ctx.buflen = 0; |
| 251 | std::uint32_t block[sha1::BLOCK_INTS]; |
| 252 | sha1::make_block(p: ctx.buf, block); |
| 253 | sha1::transform(digest: ctx.digest, block); |
| 254 | ++ctx.blocks; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | void |
| 259 | finish( |
| 260 | sha1_context& ctx, |
| 261 | void* digest) noexcept |
| 262 | { |
| 263 | using sha1::BLOCK_INTS; |
| 264 | using sha1::BLOCK_BYTES; |
| 265 | |
| 266 | std::uint64_t total_bits = |
| 267 | (ctx.blocks*64 + ctx.buflen) * 8; |
| 268 | // pad |
| 269 | ctx.buf[ctx.buflen++] = 0x80; |
| 270 | auto const buflen = ctx.buflen; |
| 271 | while(ctx.buflen < 64) |
| 272 | ctx.buf[ctx.buflen++] = 0x00; |
| 273 | std::uint32_t block[BLOCK_INTS]; |
| 274 | sha1::make_block(p: ctx.buf, block); |
| 275 | if(buflen > BLOCK_BYTES - 8) |
| 276 | { |
| 277 | sha1::transform(digest: ctx.digest, block); |
| 278 | for(size_t i = 0; i < BLOCK_INTS - 2; i++) |
| 279 | block[i] = 0; |
| 280 | } |
| 281 | |
| 282 | /* Append total_bits, split this uint64_t into two uint32_t */ |
| 283 | block[BLOCK_INTS - 1] = total_bits & 0xffffffff; |
| 284 | block[BLOCK_INTS - 2] = (total_bits >> 32); |
| 285 | sha1::transform(digest: ctx.digest, block); |
| 286 | for(std::size_t i = 0; i < sha1::DIGEST_BYTES/4; i++) |
| 287 | { |
| 288 | std::uint8_t* d = |
| 289 | static_cast<std::uint8_t*>(digest) + 4 * i; |
| 290 | d[3] = ctx.digest[i] & 0xff; |
| 291 | d[2] = (ctx.digest[i] >> 8) & 0xff; |
| 292 | d[1] = (ctx.digest[i] >> 16) & 0xff; |
| 293 | d[0] = (ctx.digest[i] >> 24) & 0xff; |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | } // detail |
| 298 | } // beast |
| 299 | } // boost |
| 300 | |
| 301 | #endif |
| 302 | |