1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 "net/base/hash_value.h"
6 #include "base/strings/string_util.h"
7 
8 #include <stdlib.h>
9 #include <algorithm>
10 
11 #include "base/base64.h"
12 #include "base/check_op.h"
13 #include "base/notreached.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "crypto/sha2.h"
17 
18 namespace net {
19 
20 namespace {
21 
22 // LessThan comparator for use with std::binary_search() in determining
23 // whether a SHA-256 HashValue appears within a sorted array of
24 // SHA256HashValues.
25 struct SHA256ToHashValueComparator {
operator ()net::__anon7ec020390111::SHA256ToHashValueComparator26   bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const {
27     DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag());
28     return memcmp(lhs.data, rhs.data(), rhs.size()) < 0;
29   }
30 
operator ()net::__anon7ec020390111::SHA256ToHashValueComparator31   bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const {
32     DCHECK_EQ(HASH_VALUE_SHA256, lhs.tag());
33     return memcmp(lhs.data(), rhs.data, lhs.size()) < 0;
34   }
35 };
36 
37 }  // namespace
38 
39 
HashValue(const SHA256HashValue & hash)40 HashValue::HashValue(const SHA256HashValue& hash)
41     : HashValue(HASH_VALUE_SHA256) {
42   fingerprint.sha256 = hash;
43 }
44 
FromString(const base::StringPiece value)45 bool HashValue::FromString(const base::StringPiece value) {
46   base::StringPiece base64_str;
47   if (base::StartsWith(value, "sha256/")) {
48     tag_ = HASH_VALUE_SHA256;
49     base64_str = value.substr(7);
50   } else {
51     return false;
52   }
53 
54   std::string decoded;
55   if (!base::Base64Decode(base64_str, &decoded) || decoded.size() != size())
56     return false;
57 
58   memcpy(data(), decoded.data(), size());
59   return true;
60 }
61 
ToString() const62 std::string HashValue::ToString() const {
63   std::string base64_str;
64   base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>(data()),
65                                        size()), &base64_str);
66   switch (tag_) {
67     case HASH_VALUE_SHA256:
68       return std::string("sha256/") + base64_str;
69   }
70 
71   NOTREACHED() << "Unknown HashValueTag " << tag_;
72   return std::string("unknown/" + base64_str);
73 }
74 
size() const75 size_t HashValue::size() const {
76   switch (tag_) {
77     case HASH_VALUE_SHA256:
78       return sizeof(fingerprint.sha256.data);
79   }
80 
81   NOTREACHED() << "Unknown HashValueTag " << tag_;
82   // While an invalid tag should not happen, return a non-zero length
83   // to avoid compiler warnings when the result of size() is
84   // used with functions like memset.
85   return sizeof(fingerprint.sha256.data);
86 }
87 
data()88 unsigned char* HashValue::data() {
89   return const_cast<unsigned char*>(const_cast<const HashValue*>(this)->data());
90 }
91 
data() const92 const unsigned char* HashValue::data() const {
93   switch (tag_) {
94     case HASH_VALUE_SHA256:
95       return fingerprint.sha256.data;
96   }
97 
98   NOTREACHED() << "Unknown HashValueTag " << tag_;
99   return nullptr;
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   return false;
113 }
114 
operator !=(const HashValue & lhs,const HashValue & rhs)115 bool operator!=(const HashValue& lhs, const HashValue& rhs) {
116   return !(lhs == rhs);
117 }
118 
operator <(const HashValue & lhs,const HashValue & rhs)119 bool operator<(const HashValue& lhs, const HashValue& rhs) {
120   if (lhs.tag_ != rhs.tag_)
121     return lhs.tag_ < rhs.tag_;
122 
123   switch (lhs.tag_) {
124     case HASH_VALUE_SHA256:
125       return lhs.fingerprint.sha256 < rhs.fingerprint.sha256;
126   }
127 
128   NOTREACHED();
129   return false;
130 }
131 
operator >(const HashValue & lhs,const HashValue & rhs)132 bool operator>(const HashValue& lhs, const HashValue& rhs) {
133   return rhs < lhs;
134 }
135 
operator <=(const HashValue & lhs,const HashValue & rhs)136 bool operator<=(const HashValue& lhs, const HashValue& rhs) {
137   return !(lhs > rhs);
138 }
139 
operator >=(const HashValue & lhs,const HashValue & rhs)140 bool operator>=(const HashValue& lhs, const HashValue& rhs) {
141   return !(lhs < rhs);
142 }
143 
IsSHA256HashInSortedArray(const HashValue & hash,base::span<const SHA256HashValue> array)144 bool IsSHA256HashInSortedArray(const HashValue& hash,
145                                base::span<const SHA256HashValue> array) {
146   return std::binary_search(array.begin(), array.end(), hash,
147                             SHA256ToHashValueComparator());
148 }
149 
IsAnySHA256HashInSortedArray(base::span<const HashValue> hashes,base::span<const SHA256HashValue> array)150 bool IsAnySHA256HashInSortedArray(base::span<const HashValue> hashes,
151                                   base::span<const SHA256HashValue> array) {
152   for (const auto& hash : hashes) {
153     if (hash.tag() != HASH_VALUE_SHA256)
154       continue;
155 
156     if (IsSHA256HashInSortedArray(hash, array))
157       return true;
158   }
159   return false;
160 }
161 
162 }  // namespace net
163