1 // Copyright (c) 2011 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 "crypto/encryptor.h"
10 #include "base/logging.h"
11 #include "crypto/nss_util.h"
12 #include "crypto/symmetric_key.h"
18 inline CK_MECHANISM_TYPE
GetMechanism(Encryptor::Mode mode
) {
21 return CKM_AES_CBC_PAD
;
23 // AES-CTR encryption uses ECB encryptor as a building block since
24 // NSS doesn't support CTR encryption mode.
27 NOTREACHED() << "Unsupported mode of operation";
30 return static_cast<CK_MECHANISM_TYPE
>(-1);
35 Encryptor::Encryptor()
41 Encryptor::~Encryptor() {
44 bool Encryptor::Init(SymmetricKey
* key
,
46 const base::StringPiece
& iv
) {
48 DCHECK(CBC
== mode
|| CTR
== mode
) << "Unsupported mode of operation";
53 if (mode
== CBC
&& iv
.size() != AES_BLOCK_SIZE
)
59 iv_item
.type
= siBuffer
;
60 iv_item
.data
= reinterpret_cast<unsigned char*>(
61 const_cast<char *>(iv
.data()));
62 iv_item
.len
= iv
.size();
64 param_
.reset(PK11_ParamFromIV(GetMechanism(mode
), &iv_item
));
67 param_
.reset(PK11_ParamFromIV(GetMechanism(mode
), NULL
));
71 return param_
!= NULL
;
74 bool Encryptor::Encrypt(const base::StringPiece
& plaintext
,
75 std::string
* ciphertext
) {
76 CHECK(!plaintext
.empty() || (mode_
== CBC
));
77 ScopedPK11Context
context(PK11_CreateContextBySymKey(GetMechanism(mode_
),
84 return (mode_
== CTR
) ?
85 CryptCTR(context
.get(), plaintext
, ciphertext
) :
86 Crypt(context
.get(), plaintext
, ciphertext
);
89 bool Encryptor::Decrypt(const base::StringPiece
& ciphertext
,
90 std::string
* plaintext
) {
91 CHECK(!ciphertext
.empty());
92 ScopedPK11Context
context(PK11_CreateContextBySymKey(
93 GetMechanism(mode_
), (mode_
== CTR
? CKA_ENCRYPT
: CKA_DECRYPT
),
94 key_
->key(), param_
.get()));
99 return CryptCTR(context
.get(), ciphertext
, plaintext
);
101 if (ciphertext
.size() % AES_BLOCK_SIZE
!= 0) {
102 // Decryption will fail if the input is not a multiple of the block size.
103 // PK11_CipherOp has a bug where it will do an invalid memory access before
104 // the start of the input, so avoid calling it. (NSS bug 922780).
109 return Crypt(context
.get(), ciphertext
, plaintext
);
112 bool Encryptor::Crypt(PK11Context
* context
,
113 const base::StringPiece
& input
,
114 std::string
* output
) {
115 size_t output_len
= input
.size() + AES_BLOCK_SIZE
;
116 CHECK_GT(output_len
, input
.size());
118 output
->resize(output_len
);
120 reinterpret_cast<uint8
*>(const_cast<char*>(output
->data()));
122 int input_len
= input
.size();
124 reinterpret_cast<uint8
*>(const_cast<char*>(input
.data()));
127 SECStatus rv
= PK11_CipherOp(context
,
134 if (SECSuccess
!= rv
) {
139 unsigned int digest_len
;
140 rv
= PK11_DigestFinal(context
,
141 output_data
+ op_len
,
143 output_len
- op_len
);
144 if (SECSuccess
!= rv
) {
149 output
->resize(op_len
+ digest_len
);
153 bool Encryptor::CryptCTR(PK11Context
* context
,
154 const base::StringPiece
& input
,
155 std::string
* output
) {
156 if (!counter_
.get()) {
157 LOG(ERROR
) << "Counter value not set in CTR mode.";
161 size_t output_len
= ((input
.size() + AES_BLOCK_SIZE
- 1) / AES_BLOCK_SIZE
) *
163 CHECK_GE(output_len
, input
.size());
164 output
->resize(output_len
);
166 reinterpret_cast<uint8
*>(const_cast<char*>(output
->data()));
169 bool ret
= GenerateCounterMask(input
.size(), output_data
, &mask_len
);
173 CHECK_EQ(mask_len
, output_len
);
175 SECStatus rv
= PK11_CipherOp(context
,
181 if (SECSuccess
!= rv
)
183 CHECK_EQ(static_cast<int>(mask_len
), op_len
);
185 unsigned int digest_len
;
186 rv
= PK11_DigestFinal(context
,
190 if (SECSuccess
!= rv
)
194 // Use |output_data| to mask |input|.
196 reinterpret_cast<uint8
*>(const_cast<char*>(input
.data())),
197 input
.length(), output_data
, output_data
);
198 output
->resize(input
.length());
202 } // namespace crypto