OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 "extensions/browser/api/lock_screen_data/data_item.h" |
| 6 |
| 7 #include <utility> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/files/file.h" |
| 11 #include "base/files/file_path.h" |
| 12 #include "base/files/file_util.h" |
| 13 #include "base/location.h" |
| 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/sequenced_task_runner.h" |
| 16 #include "base/task_scheduler/post_task.h" |
| 17 #include "base/values.h" |
| 18 #include "crypto/encryptor.h" |
| 19 #include "crypto/symmetric_key.h" |
| 20 #include "extensions/browser/api/lock_screen_data/operation_result.h" |
| 21 |
| 22 namespace extensions { |
| 23 namespace lock_screen_data { |
| 24 |
| 25 namespace { |
| 26 |
| 27 // Keys used to describe a data item in its dictionary value representation: |
| 28 const char kPrefKeyId[] = "id"; |
| 29 const char kPrefKeyBackingFile[] = "backing_file"; |
| 30 |
| 31 // Writes |data| to file specified by |path|. The written data will be encrypted |
| 32 // using symmetric AES key |encryption_key|. |
| 33 // |result| - set to the resulting write operation status. |
| 34 // Expected to be called on worker thread. |
| 35 void WriteImpl(const base::FilePath& path, |
| 36 const std::vector<char>& data, |
| 37 const std::string& encryption_key, |
| 38 OperationResult* result) { |
| 39 std::string iv(16, ' '); |
| 40 std::unique_ptr<crypto::SymmetricKey> key = |
| 41 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, encryption_key); |
| 42 if (!key) { |
| 43 *result = OperationResult::kInvalidKey; |
| 44 return; |
| 45 } |
| 46 |
| 47 crypto::Encryptor encryptor; |
| 48 if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)) { |
| 49 *result = OperationResult::kInvalidKey; |
| 50 return; |
| 51 } |
| 52 |
| 53 std::string encrypted; |
| 54 if (!encryptor.Encrypt(std::string(data.data(), data.size()), &encrypted)) { |
| 55 *result = OperationResult::kInvalidKey; |
| 56 return; |
| 57 } |
| 58 |
| 59 base::File::Error error; |
| 60 if (!base::DirectoryExists(path.DirName()) && |
| 61 !base::CreateDirectoryAndGetError(path.DirName(), &error)) { |
| 62 *result = OperationResult::kFileCreationFailed; |
| 63 return; |
| 64 } |
| 65 |
| 66 int write_size = base::WriteFile(path, encrypted.data(), encrypted.size()); |
| 67 *result = (write_size == static_cast<int>(encrypted.size())) |
| 68 ? OperationResult::kSuccess |
| 69 : OperationResult::kFileWriteFailed; |
| 70 } |
| 71 |
| 72 // Reads encrypted data from file specified by |path|. The read data will be |
| 73 // decrypted using using symmetric AES key |encryption_key| before being |
| 74 // returned. |
| 75 // |result| - set to the resulting write operation status. |
| 76 // |data| - set to the clear-text data read from the file. |
| 77 // Expected to be called on worker thread. |
| 78 void ReadImpl(const base::FilePath& path, |
| 79 const std::string& decryption_key, |
| 80 OperationResult* result, |
| 81 std::vector<char>* data) { |
| 82 std::string read_data; |
| 83 if (!base::ReadFileToString(path, &read_data)) { |
| 84 *result = base::PathExists(path) ? OperationResult::kFileReadFailed |
| 85 : OperationResult::kNotFound; |
| 86 return; |
| 87 } |
| 88 |
| 89 std::string iv(16, ' '); |
| 90 std::unique_ptr<crypto::SymmetricKey> key = |
| 91 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, decryption_key); |
| 92 if (!key) { |
| 93 *result = OperationResult::kInvalidKey; |
| 94 return; |
| 95 } |
| 96 |
| 97 crypto::Encryptor encryptor; |
| 98 if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)) { |
| 99 *result = OperationResult::kInvalidKey; |
| 100 return; |
| 101 } |
| 102 |
| 103 std::string decrypted; |
| 104 if (!encryptor.Decrypt(read_data, &decrypted)) { |
| 105 *result = OperationResult::kWrongKey; |
| 106 return; |
| 107 } |
| 108 |
| 109 std::vector<char> result_data(decrypted.data(), |
| 110 decrypted.data() + decrypted.size()); |
| 111 data->swap(result_data); |
| 112 *result = OperationResult::kSuccess; |
| 113 } |
| 114 |
| 115 // Deletes file under |file_path|. |
| 116 void DeleteImpl(const base::FilePath& file_path, |
| 117 bool recursive, |
| 118 OperationResult* result) { |
| 119 *result = base::DeleteFile(file_path, recursive) |
| 120 ? OperationResult::kSuccess |
| 121 : OperationResult::kFileDeleteFailed; |
| 122 } |
| 123 |
| 124 } // namespace |
| 125 |
| 126 DataItem::DataItem(const std::string& id) : id_(id), weak_ptr_factory_(this) {} |
| 127 |
| 128 DataItem::~DataItem() = default; |
| 129 |
| 130 std::unique_ptr<base::DictionaryValue> DataItem::ToValue() { |
| 131 std::unique_ptr<base::DictionaryValue> result = |
| 132 base::MakeUnique<base::DictionaryValue>(); |
| 133 result->SetString(kPrefKeyId, id_); |
| 134 result->SetString(kPrefKeyBackingFile, backing_file_.value()); |
| 135 return result; |
| 136 } |
| 137 |
| 138 bool DataItem::InitFromValue(const base::Value& value) { |
| 139 const base::DictionaryValue* dict_value = nullptr; |
| 140 if (!value.GetAsDictionary(&dict_value)) |
| 141 return false; |
| 142 |
| 143 std::string item_id; |
| 144 if (!dict_value->GetString(kPrefKeyId, &item_id) || id() != item_id) |
| 145 return false; |
| 146 |
| 147 std::string backing_file; |
| 148 if (dict_value->GetString(kPrefKeyBackingFile, &backing_file)) |
| 149 set_backing_file(base::FilePath(backing_file)); |
| 150 |
| 151 return true; |
| 152 } |
| 153 |
| 154 OperationResult DataItem::Write( |
| 155 const std::vector<char>& data, |
| 156 const std::string& crypto_key, |
| 157 const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 158 const WriteCallback& callback) { |
| 159 if (backing_file_.empty()) |
| 160 return OperationResult::kNoBackingFile; |
| 161 |
| 162 std::unique_ptr<OperationResult> result = |
| 163 base::MakeUnique<OperationResult>(OperationResult::kFailed); |
| 164 OperationResult* result_ptr = result.get(); |
| 165 |
| 166 task_runner->PostTaskAndReply( |
| 167 FROM_HERE, |
| 168 base::Bind(&WriteImpl, backing_file_, data, crypto_key, result_ptr), |
| 169 base::Bind(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(), |
| 170 callback, base::Passed(&result))); |
| 171 return OperationResult::kPending; |
| 172 } |
| 173 |
| 174 OperationResult DataItem::Read( |
| 175 const std::string& crypto_key, |
| 176 const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 177 const ReadCallback& callback) { |
| 178 if (backing_file_.empty()) |
| 179 return OperationResult::kNoBackingFile; |
| 180 |
| 181 std::unique_ptr<OperationResult> result = |
| 182 base::MakeUnique<OperationResult>(OperationResult::kFailed); |
| 183 OperationResult* result_ptr = result.get(); |
| 184 |
| 185 std::unique_ptr<std::vector<char>> data = |
| 186 base::MakeUnique<std::vector<char>>(); |
| 187 std::vector<char>* data_ptr = data.get(); |
| 188 |
| 189 task_runner->PostTaskAndReply( |
| 190 FROM_HERE, |
| 191 base::Bind(&ReadImpl, backing_file_, crypto_key, result_ptr, data_ptr), |
| 192 base::Bind(&DataItem::OnReadDone, weak_ptr_factory_.GetWeakPtr(), |
| 193 callback, base::Passed(&result), base::Passed(&data))); |
| 194 return OperationResult::kPending; |
| 195 } |
| 196 |
| 197 OperationResult DataItem::Delete( |
| 198 const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 199 const DeleteCallback& callback) { |
| 200 if (backing_file_.empty()) |
| 201 return OperationResult::kNoBackingFile; |
| 202 |
| 203 std::unique_ptr<OperationResult> result = |
| 204 base::MakeUnique<OperationResult>(OperationResult::kFailed); |
| 205 OperationResult* result_ptr = result.get(); |
| 206 |
| 207 task_runner->PostTaskAndReply( |
| 208 FROM_HERE, base::Bind(&DeleteImpl, backing_file_, false, result_ptr), |
| 209 base::Bind(&DataItem::OnDeleteDone, weak_ptr_factory_.GetWeakPtr(), |
| 210 callback, base::Passed(&result))); |
| 211 |
| 212 backing_file_ = base::FilePath(); |
| 213 return OperationResult::kPending; |
| 214 } |
| 215 |
| 216 void DataItem::OnWriteDone(const DataItem::WriteCallback& callback, |
| 217 std::unique_ptr<OperationResult> success) { |
| 218 callback.Run(*success); |
| 219 } |
| 220 |
| 221 void DataItem::OnReadDone(const DataItem::ReadCallback& callback, |
| 222 std::unique_ptr<OperationResult> success, |
| 223 std::unique_ptr<std::vector<char>> data) { |
| 224 callback.Run(*success, std::move(data)); |
| 225 } |
| 226 |
| 227 void DataItem::OnDeleteDone(const DataItem::DeleteCallback& callback, |
| 228 std::unique_ptr<OperationResult> success) { |
| 229 callback.Run(*success); |
| 230 } |
| 231 |
| 232 } // namespace lock_screen_data |
| 233 } // namespace extensions |
OLD | NEW |