Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / components / webcrypto / nss / sha_nss.cc
blob17800a16cac5a567541a1d4a64e4da66c2411166
1 // Copyright 2014 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.
5 #include <sechash.h>
6 #include <vector>
8 #include "base/stl_util.h"
9 #include "components/webcrypto/algorithm_implementation.h"
10 #include "components/webcrypto/crypto_data.h"
11 #include "components/webcrypto/nss/util_nss.h"
12 #include "components/webcrypto/status.h"
13 #include "components/webcrypto/webcrypto_util.h"
14 #include "crypto/nss_util.h"
15 #include "crypto/scoped_nss_types.h"
17 namespace webcrypto {
19 namespace {
21 HASH_HashType WebCryptoAlgorithmToNSSHashType(
22 blink::WebCryptoAlgorithmId algorithm) {
23 switch (algorithm) {
24 case blink::WebCryptoAlgorithmIdSha1:
25 return HASH_AlgSHA1;
26 case blink::WebCryptoAlgorithmIdSha256:
27 return HASH_AlgSHA256;
28 case blink::WebCryptoAlgorithmIdSha384:
29 return HASH_AlgSHA384;
30 case blink::WebCryptoAlgorithmIdSha512:
31 return HASH_AlgSHA512;
32 default:
33 // Not a digest algorithm.
34 return HASH_AlgNULL;
38 // Implementation of blink::WebCryptoDigester, an internal Blink detail not
39 // part of WebCrypto, that allows chunks of data to be streamed in before
40 // computing a SHA-* digest (as opposed to ShaImplementation, which computes
41 // digests over complete messages)
42 class DigestorNSS : public blink::WebCryptoDigestor {
43 public:
44 explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id)
45 : hash_context_(NULL), algorithm_id_(algorithm_id) {}
47 ~DigestorNSS() override {
48 if (!hash_context_)
49 return;
51 HASH_Destroy(hash_context_);
52 hash_context_ = NULL;
55 bool consume(const unsigned char* data, unsigned int size) override {
56 return ConsumeWithStatus(data, size).IsSuccess();
59 Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
60 // Initialize everything if the object hasn't been initialized yet.
61 if (!hash_context_) {
62 Status error = Init();
63 if (!error.IsSuccess())
64 return error;
67 HASH_Update(hash_context_, data, size);
69 return Status::Success();
72 bool finish(unsigned char*& result_data,
73 unsigned int& result_data_size) override {
74 Status error = FinishInternal(result_, &result_data_size);
75 if (!error.IsSuccess())
76 return false;
77 result_data = result_;
78 return true;
81 Status FinishWithVectorAndStatus(std::vector<uint8_t>* result) {
82 if (!hash_context_)
83 return Status::ErrorUnexpected();
85 unsigned int result_length = HASH_ResultLenContext(hash_context_);
86 result->resize(result_length);
87 unsigned char* digest = vector_as_array(result);
88 unsigned int digest_size; // ignored
89 return FinishInternal(digest, &digest_size);
92 private:
93 Status Init() {
94 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm_id_);
96 if (hash_type == HASH_AlgNULL)
97 return Status::ErrorUnsupported();
99 hash_context_ = HASH_Create(hash_type);
100 if (!hash_context_)
101 return Status::OperationError();
103 HASH_Begin(hash_context_);
105 return Status::Success();
108 Status FinishInternal(unsigned char* result, unsigned int* result_size) {
109 if (!hash_context_) {
110 Status error = Init();
111 if (!error.IsSuccess())
112 return error;
115 unsigned int hash_result_length = HASH_ResultLenContext(hash_context_);
116 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
118 HASH_End(hash_context_, result, result_size, hash_result_length);
120 if (*result_size != hash_result_length)
121 return Status::ErrorUnexpected();
122 return Status::Success();
125 HASHContext* hash_context_;
126 blink::WebCryptoAlgorithmId algorithm_id_;
127 unsigned char result_[HASH_LENGTH_MAX];
130 class ShaImplementation : public AlgorithmImplementation {
131 public:
132 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
133 const CryptoData& data,
134 std::vector<uint8_t>* buffer) const override {
135 DigestorNSS digestor(algorithm.id());
136 Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
137 // http://crbug.com/366427: the spec does not define any other failures for
138 // digest, so none of the subsequent errors are spec compliant.
139 if (!error.IsSuccess())
140 return error;
141 return digestor.FinishWithVectorAndStatus(buffer);
145 } // namespace
147 AlgorithmImplementation* CreatePlatformShaImplementation() {
148 return new ShaImplementation();
151 scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
152 blink::WebCryptoAlgorithmId algorithm) {
153 return scoped_ptr<blink::WebCryptoDigestor>(new DigestorNSS(algorithm));
156 } // namespace webcrypto