7 #include <openssl/md5.h>
8 #include <openssl/sha.h>
22 #include <sys/types.h>
34 memset(hash
, 0, maxHashSize
);
38 Hash::Hash(HashType type
)
41 if (type
== htMD5
) hashSize
= md5HashSize
;
42 else if (type
== htSHA1
) hashSize
= sha1HashSize
;
43 else if (type
== htSHA256
) hashSize
= sha256HashSize
;
44 else if (type
== htSHA512
) hashSize
= sha512HashSize
;
45 else throw Error("unknown hash type");
46 assert(hashSize
<= maxHashSize
);
47 memset(hash
, 0, maxHashSize
);
51 bool Hash::operator == (const Hash
& h2
) const
53 if (hashSize
!= h2
.hashSize
) return false;
54 for (unsigned int i
= 0; i
< hashSize
; i
++)
55 if (hash
[i
] != h2
.hash
[i
]) return false;
60 bool Hash::operator != (const Hash
& h2
) const
62 return !(*this == h2
);
66 bool Hash::operator < (const Hash
& h
) const
68 for (unsigned int i
= 0; i
< hashSize
; i
++) {
69 if (hash
[i
] < h
.hash
[i
]) return true;
70 if (hash
[i
] > h
.hash
[i
]) return false;
76 const string base16Chars
= "0123456789abcdef";
79 string
printHash(const Hash
& hash
)
81 char buf
[hash
.hashSize
* 2];
82 for (unsigned int i
= 0; i
< hash
.hashSize
; i
++) {
83 buf
[i
* 2] = base16Chars
[hash
.hash
[i
] >> 4];
84 buf
[i
* 2 + 1] = base16Chars
[hash
.hash
[i
] & 0x0f];
86 return string(buf
, hash
.hashSize
* 2);
90 Hash
parseHash(HashType ht
, const string
& s
)
93 if (s
.length() != hash
.hashSize
* 2)
94 throw Error(format("invalid hash `%1%'") % s
);
95 for (unsigned int i
= 0; i
< hash
.hashSize
; i
++) {
96 string
s2(s
, i
* 2, 2);
97 if (!isxdigit(s2
[0]) || !isxdigit(s2
[1]))
98 throw Error(format("invalid hash `%1%'") % s
);
99 std::istringstream
str(s2
);
101 str
>> std::hex
>> n
;
108 unsigned int hashLength32(const Hash
& hash
)
110 return (hash
.hashSize
* 8 - 1) / 5 + 1;
115 const string base32Chars
= "0123456789abcdfghijklmnpqrsvwxyz";
118 string
printHash32(const Hash
& hash
)
121 unsigned int len
= hashLength32(hash
);
126 for (int n
= len
- 1; n
>= 0; n
--) {
127 unsigned int b
= n
* 5;
128 unsigned int i
= b
/ 8;
129 unsigned int j
= b
% 8;
132 | (i
>= hash
.hashSize
- 1 ? 0 : hash
.hash
[i
+ 1] << (8 - j
));
133 s
.push_back(base32Chars
[c
& 0x1f]);
140 string
printHash16or32(const Hash
& hash
)
142 return hash
.type
== htMD5
? printHash(hash
) : printHash32(hash
);
146 Hash
parseHash32(HashType ht
, const string
& s
)
149 unsigned int len
= hashLength32(ht
);
150 assert(s
.size() == len
);
152 for (unsigned int n
= 0; n
< len
; ++n
) {
153 char c
= s
[len
- n
- 1];
155 for (digit
= 0; digit
< base32Chars
.size(); ++digit
) /* !!! slow */
156 if (base32Chars
[digit
] == c
) break;
158 throw Error(format("invalid base-32 hash '%1%'") % s
);
159 unsigned int b
= n
* 5;
160 unsigned int i
= b
/ 8;
161 unsigned int j
= b
% 8;
162 hash
.hash
[i
] |= digit
<< j
;
163 if (i
< hash
.hashSize
- 1) hash
.hash
[i
+ 1] |= digit
>> (8 - j
);
170 Hash
parseHash16or32(HashType ht
, const string
& s
)
173 if (s
.size() == hash
.hashSize
* 2)
174 /* hexadecimal representation */
175 hash
= parseHash(ht
, s
);
176 else if (s
.size() == hashLength32(hash
))
177 /* base-32 representation */
178 hash
= parseHash32(ht
, s
);
180 throw Error(format("hash `%1%' has wrong length for hash type `%2%'")
181 % s
% printHashType(ht
));
186 bool isHash(const string
& s
)
188 if (s
.length() != 32) return false;
189 for (int i
= 0; i
< 32; i
++) {
191 if (!((c
>= '0' && c
<= '9') ||
192 (c
>= 'a' && c
<= 'f')))
208 static void start(HashType ht
, Ctx
& ctx
)
210 if (ht
== htMD5
) MD5_Init(&ctx
.md5
);
211 else if (ht
== htSHA1
) SHA1_Init(&ctx
.sha1
);
212 else if (ht
== htSHA256
) SHA256_Init(&ctx
.sha256
);
213 else if (ht
== htSHA512
) SHA512_Init(&ctx
.sha512
);
217 static void update(HashType ht
, Ctx
& ctx
,
218 const unsigned char * bytes
, unsigned int len
)
220 if (ht
== htMD5
) MD5_Update(&ctx
.md5
, bytes
, len
);
221 else if (ht
== htSHA1
) SHA1_Update(&ctx
.sha1
, bytes
, len
);
222 else if (ht
== htSHA256
) SHA256_Update(&ctx
.sha256
, bytes
, len
);
223 else if (ht
== htSHA512
) SHA512_Update(&ctx
.sha512
, bytes
, len
);
227 static void finish(HashType ht
, Ctx
& ctx
, unsigned char * hash
)
229 if (ht
== htMD5
) MD5_Final(hash
, &ctx
.md5
);
230 else if (ht
== htSHA1
) SHA1_Final(hash
, &ctx
.sha1
);
231 else if (ht
== htSHA256
) SHA256_Final(hash
, &ctx
.sha256
);
232 else if (ht
== htSHA512
) SHA512_Final(hash
, &ctx
.sha512
);
236 Hash
hashString(HashType ht
, const string
& s
)
241 update(ht
, ctx
, (const unsigned char *) s
.data(), s
.length());
242 finish(ht
, ctx
, hash
.hash
);
247 Hash
hashFile(HashType ht
, const Path
& path
)
253 AutoCloseFD fd
= open(path
.c_str(), O_RDONLY
);
254 if (fd
== -1) throw SysError(format("opening file `%1%'") % path
);
256 unsigned char buf
[8192];
258 while ((n
= read(fd
, buf
, sizeof(buf
)))) {
260 if (n
== -1) throw SysError(format("reading file `%1%'") % path
);
261 update(ht
, ctx
, buf
, n
);
264 finish(ht
, ctx
, hash
.hash
);
269 HashSink::HashSink(HashType ht
) : ht(ht
)
276 HashSink::~HashSink()
282 void HashSink::write(const unsigned char * data
, size_t len
)
285 update(ht
, *ctx
, data
, len
);
288 HashResult
HashSink::finish()
292 nix::finish(ht
, *ctx
, hash
.hash
);
293 return HashResult(hash
, bytes
);
296 HashResult
HashSink::currentHash()
301 nix::finish(ht
, ctx2
, hash
.hash
);
302 return HashResult(hash
, bytes
);
307 HashType ht
, const Path
& path
, PathFilter
& filter
)
310 dumpPath(path
, sink
, filter
);
311 return sink
.finish();
315 Hash
compressHash(const Hash
& hash
, unsigned int newSize
)
318 h
.hashSize
= newSize
;
319 for (unsigned int i
= 0; i
< hash
.hashSize
; ++i
)
320 h
.hash
[i
% newSize
] ^= hash
.hash
[i
];
325 HashType
parseHashType(const string
& s
)
327 if (s
== "md5") return htMD5
;
328 else if (s
== "sha1") return htSHA1
;
329 else if (s
== "sha256") return htSHA256
;
330 else if (s
== "sha512") return htSHA512
;
331 else return htUnknown
;
335 string
printHashType(HashType ht
)
337 if (ht
== htMD5
) return "md5";
338 else if (ht
== htSHA1
) return "sha1";
339 else if (ht
== htSHA256
) return "sha256";
340 else if (ht
== htSHA512
) return "sha512";
341 else throw Error("cannot print unknown hash type");