xref: /aosp_15_r20/external/cronet/base/hash/sha1_nacl.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2011 The Chromium Authors
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 <stddef.h>
6 #include <stdint.h>
7 #include <string.h>
8 
9 #include <string_view>
10 
11 #include "base/hash/sha1.h"
12 #include "base/numerics/byte_conversions.h"
13 
14 namespace base {
15 // Implementation of SHA-1. Only handles data in byte-sized blocks,
16 // which simplifies the code a fair bit.
17 
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 
f(uint32_t t,uint32_t B,uint32_t C,uint32_t D)32 static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t D) {
33   if (t < 20)
34     return (B & C) | ((~B) & D);
35   if (t < 40)
36     return B ^ C ^ D;
37   if (t < 60)
38     return (B & C) | (B & D) | (C & D);
39   return B ^ C ^ D;
40 }
41 
S(uint32_t n,uint32_t X)42 static inline uint32_t S(uint32_t n, uint32_t X) {
43   return (X << n) | (X >> (32 - n));
44 }
45 
K(uint32_t t)46 static inline uint32_t K(uint32_t t) {
47   if (t < 20)
48     return 0x5a827999;
49   if (t < 40)
50     return 0x6ed9eba1;
51   if (t < 60)
52     return 0x8f1bbcdc;
53   return 0xca62c1d6;
54 }
55 
Init()56 void SHA1Context::Init() {
57   A = 0;
58   B = 0;
59   C = 0;
60   D = 0;
61   E = 0;
62   cursor = 0;
63   l = 0;
64   H[0] = 0x67452301;
65   H[1] = 0xefcdab89;
66   H[2] = 0x98badcfe;
67   H[3] = 0x10325476;
68   H[4] = 0xc3d2e1f0;
69 }
70 
Update(const void * data,size_t nbytes)71 void SHA1Context::Update(const void* data, size_t nbytes) {
72   const uint8_t* d = reinterpret_cast<const uint8_t*>(data);
73   while (nbytes--) {
74     M[cursor++] = *d++;
75     if (cursor >= 64) {
76       Process();
77     }
78     l += 8;
79   }
80 }
81 
Final()82 void SHA1Context::Final() {
83   Pad();
84   Process();
85 
86   for (auto& t : H) {
87     t = ByteSwap(t);
88   }
89 }
90 
GetDigest() const91 const unsigned char* SHA1Context::GetDigest() const {
92   return reinterpret_cast<const unsigned char*>(H);
93 }
94 
Pad()95 void SHA1Context::Pad() {
96   M[cursor++] = 0x80;
97 
98   if (cursor > 64 - 8) {
99     // pad out to next block
100     while (cursor < 64) {
101       M[cursor++] = 0;
102     }
103 
104     Process();
105   }
106 
107   while (cursor < 64 - 8) {
108     M[cursor++] = 0;
109   }
110 
111   M[cursor++] = (l >> 56) & 0xff;
112   M[cursor++] = (l >> 48) & 0xff;
113   M[cursor++] = (l >> 40) & 0xff;
114   M[cursor++] = (l >> 32) & 0xff;
115   M[cursor++] = (l >> 24) & 0xff;
116   M[cursor++] = (l >> 16) & 0xff;
117   M[cursor++] = (l >> 8) & 0xff;
118   M[cursor++] = l & 0xff;
119 }
120 
Process()121 void SHA1Context::Process() {
122   uint32_t t;
123 
124   // Each a...e corresponds to a section in the FIPS 180-3 algorithm.
125 
126   // a.
127   //
128   // W and M are in a union, so no need to memcpy.
129   // memcpy(W, M, sizeof(M));
130   for (t = 0; t < 16; ++t) {
131     W[t] = ByteSwap(W[t]);
132   }
133 
134   // b.
135   for (t = 16; t < 80; ++t) {
136     W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
137   }
138 
139   // c.
140   A = H[0];
141   B = H[1];
142   C = H[2];
143   D = H[3];
144   E = H[4];
145 
146   // d.
147   for (t = 0; t < 80; ++t) {
148     uint32_t TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
149     E = D;
150     D = C;
151     C = S(30, B);
152     B = A;
153     A = TEMP;
154   }
155 
156   // e.
157   H[0] += A;
158   H[1] += B;
159   H[2] += C;
160   H[3] += D;
161   H[4] += E;
162 
163   cursor = 0;
164 }
165 
166 // These functions allow streaming SHA-1 operations.
SHA1Init(SHA1Context & context)167 void SHA1Init(SHA1Context& context) {
168   context.Init();
169 }
170 
SHA1Update(const std::string_view data,SHA1Context & context)171 void SHA1Update(const std::string_view data, SHA1Context& context) {
172   context.Update(data.data(), data.size());
173 }
174 
SHA1Final(SHA1Context & context,SHA1Digest & digest)175 void SHA1Final(SHA1Context& context, SHA1Digest& digest) {
176   context.Final();
177   memcpy(digest.data(), context.GetDigest(), kSHA1Length);
178 }
179 
SHA1HashSpan(span<const uint8_t> data)180 SHA1Digest SHA1HashSpan(span<const uint8_t> data) {
181   SHA1Digest hash;
182   SHA1HashBytes(data.data(), data.size(), hash.data());
183   return hash;
184 }
185 
SHA1HashString(std::string_view str)186 std::string SHA1HashString(std::string_view str) {
187   char hash[kSHA1Length];
188   SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.data()),
189                 str.length(), reinterpret_cast<unsigned char*>(hash));
190   return std::string(hash, kSHA1Length);
191 }
192 
SHA1HashBytes(const unsigned char * data,size_t len,unsigned char * hash)193 void SHA1HashBytes(const unsigned char* data, size_t len, unsigned char* hash) {
194   SHA1Context context;
195   context.Init();
196   context.Update(data, len);
197   context.Final();
198 
199   memcpy(hash, context.GetDigest(), kSHA1Length);
200 }
201 
202 }  // namespace base
203