hwid_checker.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/login/hwid_checker.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <cstdio>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/sys_info.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chromeos/chromeos_switches.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/system/statistics_provider.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/re2/re2/re2.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/zlib/zlib.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)unsigned CalculateCRC32(const std::string& data) {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return static_cast<unsigned>(crc32(
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0,
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reinterpret_cast<const Bytef*>(data.c_str()),
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data.length()));
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string CalculateHWIDv2Checksum(const std::string& data) {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned crc32 = CalculateCRC32(data);
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We take four least significant decimal digits of CRC-32.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  char checksum[5];
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int snprintf_result =
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      snprintf(checksum, 5, "%04u", crc32 % 10000);
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG_ASSERT(snprintf_result == 4);
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return checksum;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsCorrectHWIDv2(const std::string& hwid) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string body;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!RE2::FullMatch(hwid, "([\\s\\S]*) (\\d{4})", &body, &checksum))
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CalculateHWIDv2Checksum(body) == checksum;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool IsExceptionalHWID(const std::string& hwid) {
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return RE2::PartialMatch(hwid, "^(SPRING [A-D])|(FALCO A)");
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstd::string CalculateExceptionalHWIDChecksum(const std::string& data) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned crc32 = CalculateCRC32(data);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We take 10 least significant bits of CRC-32 and encode them in 2 characters
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // using Base32 alphabet.
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checksum += base32_alphabet[(crc32 >> 5) & 0x1f];
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checksum += base32_alphabet[crc32 & 0x1f];
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return checksum;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool IsCorrectExceptionalHWID(const std::string& hwid) {
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!IsExceptionalHWID(hwid))
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string bom;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!RE2::FullMatch(hwid, "[A-Z0-9]+ ((?:[A-Z2-7]{4}-)*[A-Z2-7]{1,4})", &bom))
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bom.length() < 2)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hwid_without_dashes;
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::RemoveChars(hwid, "-", &hwid_without_dashes);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG_ASSERT(hwid_without_dashes.length() >= 2);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string not_checksum =
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hwid_without_dashes.substr(0, hwid_without_dashes.length() - 2);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum =
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hwid_without_dashes.substr(hwid_without_dashes.length() - 2);
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return CalculateExceptionalHWIDChecksum(not_checksum) == checksum;
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstd::string CalculateHWIDv3Checksum(const std::string& data) {
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static const char base8_alphabet[] = "23456789";
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  unsigned crc32 = CalculateCRC32(data);
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // We take 8 least significant bits of CRC-32 and encode them in 2 characters.
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string checksum;
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  checksum += base8_alphabet[(crc32 >> 5) & 0x7];
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  checksum += base32_alphabet[crc32 & 0x1f];
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return checksum;
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool IsCorrectHWIDv3(const std::string& hwid) {
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (IsExceptionalHWID(hwid))
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string regex =
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      "([A-Z0-9]+ (?:[A-Z2-7][2-9][A-Z2-7]-)*[A-Z2-7])([2-9][A-Z2-7])";
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string not_checksum, checksum;
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!RE2::FullMatch(hwid, regex, &not_checksum, &checksum))
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::RemoveChars(not_checksum, "-", &not_checksum);
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CalculateHWIDv3Checksum(not_checksum) == checksum;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // anonymous namespace
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsHWIDCorrect(const std::string& hwid) {
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return IsCorrectHWIDv2(hwid) || IsCorrectExceptionalHWID(hwid) ||
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      IsCorrectHWIDv3(hwid);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsMachineHWIDCorrect() {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(GOOGLE_CHROME_BUILD)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (cmd_line->HasSwitch(::switches::kTestType) ||
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      cmd_line->HasSwitch(chromeos::switches::kSkipHWIDCheck))
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!base::SysInfo::IsRunningOnChromeOS())
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hwid;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::system::StatisticsProvider* stats =
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chromeos::system::StatisticsProvider::GetInstance();
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!stats->GetMachineStatistic(chromeos::system::kHardwareClassKey, &hwid)) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Couldn't get machine statistic 'hardware_class'.";
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!chromeos::IsHWIDCorrect(hwid)) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Machine has malformed HWID '" << hwid << "'.";
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace chromeos
136