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()));
98 return (mode_
== CTR
) ?
99 CryptCTR(context
.get(), ciphertext
, plaintext
) :
100 Crypt(context
.get(), ciphertext
, plaintext
);
103 bool Encryptor::Crypt(PK11Context
* context
,
104 const base::StringPiece
& input
,
105 std::string
* output
) {
106 size_t output_len
= input
.size() + AES_BLOCK_SIZE
;
107 CHECK_GT(output_len
, input
.size());
109 output
->resize(output_len
);
111 reinterpret_cast<uint8
*>(const_cast<char*>(output
->data()));
113 int input_len
= input
.size();
115 reinterpret_cast<uint8
*>(const_cast<char*>(input
.data()));
118 SECStatus rv
= PK11_CipherOp(context
,
125 if (SECSuccess
!= rv
) {
130 unsigned int digest_len
;
131 rv
= PK11_DigestFinal(context
,
132 output_data
+ op_len
,
134 output_len
- op_len
);
135 if (SECSuccess
!= rv
) {
140 output
->resize(op_len
+ digest_len
);
144 bool Encryptor::CryptCTR(PK11Context
* context
,
145 const base::StringPiece
& input
,
146 std::string
* output
) {
147 if (!counter_
.get()) {
148 LOG(ERROR
) << "Counter value not set in CTR mode.";
152 size_t output_len
= ((input
.size() + AES_BLOCK_SIZE
- 1) / AES_BLOCK_SIZE
) *
154 CHECK_GE(output_len
, input
.size());
155 output
->resize(output_len
);
157 reinterpret_cast<uint8
*>(const_cast<char*>(output
->data()));
160 bool ret
= GenerateCounterMask(input
.size(), output_data
, &mask_len
);
164 CHECK_EQ(mask_len
, output_len
);
166 SECStatus rv
= PK11_CipherOp(context
,
172 if (SECSuccess
!= rv
)
174 CHECK_EQ(static_cast<int>(mask_len
), op_len
);
176 unsigned int digest_len
;
177 rv
= PK11_DigestFinal(context
,
181 if (SECSuccess
!= rv
)
185 // Use |output_data| to mask |input|.
187 reinterpret_cast<uint8
*>(const_cast<char*>(input
.data())),
188 input
.length(), output_data
, output_data
);
189 output
->resize(input
.length());
193 } // namespace crypto