1 // Copyright 2012 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/base/hash_value.h"
11
12 #include <stdlib.h>
13
14 #include <algorithm>
15 #include <ostream>
16
17 #include "base/base64.h"
18 #include "base/check_op.h"
19 #include "base/containers/span.h"
20 #include "base/notreached.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_util.h"
23 #include "crypto/sha2.h"
24
25 namespace net {
26
27 namespace {
28
29 constexpr std::string_view kSha256Slash = "sha256/";
30
31 // LessThan comparator for use with std::binary_search() in determining
32 // whether a SHA-256 HashValue appears within a sorted array of
33 // SHA256HashValues.
34 struct SHA256ToHashValueComparator {
operator ()net::__anon0587063f0111::SHA256ToHashValueComparator35 bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const {
36 DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag());
37 return memcmp(lhs.data, rhs.data(), rhs.size()) < 0;
38 }
39
operator ()net::__anon0587063f0111::SHA256ToHashValueComparator40 bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const {
41 DCHECK_EQ(HASH_VALUE_SHA256, lhs.tag());
42 return memcmp(lhs.data(), rhs.data, lhs.size()) < 0;
43 }
44 };
45
46 } // namespace
47
48
HashValue(const SHA256HashValue & hash)49 HashValue::HashValue(const SHA256HashValue& hash)
50 : HashValue(HASH_VALUE_SHA256) {
51 fingerprint.sha256 = hash;
52 }
53
FromString(std::string_view value)54 bool HashValue::FromString(std::string_view value) {
55 if (!value.starts_with(kSha256Slash)) {
56 return false;
57 }
58
59 std::string_view base64_str = value.substr(kSha256Slash.size());
60
61 auto decoded = base::Base64Decode(base64_str);
62 if (!decoded || decoded->size() != size()) {
63 return false;
64 }
65 tag_ = HASH_VALUE_SHA256;
66 memcpy(data(), decoded->data(), size());
67 return true;
68 }
69
ToString() const70 std::string HashValue::ToString() const {
71 std::string base64_str = base::Base64Encode(base::span(data(), size()));
72 switch (tag_) {
73 case HASH_VALUE_SHA256:
74 return std::string(kSha256Slash) + base64_str;
75 }
76
77 NOTREACHED();
78 }
79
size() const80 size_t HashValue::size() const {
81 switch (tag_) {
82 case HASH_VALUE_SHA256:
83 return sizeof(fingerprint.sha256.data);
84 }
85
86 NOTREACHED();
87 }
88
data()89 unsigned char* HashValue::data() {
90 return const_cast<unsigned char*>(const_cast<const HashValue*>(this)->data());
91 }
92
data() const93 const unsigned char* HashValue::data() const {
94 switch (tag_) {
95 case HASH_VALUE_SHA256:
96 return fingerprint.sha256.data;
97 }
98
99 NOTREACHED();
100 }
101
operator ==(const HashValue & lhs,const HashValue & rhs)102 bool operator==(const HashValue& lhs, const HashValue& rhs) {
103 if (lhs.tag_ != rhs.tag_)
104 return false;
105
106 switch (lhs.tag_) {
107 case HASH_VALUE_SHA256:
108 return lhs.fingerprint.sha256 == rhs.fingerprint.sha256;
109 }
110
111 NOTREACHED();
112 }
113
operator !=(const HashValue & lhs,const HashValue & rhs)114 bool operator!=(const HashValue& lhs, const HashValue& rhs) {
115 return !(lhs == rhs);
116 }
117
operator <(const HashValue & lhs,const HashValue & rhs)118 bool operator<(const HashValue& lhs, const HashValue& rhs) {
119 if (lhs.tag_ != rhs.tag_)
120 return lhs.tag_ < rhs.tag_;
121
122 switch (lhs.tag_) {
123 case HASH_VALUE_SHA256:
124 return lhs.fingerprint.sha256 < rhs.fingerprint.sha256;
125 }
126
127 NOTREACHED();
128 }
129
operator >(const HashValue & lhs,const HashValue & rhs)130 bool operator>(const HashValue& lhs, const HashValue& rhs) {
131 return rhs < lhs;
132 }
133
operator <=(const HashValue & lhs,const HashValue & rhs)134 bool operator<=(const HashValue& lhs, const HashValue& rhs) {
135 return !(lhs > rhs);
136 }
137
operator >=(const HashValue & lhs,const HashValue & rhs)138 bool operator>=(const HashValue& lhs, const HashValue& rhs) {
139 return !(lhs < rhs);
140 }
141
IsSHA256HashInSortedArray(const HashValue & hash,base::span<const SHA256HashValue> array)142 bool IsSHA256HashInSortedArray(const HashValue& hash,
143 base::span<const SHA256HashValue> array) {
144 return std::binary_search(array.begin(), array.end(), hash,
145 SHA256ToHashValueComparator());
146 }
147
IsAnySHA256HashInSortedArray(base::span<const HashValue> hashes,base::span<const SHA256HashValue> array)148 bool IsAnySHA256HashInSortedArray(base::span<const HashValue> hashes,
149 base::span<const SHA256HashValue> array) {
150 for (const auto& hash : hashes) {
151 if (hash.tag() != HASH_VALUE_SHA256)
152 continue;
153
154 if (IsSHA256HashInSortedArray(hash, array))
155 return true;
156 }
157 return false;
158 }
159
160 } // namespace net
161