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
7#include "base/base64.h"
8#include "base/logging.h"
9#include "base/sha1.h"
10#include "base/strings/string_split.h"
11#include "base/strings/string_util.h"
12
13namespace net {
14
15namespace {
16
17// CompareSHA1Hashes is a helper function for using bsearch() with an array of
18// SHA1 hashes.
19int CompareSHA1Hashes(const void* a, const void* b) {
20  return memcmp(a, b, base::kSHA1Length);
21}
22
23}  // namespace
24
25
26bool SHA1HashValue::Equals(const SHA1HashValue& other) const {
27  return memcmp(data, other.data, sizeof(data)) == 0;
28}
29
30bool SHA256HashValue::Equals(const SHA256HashValue& other) const {
31  return memcmp(data, other.data, sizeof(data)) == 0;
32}
33
34bool HashValue::Equals(const HashValue& other) const {
35  if (tag != other.tag)
36    return false;
37  switch (tag) {
38    case HASH_VALUE_SHA1:
39      return fingerprint.sha1.Equals(other.fingerprint.sha1);
40    case HASH_VALUE_SHA256:
41      return fingerprint.sha256.Equals(other.fingerprint.sha256);
42    default:
43      NOTREACHED() << "Unknown HashValueTag " << tag;
44      return false;
45  }
46}
47
48bool HashValue::FromString(const base::StringPiece value) {
49  base::StringPiece base64_str;
50  if (value.starts_with("sha1/")) {
51    tag = HASH_VALUE_SHA1;
52    base64_str = value.substr(5);
53  } else if (value.starts_with("sha256/")) {
54    tag = HASH_VALUE_SHA256;
55    base64_str = value.substr(7);
56  } else {
57    return false;
58  }
59
60  std::string decoded;
61  if (!base::Base64Decode(base64_str, &decoded) || decoded.size() != size())
62    return false;
63
64  memcpy(data(), decoded.data(), size());
65  return true;
66}
67
68std::string HashValue::ToString() const {
69  std::string base64_str;
70  base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>(data()),
71                                       size()), &base64_str);
72  switch (tag) {
73  case HASH_VALUE_SHA1:
74    return std::string("sha1/") + base64_str;
75  case HASH_VALUE_SHA256:
76    return std::string("sha256/") + base64_str;
77  default:
78    NOTREACHED() << "Unknown HashValueTag " << tag;
79    return std::string("unknown/" + base64_str);
80  }
81}
82
83size_t HashValue::size() const {
84  switch (tag) {
85    case HASH_VALUE_SHA1:
86      return sizeof(fingerprint.sha1.data);
87    case HASH_VALUE_SHA256:
88      return sizeof(fingerprint.sha256.data);
89    default:
90      NOTREACHED() << "Unknown HashValueTag " << tag;
91      // While an invalid tag should not happen, return a non-zero length
92      // to avoid compiler warnings when the result of size() is
93      // used with functions like memset.
94      return sizeof(fingerprint.sha1.data);
95  }
96}
97
98unsigned char* HashValue::data() {
99  return const_cast<unsigned char*>(const_cast<const HashValue*>(this)->data());
100}
101
102const unsigned char* HashValue::data() const {
103  switch (tag) {
104    case HASH_VALUE_SHA1:
105      return fingerprint.sha1.data;
106    case HASH_VALUE_SHA256:
107      return fingerprint.sha256.data;
108    default:
109      NOTREACHED() << "Unknown HashValueTag " << tag;
110      return NULL;
111  }
112}
113
114bool IsSHA1HashInSortedArray(const SHA1HashValue& hash,
115                             const uint8* array,
116                             size_t array_byte_len) {
117  DCHECK_EQ(0u, array_byte_len % base::kSHA1Length);
118  const size_t arraylen = array_byte_len / base::kSHA1Length;
119  return NULL != bsearch(hash.data, array, arraylen, base::kSHA1Length,
120                         CompareSHA1Hashes);
121}
122
123}  // namespace net
124