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, ¬_checksum, &checksum)) 977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return false; 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::RemoveChars(not_checksum, "-", ¬_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