1 // Copyright 2015 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.
5 #include "components/gcm_driver/crypto/gcm_key_store.h"
9 #include "base/logging.h"
10 #include "components/leveldb_proto/proto_database_impl.h"
11 #include "crypto/curve25519.h"
12 #include "crypto/random.h"
16 enum class GCMKeyStore::State
{
23 GCMKeyStore::GCMKeyStore(
24 const base::FilePath
& key_store_path
,
25 const scoped_refptr
<base::SequencedTaskRunner
>& blocking_task_runner
)
26 : key_store_path_(key_store_path
),
27 blocking_task_runner_(blocking_task_runner
),
28 state_(State::UNINITIALIZED
),
30 DCHECK(blocking_task_runner
);
33 GCMKeyStore::~GCMKeyStore() {}
35 void GCMKeyStore::GetKeys(const std::string
& app_id
,
36 const KeysCallback
& callback
) {
37 LazyInitialize(base::Bind(&GCMKeyStore::GetKeysAfterInitialize
,
38 weak_factory_
.GetWeakPtr(), app_id
, callback
));
41 void GCMKeyStore::GetKeysAfterInitialize(const std::string
& app_id
,
42 const KeysCallback
& callback
) {
43 DCHECK(state_
== State::INITIALIZED
|| state_
== State::FAILED
);
44 const auto iter
= key_pairs_
.find(app_id
);
45 if (iter
== key_pairs_
.end() || state_
!= State::INITIALIZED
) {
46 callback
.Run(KeyPair());
50 callback
.Run(iter
->second
);
53 void GCMKeyStore::CreateKeys(const std::string
& app_id
,
54 const KeysCallback
& callback
) {
55 LazyInitialize(base::Bind(&GCMKeyStore::CreateKeysAfterInitialize
,
56 weak_factory_
.GetWeakPtr(), app_id
, callback
));
59 void GCMKeyStore::CreateKeysAfterInitialize(const std::string
& app_id
,
60 const KeysCallback
& callback
) {
61 DCHECK(state_
== State::INITIALIZED
|| state_
== State::FAILED
);
62 if (state_
!= State::INITIALIZED
) {
63 callback
.Run(KeyPair());
67 // Only allow creating new keys if no keys currently exist.
68 DCHECK_EQ(0u, key_pairs_
.count(app_id
));
70 // Create a Curve25519 private/public key-pair.
71 uint8_t private_key
[crypto::curve25519::kScalarBytes
];
72 uint8_t public_key
[crypto::curve25519::kBytes
];
74 crypto::RandBytes(private_key
, sizeof(private_key
));
76 // Compute the |public_key| based on the |private_key|.
77 crypto::curve25519::ScalarBaseMult(private_key
, public_key
);
79 // Store the keys in a new EncryptionData object.
80 EncryptionData encryption_data
;
81 encryption_data
.set_app_id(app_id
);
83 KeyPair
* pair
= encryption_data
.add_keys();
84 pair
->set_type(KeyPair::ECDH_CURVE_25519
);
85 pair
->set_private_key(private_key
, sizeof(private_key
));
86 pair
->set_public_key(public_key
, sizeof(public_key
));
88 using EntryVectorType
=
89 leveldb_proto::ProtoDatabase
<EncryptionData
>::KeyEntryVector
;
91 scoped_ptr
<EntryVectorType
> entries_to_save(new EntryVectorType());
92 scoped_ptr
<std::vector
<std::string
>> keys_to_remove(
93 new std::vector
<std::string
>());
95 entries_to_save
->push_back(std::make_pair(app_id
, encryption_data
));
97 database_
->UpdateEntries(
98 entries_to_save
.Pass(), keys_to_remove
.Pass(),
99 base::Bind(&GCMKeyStore::DidStoreKeys
, weak_factory_
.GetWeakPtr(), app_id
,
103 void GCMKeyStore::DidStoreKeys(const std::string
& app_id
,
105 const KeysCallback
& callback
,
107 DCHECK_EQ(0u, key_pairs_
.count(app_id
));
110 DVLOG(1) << "Unable to store the created key in the GCM Key Store.";
111 callback
.Run(KeyPair());
115 key_pairs_
[app_id
] = pair
;
117 callback
.Run(key_pairs_
[app_id
]);
120 void GCMKeyStore::DeleteKeys(const std::string
& app_id
,
121 const DeleteCallback
& callback
) {
122 LazyInitialize(base::Bind(&GCMKeyStore::DeleteKeysAfterInitialize
,
123 weak_factory_
.GetWeakPtr(), app_id
, callback
));
126 void GCMKeyStore::DeleteKeysAfterInitialize(const std::string
& app_id
,
127 const DeleteCallback
& callback
) {
128 DCHECK(state_
== State::INITIALIZED
|| state_
== State::FAILED
);
129 const auto iter
= key_pairs_
.find(app_id
);
130 if (iter
== key_pairs_
.end() || state_
!= State::INITIALIZED
) {
131 callback
.Run(true /* success */);
135 using EntryVectorType
=
136 leveldb_proto::ProtoDatabase
<EncryptionData
>::KeyEntryVector
;
138 scoped_ptr
<EntryVectorType
> entries_to_save(new EntryVectorType());
139 scoped_ptr
<std::vector
<std::string
>> keys_to_remove(
140 new std::vector
<std::string
>(1, app_id
));
142 database_
->UpdateEntries(
143 entries_to_save
.Pass(), keys_to_remove
.Pass(),
144 base::Bind(&GCMKeyStore::DidDeleteKeys
, weak_factory_
.GetWeakPtr(),
148 void GCMKeyStore::DidDeleteKeys(const std::string
& app_id
,
149 const DeleteCallback
& callback
,
152 DVLOG(1) << "Unable to delete a key from the GCM Key Store.";
153 callback
.Run(false /* success */);
157 key_pairs_
.erase(app_id
);
159 callback
.Run(true /* success */);
162 void GCMKeyStore::LazyInitialize(const base::Closure
& done_closure
) {
163 if (delayed_task_controller_
.CanRunTaskWithoutDelay()) {
168 delayed_task_controller_
.AddTask(done_closure
);
169 if (state_
== State::INITIALIZING
)
172 state_
= State::INITIALIZING
;
174 database_
.reset(new leveldb_proto::ProtoDatabaseImpl
<EncryptionData
>(
175 blocking_task_runner_
));
177 database_
->Init(key_store_path_
, base::Bind(&GCMKeyStore::DidInitialize
,
178 weak_factory_
.GetWeakPtr()));
181 void GCMKeyStore::DidInitialize(bool success
) {
183 DVLOG(1) << "Unable to initialize the GCM Key Store.";
184 state_
= State::FAILED
;
186 delayed_task_controller_
.SetReady();
190 database_
->LoadEntries(
191 base::Bind(&GCMKeyStore::DidLoadKeys
, weak_factory_
.GetWeakPtr()));
194 void GCMKeyStore::DidLoadKeys(bool success
,
195 scoped_ptr
<std::vector
<EncryptionData
>> entries
) {
197 DVLOG(1) << "Unable to load entries into the GCM Key Store.";
198 state_
= State::FAILED
;
200 delayed_task_controller_
.SetReady();
204 for (const EncryptionData
& entry
: *entries
) {
205 DCHECK_EQ(1, entry
.keys_size());
206 key_pairs_
[entry
.app_id()] = entry
.keys(0);
209 state_
= State::INITIALIZED
;
211 delayed_task_controller_
.SetReady();