Пример #1
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();
}
Пример #2
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();
}
Пример #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
/**
 * 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;
}
Пример #5
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();
}
Пример #6
0
Status
loginRecoveryQuestions(std::string &result, Lobby &lobby)
{
    // Load CarePackage:
    CarePackage carePackage;
    ABC_CHECK(loginServerGetCarePackage(lobby, carePackage));

    // Verify that the questions exist:
    if (!carePackage.questionBox())
        return ABC_ERROR(ABC_CC_NoRecoveryQuestions, "No recovery questions");

    // Create questionKey (unlocks questions):
    DataChunk questionKey;
    ABC_CHECK(carePackage.snrp4().hash(questionKey, lobby.username()));

    // Decrypt:
    DataChunk questions;
    ABC_CHECK(carePackage.questionBox().decrypt(questions, questionKey));

    result = toString(questions);
    return Status();
}
Пример #7
0
tABC_CC ABC_LoginServerGetCarePackage(const Lobby &lobby,
                                      CarePackage &result,
                                      tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_GET_CARE_PACKAGE_PATH;
    char *szCarePackage = NULL;

    ABC_CHECK_RET(ABC_LoginServerGetString(lobby, U08Buf(), U08Buf(), url.c_str(), JSON_ACCT_CARE_PACKAGE, &szCarePackage, pError));
    ABC_CHECK_NEW(result.decode(szCarePackage));

exit:
    ABC_FREE_STR(szCarePackage);

    return cc;
}
Пример #8
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;
}
Пример #9
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();
}
Пример #10
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();
}
Пример #11
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();
}
Пример #12
0
Status
loginServerGetCarePackage(const Lobby &lobby, CarePackage &result)
{
    const auto url = ABC_SERVER_ROOT "/account/carepackage/get";
    ServerRequestJson json;
    ABC_CHECK(json.setup(lobby));

    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, "care_package", nullptr)
    } resultJson(replyJson.results());

    ABC_CHECK(resultJson.packageOk());
    ABC_CHECK(result.decode(resultJson.package()));
    return Status();
}
Пример #13
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();
}