Home | History | Annotate | Download | only in login
      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/command_line.h"
     10 #include "base/logging.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/sys_info.h"
     13 #include "chrome/common/chrome_switches.h"
     14 #include "chromeos/chromeos_switches.h"
     15 #include "chromeos/system/statistics_provider.h"
     16 #include "third_party/re2/re2/re2.h"
     17 #include "third_party/zlib/zlib.h"
     18 
     19 namespace {
     20 
     21 unsigned 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 
     28 std::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 
     38 bool 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 
     46 bool IsExceptionalHWID(const std::string& hwid) {
     47   return RE2::PartialMatch(hwid, "^(SPRING [A-D])|(FALCO A)");
     48 }
     49 
     50 std::string CalculateExceptionalHWIDChecksum(const std::string& data) {
     51   static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
     52   unsigned crc32 = CalculateCRC32(data);
     53   // We take 10 least significant bits of CRC-32 and encode them in 2 characters
     54   // using Base32 alphabet.
     55   std::string checksum;
     56   checksum += base32_alphabet[(crc32 >> 5) & 0x1f];
     57   checksum += base32_alphabet[crc32 & 0x1f];
     58   return checksum;
     59 }
     60 
     61 bool IsCorrectExceptionalHWID(const std::string& hwid) {
     62   if (!IsExceptionalHWID(hwid))
     63     return false;
     64   std::string bom;
     65   if (!RE2::FullMatch(hwid, "[A-Z0-9]+ ((?:[A-Z2-7]{4}-)*[A-Z2-7]{1,4})", &bom))
     66     return false;
     67   if (bom.length() < 2)
     68     return false;
     69   std::string hwid_without_dashes;
     70   base::RemoveChars(hwid, "-", &hwid_without_dashes);
     71   LOG_ASSERT(hwid_without_dashes.length() >= 2);
     72   std::string not_checksum =
     73       hwid_without_dashes.substr(0, hwid_without_dashes.length() - 2);
     74   std::string checksum =
     75       hwid_without_dashes.substr(hwid_without_dashes.length() - 2);
     76   return CalculateExceptionalHWIDChecksum(not_checksum) == checksum;
     77 }
     78 
     79 std::string CalculateHWIDv3Checksum(const std::string& data) {
     80   static const char base8_alphabet[] = "23456789";
     81   static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
     82   unsigned crc32 = CalculateCRC32(data);
     83   // We take 8 least significant bits of CRC-32 and encode them in 2 characters.
     84   std::string checksum;
     85   checksum += base8_alphabet[(crc32 >> 5) & 0x7];
     86   checksum += base32_alphabet[crc32 & 0x1f];
     87   return checksum;
     88 }
     89 
     90 bool IsCorrectHWIDv3(const std::string& hwid) {
     91   if (IsExceptionalHWID(hwid))
     92     return false;
     93   std::string regex =
     94       "([A-Z0-9]+ (?:[A-Z2-7][2-9][A-Z2-7]-)*[A-Z2-7])([2-9][A-Z2-7])";
     95   std::string not_checksum, checksum;
     96   if (!RE2::FullMatch(hwid, regex, &not_checksum, &checksum))
     97     return false;
     98   base::RemoveChars(not_checksum, "-", &not_checksum);
     99   return CalculateHWIDv3Checksum(not_checksum) == checksum;
    100 }
    101 
    102 } // anonymous namespace
    103 
    104 namespace chromeos {
    105 
    106 bool IsHWIDCorrect(const std::string& hwid) {
    107   return IsCorrectHWIDv2(hwid) || IsCorrectExceptionalHWID(hwid) ||
    108       IsCorrectHWIDv3(hwid);
    109 }
    110 
    111 bool IsMachineHWIDCorrect() {
    112 #if !defined(GOOGLE_CHROME_BUILD)
    113   return true;
    114 #endif
    115   CommandLine* cmd_line = CommandLine::ForCurrentProcess();
    116   if (cmd_line->HasSwitch(::switches::kTestType))
    117     return true;
    118   if (!base::SysInfo::IsRunningOnChromeOS())
    119     return true;
    120   std::string hwid;
    121   chromeos::system::StatisticsProvider* stats =
    122       chromeos::system::StatisticsProvider::GetInstance();
    123   if (!stats->GetMachineStatistic(chromeos::system::kHardwareClassKey, &hwid)) {
    124     LOG(ERROR) << "Couldn't get machine statistic 'hardware_class'.";
    125     return false;
    126   }
    127   if (!chromeos::IsHWIDCorrect(hwid)) {
    128     LOG(ERROR) << "Machine has malformed HWID '" << hwid << "'.";
    129     return false;
    130   }
    131   return true;
    132 }
    133 
    134 } // namespace chromeos
    135