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/password_manager/encryptor.h"
6
7#include "base/logging.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/utf_string_conversions.h"
10#include "crypto/encryptor.h"
11#include "crypto/symmetric_key.h"
12
13namespace {
14
15// Salt for Symmetric key derivation.
16const char kSalt[] = "saltysalt";
17
18// Key size required for 128 bit AES.
19const size_t kDerivedKeySizeInBits = 128;
20
21// Constant for Symmetic key derivation.
22const size_t kEncryptionIterations = 1;
23
24// Size of initialization vector for AES 128-bit.
25const size_t kIVBlockSizeAES128 = 16;
26
27// Prefix for cypher text returned by obfuscation version.  We prefix the
28// cyphertext with this string so that future data migration can detect
29// this and migrate to full encryption without data loss.
30const char kObfuscationPrefix[] = "v10";
31
32// Generates a newly allocated SymmetricKey object based a hard-coded password.
33// Ownership of the key is passed to the caller.  Returns NULL key if a key
34// generation error occurs.
35crypto::SymmetricKey* GetEncryptionKey() {
36  // We currently "obfuscate" by encrypting and decrypting with hard-coded
37  // password.  We need to improve this password situation by moving a secure
38  // password into a system-level key store.
39  // http://crbug.com/25404 and http://crbug.com/49115
40  std::string password = "peanuts";
41  std::string salt(kSalt);
42
43  // Create an encryption key from our password and salt.
44  scoped_ptr<crypto::SymmetricKey> encryption_key(
45      crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
46                                                  password,
47                                                  salt,
48                                                  kEncryptionIterations,
49                                                  kDerivedKeySizeInBits));
50  DCHECK(encryption_key.get());
51
52  return encryption_key.release();
53}
54
55}  // namespace
56
57bool Encryptor::EncryptString16(const string16& plaintext,
58                                std::string* ciphertext) {
59  return EncryptString(UTF16ToUTF8(plaintext), ciphertext);
60}
61
62bool Encryptor::DecryptString16(const std::string& ciphertext,
63                                string16* plaintext) {
64  std::string utf8;
65  if (!DecryptString(ciphertext, &utf8))
66    return false;
67
68  *plaintext = UTF8ToUTF16(utf8);
69  return true;
70}
71
72bool Encryptor::EncryptString(const std::string& plaintext,
73                              std::string* ciphertext) {
74  // This currently "obfuscates" by encrypting with hard-coded password.
75  // We need to improve this password situation by moving a secure password
76  // into a system-level key store.
77  // http://crbug.com/25404 and http://crbug.com/49115
78
79  if (plaintext.empty()) {
80    *ciphertext = std::string();
81    return true;
82  }
83
84  scoped_ptr<crypto::SymmetricKey> encryption_key(GetEncryptionKey());
85  if (!encryption_key.get())
86    return false;
87
88  std::string iv(kIVBlockSizeAES128, ' ');
89  crypto::Encryptor encryptor;
90  if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv))
91    return false;
92
93  if (!encryptor.Encrypt(plaintext, ciphertext))
94    return false;
95
96  // Prefix the cypher text with version information.
97  ciphertext->insert(0, kObfuscationPrefix);
98  return true;
99}
100
101bool Encryptor::DecryptString(const std::string& ciphertext,
102                              std::string* plaintext) {
103  // This currently "obfuscates" by encrypting with hard-coded password.
104  // We need to improve this password situation by moving a secure password
105  // into a system-level key store.
106  // http://crbug.com/25404 and http://crbug.com/49115
107
108  if (ciphertext.empty()) {
109    *plaintext = std::string();
110    return true;
111  }
112
113  // Check that the incoming cyphertext was indeed encrypted with the expected
114  // version.  If the prefix is not found then we'll assume we're dealing with
115  // old data saved as clear text and we'll return it directly.
116  // Credit card numbers are current legacy data, so false match with prefix
117  // won't happen.
118  if (ciphertext.find(kObfuscationPrefix) != 0) {
119    *plaintext = ciphertext;
120    return true;
121  }
122
123  // Strip off the versioning prefix before decrypting.
124  std::string raw_ciphertext = ciphertext.substr(strlen(kObfuscationPrefix));
125
126  scoped_ptr<crypto::SymmetricKey> encryption_key(GetEncryptionKey());
127  if (!encryption_key.get())
128    return false;
129
130  std::string iv(kIVBlockSizeAES128, ' ');
131  crypto::Encryptor encryptor;
132  if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv))
133    return false;
134
135  if (!encryptor.Decrypt(raw_ciphertext, plaintext))
136    return false;
137
138  return true;
139}
140