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