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());
133 APT_PURE
static bool IsConfigured(const char *name
, const char *what
)
136 strprintf(option
, "APT::Hashes::%s::%s", name
, what
);
137 return _config
->FindB(option
, false);
140 APT_PURE
bool HashString::usable() const /*{{{*/
143 (Type
!= "Checksum-FileSize") &&
144 (Type
!= "MD5Sum") &&
146 !IsConfigured(Type
.c_str(), "Untrusted")
150 std::string
HashString::toStr() const /*{{{*/
152 return Type
+ ":" + Hash
;
155 APT_PURE
bool HashString::operator==(HashString
const &other
) const /*{{{*/
157 return (strcasecmp(Type
.c_str(), other
.Type
.c_str()) == 0 && Hash
== other
.Hash
);
159 APT_PURE
bool HashString::operator!=(HashString
const &other
) const
161 return !(*this == other
);
165 bool HashStringList::usable() const /*{{{*/
169 std::string
const forcedType
= _config
->Find("Acquire::ForceHash", "");
170 if (forcedType
.empty() == true)
172 // See if there is at least one usable hash
173 for (auto const &hs
: list
)
178 return find(forcedType
) != NULL
;
181 HashString
const * HashStringList::find(char const * const type
) const /*{{{*/
183 if (type
== NULL
|| type
[0] == '\0')
185 std::string
const forcedType
= _config
->Find("Acquire::ForceHash", "");
186 if (forcedType
.empty() == false)
187 return find(forcedType
.c_str());
188 for (char const * const * t
= HashString::SupportedHashes(); *t
!= NULL
; ++t
)
189 for (std::vector
<HashString
>::const_iterator hs
= list
.begin(); hs
!= list
.end(); ++hs
)
190 if (strcasecmp(hs
->HashType().c_str(), *t
) == 0)
194 for (std::vector
<HashString
>::const_iterator hs
= list
.begin(); hs
!= list
.end(); ++hs
)
195 if (strcasecmp(hs
->HashType().c_str(), type
) == 0)
200 unsigned long long HashStringList::FileSize() const /*{{{*/
202 HashString
const * const hsf
= find("Checksum-FileSize");
205 std::string
const hv
= hsf
->HashValue();
206 return strtoull(hv
.c_str(), NULL
, 10);
209 bool HashStringList::FileSize(unsigned long long const Size
) /*{{{*/
212 strprintf(size
, "%llu", Size
);
213 return push_back(HashString("Checksum-FileSize", size
));
216 bool HashStringList::supported(char const * const type
) /*{{{*/
218 for (char const * const * t
= HashString::SupportedHashes(); *t
!= NULL
; ++t
)
219 if (strcasecmp(*t
, type
) == 0)
224 bool HashStringList::push_back(const HashString
&hashString
) /*{{{*/
226 if (hashString
.HashType().empty() == true ||
227 hashString
.HashValue().empty() == true ||
228 supported(hashString
.HashType().c_str()) == false)
231 // ensure that each type is added only once
232 HashString
const * const hs
= find(hashString
.HashType().c_str());
234 return *hs
== hashString
;
236 list
.push_back(hashString
);
240 bool HashStringList::VerifyFile(std::string filename
) const /*{{{*/
242 if (usable() == false)
245 Hashes
hashes(*this);
246 FileFd
file(filename
, FileFd::ReadOnly
);
247 HashString
const * const hsf
= find("Checksum-FileSize");
250 std::string fileSize
;
251 strprintf(fileSize
, "%llu", file
.FileSize());
252 if (hsf
->HashValue() != fileSize
)
256 HashStringList
const hsl
= hashes
.GetHashStringList();
260 bool HashStringList::operator==(HashStringList
const &other
) const /*{{{*/
262 std::string
const forcedType
= _config
->Find("Acquire::ForceHash", "");
263 if (forcedType
.empty() == false)
265 HashString
const * const hs
= find(forcedType
);
266 HashString
const * const ohs
= other
.find(forcedType
);
267 if (hs
== NULL
|| ohs
== NULL
)
272 for (const_iterator hs
= begin(); hs
!= end(); ++hs
)
274 HashString
const * const ohs
= other
.find(hs
->HashType());
285 bool HashStringList::operator!=(HashStringList
const &other
) const
287 return !(*this == other
);
291 // PrivateHashes /*{{{*/
292 class PrivateHashes
{
294 unsigned long long FileSize
;
295 unsigned int CalcHashes
;
297 explicit PrivateHashes(unsigned int const CalcHashes
) : FileSize(0), CalcHashes(CalcHashes
) {}
298 explicit PrivateHashes(HashStringList
const &Hashes
) : FileSize(0) {
299 unsigned int calcHashes
= Hashes
.usable() ? 0 : ~0;
300 if (Hashes
.find("MD5Sum") != NULL
)
301 calcHashes
|= Hashes::MD5SUM
;
302 if (Hashes
.find("SHA1") != NULL
)
303 calcHashes
|= Hashes::SHA1SUM
;
304 if (Hashes
.find("SHA256") != NULL
)
305 calcHashes
|= Hashes::SHA256SUM
;
306 if (Hashes
.find("SHA512") != NULL
)
307 calcHashes
|= Hashes::SHA512SUM
;
308 CalcHashes
= calcHashes
;
312 // Hashes::Add* - Add the contents of data or FD /*{{{*/
313 bool Hashes::Add(const unsigned char * const Data
, unsigned long long const Size
)
316 APT_IGNORE_DEPRECATED_PUSH
317 if ((d
->CalcHashes
& MD5SUM
) == MD5SUM
)
318 Res
&= MD5
.Add(Data
, Size
);
319 if ((d
->CalcHashes
& SHA1SUM
) == SHA1SUM
)
320 Res
&= SHA1
.Add(Data
, Size
);
321 if ((d
->CalcHashes
& SHA256SUM
) == SHA256SUM
)
322 Res
&= SHA256
.Add(Data
, Size
);
323 if ((d
->CalcHashes
& SHA512SUM
) == SHA512SUM
)
324 Res
&= SHA512
.Add(Data
, Size
);
325 APT_IGNORE_DEPRECATED_POP
329 bool Hashes::Add(const unsigned char * const Data
, unsigned long long const Size
, unsigned int const Hashes
)
331 d
->CalcHashes
= Hashes
;
332 return Add(Data
, Size
);
334 bool Hashes::AddFD(int const Fd
,unsigned long long Size
)
336 unsigned char Buf
[64*64];
337 bool const ToEOF
= (Size
== UntilEOF
);
338 while (Size
!= 0 || ToEOF
)
340 unsigned long long n
= sizeof(Buf
);
341 if (!ToEOF
) n
= std::min(Size
, n
);
342 ssize_t
const Res
= read(Fd
,Buf
,n
);
343 if (Res
< 0 || (!ToEOF
&& Res
!= (ssize_t
) n
)) // error, or short read
345 if (ToEOF
&& Res
== 0) // EOF
348 if (Add(Buf
, Res
) == false)
353 bool Hashes::AddFD(int const Fd
,unsigned long long Size
, unsigned int const Hashes
)
355 d
->CalcHashes
= Hashes
;
356 return AddFD(Fd
, Size
);
358 bool Hashes::AddFD(FileFd
&Fd
,unsigned long long Size
)
360 unsigned char Buf
[64*64];
361 bool const ToEOF
= (Size
== 0);
362 while (Size
!= 0 || ToEOF
)
364 unsigned long long n
= sizeof(Buf
);
365 if (!ToEOF
) n
= std::min(Size
, n
);
366 unsigned long long a
= 0;
367 if (Fd
.Read(Buf
, n
, &a
) == false) // error
371 if (a
!= n
) // short read
374 else if (a
== 0) // EOF
377 if (Add(Buf
, a
) == false)
382 bool Hashes::AddFD(FileFd
&Fd
,unsigned long long Size
, unsigned int const Hashes
)
384 d
->CalcHashes
= Hashes
;
385 return AddFD(Fd
, Size
);
388 HashStringList
Hashes::GetHashStringList()
390 HashStringList hashes
;
391 APT_IGNORE_DEPRECATED_PUSH
392 if ((d
->CalcHashes
& MD5SUM
) == MD5SUM
)
393 hashes
.push_back(HashString("MD5Sum", MD5
.Result().Value()));
394 if ((d
->CalcHashes
& SHA1SUM
) == SHA1SUM
)
395 hashes
.push_back(HashString("SHA1", SHA1
.Result().Value()));
396 if ((d
->CalcHashes
& SHA256SUM
) == SHA256SUM
)
397 hashes
.push_back(HashString("SHA256", SHA256
.Result().Value()));
398 if ((d
->CalcHashes
& SHA512SUM
) == SHA512SUM
)
399 hashes
.push_back(HashString("SHA512", SHA512
.Result().Value()));
400 APT_IGNORE_DEPRECATED_POP
401 hashes
.FileSize(d
->FileSize
);
404 APT_IGNORE_DEPRECATED_PUSH
405 Hashes::Hashes() : d(new PrivateHashes(~0)) { }
406 Hashes::Hashes(unsigned int const Hashes
) : d(new PrivateHashes(Hashes
)) {}
407 Hashes::Hashes(HashStringList
const &Hashes
) : d(new PrivateHashes(Hashes
)) {}
408 Hashes::~Hashes() { delete d
; }
409 APT_IGNORE_DEPRECATED_POP