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
)
56 slot_
.reset(PK11_GetBestSlot(GetMechanism(mode
), NULL
));
63 iv_item
.type
= siBuffer
;
64 iv_item
.data
= reinterpret_cast<unsigned char*>(
65 const_cast<char *>(iv
.data()));
66 iv_item
.len
= iv
.size();
68 param_
.reset(PK11_ParamFromIV(GetMechanism(mode
), &iv_item
));
71 param_
.reset(PK11_ParamFromIV(GetMechanism(mode
), NULL
));
80 bool Encryptor::Encrypt(const base::StringPiece
& plaintext
,
81 std::string
* ciphertext
) {
82 ScopedPK11Context
context(PK11_CreateContextBySymKey(GetMechanism(mode_
),
90 return CryptCTR(context
.get(), plaintext
, ciphertext
);
92 return Crypt(context
.get(), plaintext
, ciphertext
);
95 bool Encryptor::Decrypt(const base::StringPiece
& ciphertext
,
96 std::string
* plaintext
) {
97 if (ciphertext
.empty())
100 ScopedPK11Context
context(PK11_CreateContextBySymKey(
101 GetMechanism(mode_
), (mode_
== CTR
? CKA_ENCRYPT
: CKA_DECRYPT
),
102 key_
->key(), param_
.get()));
107 return CryptCTR(context
.get(), ciphertext
, plaintext
);
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(output_len
> input
.size()) << "Output size overflow";
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(output_len
>= input
.size()) << "Output size overflow";
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(op_len
== static_cast<int>(mask_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