Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / components / os_crypt / os_crypt_mac.mm
1 // Copyright 2014 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 "components/os_crypt/os_crypt.h"
6
7 #include <CommonCrypto/CommonCryptor.h>  // for kCCBlockSizeAES128
8
9 #include "base/command_line.h"
10 #include "base/debug/leak_annotations.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/synchronization/lock.h"
15 #include "components/os_crypt/keychain_password_mac.h"
16 #include "components/os_crypt/os_crypt_switches.h"
17 #include "crypto/apple_keychain.h"
18 #include "crypto/encryptor.h"
19 #include "crypto/symmetric_key.h"
20
21 using crypto::AppleKeychain;
22
23 namespace {
24
25 // Salt for Symmetric key derivation.
26 const char kSalt[] = "saltysalt";
27
28 // Key size required for 128 bit AES.
29 const size_t kDerivedKeySizeInBits = 128;
30
31 // Constant for Symmetic key derivation.
32 const size_t kEncryptionIterations = 1003;
33
34 // TODO(dhollowa): Refactor to allow dependency injection of Keychain.
35 static bool use_mock_keychain = false;
36
37 // Prefix for cypher text returned by current encryption version.  We prefix
38 // the cypher text with this string so that future data migration can detect
39 // this and migrate to different encryption without data loss.
40 const char kEncryptionVersionPrefix[] = "v10";
41
42 // Generates a newly allocated SymmetricKey object based on the password found
43 // in the Keychain.  The generated key is for AES encryption.  Returns NULL key
44 // in the case password access is denied or key generation error occurs.
45 crypto::SymmetricKey* GetEncryptionKey() {
46   static crypto::SymmetricKey* cached_encryption_key = NULL;
47   static bool key_is_cached = false;
48   static base::Lock lock;
49   base::AutoLock auto_lock(lock);
50
51   if (key_is_cached)
52     return cached_encryption_key;
53
54   static bool mock_keychain_command_line_flag =
55       CommandLine::ForCurrentProcess()->HasSwitch(
56           os_crypt::switches::kUseMockKeychain);
57
58   std::string password;
59   if (use_mock_keychain || mock_keychain_command_line_flag) {
60     password = "mock_password";
61   } else {
62     AppleKeychain keychain;
63     KeychainPassword encryptor_password(keychain);
64     password = encryptor_password.GetPassword();
65   }
66
67   // Subsequent code must guarantee that the correct key is cached before
68   // returning.
69   key_is_cached = true;
70
71   if (password.empty())
72     return cached_encryption_key;
73
74   std::string salt(kSalt);
75
76   // Create an encryption key from our password and salt. The key is
77   // intentionally leaked.
78   cached_encryption_key =
79       crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
80                                                   password,
81                                                   salt,
82                                                   kEncryptionIterations,
83                                                   kDerivedKeySizeInBits);
84   ANNOTATE_LEAKING_OBJECT_PTR(cached_encryption_key);
85   DCHECK(cached_encryption_key);
86   return cached_encryption_key;
87 }
88
89 }  // namespace
90
91 bool OSCrypt::EncryptString16(const base::string16& plaintext,
92                               std::string* ciphertext) {
93   return EncryptString(base::UTF16ToUTF8(plaintext), ciphertext);
94 }
95
96 bool OSCrypt::DecryptString16(const std::string& ciphertext,
97                               base::string16* plaintext) {
98   std::string utf8;
99   if (!DecryptString(ciphertext, &utf8))
100     return false;
101
102   *plaintext = base::UTF8ToUTF16(utf8);
103   return true;
104 }
105
106 bool OSCrypt::EncryptString(const std::string& plaintext,
107                             std::string* ciphertext) {
108   if (plaintext.empty()) {
109     *ciphertext = std::string();
110     return true;
111   }
112
113   crypto::SymmetricKey* encryption_key = GetEncryptionKey();
114   if (!encryption_key)
115     return false;
116
117   std::string iv(kCCBlockSizeAES128, ' ');
118   crypto::Encryptor encryptor;
119   if (!encryptor.Init(encryption_key, crypto::Encryptor::CBC, iv))
120     return false;
121
122   if (!encryptor.Encrypt(plaintext, ciphertext))
123     return false;
124
125   // Prefix the cypher text with version information.
126   ciphertext->insert(0, kEncryptionVersionPrefix);
127   return true;
128 }
129
130 bool OSCrypt::DecryptString(const std::string& ciphertext,
131                             std::string* plaintext) {
132   if (ciphertext.empty()) {
133     *plaintext = std::string();
134     return true;
135   }
136
137   // Check that the incoming cyphertext was indeed encrypted with the expected
138   // version.  If the prefix is not found then we'll assume we're dealing with
139   // old data saved as clear text and we'll return it directly.
140   // Credit card numbers are current legacy data, so false match with prefix
141   // won't happen.
142   if (ciphertext.find(kEncryptionVersionPrefix) != 0) {
143     *plaintext = ciphertext;
144     return true;
145   }
146
147   // Strip off the versioning prefix before decrypting.
148   std::string raw_ciphertext =
149       ciphertext.substr(strlen(kEncryptionVersionPrefix));
150
151   crypto::SymmetricKey* encryption_key = GetEncryptionKey();
152   if (!encryption_key)
153     return false;
154
155   std::string iv(kCCBlockSizeAES128, ' ');
156   crypto::Encryptor encryptor;
157   if (!encryptor.Init(encryption_key, crypto::Encryptor::CBC, iv))
158     return false;
159
160   if (!encryptor.Decrypt(raw_ciphertext, plaintext))
161     return false;
162
163   return true;
164 }
165
166 void OSCrypt::UseMockKeychain(bool use_mock) {
167   use_mock_keychain = use_mock;
168 }
169