cryptographer.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Cryptographer::~Cryptographer() {} 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_initialized()) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized_nigori_key = 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnpackBootstrapToken(restored_bootstrap_token); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (serialized_nigori_key.empty()) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImportNigoriKey(serialized_nigori_key); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nigoris_.end() != nigoris_.find(data.key_name()); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::CanDecryptUsingDefaultKey( 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EncryptedData& data) const { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !default_nigori_name_.empty() && 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data.key_name() == default_nigori_name_; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::Encrypt( 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ::google::protobuf::MessageLite& message, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EncryptedData* encrypted) const { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(encrypted); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (default_nigori_name_.empty()) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!message.SerializeToString(&serialized)) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Message is invalid/missing a required field."; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return EncryptString(serialized, encrypted); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::EncryptString( 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& serialized, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EncryptedData* encrypted) const { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CanDecryptUsingDefaultKey(*encrypted)) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& original_serialized = DecryptToString(*encrypted); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (original_serialized == serialized) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NigoriMap::const_iterator default_nigori = 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigoris_.find(default_nigori_name_); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (default_nigori == nigoris_.end()) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Corrupt default key."; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) encrypted->set_key_name(default_nigori_name_); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_nigori->second->Encrypt(serialized, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) encrypted->mutable_blob())) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to encrypt data."; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::google::protobuf::MessageLite* message) const { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(message); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string plaintext = DecryptToString(encrypted); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return message->ParseFromString(plaintext); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Cryptographer::DecryptToString( 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EncryptedData& encrypted) const { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NigoriMap::const_iterator it = nigoris_.find(encrypted.key_name()); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nigoris_.end() == it) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Cannot decrypt message"; 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); // Caller should have called CanDecrypt(encrypt). 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string plaintext; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!it->second->Decrypt(encrypted.blob(), &plaintext)) { 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return plaintext; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(encrypted); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!nigoris_.empty()); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a bag of all the Nigori parameters we know about. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (NigoriMap::const_iterator it = nigoris_.begin(); it != nigoris_.end(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Nigori& nigori = *it->second; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKey* key = bag.add_key(); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key->set_name(it->first); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigori.ExportKeys(key->mutable_user_key(), 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key->mutable_encryption_key(), 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key->mutable_mac_key()); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Encrypt the bag with the default Nigori. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Encrypt(bag, encrypted); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddKey(const KeyParams& params) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the new Nigori and make it the default encryptor. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> nigori(new Nigori); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori->InitByDerivation(params.hostname, 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.username, 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.password)) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); // Invalid username or password. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddKeyImpl(nigori.Pass(), true); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddNonDefaultKey(const KeyParams& params) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(is_initialized()); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the new Nigori and add it to the keybag. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> nigori(new Nigori); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori->InitByDerivation(params.hostname, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.username, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.password)) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); // Invalid username or password. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddKeyImpl(nigori.Pass(), false); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddKeyFromBootstrapToken( 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string restored_bootstrap_token) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the new Nigori and make it the default encryptor. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string serialized_nigori_key = UnpackBootstrapToken( 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) restored_bootstrap_token); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ImportNigoriKey(serialized_nigori_key); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::AddKeyImpl(scoped_ptr<Nigori> initialized_nigori, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool set_as_default) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string name; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigoris_[name] = make_linked_ptr(initialized_nigori.release()); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the key we just added can decrypt the pending keys and add them 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // too if so. 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_keys_.get() && CanDecrypt(*pending_keys_)) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag pending_bag; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Decrypt(*pending_keys_, &pending_bag); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallKeyBag(pending_bag); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDefaultKey(pending_keys_->key_name()); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_keys_.reset(); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The just-added key takes priority over the pending keys as default. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (set_as_default) SetDefaultKey(name); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CanDecrypt(encrypted)); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Decrypt(encrypted, &bag)) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallKeyBag(bag); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::SetDefaultKey(const std::string& key_name) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(nigoris_.end() != nigoris_.find(key_name)); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_nigori_name_ = key_name; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) { 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!CanDecrypt(encrypted)); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!encrypted.blob().empty()); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(has_pending_keys()); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *(pending_keys_.get()); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::DecryptPendingKeys(const KeyParams& params) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Nigori nigori; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori.InitByDerivation(params.hostname, 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.username, 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.password)) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string plaintext; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori.Decrypt(pending_keys_->blob(), &plaintext)) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!bag.ParseFromString(plaintext)) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallKeyBag(bag); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& new_default_key_name = pending_keys_->key_name(); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDefaultKey(new_default_key_name); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_keys_.reset(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::GetBootstrapToken(std::string* token) const { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(token); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unencrypted_token = GetDefaultNigoriKey(); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (unencrypted_token.empty()) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encrypted_token; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!encryptor_->EncryptString(unencrypted_token, &encrypted_token)) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Base64Encode(encrypted_token, token)) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Cryptographer::UnpackBootstrapToken( 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& token) const { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (token.empty()) 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encrypted_data; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Base64Decode(token, &encrypted_data)) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Could not decode token."; 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unencrypted_token; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!encryptor_->DecryptString(encrypted_data, &unencrypted_token)) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Decryption of bootstrap token failed."; 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return unencrypted_token; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int key_size = bag.key_size(); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < key_size; ++i) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::NigoriKey key = bag.key(i); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only use this key if we don't already know about it. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nigoris_.end() == nigoris_.find(key.name())) { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> new_nigori(new Nigori); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!new_nigori->InitByImport(key.user_key(), 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.encryption_key(), 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mac_key())) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::KeybagIsStale( 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::EncryptedData& encrypted_bag) const { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_ready()) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (encrypted_bag.blob().empty()) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CanDecrypt(encrypted_bag)) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CanDecryptUsingDefaultKey(encrypted_bag)) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKeyBag bag; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Decrypt(encrypted_bag, &bag)) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to decrypt keybag for stale check. " 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Assuming keybag is corrupted."; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (static_cast<size_t>(bag.key_size()) < nigoris_.size()) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Cryptographer::GetDefaultNigoriKey() const { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_initialized()) 331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NigoriMap::const_iterator iter = nigoris_.find(default_nigori_name_); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter == nigoris_.end()) 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKey key; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!iter->second->ExportKeys(key.mutable_user_key(), 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mutable_encryption_key(), 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mutable_mac_key())) 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return key.SerializeAsString(); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Cryptographer::ImportNigoriKey(const std::string serialized_nigori_key) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (serialized_nigori_key.empty()) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::NigoriKey key; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!key.ParseFromString(serialized_nigori_key)) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<Nigori> nigori(new Nigori); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!nigori->InitByImport(key.user_key(), key.encryption_key(), 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.mac_key())) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AddKeyImpl(nigori.Pass(), true)) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace syncer 364