hwid_checker.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/login/hwid_checker.h"
6
7#include <cstdio>
8
9#include "base/chromeos/chromeos_version.h"
10#include "base/command_line.h"
11#include "base/logging.h"
12#include "base/strings/string_util.h"
13#include "chrome/browser/chromeos/system/statistics_provider.h"
14#include "chrome/common/chrome_switches.h"
15#include "chromeos/chromeos_switches.h"
16#include "third_party/re2/re2/re2.h"
17#include "third_party/zlib/zlib.h"
18
19namespace {
20
21unsigned CalculateCRC32(const std::string& data) {
22  return static_cast<unsigned>(crc32(
23      0,
24      reinterpret_cast<const Bytef*>(data.c_str()),
25      data.length()));
26}
27
28std::string CalculateHWIDv2Checksum(const std::string& data) {
29  unsigned crc32 = CalculateCRC32(data);
30  // We take four least significant decimal digits of CRC-32.
31  char checksum[5];
32  int snprintf_result =
33      snprintf(checksum, 5, "%04u", crc32 % 10000);
34  LOG_ASSERT(snprintf_result == 4);
35  return checksum;
36}
37
38bool IsCorrectHWIDv2(const std::string& hwid) {
39  std::string body;
40  std::string checksum;
41  if (!RE2::FullMatch(hwid, "([\\s\\S]*) (\\d{4})", &body, &checksum))
42    return false;
43  return CalculateHWIDv2Checksum(body) == checksum;
44}
45
46std::string CalculateHWIDv3Checksum(const std::string& data) {
47  static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
48  unsigned crc32 = CalculateCRC32(data);
49  // We take 10 least significant bits of CRC-32 and encode them in 2 characters
50  // using Base32 alphabet.
51  std::string checksum;
52  checksum += base32_alphabet[(crc32 >> 5) & 0x1f];
53  checksum += base32_alphabet[crc32 & 0x1f];
54  return checksum;
55}
56
57bool IsCorrectHWIDv3(const std::string& hwid) {
58  std::string bom;
59  if (!RE2::FullMatch(hwid, "[A-Z0-9]+ ((?:[A-Z2-7]{4}-)*[A-Z2-7]{1,4})", &bom))
60    return false;
61  if (bom.length() < 2)
62    return false;
63  std::string hwid_without_dashes;
64  RemoveChars(hwid, "-", &hwid_without_dashes);
65  LOG_ASSERT(hwid_without_dashes.length() >= 2);
66  std::string not_checksum =
67      hwid_without_dashes.substr(0, hwid_without_dashes.length() - 2);
68  std::string checksum =
69      hwid_without_dashes.substr(hwid_without_dashes.length() - 2);
70  return CalculateHWIDv3Checksum(not_checksum) == checksum;
71}
72
73} // anonymous namespace
74
75namespace chromeos {
76
77bool IsHWIDCorrect(const std::string& hwid) {
78  return IsCorrectHWIDv2(hwid) || IsCorrectHWIDv3(hwid);
79}
80
81bool IsMachineHWIDCorrect() {
82#if !defined(GOOGLE_CHROME_BUILD)
83  return true;
84#endif
85  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
86  if (cmd_line->HasSwitch(::switches::kTestType) ||
87      cmd_line->HasSwitch(chromeos::switches::kSkipHWIDCheck))
88    return true;
89  if (!base::chromeos::IsRunningOnChromeOS())
90    return true;
91  std::string hwid;
92  chromeos::system::StatisticsProvider* stats =
93      chromeos::system::StatisticsProvider::GetInstance();
94  if (!stats->GetMachineStatistic("hardware_class", &hwid)) {
95    LOG(ERROR) << "Couldn't get machine statistic 'hardware_class'.";
96    return false;
97  }
98  if (!chromeos::IsHWIDCorrect(hwid)) {
99    LOG(ERROR) << "Machine has malformed HWID '" << hwid << "'.";
100    return false;
101  }
102  return true;
103}
104
105} // namespace chromeos
106
107