#include "ash/components/arc/session/serial_number_util.h"
#include "ash/components/arc/arc_prefs.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "crypto/random.h"
#include "crypto/sha2.h"
namespace arc {
namespace {
constexpr const size_t kArcSaltFileSize = 16;
bool IsValidHexSalt(base::StringPiece hex_salt) {
std::string salt;
if (!base::HexStringToString(hex_salt, &salt)) {
LOG(WARNING) << "Not a hex string: " << hex_salt;
return false;
}
if (salt.size() != kArcSaltFileSize) {
LOG(WARNING) << "Salt size invalid: " << salt.size();
return false;
}
return true;
}
}
std::string GenerateFakeSerialNumber(base::StringPiece chromeos_user,
base::StringPiece salt) {
constexpr size_t kMaxHardwareIdLen = 20;
std::string input(chromeos_user);
input.append(salt.begin(), salt.end());
const std::string hash(crypto::SHA256HashString(input));
return base::HexEncode(hash.data(), hash.length())
.substr(0, kMaxHardwareIdLen);
}
std::string GetOrCreateSerialNumber(PrefService* local_state,
base::StringPiece chromeos_user,
base::StringPiece arc_salt_on_disk) {
DCHECK(local_state);
DCHECK(!chromeos_user.empty());
std::string hex_salt = local_state->GetString(prefs::kArcSerialNumberSalt);
if (hex_salt.empty() || !IsValidHexSalt(hex_salt)) {
if (arc_salt_on_disk.empty()) {
char rand_value[kArcSaltFileSize];
crypto::RandBytes(rand_value, kArcSaltFileSize);
hex_salt = base::HexEncode(rand_value, kArcSaltFileSize);
} else {
DCHECK_EQ(kArcSaltFileSize, arc_salt_on_disk.size());
hex_salt =
base::HexEncode(arc_salt_on_disk.data(), arc_salt_on_disk.size());
}
local_state->SetString(prefs::kArcSerialNumberSalt, hex_salt);
}
std::string decoded_salt;
const bool result = base::HexStringToString(hex_salt, &decoded_salt);
DCHECK(result) << hex_salt;
return GenerateFakeSerialNumber(chromeos_user, decoded_salt);
}
absl::optional<std::string> ReadSaltOnDisk(const base::FilePath& salt_path) {
if (!base::PathExists(salt_path)) {
VLOG(2) << "ARC salt file doesn't exist: " << salt_path;
return std::string();
}
std::string salt;
if (!base::ReadFileToString(salt_path, &salt)) {
PLOG(ERROR) << "Failed to read " << salt_path;
return absl::nullopt;
}
if (salt.size() != kArcSaltFileSize) {
LOG(WARNING) << "Ignoring invalid ARC salt on disk. size=" << salt.size();
salt.clear();
}
VLOG(1) << "Successfully read ARC salt on disk: " << salt_path;
return salt;
}
}