Updating trunk VERSION from 874.0 to 875.0
[chromium-blink-merge.git] / crypto / encryptor_nss.cc
blobc46109031ac88093ac70cf863c389faa53a16c9c
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 slot_.reset(PK11_GetBestSlot(GetMechanism(mode), NULL));
57 if (!slot_.get())
58 return false;
60 switch (mode) {
61 case CBC:
62 SECItem iv_item;
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));
69 break;
70 case CTR:
71 param_.reset(PK11_ParamFromIV(GetMechanism(mode), NULL));
72 break;
75 if (!param_.get())
76 return false;
77 return true;
80 bool Encryptor::Encrypt(const base::StringPiece& plaintext,
81 std::string* ciphertext) {
82 ScopedPK11Context context(PK11_CreateContextBySymKey(GetMechanism(mode_),
83 CKA_ENCRYPT,
84 key_->key(),
85 param_.get()));
86 if (!context.get())
87 return false;
89 if (mode_ == CTR)
90 return CryptCTR(context.get(), plaintext, ciphertext);
91 else
92 return Crypt(context.get(), plaintext, ciphertext);
95 bool Encryptor::Decrypt(const base::StringPiece& ciphertext,
96 std::string* plaintext) {
97 if (ciphertext.empty())
98 return false;
100 ScopedPK11Context context(PK11_CreateContextBySymKey(
101 GetMechanism(mode_), (mode_ == CTR ? CKA_ENCRYPT : CKA_DECRYPT),
102 key_->key(), param_.get()));
103 if (!context.get())
104 return false;
106 if (mode_ == CTR)
107 return CryptCTR(context.get(), ciphertext, plaintext);
108 else
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);
119 uint8* output_data =
120 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
122 int input_len = input.size();
123 uint8* input_data =
124 reinterpret_cast<uint8*>(const_cast<char*>(input.data()));
126 int op_len;
127 SECStatus rv = PK11_CipherOp(context,
128 output_data,
129 &op_len,
130 output_len,
131 input_data,
132 input_len);
134 if (SECSuccess != rv) {
135 output->clear();
136 return false;
139 unsigned int digest_len;
140 rv = PK11_DigestFinal(context,
141 output_data + op_len,
142 &digest_len,
143 output_len - op_len);
144 if (SECSuccess != rv) {
145 output->clear();
146 return false;
149 output->resize(op_len + digest_len);
150 return true;
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.";
158 return false;
161 size_t output_len = ((input.size() + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) *
162 AES_BLOCK_SIZE;
163 CHECK(output_len >= input.size()) << "Output size overflow";
164 output->resize(output_len);
165 uint8* output_data =
166 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
168 size_t mask_len;
169 bool ret = GenerateCounterMask(input.size(), output_data, &mask_len);
170 if (!ret)
171 return false;
173 CHECK_EQ(mask_len, output_len);
174 int op_len;
175 SECStatus rv = PK11_CipherOp(context,
176 output_data,
177 &op_len,
178 output_len,
179 output_data,
180 mask_len);
181 if (SECSuccess != rv)
182 return false;
183 CHECK(op_len == static_cast<int>(mask_len));
185 unsigned int digest_len;
186 rv = PK11_DigestFinal(context,
187 NULL,
188 &digest_len,
190 if (SECSuccess != rv)
191 return false;
192 CHECK(!digest_len);
194 // Use |output_data| to mask |input|.
195 MaskMessage(
196 reinterpret_cast<uint8*>(const_cast<char*>(input.data())),
197 input.length(), output_data, output_data);
198 output->resize(input.length());
199 return true;
202 } // namespace crypto