Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: crypto/encryptor_nss.cc

Issue 7056026: Implement AES-CTR for NSS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: done again Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "crypto/encryptor.h" 5 #include "crypto/encryptor.h"
6 6
7 #include <cryptohi.h> 7 #include <cryptohi.h>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "crypto/nss_util.h" 11 #include "crypto/nss_util.h"
12 #include "crypto/symmetric_key.h" 12 #include "crypto/symmetric_key.h"
13 13
14 namespace crypto { 14 namespace crypto {
15 15
16 namespace {
17
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.
wtc 2011/06/21 00:33:32 Please explain this is necessary because NSS doesn
Alpha Left Google 2011/06/22 21:25:17 Done.
24 return CKM_AES_ECB;
25 default:
26 NOTREACHED() << "Unsupported mode of operation";
27 break;
28 }
29 return 0;
30 }
31
32 } // namespace
33
16 Encryptor::Encryptor() 34 Encryptor::Encryptor()
17 : key_(NULL), 35 : key_(NULL),
18 mode_(CBC) { 36 mode_(CBC) {
19 EnsureNSSInit(); 37 EnsureNSSInit();
20 } 38 }
21 39
22 Encryptor::~Encryptor() { 40 Encryptor::~Encryptor() {
23 } 41 }
24 42
25 bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) { 43 bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) {
26 DCHECK(key); 44 DCHECK(key);
27 DCHECK_EQ(CBC, mode); 45 DCHECK(CBC == mode || CTR == mode) << "Unsupported mode of operation";
28 46
29 key_ = key; 47 key_ = key;
30 mode_ = mode; 48 mode_ = mode;
31 49
32 if (iv.size() != AES_BLOCK_SIZE) 50 if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
33 return false; 51 return false;
34 52
35 slot_.reset(PK11_GetBestSlot(CKM_AES_CBC_PAD, NULL)); 53 slot_.reset(PK11_GetBestSlot(GetMechanism(mode), NULL));
36 if (!slot_.get()) 54 if (!slot_.get())
37 return false; 55 return false;
38 56
39 SECItem iv_item; 57 if (mode == CBC) {
40 iv_item.type = siBuffer; 58 SECItem iv_item;
41 iv_item.data = reinterpret_cast<unsigned char*>( 59 iv_item.type = siBuffer;
42 const_cast<char *>(iv.data())); 60 iv_item.data = reinterpret_cast<unsigned char*>(
43 iv_item.len = iv.size(); 61 const_cast<char *>(iv.data()));
62 iv_item.len = iv.size();
44 63
45 param_.reset(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); 64 param_.reset(PK11_ParamFromIV(GetMechanism(mode), &iv_item));
65 } else {
66 param_.reset(PK11_ParamFromIV(GetMechanism(mode), NULL));
67 }
wtc 2011/06/21 00:33:32 I would probably use a "switch" statement here so
Alpha Left Google 2011/06/22 21:25:17 Done.
68
46 if (!param_.get()) 69 if (!param_.get())
47 return false; 70 return false;
48
49 return true; 71 return true;
50 } 72 }
51 73
52 bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) { 74 bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) {
53 ScopedPK11Context context(PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, 75 ScopedPK11Context context(PK11_CreateContextBySymKey(GetMechanism(mode_),
54 CKA_ENCRYPT, 76 CKA_ENCRYPT,
55 key_->key(), 77 key_->key(),
56 param_.get())); 78 param_.get()));
57 if (!context.get()) 79 if (!context.get())
58 return false; 80 return false;
59 81
60 size_t ciphertext_len = plaintext.size() + AES_BLOCK_SIZE; 82 return mode_ == CTR ? CryptCTR(context.get(), plaintext, ciphertext) :
61 std::vector<unsigned char> buffer(ciphertext_len); 83 Crypt(context.get(), plaintext, ciphertext);
wtc 2011/06/21 00:33:32 Nit: please use an "if" or "switch" statement here
Alpha Left Google 2011/06/22 21:25:17 Done.
62
63 int op_len;
64 SECStatus rv = PK11_CipherOp(context.get(),
65 &buffer[0],
66 &op_len,
67 ciphertext_len,
68 reinterpret_cast<unsigned char*>(
69 const_cast<char*>(plaintext.data())),
70 plaintext.size());
71 if (SECSuccess != rv)
72 return false;
73
74 unsigned int digest_len;
75 rv = PK11_DigestFinal(context.get(),
76 &buffer[op_len],
77 &digest_len,
78 ciphertext_len - op_len);
79 if (SECSuccess != rv)
80 return false;
81
82 ciphertext->assign(reinterpret_cast<char *>(&buffer[0]),
83 op_len + digest_len);
84 return true;
85 } 84 }
86 85
87 bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) { 86 bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) {
88 if (ciphertext.empty()) 87 if (ciphertext.empty())
89 return false; 88 return false;
90 89
91 ScopedPK11Context context(PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, 90 ScopedPK11Context context(PK11_CreateContextBySymKey(
92 CKA_DECRYPT, 91 GetMechanism(mode_), (mode_ == CTR ? CKA_ENCRYPT : CKA_DECRYPT),
93 key_->key(), 92 key_->key(), param_.get()));
94 param_.get()));
95 if (!context.get()) 93 if (!context.get())
96 return false; 94 return false;
97 95
98 size_t plaintext_len = ciphertext.size(); 96 return mode_ == CTR ? CryptCTR(context.get(), ciphertext, plaintext) :
99 std::vector<unsigned char> buffer(plaintext_len); 97 Crypt(context.get(), ciphertext, plaintext);
98 }
99
100 bool Encryptor::Crypt(PK11Context* context, const std::string& input,
101 std::string* output) {
102 size_t output_len = input.size() + AES_BLOCK_SIZE;
103 CHECK(output_len > input.size()) << "Output size overflow";
104
105 output->resize(output_len);
106 uint8* output_data =
107 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
108
109 int input_len = input.size();
110 uint8* input_data =
111 reinterpret_cast<uint8*>(const_cast<char*>(input.data()));
100 112
101 int op_len; 113 int op_len;
102 SECStatus rv = PK11_CipherOp(context.get(), 114 SECStatus rv = PK11_CipherOp(context,
103 &buffer[0], 115 output_data,
104 &op_len, 116 &op_len,
105 plaintext_len, 117 output_len,
106 reinterpret_cast<unsigned char*>( 118 input_data,
107 const_cast<char*>(ciphertext.data())), 119 input_len);
108 ciphertext.size()); 120
109 if (SECSuccess != rv) 121 if (SECSuccess != rv)
110 return false; 122 return false;
111 123
112 unsigned int digest_len; 124 unsigned int digest_len;
113 rv = PK11_DigestFinal(context.get(), 125 rv = PK11_DigestFinal(context,
114 &buffer[op_len], 126 output_data + op_len,
115 &digest_len, 127 &digest_len,
116 plaintext_len - op_len); 128 output_len - op_len);
117 if (SECSuccess != rv) 129 if (SECSuccess != rv)
118 return false; 130 return false;
119 131
120 plaintext->assign(reinterpret_cast<char *>(&buffer[0]), 132 output->resize(op_len + digest_len);
121 op_len + digest_len);
122 return true; 133 return true;
123 } 134 }
124 135
136 bool Encryptor::CryptCTR(PK11Context* context, const std::string& input,
137 std::string* output) {
138 if (!counter_.get()) {
139 LOG(ERROR) << "Counter value not set in CTR mode.";
140 return false;
141 }
142
143 size_t output_len = input.size() + AES_BLOCK_SIZE;
Ryan Sleevi 2011/06/20 23:47:23 nit: Is it necessary to pad |output_len| ? The und
Alpha Left Google 2011/06/20 23:59:44 This is just for convenience, it's easier to check
144 CHECK(output_len > input.size()) << "Output size overflow";
145
146 output->resize(output_len);
147 uint8* output_data =
148 reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
149
150 size_t input_len = input.size();
151 uint8* input_data =
152 reinterpret_cast<uint8*>(const_cast<char*>(input.data()));
153
154 scoped_array<uint8> ctr_mask;
155 GenerateCounterMask(input_len, &ctr_mask, &input_len);
wtc 2011/06/21 00:33:32 Since PK11_CipherOp can encrypt in place, you shou
156 CHECK(input_len <= output_len);
157 input_data = ctr_mask.get();
158
159 int op_len;
160 SECStatus rv = PK11_CipherOp(context,
161 output_data,
162 &op_len,
163 output_len,
164 input_data,
165 input_len);
Ryan Sleevi 2011/06/20 23:47:23 BUG: There is no guarantee that |op_len| will == |
Alpha Left Google 2011/06/20 23:59:44 Since this is using ECB and input_len is a multipl
166 if (SECSuccess != rv)
167 return false;
168
169 unsigned int digest_len;
170 rv = PK11_DigestFinal(context,
171 NULL,
172 &digest_len,
173 0);
174 if (SECSuccess != rv)
175 return false;
176 CHECK(!digest_len);
177
178 // Use |output_data| to mask |input|.
179 MaskMessage(
180 reinterpret_cast<uint8*>(const_cast<char*>(input.data())),
181 input.length(), output_data, output_data);
182 output->resize(input.length());
183 return true;
184 }
185
125 } // namespace crypto 186 } // namespace crypto
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698