1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
ash / components / arc / session / serial_number_util.cc [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/components/arc/session/serial_number_util.h"
#include <string_view>
#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;
// Returns true if the hex-encoded salt in Local State is valid.
bool IsValidHexSalt(std::string_view 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;
}
} // namespace
std::string GenerateFakeSerialNumber(std::string_view chromeos_user,
std::string_view 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).substr(0, kMaxHardwareIdLen);
}
std::string GetOrCreateSerialNumber(PrefService* local_state,
std::string_view chromeos_user,
std::string_view 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)) {
// This path is taken 1) on the very first ARC boot, 2) on the first boot
// after powerwash, 3) on the first boot after upgrading to ARCVM, or 4)
// when the salt in local state is corrupted.
if (arc_salt_on_disk.empty()) {
// The device doesn't have the salt file for ARC container. Create it from
// scratch in the same way as ARC container.
uint8_t rand_value[kArcSaltFileSize];
crypto::RandBytes(rand_value);
hex_salt = base::HexEncode(rand_value);
} else {
// The device has the one for container. Reuse it for ARCVM.
DCHECK_EQ(kArcSaltFileSize, arc_salt_on_disk.size());
hex_salt = base::HexEncode(arc_salt_on_disk);
}
local_state->SetString(prefs::kArcSerialNumberSalt, hex_salt);
}
// We store hex-encoded version of the salt in the local state, but to compute
// the serial number, we use the decoded version to be compatible with the
// arc-setup code for P.
std::string decoded_salt;
const bool result = base::HexStringToString(hex_salt, &decoded_salt);
DCHECK(result) << hex_salt;
return GenerateFakeSerialNumber(chromeos_user, decoded_salt);
}
std::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 std::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;
}
} // namespace arc