hwid_checker.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/string_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/system/statistics_provider.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/re2/re2/re2.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/zlib/zlib.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)unsigned CalculateCRC32(const std::string& data) {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return static_cast<unsigned>(crc32(
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0,
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reinterpret_cast<const Bytef*>(data.c_str()),
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data.length()));
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string CalculateHWIDv2Checksum(const std::string& data) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned crc32 = CalculateCRC32(data);
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We take four least significant decimal digits of CRC-32.
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  char checksum[5];
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int snprintf_result =
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      snprintf(checksum, 5, "%04u", crc32 % 10000);
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG_ASSERT(snprintf_result == 4);
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return checksum;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsCorrectHWIDv2(const std::string& hwid) {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string body;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!RE2::FullMatch(hwid, "([\\s\\S]*) (\\d{4})", &body, &checksum))
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CalculateHWIDv2Checksum(body) == checksum;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string CalculateHWIDv3Checksum(const std::string& data) {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned crc32 = CalculateCRC32(data);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We take 10 least significant bits of CRC-32 and encode them in 2 characters
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // using Base32 alphabet.
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checksum += base32_alphabet[(crc32 >> 5) & 0x1f];
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checksum += base32_alphabet[crc32 & 0x1f];
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return checksum;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsCorrectHWIDv3(const std::string& hwid) {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string bom;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!RE2::FullMatch(hwid, "[A-Z0-9]+ ((?:[A-Z2-7]{4}-)*[A-Z2-7]{1,4})", &bom))
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bom.length() < 2)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hwid_without_dashes;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RemoveChars(hwid, "-", &hwid_without_dashes);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG_ASSERT(hwid_without_dashes.length() >= 2);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string not_checksum =
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hwid_without_dashes.substr(0, hwid_without_dashes.length() - 2);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string checksum =
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hwid_without_dashes.substr(hwid_without_dashes.length() - 2);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CalculateHWIDv3Checksum(not_checksum) == checksum;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // anonymous namespace
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsHWIDCorrect(const std::string& hwid) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return IsCorrectHWIDv2(hwid) || IsCorrectHWIDv3(hwid);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsMachineHWIDCorrect() {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(GOOGLE_CHROME_BUILD)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType))
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::chromeos::IsRunningOnChromeOS())
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hwid;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::system::StatisticsProvider* stats =
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chromeos::system::StatisticsProvider::GetInstance();
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!stats->GetMachineStatistic("hardware_class", &hwid)) {
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Couldn't get machine statistic 'hardware_class'.";
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!chromeos::IsHWIDCorrect(hwid)) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Machine has malformed HWID '" << hwid << "'.";
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace chromeos
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
104