1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: hashes.cc,v 1.1 2001/03/06 07:15:29 jgg Exp $ 
   4 /* ###################################################################### 
   6    Hashes - Simple wrapper around the hash functions 
   8    This is just used to make building the methods simpler, this is the 
   9    only interface required.. 
  11    ##################################################################### */ 
  13 // Include Files                                                        /*{{{*/ 
  16 #include <apt-pkg/hashes.h> 
  17 #include <apt-pkg/fileutl.h> 
  18 #include <apt-pkg/configuration.h> 
  19 #include <apt-pkg/md5.h> 
  20 #include <apt-pkg/sha1.h> 
  21 #include <apt-pkg/sha2.h> 
  31 const char * HashString::_SupportedHashes
[] = 
  33    "SHA512", "SHA256", "SHA1", "MD5Sum", "Checksum-FileSize", NULL
 
  36 HashString::HashString() 
  40 HashString::HashString(std::string Type
, std::string Hash
) : Type(Type
), Hash(Hash
) 
  44 HashString::HashString(std::string StringedHash
)                        /*{{{*/ 
  46    if (StringedHash
.find(":") == std::string::npos
) 
  48       // legacy: md5sum without "MD5Sum:" prefix 
  49       if (StringedHash
.size() == 32) 
  54       if(_config
->FindB("Debug::Hashes",false) == true) 
  55          std::clog 
<< "HashString(string): invalid StringedHash " << StringedHash 
<< std::endl
; 
  58    std::string::size_type pos 
= StringedHash
.find(":"); 
  59    Type 
= StringedHash
.substr(0,pos
); 
  60    Hash 
= StringedHash
.substr(pos
+1, StringedHash
.size() - pos
); 
  62    if(_config
->FindB("Debug::Hashes",false) == true) 
  63       std::clog 
<< "HashString(string): " << Type 
<< " : " << Hash 
<< std::endl
; 
  66 bool HashString::VerifyFile(std::string filename
) const                 /*{{{*/ 
  68    std::string fileHash 
= GetHashForFile(filename
); 
  70    if(_config
->FindB("Debug::Hashes",false) == true) 
  71       std::clog 
<< "HashString::VerifyFile: got: " << fileHash 
<< " expected: " << toStr() << std::endl
; 
  73    return (fileHash 
== Hash
); 
  76 bool HashString::FromFile(std::string filename
)                         /*{{{*/ 
  78    // pick the strongest hash 
  80       Type 
= _SupportedHashes
[0]; 
  82    Hash 
= GetHashForFile(filename
); 
  86 std::string 
HashString::GetHashForFile(std::string filename
) const      /*{{{*/ 
  90    FileFd 
Fd(filename
, FileFd::ReadOnly
); 
  91    if(strcasecmp(Type
.c_str(), "MD5Sum") == 0) 
  95       fileHash 
= (std::string
)MD5
.Result(); 
  97    else if (strcasecmp(Type
.c_str(), "SHA1") == 0) 
 101       fileHash 
= (std::string
)SHA1
.Result(); 
 103    else if (strcasecmp(Type
.c_str(), "SHA256") == 0) 
 105       SHA256Summation SHA256
; 
 107       fileHash 
= (std::string
)SHA256
.Result(); 
 109    else if (strcasecmp(Type
.c_str(), "SHA512") == 0) 
 111       SHA512Summation SHA512
; 
 113       fileHash 
= (std::string
)SHA512
.Result(); 
 115    else if (strcasecmp(Type
.c_str(), "Checksum-FileSize") == 0) 
 116       strprintf(fileHash
, "%llu", Fd
.FileSize()); 
 122 const char** HashString::SupportedHashes()                              /*{{{*/ 
 124    return _SupportedHashes
; 
 127 APT_PURE 
bool HashString::empty() const                                 /*{{{*/ 
 129    return (Type
.empty() || Hash
.empty()); 
 132 APT_PURE 
bool HashString::usable() const                                /*{{{*/ 
 135       (Type 
!= "Checksum-FileSize") && 
 140 std::string 
HashString::toStr() const                                   /*{{{*/ 
 142    return Type 
+ ":" + Hash
; 
 145 APT_PURE 
bool HashString::operator==(HashString 
const &other
) const     /*{{{*/ 
 147    return (strcasecmp(Type
.c_str(), other
.Type
.c_str()) == 0 && Hash 
== other
.Hash
); 
 149 APT_PURE 
bool HashString::operator!=(HashString 
const &other
) const 
 151    return !(*this == other
); 
 155 bool HashStringList::usable() const                                     /*{{{*/ 
 159    std::string 
const forcedType 
= _config
->Find("Acquire::ForceHash", ""); 
 160    if (forcedType
.empty() == true) 
 162       // See if there is at least one usable hash 
 163       for (auto const &hs
: list
) 
 168    return find(forcedType
) != NULL
; 
 171 HashString 
const * HashStringList::find(char const * const type
) const /*{{{*/ 
 173    if (type 
== NULL 
|| type
[0] == '\0') 
 175       std::string 
const forcedType 
= _config
->Find("Acquire::ForceHash", ""); 
 176       if (forcedType
.empty() == false) 
 177          return find(forcedType
.c_str()); 
 178       for (char const * const * t 
= HashString::SupportedHashes(); *t 
!= NULL
; ++t
) 
 179          for (std::vector
<HashString
>::const_iterator hs 
= list
.begin(); hs 
!= list
.end(); ++hs
) 
 180             if (strcasecmp(hs
->HashType().c_str(), *t
) == 0) 
 184    for (std::vector
<HashString
>::const_iterator hs 
= list
.begin(); hs 
!= list
.end(); ++hs
) 
 185       if (strcasecmp(hs
->HashType().c_str(), type
) == 0) 
 190 unsigned long long HashStringList::FileSize() const                     /*{{{*/ 
 192    HashString 
const * const hsf 
= find("Checksum-FileSize"); 
 195    std::string 
const hv 
= hsf
->HashValue(); 
 196    return strtoull(hv
.c_str(), NULL
, 10); 
 199 bool HashStringList::FileSize(unsigned long long const Size
)            /*{{{*/ 
 202    strprintf(size
, "%llu", Size
); 
 203    return push_back(HashString("Checksum-FileSize", size
)); 
 206 bool HashStringList::supported(char const * const type
)                 /*{{{*/ 
 208    for (char const * const * t 
= HashString::SupportedHashes(); *t 
!= NULL
; ++t
) 
 209       if (strcasecmp(*t
, type
) == 0) 
 214 bool HashStringList::push_back(const HashString 
&hashString
)            /*{{{*/ 
 216    if (hashString
.HashType().empty() == true || 
 217          hashString
.HashValue().empty() == true || 
 218          supported(hashString
.HashType().c_str()) == false) 
 221    // ensure that each type is added only once 
 222    HashString 
const * const hs 
= find(hashString
.HashType().c_str()); 
 224       return *hs 
== hashString
; 
 226    list
.push_back(hashString
); 
 230 bool HashStringList::VerifyFile(std::string filename
) const             /*{{{*/ 
 232    if (usable() == false) 
 235    Hashes 
hashes(*this); 
 236    FileFd 
file(filename
, FileFd::ReadOnly
); 
 237    HashString 
const * const hsf 
= find("Checksum-FileSize"); 
 240       std::string fileSize
; 
 241       strprintf(fileSize
, "%llu", file
.FileSize()); 
 242       if (hsf
->HashValue() != fileSize
) 
 246    HashStringList 
const hsl 
= hashes
.GetHashStringList(); 
 250 bool HashStringList::operator==(HashStringList 
const &other
) const      /*{{{*/ 
 252    std::string 
const forcedType 
= _config
->Find("Acquire::ForceHash", ""); 
 253    if (forcedType
.empty() == false) 
 255       HashString 
const * const hs 
= find(forcedType
); 
 256       HashString 
const * const ohs 
= other
.find(forcedType
); 
 257       if (hs 
== NULL 
|| ohs 
== NULL
) 
 262    for (const_iterator hs 
= begin(); hs 
!= end(); ++hs
) 
 264       HashString 
const * const ohs 
= other
.find(hs
->HashType()); 
 275 bool HashStringList::operator!=(HashStringList 
const &other
) const 
 277    return !(*this == other
); 
 281 // PrivateHashes                                                        /*{{{*/ 
 282 class PrivateHashes 
{ 
 284    unsigned long long FileSize
; 
 285    unsigned int CalcHashes
; 
 287    explicit PrivateHashes(unsigned int const CalcHashes
) : FileSize(0), CalcHashes(CalcHashes
) {} 
 288    explicit PrivateHashes(HashStringList 
const &Hashes
) : FileSize(0) { 
 289       unsigned int calcHashes 
= Hashes
.usable() ? 0 : ~0; 
 290       if (Hashes
.find("MD5Sum") != NULL
) 
 291          calcHashes 
|= Hashes::MD5SUM
; 
 292       if (Hashes
.find("SHA1") != NULL
) 
 293          calcHashes 
|= Hashes::SHA1SUM
; 
 294       if (Hashes
.find("SHA256") != NULL
) 
 295          calcHashes 
|= Hashes::SHA256SUM
; 
 296       if (Hashes
.find("SHA512") != NULL
) 
 297          calcHashes 
|= Hashes::SHA512SUM
; 
 298       CalcHashes 
= calcHashes
; 
 302 // Hashes::Add* - Add the contents of data or FD                        /*{{{*/ 
 303 bool Hashes::Add(const unsigned char * const Data
, unsigned long long const Size
) 
 306 APT_IGNORE_DEPRECATED_PUSH
 
 307    if ((d
->CalcHashes 
& MD5SUM
) == MD5SUM
) 
 308       Res 
&= MD5
.Add(Data
, Size
); 
 309    if ((d
->CalcHashes 
& SHA1SUM
) == SHA1SUM
) 
 310       Res 
&= SHA1
.Add(Data
, Size
); 
 311    if ((d
->CalcHashes 
& SHA256SUM
) == SHA256SUM
) 
 312       Res 
&= SHA256
.Add(Data
, Size
); 
 313    if ((d
->CalcHashes 
& SHA512SUM
) == SHA512SUM
) 
 314       Res 
&= SHA512
.Add(Data
, Size
); 
 315 APT_IGNORE_DEPRECATED_POP
 
 319 bool Hashes::Add(const unsigned char * const Data
, unsigned long long const Size
, unsigned int const Hashes
) 
 321    d
->CalcHashes 
= Hashes
; 
 322    return Add(Data
, Size
); 
 324 bool Hashes::AddFD(int const Fd
,unsigned long long Size
) 
 326    unsigned char Buf
[64*64]; 
 327    bool const ToEOF 
= (Size 
== UntilEOF
); 
 328    while (Size 
!= 0 || ToEOF
) 
 330       unsigned long long n 
= sizeof(Buf
); 
 331       if (!ToEOF
) n 
= std::min(Size
, n
); 
 332       ssize_t 
const Res 
= read(Fd
,Buf
,n
); 
 333       if (Res 
< 0 || (!ToEOF 
&& Res 
!= (ssize_t
) n
)) // error, or short read 
 335       if (ToEOF 
&& Res 
== 0) // EOF 
 338       if (Add(Buf
, Res
) == false) 
 343 bool Hashes::AddFD(int const Fd
,unsigned long long Size
, unsigned int const Hashes
) 
 345    d
->CalcHashes 
= Hashes
; 
 346    return AddFD(Fd
, Size
); 
 348 bool Hashes::AddFD(FileFd 
&Fd
,unsigned long long Size
) 
 350    unsigned char Buf
[64*64]; 
 351    bool const ToEOF 
= (Size 
== 0); 
 352    while (Size 
!= 0 || ToEOF
) 
 354       unsigned long long n 
= sizeof(Buf
); 
 355       if (!ToEOF
) n 
= std::min(Size
, n
); 
 356       unsigned long long a 
= 0; 
 357       if (Fd
.Read(Buf
, n
, &a
) == false) // error 
 361          if (a 
!= n
) // short read 
 364       else if (a 
== 0) // EOF 
 367       if (Add(Buf
, a
) == false) 
 372 bool Hashes::AddFD(FileFd 
&Fd
,unsigned long long Size
, unsigned int const Hashes
) 
 374    d
->CalcHashes 
= Hashes
; 
 375    return AddFD(Fd
, Size
); 
 378 HashStringList 
Hashes::GetHashStringList() 
 380    HashStringList hashes
; 
 381 APT_IGNORE_DEPRECATED_PUSH
 
 382    if ((d
->CalcHashes 
& MD5SUM
) == MD5SUM
) 
 383       hashes
.push_back(HashString("MD5Sum", MD5
.Result().Value())); 
 384    if ((d
->CalcHashes 
& SHA1SUM
) == SHA1SUM
) 
 385       hashes
.push_back(HashString("SHA1", SHA1
.Result().Value())); 
 386    if ((d
->CalcHashes 
& SHA256SUM
) == SHA256SUM
) 
 387       hashes
.push_back(HashString("SHA256", SHA256
.Result().Value())); 
 388    if ((d
->CalcHashes 
& SHA512SUM
) == SHA512SUM
) 
 389       hashes
.push_back(HashString("SHA512", SHA512
.Result().Value())); 
 390 APT_IGNORE_DEPRECATED_POP
 
 391    hashes
.FileSize(d
->FileSize
); 
 394 APT_IGNORE_DEPRECATED_PUSH
 
 395 Hashes::Hashes() : d(new PrivateHashes(~0)) { } 
 396 Hashes::Hashes(unsigned int const Hashes
) : d(new PrivateHashes(Hashes
)) {} 
 397 Hashes::Hashes(HashStringList 
const &Hashes
) : d(new PrivateHashes(Hashes
)) {} 
 398 Hashes::~Hashes() { delete d
; } 
 399 APT_IGNORE_DEPRECATED_POP