Fix protobuf_lite_java action ordering in gyp.
[chromium-blink-merge.git] / crypto / encryptor_nss.cc
blob280e38be46de8bfb7d650cb7cb610aa62dc36f8f
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"
7 #include <cryptohi.h>
8 #include <vector>
10 #include "base/logging.h"
11 #include "crypto/nss_util.h"
12 #include "crypto/symmetric_key.h"
14 namespace crypto {
16 namespace {
18 inline CK_MECHANISM_TYPE GetMechanism(Encryptor::Mode mode) {
19 switch (mode) {
20 case Encryptor::CBC:
21 return CKM_AES_CBC_PAD;
22 case Encryptor::CTR:
23 // AES-CTR encryption uses ECB encryptor as a building block since
24 // NSS doesn't support CTR encryption mode.
25 return CKM_AES_ECB;
26 default:
27 NOTREACHED() << "Unsupported mode of operation";
28 break;
30 return static_cast<CK_MECHANISM_TYPE>(-1);
33 } // namespace
35 Encryptor::Encryptor()
36 : key_(NULL),
37 mode_(CBC) {
38 EnsureNSSInit();
41 Encryptor::~Encryptor() {
44 bool Encryptor::Init(SymmetricKey* key,
45 Mode mode,
46 const base::StringPiece& iv) {
47 DCHECK(key);
48 DCHECK(CBC == mode || CTR == mode) << "Unsupported mode of operation";
50 key_ = key;
51 mode_ = mode;
53 if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
54 return false;
56 switch (mode) {
57 case CBC:
58 SECItem iv_item;
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));
65 break;
66 case CTR:
67 param_.reset(PK11_ParamFromIV(GetMechanism(mode), NULL));
68 break;
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_),
78 CKA_ENCRYPT,
79 key_->key(),
80 param_.get()));
81 if (!context.get())
82 return false;
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()));
95 if (!context.get())
96 return false;
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);
110 uint8* output_data =
111 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
113 int input_len = input.size();
114 uint8* input_data =
115 reinterpret_cast<uint8*>(const_cast<char*>(input.data()));
117 int op_len;
118 SECStatus rv = PK11_CipherOp(context,
119 output_data,
120 &op_len,
121 output_len,
122 input_data,
123 input_len);
125 if (SECSuccess != rv) {
126 output->clear();
127 return false;
130 unsigned int digest_len;
131 rv = PK11_DigestFinal(context,
132 output_data + op_len,
133 &digest_len,
134 output_len - op_len);
135 if (SECSuccess != rv) {
136 output->clear();
137 return false;
140 output->resize(op_len + digest_len);
141 return true;
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.";
149 return false;
152 size_t output_len = ((input.size() + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) *
153 AES_BLOCK_SIZE;
154 CHECK_GE(output_len, input.size());
155 output->resize(output_len);
156 uint8* output_data =
157 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
159 size_t mask_len;
160 bool ret = GenerateCounterMask(input.size(), output_data, &mask_len);
161 if (!ret)
162 return false;
164 CHECK_EQ(mask_len, output_len);
165 int op_len;
166 SECStatus rv = PK11_CipherOp(context,
167 output_data,
168 &op_len,
169 output_len,
170 output_data,
171 mask_len);
172 if (SECSuccess != rv)
173 return false;
174 CHECK_EQ(static_cast<int>(mask_len), op_len);
176 unsigned int digest_len;
177 rv = PK11_DigestFinal(context,
178 NULL,
179 &digest_len,
181 if (SECSuccess != rv)
182 return false;
183 CHECK(!digest_len);
185 // Use |output_data| to mask |input|.
186 MaskMessage(
187 reinterpret_cast<uint8*>(const_cast<char*>(input.data())),
188 input.length(), output_data, output_data);
189 output->resize(input.length());
190 return true;
193 } // namespace crypto