• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <CommonCrypto/CommonCryptor.h>  // for kCCBlockSizeAES128
8
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/utf_string_conversions.h"
12#include "crypto/encryptor.h"
13#include "crypto/symmetric_key.h"
14#include "chrome/browser/password_manager/encryptor_password_mac.h"
15#include "chrome/browser/keychain_mac.h"
16
17namespace {
18
19// Salt for Symmetric key derivation.
20const char kSalt[] = "saltysalt";
21
22// Key size required for 128 bit AES.
23const size_t kDerivedKeySizeInBits = 128;
24
25// Constant for Symmetic key derivation.
26const size_t kEncryptionIterations = 1003;
27
28// TODO(dhollowa): Refactor to allow dependency injection of Keychain.
29static bool use_mock_keychain = false;
30
31// Prefix for cypher text returned by current encryption version.  We prefix
32// the cypher text with this string so that future data migration can detect
33// this and migrate to different encryption without data loss.
34const char kEncryptionVersionPrefix[] = "v10";
35
36// Generates a newly allocated SymmetricKey object based on the password found
37// in the Keychain.  The generated key is for AES encryption.  Ownership of the
38// key is passed to the caller.  Returns NULL key in the case password access
39// is denied or key generation error occurs.
40crypto::SymmetricKey* GetEncryptionKey() {
41
42  std::string password;
43  if (use_mock_keychain) {
44    password = "mock_password";
45  } else {
46    MacKeychain keychain;
47    EncryptorPassword encryptor_password(keychain);
48    password = encryptor_password.GetEncryptorPassword();
49  }
50
51  if (password.empty())
52    return NULL;
53
54  std::string salt(kSalt);
55
56  // Create an encryption key from our password and salt.
57  scoped_ptr<crypto::SymmetricKey> encryption_key(
58      crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
59                                                  password,
60                                                  salt,
61                                                  kEncryptionIterations,
62                                                  kDerivedKeySizeInBits));
63  DCHECK(encryption_key.get());
64
65  return encryption_key.release();
66}
67
68}  // namespace
69
70bool Encryptor::EncryptString16(const string16& plaintext,
71                                std::string* ciphertext) {
72  return EncryptString(UTF16ToUTF8(plaintext), ciphertext);
73}
74
75bool Encryptor::DecryptString16(const std::string& ciphertext,
76                                string16* plaintext) {
77  std::string utf8;
78  if (!DecryptString(ciphertext, &utf8))
79    return false;
80
81  *plaintext = UTF8ToUTF16(utf8);
82  return true;
83}
84
85bool Encryptor::EncryptString(const std::string& plaintext,
86                              std::string* ciphertext) {
87  if (plaintext.empty()) {
88    *ciphertext = std::string();
89    return true;
90  }
91
92  scoped_ptr<crypto::SymmetricKey> encryption_key(GetEncryptionKey());
93  if (!encryption_key.get())
94    return false;
95
96  std::string iv(kCCBlockSizeAES128, ' ');
97  crypto::Encryptor encryptor;
98  if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv))
99    return false;
100
101  if (!encryptor.Encrypt(plaintext, ciphertext))
102    return false;
103
104  // Prefix the cypher text with version information.
105  ciphertext->insert(0, kEncryptionVersionPrefix);
106  return true;
107}
108
109bool Encryptor::DecryptString(const std::string& ciphertext,
110                              std::string* plaintext) {
111  if (ciphertext.empty()) {
112    *plaintext = std::string();
113    return true;
114  }
115
116  // Check that the incoming cyphertext was indeed encrypted with the expected
117  // version.  If the prefix is not found then we'll assume we're dealing with
118  // old data saved as clear text and we'll return it directly.
119  // Credit card numbers are current legacy data, so false match with prefix
120  // won't happen.
121  if (ciphertext.find(kEncryptionVersionPrefix) != 0) {
122    *plaintext = ciphertext;
123    return true;
124  }
125
126  // Strip off the versioning prefix before decrypting.
127  std::string raw_ciphertext =
128      ciphertext.substr(strlen(kEncryptionVersionPrefix));
129
130  scoped_ptr<crypto::SymmetricKey> encryption_key(GetEncryptionKey());
131  if (!encryption_key.get())
132    return false;
133
134  std::string iv(kCCBlockSizeAES128, ' ');
135  crypto::Encryptor encryptor;
136  if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv))
137    return false;
138
139  if (!encryptor.Decrypt(raw_ciphertext, plaintext))
140    return false;
141
142  return true;
143}
144
145void Encryptor::UseMockKeychain(bool use_mock) {
146  use_mock_keychain = use_mock;
147}
148
149