hwid_checker.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
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/chromeos/chromeos_version.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
125e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/system/statistics_provider.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chromeos/chromeos_switches.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)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string CalculateHWIDv3Checksum(const std::string& data) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned crc32 = CalculateCRC32(data);
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We take 10 least significant bits of CRC-32 and encode them in 2 characters
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // using Base32 alphabet.
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checksum += base32_alphabet[(crc32 >> 5) & 0x1f];
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checksum += base32_alphabet[crc32 & 0x1f];
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return checksum;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsCorrectHWIDv3(const std::string& hwid) {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string bom;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!RE2::FullMatch(hwid, "[A-Z0-9]+ ((?:[A-Z2-7]{4}-)*[A-Z2-7]{1,4})", &bom))
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bom.length() < 2)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hwid_without_dashes;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RemoveChars(hwid, "-", &hwid_without_dashes);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG_ASSERT(hwid_without_dashes.length() >= 2);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string not_checksum =
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hwid_without_dashes.substr(0, hwid_without_dashes.length() - 2);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum =
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hwid_without_dashes.substr(hwid_without_dashes.length() - 2);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CalculateHWIDv3Checksum(not_checksum) == checksum;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // anonymous namespace
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsHWIDCorrect(const std::string& hwid) {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return IsCorrectHWIDv2(hwid) || IsCorrectHWIDv3(hwid);
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsMachineHWIDCorrect() {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(GOOGLE_CHROME_BUILD)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (cmd_line->HasSwitch(::switches::kTestType) ||
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      cmd_line->HasSwitch(chromeos::switches::kSkipHWIDCheck))
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::chromeos::IsRunningOnChromeOS())
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hwid;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::system::StatisticsProvider* stats =
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chromeos::system::StatisticsProvider::GetInstance();
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!stats->GetMachineStatistic("hardware_class", &hwid)) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Couldn't get machine statistic 'hardware_class'.";
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!chromeos::IsHWIDCorrect(hwid)) {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Machine has malformed HWID '" << hwid << "'.";
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace chromeos
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
107