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.
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"
21 HASH_HashType
WebCryptoAlgorithmToNSSHashType(
22 blink::WebCryptoAlgorithmId algorithm
) {
24 case blink::WebCryptoAlgorithmIdSha1
:
26 case blink::WebCryptoAlgorithmIdSha256
:
27 return HASH_AlgSHA256
;
28 case blink::WebCryptoAlgorithmIdSha384
:
29 return HASH_AlgSHA384
;
30 case blink::WebCryptoAlgorithmIdSha512
:
31 return HASH_AlgSHA512
;
33 // Not a digest algorithm.
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
{
44 explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id
)
45 : hash_context_(NULL
), algorithm_id_(algorithm_id
) {}
47 ~DigestorNSS() override
{
51 HASH_Destroy(hash_context_
);
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.
62 Status error
= Init();
63 if (!error
.IsSuccess())
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())
77 result_data
= result_
;
81 Status
FinishWithVectorAndStatus(std::vector
<uint8_t>* result
) {
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
);
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
);
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())
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
{
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())
141 return digestor
.FinishWithVectorAndStatus(buffer
);
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