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

Side by Side Diff: chrome/browser/sync/util/nigori.cc

Issue 8468023: Move encryption related files from util folder to encryption folder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: For review. Created 9 years, 1 month 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
(Empty)
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.
4
5 #include "chrome/browser/sync/util/nigori.h"
6
7 #if defined(OS_WIN)
8 #include <winsock2.h> // for htonl
9 #else
10 #include <arpa/inet.h>
11 #endif
12
13 #include <sstream>
14 #include <vector>
15
16 #include "base/base64.h"
17 #include "base/logging.h"
18 #include "base/rand_util.h"
19 #include "base/string_util.h"
20 #include "crypto/encryptor.h"
21 #include "crypto/hmac.h"
22
23 using base::Base64Encode;
24 using base::Base64Decode;
25 using base::RandInt;
26 using crypto::Encryptor;
27 using crypto::HMAC;
28 using crypto::SymmetricKey;
29
30 namespace browser_sync {
31
32 // NigoriStream simplifies the concatenation operation of the Nigori protocol.
33 class NigoriStream {
34 public:
35 // Append the big-endian representation of the length of |value| with 32 bits,
36 // followed by |value| itself to the stream.
37 NigoriStream& operator<<(const std::string& value) {
38 uint32 size = htonl(value.size());
39 stream_.write((char *) &size, sizeof(uint32));
40 stream_ << value;
41 return *this;
42 }
43
44 // Append the big-endian representation of the length of |type| with 32 bits,
45 // followed by the big-endian representation of the value of |type|, with 32
46 // bits, to the stream.
47 NigoriStream& operator<<(const Nigori::Type type) {
48 uint32 size = htonl(sizeof(uint32));
49 stream_.write((char *) &size, sizeof(uint32));
50 uint32 value = htonl(type);
51 stream_.write((char *) &value, sizeof(uint32));
52 return *this;
53 }
54
55 std::string str() {
56 return stream_.str();
57 }
58
59 private:
60 std::ostringstream stream_;
61 };
62
63 // static
64 const char Nigori::kSaltSalt[] = "saltsalt";
65
66 Nigori::Nigori() {
67 }
68
69 Nigori::~Nigori() {
70 }
71
72 bool Nigori::InitByDerivation(const std::string& hostname,
73 const std::string& username,
74 const std::string& password) {
75 NigoriStream salt_password;
76 salt_password << username << hostname;
77
78 // Suser = PBKDF2(Username || Servername, "saltsalt", Nsalt, 8)
79 scoped_ptr<SymmetricKey> user_salt(SymmetricKey::DeriveKeyFromPassword(
80 SymmetricKey::HMAC_SHA1, salt_password.str(),
81 kSaltSalt,
82 kSaltIterations,
83 kSaltKeySizeInBits));
84 DCHECK(user_salt.get());
85
86 std::string raw_user_salt;
87 if (!user_salt->GetRawKey(&raw_user_salt))
88 return false;
89
90 // Kuser = PBKDF2(P, Suser, Nuser, 16)
91 user_key_.reset(SymmetricKey::DeriveKeyFromPassword(SymmetricKey::AES,
92 password, raw_user_salt, kUserIterations, kDerivedKeySizeInBits));
93 DCHECK(user_key_.get());
94
95 // Kenc = PBKDF2(P, Suser, Nenc, 16)
96 encryption_key_.reset(SymmetricKey::DeriveKeyFromPassword(SymmetricKey::AES,
97 password, raw_user_salt, kEncryptionIterations, kDerivedKeySizeInBits));
98 DCHECK(encryption_key_.get());
99
100 // Kmac = PBKDF2(P, Suser, Nmac, 16)
101 mac_key_.reset(SymmetricKey::DeriveKeyFromPassword(
102 SymmetricKey::HMAC_SHA1, password, raw_user_salt, kSigningIterations,
103 kDerivedKeySizeInBits));
104 DCHECK(mac_key_.get());
105
106 return user_key_.get() && encryption_key_.get() && mac_key_.get();
107 }
108
109 bool Nigori::InitByImport(const std::string& user_key,
110 const std::string& encryption_key,
111 const std::string& mac_key) {
112 user_key_.reset(SymmetricKey::Import(SymmetricKey::AES, user_key));
113 DCHECK(user_key_.get());
114
115 encryption_key_.reset(SymmetricKey::Import(SymmetricKey::AES,
116 encryption_key));
117 DCHECK(encryption_key_.get());
118
119 mac_key_.reset(SymmetricKey::Import(SymmetricKey::HMAC_SHA1, mac_key));
120 DCHECK(mac_key_.get());
121
122 return user_key_.get() && encryption_key_.get() && mac_key_.get();
123 }
124
125 // Permute[Kenc,Kmac](type || name)
126 bool Nigori::Permute(Type type, const std::string& name,
127 std::string* permuted) const {
128 DCHECK_LT(0U, name.size());
129
130 NigoriStream plaintext;
131 plaintext << type << name;
132
133 Encryptor encryptor;
134 if (!encryptor.Init(encryption_key_.get(), Encryptor::CBC,
135 std::string(kIvSize, 0)))
136 return false;
137
138 std::string ciphertext;
139 if (!encryptor.Encrypt(plaintext.str(), &ciphertext))
140 return false;
141
142 std::string raw_mac_key;
143 if (!mac_key_->GetRawKey(&raw_mac_key))
144 return false;
145
146 HMAC hmac(HMAC::SHA256);
147 if (!hmac.Init(raw_mac_key))
148 return false;
149
150 std::vector<unsigned char> hash(kHashSize);
151 if (!hmac.Sign(ciphertext, &hash[0], hash.size()))
152 return false;
153
154 std::string output;
155 output.assign(ciphertext);
156 output.append(hash.begin(), hash.end());
157
158 return Base64Encode(output, permuted);
159 }
160
161 std::string GenerateRandomString(size_t size) {
162 // TODO(albertb): Use a secure random function.
163 std::string random(size, 0);
164 for (size_t i = 0; i < size; ++i)
165 random[i] = RandInt(0, 0xff);
166 return random;
167 }
168
169 // Enc[Kenc,Kmac](value)
170 bool Nigori::Encrypt(const std::string& value, std::string* encrypted) const {
171 if (0U >= value.size())
172 return false;
173
174 std::string iv = GenerateRandomString(kIvSize);
175
176 Encryptor encryptor;
177 if (!encryptor.Init(encryption_key_.get(), Encryptor::CBC, iv))
178 return false;
179
180 std::string ciphertext;
181 if (!encryptor.Encrypt(value, &ciphertext))
182 return false;
183
184 std::string raw_mac_key;
185 if (!mac_key_->GetRawKey(&raw_mac_key))
186 return false;
187
188 HMAC hmac(HMAC::SHA256);
189 if (!hmac.Init(raw_mac_key))
190 return false;
191
192 std::vector<unsigned char> hash(kHashSize);
193 if (!hmac.Sign(ciphertext, &hash[0], hash.size()))
194 return false;
195
196 std::string output;
197 output.assign(iv);
198 output.append(ciphertext);
199 output.append(hash.begin(), hash.end());
200
201 return Base64Encode(output, encrypted);
202 }
203
204 bool Nigori::Decrypt(const std::string& encrypted, std::string* value) const {
205 std::string input;
206 if (!Base64Decode(encrypted, &input))
207 return false;
208
209 if (input.size() < kIvSize * 2 + kHashSize)
210 return false;
211
212 // The input is:
213 // * iv (16 bytes)
214 // * ciphertext (multiple of 16 bytes)
215 // * hash (32 bytes)
216 std::string iv(input.substr(0, kIvSize));
217 std::string ciphertext(input.substr(kIvSize,
218 input.size() - (kIvSize + kHashSize)));
219 std::string hash(input.substr(input.size() - kHashSize, kHashSize));
220
221 std::string raw_mac_key;
222 if (!mac_key_->GetRawKey(&raw_mac_key))
223 return false;
224
225 HMAC hmac(HMAC::SHA256);
226 if (!hmac.Init(raw_mac_key))
227 return false;
228
229 std::vector<unsigned char> expected(kHashSize);
230 if (!hmac.Sign(ciphertext, &expected[0], expected.size()))
231 return false;
232
233 if (hash.compare(0, hash.size(),
234 reinterpret_cast<char *>(&expected[0]),
235 expected.size()))
236 return false;
237
238 Encryptor encryptor;
239 if (!encryptor.Init(encryption_key_.get(), Encryptor::CBC, iv))
240 return false;
241
242 std::string plaintext;
243 if (!encryptor.Decrypt(ciphertext, value))
244 return false;
245
246 return true;
247 }
248
249 bool Nigori::ExportKeys(std::string* user_key,
250 std::string* encryption_key,
251 std::string* mac_key) const {
252 DCHECK(user_key);
253 DCHECK(encryption_key);
254 DCHECK(mac_key);
255
256 return user_key_->GetRawKey(user_key) &&
257 encryption_key_->GetRawKey(encryption_key) &&
258 mac_key_->GetRawKey(mac_key);
259 }
260
261 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698