1 : #include "config.h"
2 :
3 : #include <iostream>
4 : #include <cstring>
5 :
6 : #ifdef HAVE_OPENSSL
7 : #include <openssl/md5.h>
8 : #include <openssl/sha.h>
9 : #else
10 : extern "C" {
11 : #include "md5.h"
12 : #include "sha1.h"
13 : #include "sha256.h"
14 : }
15 : #endif
16 :
17 : #include "hash.hh"
18 : #include "archive.hh"
19 : #include "util.hh"
20 :
21 : #include <sys/types.h>
22 : #include <sys/stat.h>
23 : #include <fcntl.h>
24 :
25 :
26 : namespace nix {
27 :
28 :
29 33285 : Hash::Hash()
30 : {
31 33285 : type = htUnknown;
32 33285 : hashSize = 0;
33 33285 : memset(hash, 0, maxHashSize);
34 33285 : }
35 :
36 :
37 12392 : Hash::Hash(HashType type)
38 : {
39 12392 : this->type = type;
40 12392 : if (type == htMD5) hashSize = md5HashSize;
41 12354 : else if (type == htSHA1) hashSize = sha1HashSize;
42 12322 : else if (type == htSHA256) hashSize = sha256HashSize;
43 0 : else throw Error("unknown hash type");
44 12392 : assert(hashSize <= maxHashSize);
45 12392 : memset(hash, 0, maxHashSize);
46 12392 : }
47 :
48 :
49 79 : bool Hash::operator == (const Hash & h2) const
50 : {
51 79 : if (hashSize != h2.hashSize) return false;
52 2503 : for (unsigned int i = 0; i < hashSize; i++)
53 2425 : if (hash[i] != h2.hash[i]) return false;
54 78 : return true;
55 : }
56 :
57 :
58 79 : bool Hash::operator != (const Hash & h2) const
59 : {
60 79 : return !(*this == h2);
61 : }
62 :
63 :
64 0 : bool Hash::operator < (const Hash & h) const
65 : {
66 0 : for (unsigned int i = 0; i < hashSize; i++) {
67 0 : if (hash[i] < h.hash[i]) return true;
68 0 : if (hash[i] > h.hash[i]) return false;
69 : }
70 0 : return false;
71 : }
72 :
73 :
74 1151 : const string base16Chars = "0123456789abcdef";
75 :
76 :
77 6156 : string printHash(const Hash & hash)
78 : {
79 6156 : char buf[hash.hashSize * 2];
80 202692 : for (unsigned int i = 0; i < hash.hashSize; i++) {
81 196536 : buf[i * 2] = base16Chars[hash.hash[i] >> 4];
82 196536 : buf[i * 2 + 1] = base16Chars[hash.hash[i] & 0x0f];
83 : }
84 6156 : return string(buf, hash.hashSize * 2);
85 : }
86 :
87 :
88 5498 : Hash parseHash(HashType ht, const string & s)
89 : {
90 5498 : Hash hash(ht);
91 5498 : if (s.length() != hash.hashSize * 2)
92 0 : throw Error(format("invalid hash `%1%'") % s);
93 181198 : for (unsigned int i = 0; i < hash.hashSize; i++) {
94 175700 : string s2(s, i * 2, 2);
95 175700 : if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
96 0 : throw Error(format("invalid hash `%1%'") % s);
97 175700 : std::istringstream str(s2);
98 : int n;
99 175700 : str >> std::hex >> n;
100 175700 : hash.hash[i] = n;
101 : }
102 : return hash;
103 : }
104 :
105 :
106 21528 : static unsigned char divMod(unsigned char * bytes, unsigned char y)
107 : {
108 21528 : unsigned int borrow = 0;
109 :
110 21528 : int pos = Hash::maxHashSize - 1;
111 21528 : while (pos >= 0 && !bytes[pos]) --pos;
112 :
113 262593 : for ( ; pos >= 0; --pos) {
114 241065 : unsigned int s = bytes[pos] + (borrow << 8);
115 241065 : unsigned int d = s / y;
116 241065 : borrow = s % y;
117 241065 : bytes[pos] = d;
118 : }
119 :
120 21528 : return borrow;
121 : }
122 :
123 :
124 652 : unsigned int hashLength32(const Hash & hash)
125 : {
126 652 : return (hash.hashSize * 8 - 1) / 5 + 1;
127 : }
128 :
129 :
130 : // omitted: E O U T
131 1704 : const string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
132 :
133 :
134 649 : string printHash32(const Hash & hash)
135 : {
136 649 : Hash hash2(hash);
137 649 : unsigned int len = hashLength32(hash);
138 :
139 649 : const char * chars = base32Chars.c_str();
140 :
141 649 : string s(len, '0');
142 :
143 649 : int pos = len - 1;
144 22826 : while (pos >= 0) {
145 21528 : unsigned char digit = divMod(hash2.hash, 32);
146 21528 : s[pos--] = chars[digit];
147 : }
148 :
149 21417 : for (unsigned int i = 0; i < hash2.maxHashSize; ++i)
150 20768 : assert(hash2.hash[i] == 0);
151 :
152 0 : return s;
153 : }
154 :
155 :
156 792 : static bool mul(unsigned char * bytes, unsigned char y, int maxSize)
157 : {
158 792 : unsigned char carry = 0;
159 :
160 25368 : for (int pos = 0; pos < maxSize; ++pos) {
161 24576 : unsigned int m = bytes[pos] * y + carry;
162 24576 : bytes[pos] = m & 0xff;
163 24576 : carry = m >> 8;
164 : }
165 :
166 792 : return carry;
167 : }
168 :
169 :
170 792 : static bool add(unsigned char * bytes, unsigned char y, int maxSize)
171 : {
172 792 : unsigned char carry = y;
173 :
174 792 : for (int pos = 0; pos < maxSize; ++pos) {
175 792 : unsigned int m = bytes[pos] + carry;
176 792 : bytes[pos] = m & 0xff;
177 792 : carry = m >> 8;
178 792 : if (carry == 0) break;
179 : }
180 :
181 792 : return carry;
182 : }
183 :
184 :
185 16 : Hash parseHash32(HashType ht, const string & s)
186 : {
187 16 : Hash hash(ht);
188 :
189 16 : const char * chars = base32Chars.c_str();
190 :
191 808 : for (unsigned int i = 0; i < s.length(); ++i) {
192 792 : char c = s[i];
193 : unsigned char digit;
194 12727 : for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
195 12727 : if (chars[digit] == c) break;
196 792 : if (digit >= 32)
197 0 : throw Error(format("invalid base-32 hash `%1%'") % s);
198 792 : if (mul(hash.hash, 32, hash.hashSize) ||
199 : add(hash.hash, digit, hash.hashSize))
200 0 : throw Error(format("base-32 hash `%1%' is too large") % s);
201 : }
202 :
203 : return hash;
204 : }
205 :
206 :
207 0 : bool isHash(const string & s)
208 : {
209 0 : if (s.length() != 32) return false;
210 0 : for (int i = 0; i < 32; i++) {
211 0 : char c = s[i];
212 0 : if (!((c >= '0' && c <= '9') ||
213 : (c >= 'a' && c <= 'f')))
214 0 : return false;
215 : }
216 0 : return true;
217 : }
218 :
219 :
220 : union Ctx
221 : {
222 : MD5_CTX md5;
223 : SHA_CTX sha1;
224 : SHA256_CTX sha256;
225 : };
226 :
227 :
228 6859 : static void start(HashType ht, Ctx & ctx)
229 : {
230 6859 : if (ht == htMD5) MD5_Init(&ctx.md5);
231 6840 : else if (ht == htSHA1) SHA1_Init(&ctx.sha1);
232 6818 : else if (ht == htSHA256) SHA256_Init(&ctx.sha256);
233 6859 : }
234 :
235 :
236 : static void update(HashType ht, Ctx & ctx,
237 111155 : const unsigned char * bytes, unsigned int len)
238 : {
239 111155 : if (ht == htMD5) MD5_Update(&ctx.md5, bytes, len);
240 110700 : else if (ht == htSHA1) SHA1_Update(&ctx.sha1, bytes, len);
241 110563 : else if (ht == htSHA256) SHA256_Update(&ctx.sha256, bytes, len);
242 111155 : }
243 :
244 :
245 6854 : static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
246 : {
247 6854 : if (ht == htMD5) MD5_Final(hash, &ctx.md5);
248 6835 : else if (ht == htSHA1) SHA1_Final(hash, &ctx.sha1);
249 6813 : else if (ht == htSHA256) SHA256_Final(hash, &ctx.sha256);
250 6854 : }
251 :
252 :
253 1235 : Hash hashString(HashType ht, const string & s)
254 : {
255 : Ctx ctx;
256 1235 : Hash hash(ht);
257 1235 : start(ht, ctx);
258 1235 : update(ht, ctx, (const unsigned char *) s.c_str(), s.length());
259 1235 : finish(ht, ctx, hash.hash);
260 : return hash;
261 : }
262 :
263 :
264 69 : Hash hashFile(HashType ht, const Path & path)
265 : {
266 : Ctx ctx;
267 69 : Hash hash(ht);
268 69 : start(ht, ctx);
269 :
270 69 : AutoCloseFD fd = open(path.c_str(), O_RDONLY);
271 69 : if (fd == -1) throw SysError(format("opening file `%1%'") % path);
272 :
273 : unsigned char buf[8192];
274 : ssize_t n;
275 206 : while ((n = read(fd, buf, sizeof(buf)))) {
276 68 : checkInterrupt();
277 68 : if (n == -1) throw SysError(format("reading file `%1%'") % path);
278 68 : update(ht, ctx, buf, n);
279 : }
280 :
281 69 : finish(ht, ctx, hash.hash);
282 69 : return hash;
283 : }
284 :
285 :
286 5555 : HashSink::HashSink(HashType ht) : ht(ht)
287 : {
288 5555 : ctx = new Ctx;
289 5555 : start(ht, *ctx);
290 5555 : }
291 :
292 5555 : HashSink::~HashSink()
293 : {
294 5555 : delete ctx;
295 5555 : }
296 :
297 : void HashSink::operator ()
298 109852 : (const unsigned char * data, unsigned int len)
299 : {
300 109852 : update(ht, *ctx, data, len);
301 109852 : }
302 :
303 5550 : Hash HashSink::finish()
304 : {
305 5550 : Hash hash(ht);
306 5550 : nix::finish(ht, *ctx, hash.hash);
307 : return hash;
308 : }
309 :
310 :
311 5545 : Hash hashPath(HashType ht, const Path & path, PathFilter & filter)
312 : {
313 5545 : HashSink sink(ht);
314 5545 : dumpPath(path, sink, filter);
315 5545 : return sink.finish();
316 : }
317 :
318 :
319 592 : Hash compressHash(const Hash & hash, unsigned int newSize)
320 : {
321 592 : Hash h;
322 592 : h.hashSize = newSize;
323 19536 : for (unsigned int i = 0; i < hash.hashSize; ++i)
324 18944 : h.hash[i % newSize] ^= hash.hash[i];
325 : return h;
326 : }
327 :
328 :
329 5582 : HashType parseHashType(const string & s)
330 : {
331 5582 : if (s == "md5") return htMD5;
332 5559 : else if (s == "sha1") return htSHA1;
333 5550 : else if (s == "sha256") return htSHA256;
334 0 : else return htUnknown;
335 : }
336 :
337 0 :
338 1106 : }
|