Status Login::loadOffline() { ABC_CHECK(store.paths(paths, true)); LoginPackage loginPackage; ABC_CHECK(loginPackage.load(paths.loginPackagePath())); ABC_CHECK(loginPackage.passwordAuthBox().decrypt(passwordAuth_, dataKey_)); // Look for an existing rootKeyBox: JsonBox rootKeyBox; if (fileExists(paths.rootKeyPath())) { ABC_CHECK(rootKeyBox.load(paths.rootKeyPath())); } else { // Try asking the server: AuthJson authJson; LoginReplyJson loginJson; ABC_CHECK(authJson.loginSet(*this)); ABC_CHECK(loginServerLogin(loginJson, authJson)); ABC_CHECK(loginJson.save(*this)); rootKeyBox = loginJson.rootKeyBox(); } // Otherwise, there just isn't one. // Extract the rootKey: if (rootKeyBox.ok()) ABC_CHECK(rootKeyBox.decrypt(rootKey_, dataKey_)); else ABC_CHECK(rootKeyUpgrade()); return Status(); }
Status loginRecoverySet(Login &login, const std::string &recoveryQuestions, const std::string &recoveryAnswers) { std::string LRA = login.lobby.username() + recoveryAnswers; // Load the packages: CarePackage carePackage; LoginPackage loginPackage; ABC_CHECK(carePackage.load(login.paths.carePackagePath())); ABC_CHECK(loginPackage.load(login.paths.loginPackagePath())); // Load the old keys: DataChunk authKey = login.authKey(); // Update scrypt parameters: JsonSnrp snrp; ABC_CHECK(snrp.create()); ABC_CHECK(carePackage.snrp3Set(snrp)); ABC_CHECK(snrp.create()); ABC_CHECK(carePackage.snrp4Set(snrp)); // Make questionKey (unlocks questions): DataChunk questionKey; ABC_CHECK(carePackage.snrp4().hash(questionKey, login.lobby.username())); // Encrypt the questions: JsonBox box; ABC_CHECK(box.encrypt(recoveryQuestions, questionKey)); ABC_CHECK(carePackage.questionBoxSet(box)); // Make recoveryKey (unlocks dataKey): DataChunk recoveryKey; ABC_CHECK(carePackage.snrp3().hash(recoveryKey, LRA)); // Encrypt dataKey: ABC_CHECK(box.encrypt(login.dataKey(), recoveryKey)); ABC_CHECK(loginPackage.recoveryBoxSet(box)); // Make recoveryAuthKey (unlocks the server): DataChunk recoveryAuthKey; ABC_CHECK(usernameSnrp().hash(recoveryAuthKey, LRA)); // Encrypt recoveryAuthKey (needed for atomic password updates): ABC_CHECK(box.encrypt(recoveryAuthKey, login.dataKey())); ABC_CHECK(loginPackage.ELRA1Set(box)); // Change the server login: ABC_CHECK(loginServerChangePassword(login, authKey, recoveryAuthKey, carePackage, loginPackage)); // Change the on-disk login: ABC_CHECK(carePackage.save(login.paths.carePackagePath())); ABC_CHECK(loginPackage.save(login.paths.loginPackagePath())); return Status(); }
Status loginRecoverySet(Login &login, const std::string &recoveryQuestions, const std::string &recoveryAnswers) { std::string LRA = login.store.username() + recoveryAnswers; // Load the packages: CarePackage carePackage; LoginPackage loginPackage; ABC_CHECK(carePackage.load(login.paths.carePackagePath())); ABC_CHECK(loginPackage.load(login.paths.loginPackagePath())); // Load the old keys: DataChunk passwordAuth = login.passwordAuth(); // Update scrypt parameters: JsonSnrp snrp; ABC_CHECK(snrp.create()); ABC_CHECK(carePackage.recoveryKeySnrpSet(snrp)); ABC_CHECK(snrp.create()); ABC_CHECK(carePackage.questionKeySnrpSet(snrp)); // Make questionKey (unlocks questions): DataChunk questionKey; ABC_CHECK(carePackage.questionKeySnrp().hash(questionKey, login.store.username())); // Encrypt the questions: JsonBox questionBox; ABC_CHECK(questionBox.encrypt(recoveryQuestions, questionKey)); ABC_CHECK(carePackage.questionBoxSet(questionBox)); // Make recoveryKey (unlocks dataKey): DataChunk recoveryKey; ABC_CHECK(carePackage.recoveryKeySnrp().hash(recoveryKey, LRA)); // Encrypt dataKey: JsonBox recoveryBox; ABC_CHECK(recoveryBox.encrypt(login.dataKey(), recoveryKey)); ABC_CHECK(loginPackage.recoveryBoxSet(recoveryBox)); // Make recoveryAuth (unlocks the server): DataChunk recoveryAuth; ABC_CHECK(usernameSnrp().hash(recoveryAuth, LRA)); // Change the server login: ABC_CHECK(loginServerChangePassword(login, passwordAuth, recoveryAuth, carePackage, loginPackage)); // Change the on-disk login: ABC_CHECK(carePackage.save(login.paths.carePackagePath())); ABC_CHECK(loginPackage.save(login.paths.loginPackagePath())); return Status(); }
Status Login::repoFindLocal(JsonPtr &result, const std::string &type) { // If this is an Airbitz account, try the legacy `syncKey`: if (repoTypeAirbitzAccount == type) { LoginPackage loginPackage; ABC_CHECK(loginPackage.load(paths.loginPackagePath())); if (loginPackage.syncKeyBox().ok()) { DataChunk syncKey; ABC_CHECK(loginPackage.syncKeyBox().decrypt(syncKey, dataKey_)); AccountRepoJson repoJson; ABC_CHECK(repoJson.syncKeySet(base64Encode(syncKey))); ABC_CHECK(repoJson.dataKeySet(base64Encode(dataKey_))); result = repoJson; return Status(); } } // Search the on-disk array: LoginStashJson stashJson; if (stashJson.load(paths.stashPath())) { auto keyBoxesJson = stashJson.keyBoxes(); size_t keyBoxesSize = keyBoxesJson.size(); for (size_t i = 0; i < keyBoxesSize; i++) { JsonBox boxJson(keyBoxesJson[i]); DataChunk keyBytes; KeyJson keyJson; ABC_CHECK(boxJson.decrypt(keyBytes, dataKey_)); ABC_CHECK(keyJson.decode(toString(keyBytes))); if (keyJson.typeOk() && type == keyJson.type()) { result = keyJson.keys(); return Status(); } } } return ABC_ERROR(ABC_CC_AccountDoesNotExist, "No such repo"); }