]>
Commit | Line | Data |
---|---|---|
1 | // -*- mode: cpp; mode: fold -*- | |
2 | // Description /*{{{*/ | |
3 | // $Id: hashes.cc,v 1.1 2001/03/06 07:15:29 jgg Exp $ | |
4 | /* ###################################################################### | |
5 | ||
6 | Hashes - Simple wrapper around the hash functions | |
7 | ||
8 | This is just used to make building the methods simpler, this is the | |
9 | only interface required.. | |
10 | ||
11 | ##################################################################### */ | |
12 | /*}}}*/ | |
13 | // Include Files /*{{{*/ | |
14 | #include <config.h> | |
15 | ||
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> | |
22 | ||
23 | #include <stddef.h> | |
24 | #include <algorithm> | |
25 | #include <unistd.h> | |
26 | #include <string> | |
27 | #include <iostream> | |
28 | /*}}}*/ | |
29 | ||
30 | const char * HashString::_SupportedHashes[] = | |
31 | { | |
32 | "SHA512", "SHA256", "SHA1", "MD5Sum", "Checksum-FileSize", NULL | |
33 | }; | |
34 | ||
35 | HashString::HashString() | |
36 | { | |
37 | } | |
38 | ||
39 | HashString::HashString(std::string Type, std::string Hash) : Type(Type), Hash(Hash) | |
40 | { | |
41 | } | |
42 | ||
43 | HashString::HashString(std::string StringedHash) /*{{{*/ | |
44 | { | |
45 | if (StringedHash.find(":") == std::string::npos) | |
46 | { | |
47 | // legacy: md5sum without "MD5Sum:" prefix | |
48 | if (StringedHash.size() == 32) | |
49 | { | |
50 | Type = "MD5Sum"; | |
51 | Hash = StringedHash; | |
52 | } | |
53 | if(_config->FindB("Debug::Hashes",false) == true) | |
54 | std::clog << "HashString(string): invalid StringedHash " << StringedHash << std::endl; | |
55 | return; | |
56 | } | |
57 | std::string::size_type pos = StringedHash.find(":"); | |
58 | Type = StringedHash.substr(0,pos); | |
59 | Hash = StringedHash.substr(pos+1, StringedHash.size() - pos); | |
60 | ||
61 | if(_config->FindB("Debug::Hashes",false) == true) | |
62 | std::clog << "HashString(string): " << Type << " : " << Hash << std::endl; | |
63 | } | |
64 | /*}}}*/ | |
65 | bool HashString::VerifyFile(std::string filename) const /*{{{*/ | |
66 | { | |
67 | std::string fileHash = GetHashForFile(filename); | |
68 | ||
69 | if(_config->FindB("Debug::Hashes",false) == true) | |
70 | std::clog << "HashString::VerifyFile: got: " << fileHash << " expected: " << toStr() << std::endl; | |
71 | ||
72 | return (fileHash == Hash); | |
73 | } | |
74 | /*}}}*/ | |
75 | bool HashString::FromFile(std::string filename) /*{{{*/ | |
76 | { | |
77 | // pick the strongest hash | |
78 | if (Type == "") | |
79 | Type = _SupportedHashes[0]; | |
80 | ||
81 | Hash = GetHashForFile(filename); | |
82 | return true; | |
83 | } | |
84 | /*}}}*/ | |
85 | std::string HashString::GetHashForFile(std::string filename) const /*{{{*/ | |
86 | { | |
87 | std::string fileHash; | |
88 | ||
89 | FileFd Fd(filename, FileFd::ReadOnly); | |
90 | if(strcasecmp(Type.c_str(), "MD5Sum") == 0) | |
91 | { | |
92 | MD5Summation MD5; | |
93 | MD5.AddFD(Fd); | |
94 | fileHash = (std::string)MD5.Result(); | |
95 | } | |
96 | else if (strcasecmp(Type.c_str(), "SHA1") == 0) | |
97 | { | |
98 | SHA1Summation SHA1; | |
99 | SHA1.AddFD(Fd); | |
100 | fileHash = (std::string)SHA1.Result(); | |
101 | } | |
102 | else if (strcasecmp(Type.c_str(), "SHA256") == 0) | |
103 | { | |
104 | SHA256Summation SHA256; | |
105 | SHA256.AddFD(Fd); | |
106 | fileHash = (std::string)SHA256.Result(); | |
107 | } | |
108 | else if (strcasecmp(Type.c_str(), "SHA512") == 0) | |
109 | { | |
110 | SHA512Summation SHA512; | |
111 | SHA512.AddFD(Fd); | |
112 | fileHash = (std::string)SHA512.Result(); | |
113 | } | |
114 | else if (strcasecmp(Type.c_str(), "Checksum-FileSize") == 0) | |
115 | strprintf(fileHash, "%llu", Fd.FileSize()); | |
116 | Fd.Close(); | |
117 | ||
118 | return fileHash; | |
119 | } | |
120 | /*}}}*/ | |
121 | const char** HashString::SupportedHashes() /*{{{*/ | |
122 | { | |
123 | return _SupportedHashes; | |
124 | } | |
125 | /*}}}*/ | |
126 | APT_PURE bool HashString::empty() const /*{{{*/ | |
127 | { | |
128 | return (Type.empty() || Hash.empty()); | |
129 | } | |
130 | /*}}}*/ | |
131 | std::string HashString::toStr() const /*{{{*/ | |
132 | { | |
133 | return Type + ":" + Hash; | |
134 | } | |
135 | /*}}}*/ | |
136 | APT_PURE bool HashString::operator==(HashString const &other) const /*{{{*/ | |
137 | { | |
138 | return (strcasecmp(Type.c_str(), other.Type.c_str()) == 0 && Hash == other.Hash); | |
139 | } | |
140 | APT_PURE bool HashString::operator!=(HashString const &other) const | |
141 | { | |
142 | return !(*this == other); | |
143 | } | |
144 | /*}}}*/ | |
145 | ||
146 | bool HashStringList::usable() const /*{{{*/ | |
147 | { | |
148 | if (empty() == true) | |
149 | return false; | |
150 | std::string const forcedType = _config->Find("Acquire::ForceHash", ""); | |
151 | if (forcedType.empty() == true) | |
152 | { | |
153 | // FileSize alone isn't usable | |
154 | for (std::vector<HashString>::const_iterator hs = list.begin(); hs != list.end(); ++hs) | |
155 | if (hs->HashType() != "Checksum-FileSize") | |
156 | return true; | |
157 | return false; | |
158 | } | |
159 | return find(forcedType) != NULL; | |
160 | } | |
161 | /*}}}*/ | |
162 | HashString const * HashStringList::find(char const * const type) const /*{{{*/ | |
163 | { | |
164 | if (type == NULL || type[0] == '\0') | |
165 | { | |
166 | std::string const forcedType = _config->Find("Acquire::ForceHash", ""); | |
167 | if (forcedType.empty() == false) | |
168 | return find(forcedType.c_str()); | |
169 | for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t) | |
170 | for (std::vector<HashString>::const_iterator hs = list.begin(); hs != list.end(); ++hs) | |
171 | if (strcasecmp(hs->HashType().c_str(), *t) == 0) | |
172 | return &*hs; | |
173 | return NULL; | |
174 | } | |
175 | for (std::vector<HashString>::const_iterator hs = list.begin(); hs != list.end(); ++hs) | |
176 | if (strcasecmp(hs->HashType().c_str(), type) == 0) | |
177 | return &*hs; | |
178 | return NULL; | |
179 | } | |
180 | /*}}}*/ | |
181 | bool HashStringList::supported(char const * const type) /*{{{*/ | |
182 | { | |
183 | for (char const * const * t = HashString::SupportedHashes(); *t != NULL; ++t) | |
184 | if (strcasecmp(*t, type) == 0) | |
185 | return true; | |
186 | return false; | |
187 | } | |
188 | /*}}}*/ | |
189 | bool HashStringList::push_back(const HashString &hashString) /*{{{*/ | |
190 | { | |
191 | if (hashString.HashType().empty() == true || | |
192 | hashString.HashValue().empty() == true || | |
193 | supported(hashString.HashType().c_str()) == false) | |
194 | return false; | |
195 | ||
196 | // ensure that each type is added only once | |
197 | HashString const * const hs = find(hashString.HashType().c_str()); | |
198 | if (hs != NULL) | |
199 | return *hs == hashString; | |
200 | ||
201 | list.push_back(hashString); | |
202 | return true; | |
203 | } | |
204 | /*}}}*/ | |
205 | bool HashStringList::VerifyFile(std::string filename) const /*{{{*/ | |
206 | { | |
207 | if (list.empty() == true) | |
208 | return false; | |
209 | HashString const * const hs = find(NULL); | |
210 | if (hs == NULL || hs->VerifyFile(filename) == false) | |
211 | return false; | |
212 | HashString const * const hsf = find("Checksum-FileSize"); | |
213 | if (hsf != NULL && hsf->VerifyFile(filename) == false) | |
214 | return false; | |
215 | return true; | |
216 | } | |
217 | /*}}}*/ | |
218 | bool HashStringList::operator==(HashStringList const &other) const /*{{{*/ | |
219 | { | |
220 | std::string const forcedType = _config->Find("Acquire::ForceHash", ""); | |
221 | if (forcedType.empty() == false) | |
222 | { | |
223 | HashString const * const hs = find(forcedType); | |
224 | HashString const * const ohs = other.find(forcedType); | |
225 | if (hs == NULL || ohs == NULL) | |
226 | return false; | |
227 | return *hs == *ohs; | |
228 | } | |
229 | short matches = 0; | |
230 | for (const_iterator hs = begin(); hs != end(); ++hs) | |
231 | { | |
232 | HashString const * const ohs = other.find(hs->HashType()); | |
233 | if (ohs == NULL) | |
234 | continue; | |
235 | if (*hs != *ohs) | |
236 | return false; | |
237 | ++matches; | |
238 | } | |
239 | if (matches == 0) | |
240 | return false; | |
241 | return true; | |
242 | } | |
243 | bool HashStringList::operator!=(HashStringList const &other) const | |
244 | { | |
245 | return !(*this == other); | |
246 | } | |
247 | /*}}}*/ | |
248 | ||
249 | // PrivateHashes /*{{{*/ | |
250 | class PrivateHashes { | |
251 | public: | |
252 | unsigned long long FileSize; | |
253 | ||
254 | PrivateHashes() : FileSize(0) {} | |
255 | }; | |
256 | /*}}}*/ | |
257 | // Hashes::Add* - Add the contents of data or FD /*{{{*/ | |
258 | bool Hashes::Add(const unsigned char * const Data,unsigned long long const Size, unsigned int const Hashes) | |
259 | { | |
260 | bool Res = true; | |
261 | APT_IGNORE_DEPRECATED_PUSH | |
262 | if ((Hashes & MD5SUM) == MD5SUM) | |
263 | Res &= MD5.Add(Data, Size); | |
264 | if ((Hashes & SHA1SUM) == SHA1SUM) | |
265 | Res &= SHA1.Add(Data, Size); | |
266 | if ((Hashes & SHA256SUM) == SHA256SUM) | |
267 | Res &= SHA256.Add(Data, Size); | |
268 | if ((Hashes & SHA512SUM) == SHA512SUM) | |
269 | Res &= SHA512.Add(Data, Size); | |
270 | APT_IGNORE_DEPRECATED_POP | |
271 | d->FileSize += Size; | |
272 | return Res; | |
273 | } | |
274 | bool Hashes::AddFD(int const Fd,unsigned long long Size, unsigned int const Hashes) | |
275 | { | |
276 | unsigned char Buf[64*64]; | |
277 | bool const ToEOF = (Size == UntilEOF); | |
278 | while (Size != 0 || ToEOF) | |
279 | { | |
280 | unsigned long long n = sizeof(Buf); | |
281 | if (!ToEOF) n = std::min(Size, n); | |
282 | ssize_t const Res = read(Fd,Buf,n); | |
283 | if (Res < 0 || (!ToEOF && Res != (ssize_t) n)) // error, or short read | |
284 | return false; | |
285 | if (ToEOF && Res == 0) // EOF | |
286 | break; | |
287 | Size -= Res; | |
288 | if (Add(Buf, Res, Hashes) == false) | |
289 | return false; | |
290 | } | |
291 | return true; | |
292 | } | |
293 | bool Hashes::AddFD(FileFd &Fd,unsigned long long Size, unsigned int const Hashes) | |
294 | { | |
295 | unsigned char Buf[64*64]; | |
296 | bool const ToEOF = (Size == 0); | |
297 | while (Size != 0 || ToEOF) | |
298 | { | |
299 | unsigned long long n = sizeof(Buf); | |
300 | if (!ToEOF) n = std::min(Size, n); | |
301 | unsigned long long a = 0; | |
302 | if (Fd.Read(Buf, n, &a) == false) // error | |
303 | return false; | |
304 | if (ToEOF == false) | |
305 | { | |
306 | if (a != n) // short read | |
307 | return false; | |
308 | } | |
309 | else if (a == 0) // EOF | |
310 | break; | |
311 | Size -= a; | |
312 | if (Add(Buf, a, Hashes) == false) | |
313 | return false; | |
314 | } | |
315 | return true; | |
316 | } | |
317 | /*}}}*/ | |
318 | HashStringList Hashes::GetHashStringList() | |
319 | { | |
320 | HashStringList hashes; | |
321 | APT_IGNORE_DEPRECATED_PUSH | |
322 | hashes.push_back(HashString("MD5Sum", MD5.Result().Value())); | |
323 | hashes.push_back(HashString("SHA1", SHA1.Result().Value())); | |
324 | hashes.push_back(HashString("SHA256", SHA256.Result().Value())); | |
325 | hashes.push_back(HashString("SHA512", SHA512.Result().Value())); | |
326 | APT_IGNORE_DEPRECATED_POP | |
327 | std::string SizeStr; | |
328 | strprintf(SizeStr, "%llu", d->FileSize); | |
329 | hashes.push_back(HashString("Checksum-FileSize", SizeStr)); | |
330 | return hashes; | |
331 | } | |
332 | APT_IGNORE_DEPRECATED_PUSH | |
333 | Hashes::Hashes() { d = new PrivateHashes(); } | |
334 | Hashes::~Hashes() { delete d; } | |
335 | APT_IGNORE_DEPRECATED_POP |