示例#1
0
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();
}
示例#2
0
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();
}
示例#3
0
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();
}
示例#4
0
Status
loginServerGetLoginPackage(const Lobby &lobby,
                           DataSlice LP1, DataSlice LRA1, LoginPackage &result, JsonPtr &rootKeyBox)
{
    const auto url = ABC_SERVER_ROOT "/account/loginpackage/get";
    ServerRequestJson json;
    ABC_CHECK(json.setup(lobby));
    if (LP1.size())
        ABC_CHECK(json.authKeySet(base64Encode(LP1)));
    if (LRA1.size())
        ABC_CHECK(json.recoveryAuthKeySet(base64Encode(LRA1)));

    HttpReply reply;
    ABC_CHECK(AirbitzRequest().post(reply, url, json.encode()));
    ServerReplyJson replyJson;
    ABC_CHECK(replyJson.decode(reply.body));
    ABC_CHECK(replyJson.ok());

    struct ResultJson:
        public JsonObject
    {
        ABC_JSON_CONSTRUCTORS(ResultJson, JsonObject)
        ABC_JSON_STRING(package, "login_package", nullptr)
        ABC_JSON_VALUE(rootKeyBox, "rootKeyBox", JsonPtr)
    } resultJson(replyJson.results());

    ABC_CHECK(resultJson.packageOk());
    ABC_CHECK(result.decode(resultJson.package()));
    if (json_is_object(resultJson.rootKeyBox().get()))
        rootKeyBox = resultJson.rootKeyBox();
    return Status();
}
示例#5
0
Status
loginServerChangePassword(const Login &login,
                          DataSlice newLP1, DataSlice newLRA1,
                          const CarePackage &carePackage, const LoginPackage &loginPackage)
{
    const auto url = ABC_SERVER_ROOT "/account/password/update";
    JsonPtr json(json_pack("{ss, ss, ss, ss, ss}",
                           ABC_SERVER_JSON_L1_FIELD,      base64Encode(login.lobby.authId()).c_str(),
                           ABC_SERVER_JSON_LP1_FIELD,     base64Encode(login.authKey()).c_str(),
                           ABC_SERVER_JSON_NEW_LP1_FIELD, base64Encode(newLP1).c_str(),
                           ABC_SERVER_JSON_CARE_PACKAGE_FIELD,  carePackage.encode().c_str(),
                           ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackage.encode().c_str()));
    if (newLRA1.size())
    {
        json_object_set_new(json.get(), ABC_SERVER_JSON_NEW_LRA1_FIELD,
                            json_string(base64Encode(newLRA1).c_str()));
    }

    HttpReply reply;
    ABC_CHECK(AirbitzRequest().post(reply, url, json.encode()));
    ServerReplyJson replyJson;
    ABC_CHECK(replyJson.decode(reply.body));
    ABC_CHECK(replyJson.ok());

    return Status();
}
示例#6
0
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");
}
示例#7
0
/**
 * Changes the password for an account on the server.
 *
 * This function sends information to the server to change the password for an account.
 * Either the old LP1 or LRA1 can be used for authentication.
 *
 * @param oldLP1 Old password hash for the account (if this is empty, LRA1 is used instead)
 * @param LRA1   LRA1 for the account (used if oldP1 is empty)
 */
tABC_CC ABC_LoginServerChangePassword(const Lobby &lobby,
                                      tABC_U08Buf oldLP1,
                                      tABC_U08Buf newLP1,
                                      tABC_U08Buf newLRA1,
                                      const CarePackage &carePackage,
                                      const LoginPackage &loginPackage,
                                      tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    HttpReply reply;
    std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_CHANGE_PASSWORD_PATH;
    ServerReplyJson replyJson;
    char *szPost    = NULL;
    std::string carePackageStr;
    std::string loginPackageStr;
    json_t *pJSON_OldLRA1   = NULL;
    json_t *pJSON_NewLRA1   = NULL;
    json_t *pJSON_Root = NULL;

    ABC_CHECK_NULL_BUF(oldLP1);
    ABC_CHECK_NULL_BUF(newLP1);

    ABC_CHECK_NEW(carePackage.encode(carePackageStr));
    ABC_CHECK_NEW(loginPackage.encode(loginPackageStr));

    // Encode those:
    pJSON_Root = json_pack("{ss, ss, ss, ss, ss}",
        ABC_SERVER_JSON_L1_FIELD,      base64Encode(lobby.authId()).c_str(),
        ABC_SERVER_JSON_LP1_FIELD,     base64Encode(oldLP1).c_str(),
        ABC_SERVER_JSON_NEW_LP1_FIELD, base64Encode(newLP1).c_str(),
        ABC_SERVER_JSON_CARE_PACKAGE_FIELD,  carePackageStr.c_str(),
        ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackageStr.c_str());

    // set up the recovery, if any:
    if (newLRA1.size())
    {
        pJSON_NewLRA1 = json_string(base64Encode(newLRA1).c_str());
        json_object_set(pJSON_Root, ABC_SERVER_JSON_NEW_LRA1_FIELD, pJSON_NewLRA1);
    }

    // create the post data
    szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT);

    // send the command
    ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost));

    ABC_CHECK_NEW(replyJson.decode(reply.body));
    ABC_CHECK_NEW(replyJson.ok());

exit:
    ABC_FREE_STR(szPost);
    if (pJSON_OldLRA1)  json_decref(pJSON_OldLRA1);
    if (pJSON_NewLRA1)  json_decref(pJSON_NewLRA1);
    if (pJSON_Root)     json_decref(pJSON_Root);

    return cc;
}
示例#8
0
Status
loginRecovery(std::shared_ptr<Login> &result,
              Lobby &lobby, const std::string &recoveryAnswers,
              AuthError &authError)
{
    std::string LRA = lobby.username() + recoveryAnswers;

    // Get the CarePackage:
    CarePackage carePackage;
    ABC_CHECK(loginServerGetCarePackage(lobby, carePackage));

    // Make recoveryAuthKey (unlocks the server):
    DataChunk recoveryAuthKey;
    ABC_CHECK(usernameSnrp().hash(recoveryAuthKey, LRA));

    // Get the LoginPackage:
    LoginPackage loginPackage;
    JsonPtr rootKeyBox;
    ABC_CHECK(loginServerGetLoginPackage(lobby, U08Buf(), recoveryAuthKey,
                                         loginPackage, rootKeyBox,
                                         authError));

    // Make recoveryKey (unlocks dataKey):
    DataChunk recoveryKey;
    ABC_CHECK(carePackage.snrp3().hash(recoveryKey, LRA));

    // Decrypt dataKey (unlocks the account):
    DataChunk dataKey;
    ABC_CHECK(loginPackage.recoveryBox().decrypt(dataKey, recoveryKey));

    // Create the Login object:
    std::shared_ptr<Login> out;
    ABC_CHECK(Login::create(out, lobby, dataKey,
                            loginPackage, rootKeyBox, false));

    // Set up the on-disk login:
    ABC_CHECK(carePackage.save(out->paths.carePackagePath()));
    ABC_CHECK(loginPackage.save(out->paths.loginPackagePath()));

    result = std::move(out);
    return Status();
}
示例#9
0
/**
 * Creates an account on the server.
 *
 * This function sends information to the server to create an account.
 * If the account was created, ABC_CC_Ok is returned.
 * If the account already exists, ABC_CC_AccountAlreadyExists is returned.
 *
 * @param LP1  Password hash for the account
 */
tABC_CC ABC_LoginServerCreate(const Lobby &lobby,
                              tABC_U08Buf LP1,
                              const CarePackage &carePackage,
                              const LoginPackage &loginPackage,
                              const char *szRepoAcctKey,
                              tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    HttpReply reply;
    std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_ACCOUNT_CREATE_PATH;
    ServerReplyJson replyJson;
    char *szPost    = NULL;
    std::string carePackageStr;
    std::string loginPackageStr;
    json_t *pJSON_Root = NULL;

    ABC_CHECK_NULL_BUF(LP1);

    ABC_CHECK_NEW(carePackage.encode(carePackageStr));
    ABC_CHECK_NEW(loginPackage.encode(loginPackageStr));

    // create the post data
    pJSON_Root = json_pack("{ssssssssss}",
        ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(),
        ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str(),
        ABC_SERVER_JSON_CARE_PACKAGE_FIELD, carePackageStr.c_str(),
        ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackageStr.c_str(),
        ABC_SERVER_JSON_REPO_FIELD, szRepoAcctKey);
    szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT);

    // send the command
    ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost));

    // decode the result
    ABC_CHECK_NEW(replyJson.decode(reply.body));
    ABC_CHECK_NEW(replyJson.ok());

exit:
    ABC_FREE_STR(szPost);
    if (pJSON_Root)     json_decref(pJSON_Root);

    return cc;
}
示例#10
0
tABC_CC ABC_LoginServerGetLoginPackage(const Lobby &lobby,
                                       tABC_U08Buf LP1,
                                       tABC_U08Buf LRA1,
                                       LoginPackage &result,
                                       tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_LOGIN_PACK_GET_PATH;
    char *szLoginPackage = NULL;

    ABC_CHECK_RET(ABC_LoginServerGetString(lobby, LP1, LRA1, url.c_str(), JSON_ACCT_LOGIN_PACKAGE, &szLoginPackage, pError));
    ABC_CHECK_NEW(result.decode(szLoginPackage));

exit:
    ABC_FREE_STR(szLoginPackage);

    return cc;
}
示例#11
0
Status
loginServerCreate(const LoginStore &store, DataSlice LP1,
                  const CarePackage &carePackage,
                  const LoginPackage &loginPackage,
                  const std::string &syncKey)
{
    const auto url = ABC_SERVER_ROOT "/v1/account/create";
    ServerRequestJson json;
    ABC_CHECK(json.setup(store));
    ABC_CHECK(json.passwordAuthSet(base64Encode(LP1)));
    ABC_CHECK(json.set(ABC_SERVER_JSON_CARE_PACKAGE_FIELD, carePackage.encode()));
    ABC_CHECK(json.set(ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackage.encode()));
    ABC_CHECK(json.set(ABC_SERVER_JSON_REPO_FIELD, syncKey));

    HttpReply reply;
    ABC_CHECK(AirbitzRequest().post(reply, url, json.encode()));
    ServerReplyJson replyJson;
    ABC_CHECK(replyJson.decode(reply));

    return Status();
}
示例#12
0
Status
loginServerCreate(const Lobby &lobby, DataSlice LP1,
                  const CarePackage &carePackage, const LoginPackage &loginPackage,
                  const std::string &syncKey)
{
    const auto url = ABC_SERVER_ROOT "/account/create";
    JsonPtr json(json_pack("{ssssssssss}",
                           ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(),
                           ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str(),
                           ABC_SERVER_JSON_CARE_PACKAGE_FIELD, carePackage.encode().c_str(),
                           ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackage.encode().c_str(),
                           ABC_SERVER_JSON_REPO_FIELD, syncKey.c_str()));

    HttpReply reply;
    ABC_CHECK(AirbitzRequest().post(reply, url, json.encode()));
    ServerReplyJson replyJson;
    ABC_CHECK(replyJson.decode(reply.body));
    ABC_CHECK(replyJson.ok());

    return Status();
}
示例#13
0
Status
loginServerChangePassword(const Login &login,
                          DataSlice newLP1, DataSlice newLRA1,
                          const CarePackage &carePackage,
                          const LoginPackage &loginPackage)
{
    const auto url = ABC_SERVER_ROOT "/v1/account/password/update";
    ServerRequestJson json;
    ABC_CHECK(json.setup(login));
    ABC_CHECK(json.set(ABC_SERVER_JSON_NEW_LP1_FIELD, base64Encode(newLP1)));
    ABC_CHECK(json.set(ABC_SERVER_JSON_CARE_PACKAGE_FIELD, carePackage.encode()));
    ABC_CHECK(json.set(ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackage.encode()));
    if (newLRA1.size())
    {
        ABC_CHECK(json.set(ABC_SERVER_JSON_NEW_LRA1_FIELD, base64Encode(newLRA1)));
    }

    HttpReply reply;
    ABC_CHECK(AirbitzRequest().post(reply, url, json.encode()));
    ServerReplyJson replyJson;
    ABC_CHECK(replyJson.decode(reply));

    return Status();
}
示例#14
0
Status
Login::createNew(const char *password)
{
    LoginPackage loginPackage;
    JsonSnrp snrp;

    // Set up care package:
    CarePackage carePackage;
    ABC_CHECK(snrp.create());
    ABC_CHECK(carePackage.passwordKeySnrpSet(snrp));

    // Set up syncKey:
    DataChunk syncKey;
    JsonBox syncKeyBox;
    ABC_CHECK(randomData(syncKey, SYNC_KEY_LENGTH));
    ABC_CHECK(syncKeyBox.encrypt(syncKey, dataKey_));
    ABC_CHECK(loginPackage.syncKeyBoxSet(syncKeyBox));

    // Set up passwordAuth (LP1):
    if (password)
    {
        std::string LP = store.username() + password;

        // Generate passwordAuth:
        ABC_CHECK(usernameSnrp().hash(passwordAuth_, LP));

        // We have a password, so use it to encrypt dataKey:
        DataChunk passwordKey;
        JsonBox passwordBox;
        ABC_CHECK(carePackage.passwordKeySnrp().hash(passwordKey, LP));
        ABC_CHECK(passwordBox.encrypt(dataKey_, passwordKey));
        ABC_CHECK(loginPackage.passwordBoxSet(passwordBox));
    }
    else
    {
        // Generate passwordAuth:
        ABC_CHECK(randomData(passwordAuth_, scryptDefaultSize));
    }
    JsonBox passwordAuthBox;
    ABC_CHECK(passwordAuthBox.encrypt(passwordAuth_, dataKey_));
    ABC_CHECK(loginPackage.passwordAuthBoxSet(passwordAuthBox));

    // Create the account and repo on server:
    ABC_CHECK(loginServerCreate(store, passwordAuth_,
                                carePackage, loginPackage, base16Encode(syncKey)));

    // Set up the on-disk login:
    ABC_CHECK(store.paths(paths, true));
    ABC_CHECK(carePackage.save(paths.carePackagePath()));
    ABC_CHECK(loginPackage.save(paths.loginPackagePath()));
    ABC_CHECK(rootKeyUpgrade());

    // Save the bare minimum needed to access the Airbitz account:
    LoginStashJson stashJson;
    ABC_CHECK(stashJson.loginIdSet(base64Encode(store.userId())));
    ABC_CHECK(stashJson.syncKeyBoxSet(syncKeyBox));
    stashJson.save(paths.stashPath());

    // Latch the account:
    ABC_CHECK(loginServerActivate(*this));

    return Status();
}