finnur@chromium.org | 0777cfc | 2011-02-14 09:25:30 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/sha1.h" |
| 6 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | #include <stdint.h> |
hans@chromium.org | 5035f68 | 2011-03-13 21:17:20 | [diff] [blame] | 9 | #include <string.h> |
| 10 | |
robert.bradford | 0bf0dd80 | 2016-06-17 20:11:04 | [diff] [blame] | 11 | #include "base/sys_byteorder.h" |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 12 | |
| 13 | namespace base { |
| 14 | |
| 15 | // Implementation of SHA-1. Only handles data in byte-sized blocks, |
| 16 | // which simplifies the code a fair bit. |
| 17 | |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 18 | // Identifier names follow notation in FIPS PUB 180-3, where you'll |
| 19 | // also find a description of the algorithm: |
| 20 | // http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf |
| 21 | |
| 22 | // Usage example: |
| 23 | // |
| 24 | // SecureHashAlgorithm sha; |
| 25 | // while(there is data to hash) |
| 26 | // sha.Update(moredata, size of data); |
| 27 | // sha.Final(); |
| 28 | // memcpy(somewhere, sha.Digest(), 20); |
| 29 | // |
| 30 | // to reuse the instance of sha, call sha.Init(); |
| 31 | |
| 32 | // TODO(jhawkins): Replace this implementation with a per-platform |
wtc@chromium.org | 94d557e | 2010-06-23 21:41:40 | [diff] [blame] | 33 | // implementation using each platform's crypto library. See |
| 34 | // http://crbug.com/47218 |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 35 | |
| 36 | class SecureHashAlgorithm { |
| 37 | public: |
| 38 | SecureHashAlgorithm() { Init(); } |
| 39 | |
| 40 | static const int kDigestSizeBytes; |
| 41 | |
| 42 | void Init(); |
| 43 | void Update(const void* data, size_t nbytes); |
| 44 | void Final(); |
| 45 | |
| 46 | // 20 bytes of message digest. |
| 47 | const unsigned char* Digest() const { |
| 48 | return reinterpret_cast<const unsigned char*>(H); |
| 49 | } |
| 50 | |
| 51 | private: |
| 52 | void Pad(); |
| 53 | void Process(); |
| 54 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 55 | uint32_t A, B, C, D, E; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 56 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 57 | uint32_t H[5]; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 58 | |
| 59 | union { |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 60 | uint32_t W[80]; |
| 61 | uint8_t M[64]; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 62 | }; |
| 63 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 64 | uint32_t cursor; |
| 65 | uint64_t l; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 66 | }; |
| 67 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 68 | static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t D) { |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 69 | if (t < 20) |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 70 | return (B & C) | ((~B) & D); |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 71 | if (t < 40) |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 72 | return B ^ C ^ D; |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 73 | if (t < 60) |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 74 | return (B & C) | (B & D) | (C & D); |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 75 | return B ^ C ^ D; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 76 | } |
| 77 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 78 | static inline uint32_t S(uint32_t n, uint32_t X) { |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 79 | return (X << n) | (X >> (32-n)); |
| 80 | } |
| 81 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 82 | static inline uint32_t K(uint32_t t) { |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 83 | if (t < 20) |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 84 | return 0x5a827999; |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 85 | if (t < 40) |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 86 | return 0x6ed9eba1; |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 87 | if (t < 60) |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 88 | return 0x8f1bbcdc; |
Tom Anderson | 68a48f7a | 2018-09-11 17:52:39 | [diff] [blame] | 89 | return 0xca62c1d6; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 90 | } |
| 91 | |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 92 | const int SecureHashAlgorithm::kDigestSizeBytes = 20; |
| 93 | |
| 94 | void SecureHashAlgorithm::Init() { |
finnur@chromium.org | 0777cfc | 2011-02-14 09:25:30 | [diff] [blame] | 95 | A = 0; |
| 96 | B = 0; |
| 97 | C = 0; |
| 98 | D = 0; |
| 99 | E = 0; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 100 | cursor = 0; |
| 101 | l = 0; |
| 102 | H[0] = 0x67452301; |
| 103 | H[1] = 0xefcdab89; |
| 104 | H[2] = 0x98badcfe; |
| 105 | H[3] = 0x10325476; |
| 106 | H[4] = 0xc3d2e1f0; |
| 107 | } |
| 108 | |
| 109 | void SecureHashAlgorithm::Final() { |
| 110 | Pad(); |
| 111 | Process(); |
| 112 | |
jdoerrie | 6c622935 | 2018-10-22 15:55:43 | [diff] [blame] | 113 | for (auto& t : H) |
| 114 | t = ByteSwap(t); |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | void SecureHashAlgorithm::Update(const void* data, size_t nbytes) { |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 118 | const uint8_t* d = reinterpret_cast<const uint8_t*>(data); |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 119 | while (nbytes--) { |
| 120 | M[cursor++] = *d++; |
| 121 | if (cursor >= 64) |
| 122 | Process(); |
| 123 | l += 8; |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | void SecureHashAlgorithm::Pad() { |
| 128 | M[cursor++] = 0x80; |
| 129 | |
| 130 | if (cursor > 64-8) { |
| 131 | // pad out to next block |
| 132 | while (cursor < 64) |
| 133 | M[cursor++] = 0; |
| 134 | |
| 135 | Process(); |
| 136 | } |
| 137 | |
wtc@chromium.org | 5c5a202 | 2014-07-14 14:46:09 | [diff] [blame] | 138 | while (cursor < 64-8) |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 139 | M[cursor++] = 0; |
| 140 | |
wtc@chromium.org | 5c5a202 | 2014-07-14 14:46:09 | [diff] [blame] | 141 | M[cursor++] = (l >> 56) & 0xff; |
| 142 | M[cursor++] = (l >> 48) & 0xff; |
| 143 | M[cursor++] = (l >> 40) & 0xff; |
| 144 | M[cursor++] = (l >> 32) & 0xff; |
| 145 | M[cursor++] = (l >> 24) & 0xff; |
| 146 | M[cursor++] = (l >> 16) & 0xff; |
| 147 | M[cursor++] = (l >> 8) & 0xff; |
| 148 | M[cursor++] = l & 0xff; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | void SecureHashAlgorithm::Process() { |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 152 | uint32_t t; |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 153 | |
| 154 | // Each a...e corresponds to a section in the FIPS 180-3 algorithm. |
| 155 | |
| 156 | // a. |
| 157 | // |
| 158 | // W and M are in a union, so no need to memcpy. |
| 159 | // memcpy(W, M, sizeof(M)); |
| 160 | for (t = 0; t < 16; ++t) |
robert.bradford | 0bf0dd80 | 2016-06-17 20:11:04 | [diff] [blame] | 161 | W[t] = ByteSwap(W[t]); |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 162 | |
| 163 | // b. |
| 164 | for (t = 16; t < 80; ++t) |
| 165 | W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); |
| 166 | |
| 167 | // c. |
| 168 | A = H[0]; |
| 169 | B = H[1]; |
| 170 | C = H[2]; |
| 171 | D = H[3]; |
| 172 | E = H[4]; |
| 173 | |
| 174 | // d. |
| 175 | for (t = 0; t < 80; ++t) { |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 176 | uint32_t TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t); |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 177 | E = D; |
| 178 | D = C; |
| 179 | C = S(30, B); |
| 180 | B = A; |
| 181 | A = TEMP; |
| 182 | } |
| 183 | |
| 184 | // e. |
| 185 | H[0] += A; |
| 186 | H[1] += B; |
| 187 | H[2] += C; |
| 188 | H[3] += D; |
| 189 | H[4] += E; |
| 190 | |
| 191 | cursor = 0; |
| 192 | } |
| 193 | |
Henrik Grunell | fc4ffc7 | 2017-11-30 11:56:44 | [diff] [blame] | 194 | std::string SHA1HashString(const std::string& str) { |
hans@chromium.org | 5035f68 | 2011-03-13 21:17:20 | [diff] [blame] | 195 | char hash[SecureHashAlgorithm::kDigestSizeBytes]; |
Henrik Grunell | fc4ffc7 | 2017-11-30 11:56:44 | [diff] [blame] | 196 | SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.c_str()), |
hans@chromium.org | 5035f68 | 2011-03-13 21:17:20 | [diff] [blame] | 197 | str.length(), reinterpret_cast<unsigned char*>(hash)); |
| 198 | return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes); |
| 199 | } |
| 200 | |
| 201 | void SHA1HashBytes(const unsigned char* data, size_t len, |
| 202 | unsigned char* hash) { |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 203 | SecureHashAlgorithm sha; |
hans@chromium.org | 5035f68 | 2011-03-13 21:17:20 | [diff] [blame] | 204 | sha.Update(data, len); |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 205 | sha.Final(); |
hans@chromium.org | 5035f68 | 2011-03-13 21:17:20 | [diff] [blame] | 206 | |
| 207 | memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes); |
jhawkins@chromium.org | c2ad1e3 | 2009-11-04 19:29:58 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | } // namespace base |