blob: 0605d60e784e13a9c2db7c12a8b2376ed75c6ed6 [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cryptohome/scrypt_verifier.h"
#include <memory>
#include <string>
#include <utility>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include <brillo/secure_blob.h>
#include <brillo/secure_string.h>
#include <cryptohome/proto_bindings/UserDataAuth.pb.h>
#include <libhwsec-foundation/crypto/scrypt.h>
#include <libhwsec-foundation/crypto/secure_blob_util.h>
#include "cryptohome/auth_factor/auth_factor_metadata.h"
#include "cryptohome/auth_factor/auth_factor_type.h"
#include "cryptohome/error/cryptohome_error.h"
#include "cryptohome/error/location_utils.h"
#include "cryptohome/error/locations.h"
#include "cryptohome/key_objects.h"
namespace cryptohome {
namespace {
using ::cryptohome::error::CryptohomeError;
using ::cryptohome::error::ErrorAction;
using ::cryptohome::error::ErrorActionSet;
using ::hwsec_foundation::CreateSecureRandomBlob;
using ::hwsec_foundation::Scrypt;
using ::hwsec_foundation::status::MakeStatus;
using ::hwsec_foundation::status::OkStatus;
constexpr int kScryptNFactor = 1 << 12; // 2^12
constexpr int kScryptRFactor = 8;
constexpr int kScryptPFactor = 1;
constexpr int kScryptSaltSize = 256 / CHAR_BIT;
constexpr int kScryptOutputSize = 256 / CHAR_BIT;
} // namespace
std::unique_ptr<ScryptVerifier> ScryptVerifier::Create(
std::string auth_factor_label, const brillo::SecureBlob& passkey) {
// Create a salt and try to scrypt the passkey with it.
brillo::SecureBlob scrypt_salt = CreateSecureRandomBlob(kScryptSaltSize);
brillo::SecureBlob verifier(kScryptOutputSize, 0);
if (Scrypt(passkey, scrypt_salt, kScryptNFactor, kScryptRFactor,
kScryptPFactor, &verifier)) {
return base::WrapUnique(new ScryptVerifier(std::move(auth_factor_label),
std::move(scrypt_salt),
std::move(verifier)));
}
// If the Scrypt failed, then we can't make a verifier with this passkey.
return nullptr;
}
ScryptVerifier::ScryptVerifier(std::string auth_factor_label,
brillo::SecureBlob scrypt_salt,
brillo::SecureBlob verifier)
: SyncCredentialVerifier(AuthFactorType::kPassword,
std::move(auth_factor_label),
{.metadata = PasswordAuthFactorMetadata()}),
scrypt_salt_(std::move(scrypt_salt)),
verifier_(std::move(verifier)) {}
CryptohomeStatus ScryptVerifier::VerifySync(const AuthInput& input) const {
// The input must contain user input, otherwise there's nothing to verify.
if (!input.user_input) {
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocScryptVerifierVerifyNoUserInput),
ErrorActionSet({ErrorAction::kIncorrectAuth}),
user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT);
}
// Scrypt the input using the verifier salt.
brillo::SecureBlob hashed_secret(kScryptOutputSize, 0);
if (!Scrypt(*input.user_input, scrypt_salt_, kScryptNFactor, kScryptRFactor,
kScryptPFactor, &hashed_secret)) {
LOG(ERROR) << "Scrypt failed.";
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocScryptVerifierVerifyScryptFailed),
ErrorActionSet({ErrorAction::kIncorrectAuth}),
user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED);
}
// Compare the encrypted input against the hashed secret.
if (verifier_.size() != hashed_secret.size()) {
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocScryptVerifierVerifyWrongScryptOutputSize),
ErrorActionSet({ErrorAction::kIncorrectAuth}),
user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED);
}
if (brillo::SecureMemcmp(hashed_secret.data(), verifier_.data(),
verifier_.size()) == 0) {
return OkStatus<CryptohomeError>();
} else {
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocScryptVerifierVerifySecretMismatch),
ErrorActionSet({ErrorAction::kIncorrectAuth}),
user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED);
}
}
} // namespace cryptohome