blob: ca5d5239a2a966c19e1f164ec5db065078672474 [file] [log] [blame]
[email protected]663d0ee2011-02-16 10:11:031// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]39422e32010-03-25 19:13:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]4b559b4d2011-04-14 17:37:145#include "crypto/encryptor.h"
[email protected]39422e32010-03-25 19:13:006
7#include <cryptohi.h>
8#include <vector>
9
10#include "base/logging.h"
[email protected]4b559b4d2011-04-14 17:37:1411#include "crypto/nss_util.h"
12#include "crypto/symmetric_key.h"
[email protected]39422e32010-03-25 19:13:0013
[email protected]4b559b4d2011-04-14 17:37:1414namespace crypto {
[email protected]39422e32010-03-25 19:13:0015
[email protected]2377cdee2011-06-24 20:46:0616namespace {
17
18inline 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;
29 }
30 return static_cast<CK_MECHANISM_TYPE>(-1);
31}
32
33} // namespace
34
[email protected]663d0ee2011-02-16 10:11:0335Encryptor::Encryptor()
36 : key_(NULL),
37 mode_(CBC) {
[email protected]39422e32010-03-25 19:13:0038 EnsureNSSInit();
39}
40
41Encryptor::~Encryptor() {
42}
43
[email protected]44a016a82011-07-08 02:53:0944bool Encryptor::Init(SymmetricKey* key,
45 Mode mode,
46 const base::StringPiece& iv) {
[email protected]39422e32010-03-25 19:13:0047 DCHECK(key);
[email protected]2377cdee2011-06-24 20:46:0648 DCHECK(CBC == mode || CTR == mode) << "Unsupported mode of operation";
[email protected]39422e32010-03-25 19:13:0049
[email protected]1b47ce22010-03-31 16:18:3050 key_ = key;
[email protected]39422e32010-03-25 19:13:0051 mode_ = mode;
[email protected]1b47ce22010-03-31 16:18:3052
[email protected]2377cdee2011-06-24 20:46:0653 if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
[email protected]39422e32010-03-25 19:13:0054 return false;
55
[email protected]2377cdee2011-06-24 20:46:0656 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();
[email protected]39422e32010-03-25 19:13:0063
[email protected]2377cdee2011-06-24 20:46:0664 param_.reset(PK11_ParamFromIV(GetMechanism(mode), &iv_item));
65 break;
66 case CTR:
67 param_.reset(PK11_ParamFromIV(GetMechanism(mode), NULL));
68 break;
69 }
70
[email protected]fdce4782011-11-29 20:06:1871 return param_ != NULL;
[email protected]39422e32010-03-25 19:13:0072}
73
[email protected]44a016a82011-07-08 02:53:0974bool Encryptor::Encrypt(const base::StringPiece& plaintext,
75 std::string* ciphertext) {
[email protected]fdce4782011-11-29 20:06:1876 CHECK(!plaintext.empty() || (mode_ == CBC));
[email protected]2377cdee2011-06-24 20:46:0677 ScopedPK11Context context(PK11_CreateContextBySymKey(GetMechanism(mode_),
[email protected]39422e32010-03-25 19:13:0078 CKA_ENCRYPT,
79 key_->key(),
80 param_.get()));
81 if (!context.get())
82 return false;
83
[email protected]fdce4782011-11-29 20:06:1884 return (mode_ == CTR) ?
85 CryptCTR(context.get(), plaintext, ciphertext) :
86 Crypt(context.get(), plaintext, ciphertext);
[email protected]39422e32010-03-25 19:13:0087}
88
[email protected]44a016a82011-07-08 02:53:0989bool Encryptor::Decrypt(const base::StringPiece& ciphertext,
90 std::string* plaintext) {
[email protected]fdce4782011-11-29 20:06:1891 CHECK(!ciphertext.empty());
[email protected]2377cdee2011-06-24 20:46:0692 ScopedPK11Context context(PK11_CreateContextBySymKey(
93 GetMechanism(mode_), (mode_ == CTR ? CKA_ENCRYPT : CKA_DECRYPT),
94 key_->key(), param_.get()));
[email protected]39422e32010-03-25 19:13:0095 if (!context.get())
96 return false;
97
[email protected]1a39c7b2013-10-01 10:34:2798 if (mode_ == CTR)
99 return CryptCTR(context.get(), ciphertext, plaintext);
100
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
[email protected]b06bf4f2013-10-02 19:42:52104 // the start of the input, so avoid calling it. (NSS bug 922780).
[email protected]1a39c7b2013-10-01 10:34:27105 plaintext->clear();
106 return false;
107 }
108
109 return Crypt(context.get(), ciphertext, plaintext);
[email protected]2377cdee2011-06-24 20:46:06110}
111
[email protected]44a016a82011-07-08 02:53:09112bool Encryptor::Crypt(PK11Context* context,
113 const base::StringPiece& input,
[email protected]2377cdee2011-06-24 20:46:06114 std::string* output) {
115 size_t output_len = input.size() + AES_BLOCK_SIZE;
[email protected]fdce4782011-11-29 20:06:18116 CHECK_GT(output_len, input.size());
[email protected]2377cdee2011-06-24 20:46:06117
118 output->resize(output_len);
119 uint8* output_data =
120 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
121
122 int input_len = input.size();
123 uint8* input_data =
124 reinterpret_cast<uint8*>(const_cast<char*>(input.data()));
[email protected]39422e32010-03-25 19:13:00125
126 int op_len;
[email protected]2377cdee2011-06-24 20:46:06127 SECStatus rv = PK11_CipherOp(context,
128 output_data,
[email protected]39422e32010-03-25 19:13:00129 &op_len,
[email protected]2377cdee2011-06-24 20:46:06130 output_len,
131 input_data,
132 input_len);
133
134 if (SECSuccess != rv) {
135 output->clear();
[email protected]39422e32010-03-25 19:13:00136 return false;
[email protected]2377cdee2011-06-24 20:46:06137 }
[email protected]39422e32010-03-25 19:13:00138
139 unsigned int digest_len;
[email protected]2377cdee2011-06-24 20:46:06140 rv = PK11_DigestFinal(context,
141 output_data + op_len,
[email protected]39422e32010-03-25 19:13:00142 &digest_len,
[email protected]2377cdee2011-06-24 20:46:06143 output_len - op_len);
144 if (SECSuccess != rv) {
145 output->clear();
146 return false;
147 }
148
149 output->resize(op_len + digest_len);
150 return true;
151}
152
[email protected]44a016a82011-07-08 02:53:09153bool Encryptor::CryptCTR(PK11Context* context,
154 const base::StringPiece& input,
[email protected]2377cdee2011-06-24 20:46:06155 std::string* output) {
156 if (!counter_.get()) {
157 LOG(ERROR) << "Counter value not set in CTR mode.";
158 return false;
159 }
160
161 size_t output_len = ((input.size() + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) *
162 AES_BLOCK_SIZE;
[email protected]fdce4782011-11-29 20:06:18163 CHECK_GE(output_len, input.size());
[email protected]2377cdee2011-06-24 20:46:06164 output->resize(output_len);
165 uint8* output_data =
166 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
167
168 size_t mask_len;
169 bool ret = GenerateCounterMask(input.size(), output_data, &mask_len);
170 if (!ret)
[email protected]39422e32010-03-25 19:13:00171 return false;
172
[email protected]2377cdee2011-06-24 20:46:06173 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;
[email protected]fdce4782011-11-29 20:06:18183 CHECK_EQ(static_cast<int>(mask_len), op_len);
[email protected]2377cdee2011-06-24 20:46:06184
185 unsigned int digest_len;
186 rv = PK11_DigestFinal(context,
187 NULL,
188 &digest_len,
189 0);
190 if (SECSuccess != rv)
191 return false;
192 CHECK(!digest_len);
193
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());
[email protected]39422e32010-03-25 19:13:00199 return true;
200}
201
[email protected]4b559b4d2011-04-14 17:37:14202} // namespace crypto