summaryrefslogtreecommitdiffstats
path: root/base/sha1_win.cc
blob: 0d0cf2c0a4c4bc3f2355ecb619ab51e8651052cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/sha1.h"

#include <windows.h>
#include <wincrypt.h>

#include "base/logging.h"

namespace base {

// Implementation of SHA-1 using Windows CryptoAPI.

// Usage example:
//
// SecureHashAlgorithm sha;
// while(there is data to hash)
//   sha.Update(moredata, size of data);
// sha.Final();
// memcpy(somewhere, sha.Digest(), 20);
//
// to reuse the instance of sha, call sha.Init();

class SecureHashAlgorithm {
 public:
  SecureHashAlgorithm() : prov_(NULL), hash_(NULL) { Init(); }

  void Init();
  void Update(const void* data, size_t nbytes);
  void Final();

  // 20 bytes of message digest.
  const unsigned char* Digest() const {
    return reinterpret_cast<const unsigned char*>(result_.data());
  }

 private:
  // Cleans up prov_, hash_, and result_.
  void Cleanup();

  HCRYPTPROV prov_;
  HCRYPTHASH hash_;
  std::string result_;
};

void SecureHashAlgorithm::Init() {
  Cleanup();

  if (!CryptAcquireContext(&prov_, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
    LOG(ERROR) << "CryptAcquireContext failed: " << GetLastError();
    return;
  }

  // Initialize the hash.
  if (!CryptCreateHash(prov_, CALG_SHA1, 0, 0, &hash_)) {
    LOG(ERROR) << "CryptCreateHash failed: " << GetLastError();
    return;
  }
}

void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
  BOOL ok = CryptHashData(hash_, reinterpret_cast<CONST BYTE*>(data),
                          static_cast<DWORD>(nbytes), 0);
  CHECK(ok) << "CryptHashData failed: " << GetLastError();
}

void SecureHashAlgorithm::Final() {
  DWORD hash_len = 0;
  DWORD buffer_size = sizeof(hash_len);
  if (!CryptGetHashParam(hash_, HP_HASHSIZE,
                         reinterpret_cast<unsigned char*>(&hash_len),
                         &buffer_size, 0)) {
    LOG(ERROR) << "CryptGetHashParam(HP_HASHSIZE) failed: " << GetLastError();
    result_.assign(SHA1_LENGTH, '\0');
    return;
  }

  // Get the hash data.
  if (!CryptGetHashParam(hash_, HP_HASHVAL,
                         reinterpret_cast<BYTE*>(WriteInto(&result_,
                                                           hash_len + 1)),
                         &hash_len, 0)) {
    LOG(ERROR) << "CryptGetHashParam(HP_HASHVAL) failed: " << GetLastError();
    result_.assign(SHA1_LENGTH, '\0');
    return;
  }
}

void SecureHashAlgorithm::Cleanup() {
  BOOL ok;
  if (hash_) {
    ok = CryptDestroyHash(hash_);
    DCHECK(ok);
    hash_ = NULL;
  }
  if (prov_) {
    ok = CryptReleaseContext(prov_, 0);
    DCHECK(ok);
    prov_ = NULL;
  }
  result_.clear();
}

std::string SHA1HashString(const std::string& str) {
  SecureHashAlgorithm sha;
  sha.Update(str.c_str(), str.length());
  sha.Final();
  std::string out(reinterpret_cast<const char*>(sha.Digest()), SHA1_LENGTH);
  return out;
}

}  // namespace base