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, ¬_checksum, &checksum)) 97 return false; 98 base::RemoveChars(not_checksum, "-", ¬_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