cryptographer.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/util/cryptographer.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/nigori_specifics.pb.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/util/encryptor.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNigoriTag[] = "google_chrome_nigori"; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We name a particular Nigori instance (ie. a triplet consisting of a hostname, 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a username, and a password) by calling Permute on this string. Since the 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// output of Permute is always the same for a given triplet, clients will always 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// assign the same name to a particular triplet. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNigoriKeyName[] = "nigori-key"; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Cryptographer::Cryptographer(Encryptor* encryptor) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : encryptor_(encryptor) { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(encryptor); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)Cryptographer::Cryptographer(const Cryptographer& other) 3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) : encryptor_(other.encryptor_), 3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) default_nigori_name_(other.default_nigori_name_) { 3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (NigoriMap::const_iterator it = other.nigoris_.begin(); 3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) it != other.nigoris_.end(); 3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ++it) { 3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) std::string user_key, encryption_key, mac_key; 3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) it->second->ExportKeys(&user_key, &encryption_key, &mac_key); 3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) linked_ptr<Nigori> nigori_copy(new Nigori()); 3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) nigori_copy->InitByImport(user_key, encryption_key, mac_key); 4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) nigoris_.insert(std::make_pair(it->first, nigori_copy)); 4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (other.pending_keys_) { 4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) pending_keys_.reset(new sync_pb::EncryptedData(*(other.pending_keys_))); 4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Cryptographer::~Cryptographer() {} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_initialized()) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized_nigori_key = 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnpackBootstrapToken(restored_bootstrap_token); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (serialized_nigori_key.empty()) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImportNigoriKey(serialized_nigori_key); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nigoris_.end() != nigoris_.find(data.key_name()); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::CanDecryptUsingDefaultKey( 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EncryptedData& data) const { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !default_nigori_name_.empty() && 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data.key_name() == default_nigori_name_; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::Encrypt( 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ::google::protobuf::MessageLite& message, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EncryptedData* encrypted) const { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(encrypted); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (default_nigori_name_.empty()) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!message.SerializeToString(&serialized)) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Message is invalid/missing a required field."; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return EncryptString(serialized, encrypted); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::EncryptString( 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& serialized, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EncryptedData* encrypted) const { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CanDecryptUsingDefaultKey(*encrypted)) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& original_serialized = DecryptToString(*encrypted); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (original_serialized == serialized) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NigoriMap::const_iterator default_nigori = 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigoris_.find(default_nigori_name_); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (default_nigori == nigoris_.end()) { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Corrupt default key."; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) encrypted->set_key_name(default_nigori_name_); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_nigori->second->Encrypt(serialized, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) encrypted->mutable_blob())) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to encrypt data."; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::google::protobuf::MessageLite* message) const { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(message); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string plaintext = DecryptToString(encrypted); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return message->ParseFromString(plaintext); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Cryptographer::DecryptToString( 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EncryptedData& encrypted) const { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NigoriMap::const_iterator it = nigoris_.find(encrypted.key_name()); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nigoris_.end() == it) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Cannot decrypt message"; 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); // Caller should have called CanDecrypt(encrypt). 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string plaintext; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!it->second->Decrypt(encrypted.blob(), &plaintext)) { 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return plaintext; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(encrypted); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!nigoris_.empty()); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a bag of all the Nigori parameters we know about. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (NigoriMap::const_iterator it = nigoris_.begin(); it != nigoris_.end(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Nigori& nigori = *it->second; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKey* key = bag.add_key(); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key->set_name(it->first); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigori.ExportKeys(key->mutable_user_key(), 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key->mutable_encryption_key(), 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key->mutable_mac_key()); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Encrypt the bag with the default Nigori. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Encrypt(bag, encrypted); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddKey(const KeyParams& params) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the new Nigori and make it the default encryptor. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> nigori(new Nigori); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori->InitByDerivation(params.hostname, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.username, 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.password)) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); // Invalid username or password. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddKeyImpl(nigori.Pass(), true); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddNonDefaultKey(const KeyParams& params) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(is_initialized()); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the new Nigori and add it to the keybag. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> nigori(new Nigori); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori->InitByDerivation(params.hostname, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.username, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.password)) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); // Invalid username or password. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddKeyImpl(nigori.Pass(), false); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddKeyFromBootstrapToken( 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string restored_bootstrap_token) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the new Nigori and make it the default encryptor. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized_nigori_key = UnpackBootstrapToken( 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) restored_bootstrap_token); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ImportNigoriKey(serialized_nigori_key); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddKeyImpl(scoped_ptr<Nigori> initialized_nigori, 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool set_as_default) { 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string name; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigoris_[name] = make_linked_ptr(initialized_nigori.release()); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the key we just added can decrypt the pending keys and add them 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // too if so. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_keys_.get() && CanDecrypt(*pending_keys_)) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag pending_bag; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Decrypt(*pending_keys_, &pending_bag); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallKeyBag(pending_bag); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDefaultKey(pending_keys_->key_name()); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_keys_.reset(); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The just-added key takes priority over the pending keys as default. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (set_as_default) SetDefaultKey(name); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CanDecrypt(encrypted)); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Decrypt(encrypted, &bag)) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallKeyBag(bag); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::SetDefaultKey(const std::string& key_name) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(nigoris_.end() != nigoris_.find(key_name)); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_nigori_name_ = key_name; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!CanDecrypt(encrypted)); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!encrypted.blob().empty()); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(has_pending_keys()); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *(pending_keys_.get()); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::DecryptPendingKeys(const KeyParams& params) { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Nigori nigori; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori.InitByDerivation(params.hostname, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.username, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.password)) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string plaintext; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori.Decrypt(pending_keys_->blob(), &plaintext)) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!bag.ParseFromString(plaintext)) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallKeyBag(bag); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& new_default_key_name = pending_keys_->key_name(); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDefaultKey(new_default_key_name); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_keys_.reset(); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::GetBootstrapToken(std::string* token) const { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(token); 2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string unencrypted_token = GetDefaultNigoriKeyData(); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (unencrypted_token.empty()) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encrypted_token; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!encryptor_->EncryptString(unencrypted_token, &encrypted_token)) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Base64Encode(encrypted_token, token); 283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Cryptographer::UnpackBootstrapToken( 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& token) const { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (token.empty()) 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encrypted_data; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Base64Decode(token, &encrypted_data)) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Could not decode token."; 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unencrypted_token; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!encryptor_->DecryptString(encrypted_data, &unencrypted_token)) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Decryption of bootstrap token failed."; 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return unencrypted_token; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int key_size = bag.key_size(); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < key_size; ++i) { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::NigoriKey key = bag.key(i); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only use this key if we don't already know about it. 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nigoris_.end() == nigoris_.find(key.name())) { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> new_nigori(new Nigori); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!new_nigori->InitByImport(key.user_key(), 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.encryption_key(), 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mac_key())) { 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::KeybagIsStale( 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EncryptedData& encrypted_bag) const { 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_ready()) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (encrypted_bag.blob().empty()) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CanDecrypt(encrypted_bag)) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CanDecryptUsingDefaultKey(encrypted_bag)) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Decrypt(encrypted_bag, &bag)) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to decrypt keybag for stale check. " 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Assuming keybag is corrupted."; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (static_cast<size_t>(bag.key_size()) < nigoris_.size()) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string Cryptographer::GetDefaultNigoriKeyName() const { 3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return default_nigori_name_; 3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string Cryptographer::GetDefaultNigoriKeyData() const { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_initialized()) 351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NigoriMap::const_iterator iter = nigoris_.find(default_nigori_name_); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter == nigoris_.end()) 354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKey key; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!iter->second->ExportKeys(key.mutable_user_key(), 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mutable_encryption_key(), 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mutable_mac_key())) 359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return key.SerializeAsString(); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::ImportNigoriKey(const std::string serialized_nigori_key) { 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (serialized_nigori_key.empty()) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKey key; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!key.ParseFromString(serialized_nigori_key)) 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> nigori(new Nigori); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori->InitByImport(key.user_key(), key.encryption_key(), 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mac_key())) { 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AddKeyImpl(nigori.Pass(), true)) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace syncer 384