about summary refs log tree commit diff
path: root/src/libutil/hash.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil/hash.cc')
-rw-r--r--src/libutil/hash.cc60
1 files changed, 36 insertions, 24 deletions
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index a83ba0a81817..c17f1c4d5150 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -3,16 +3,8 @@
 #include <iostream>
 #include <cstring>
 
-#ifdef HAVE_OPENSSL
 #include <openssl/md5.h>
 #include <openssl/sha.h>
-#else
-extern "C" {
-#include "md5.h"
-#include "sha1.h"
-#include "sha256.h"
-}
-#endif
 
 #include "hash.hh"
 #include "archive.hh"
@@ -40,7 +32,8 @@ Hash::Hash(HashType type)
     if (type == htMD5) hashSize = md5HashSize;
     else if (type == htSHA1) hashSize = sha1HashSize;
     else if (type == htSHA256) hashSize = sha256HashSize;
-    else throw Error("unknown hash type");
+    else if (type == htSHA512) hashSize = sha512HashSize;
+    else abort();
     assert(hashSize <= maxHashSize);
     memset(hash, 0, maxHashSize);
 }
@@ -71,6 +64,12 @@ bool Hash::operator < (const Hash & h) const
 }
 
 
+std::string Hash::to_string(bool base32) const
+{
+    return printHashType(type) + ":" + (base32 ? printHash32(*this) : printHash(*this));
+}
+
+
 const string base16Chars = "0123456789abcdef";
 
 
@@ -85,15 +84,28 @@ string printHash(const Hash & hash)
 }
 
 
+Hash parseHash(const string & s)
+{
+    string::size_type colon = s.find(':');
+    if (colon == string::npos)
+        throw BadHash(format("invalid hash ‘%s’") % s);
+    string hts = string(s, 0, colon);
+    HashType ht = parseHashType(hts);
+    if (ht == htUnknown)
+        throw BadHash(format("unknown hash type ‘%s’") % hts);
+    return parseHash16or32(ht, string(s, colon + 1));
+}
+
+
 Hash parseHash(HashType ht, const string & s)
 {
     Hash hash(ht);
     if (s.length() != hash.hashSize * 2)
-        throw Error(format("invalid hash ‘%1%’") % s);
+        throw BadHash(format("invalid hash ‘%1%’") % s);
     for (unsigned int i = 0; i < hash.hashSize; i++) {
         string s2(s, i * 2, 2);
         if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
-            throw Error(format("invalid hash ‘%1%’") % s);
+            throw BadHash(format("invalid hash ‘%1%’") % s);
         std::istringstream str(s2);
         int n;
         str >> std::hex >> n;
@@ -103,20 +115,14 @@ Hash parseHash(HashType ht, const string & s)
 }
 
 
-unsigned int hashLength32(const Hash & hash)
-{
-    return (hash.hashSize * 8 - 1) / 5 + 1;
-}
-
-
 // omitted: E O U T
 const string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
 
 
 string printHash32(const Hash & hash)
 {
-    Hash hash2(hash);
-    unsigned int len = hashLength32(hash);
+    size_t len = hash.base32Len();
+    assert(len);
 
     string s;
     s.reserve(len);
@@ -144,7 +150,7 @@ string printHash16or32(const Hash & hash)
 Hash parseHash32(HashType ht, const string & s)
 {
     Hash hash(ht);
-    unsigned int len = hashLength32(ht);
+    size_t len = hash.base32Len();
     assert(s.size() == len);
 
     for (unsigned int n = 0; n < len; ++n) {
@@ -153,7 +159,7 @@ Hash parseHash32(HashType ht, const string & s)
         for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
             if (base32Chars[digit] == c) break;
         if (digit >= 32)
-            throw Error(format("invalid base-32 hash ‘%1%’") % s);
+            throw BadHash(format("invalid base-32 hash ‘%1%’") % s);
         unsigned int b = n * 5;
         unsigned int i = b / 8;
         unsigned int j = b % 8;
@@ -171,11 +177,11 @@ Hash parseHash16or32(HashType ht, const string & s)
     if (s.size() == hash.hashSize * 2)
         /* hexadecimal representation */
         hash = parseHash(ht, s);
-    else if (s.size() == hashLength32(hash))
+    else if (s.size() == hash.base32Len())
         /* base-32 representation */
         hash = parseHash32(ht, s);
     else
-        throw Error(format("hash ‘%1%’ has wrong length for hash type ‘%2%’")
+        throw BadHash(format("hash ‘%1%’ has wrong length for hash type ‘%2%’")
             % s % printHashType(ht));
     return hash;
 }
@@ -199,6 +205,7 @@ union Ctx
     MD5_CTX md5;
     SHA_CTX sha1;
     SHA256_CTX sha256;
+    SHA512_CTX sha512;
 };
 
 
@@ -207,6 +214,7 @@ static void start(HashType ht, Ctx & ctx)
     if (ht == htMD5) MD5_Init(&ctx.md5);
     else if (ht == htSHA1) SHA1_Init(&ctx.sha1);
     else if (ht == htSHA256) SHA256_Init(&ctx.sha256);
+    else if (ht == htSHA512) SHA512_Init(&ctx.sha512);
 }
 
 
@@ -216,6 +224,7 @@ static void update(HashType ht, Ctx & ctx,
     if (ht == htMD5) MD5_Update(&ctx.md5, bytes, len);
     else if (ht == htSHA1) SHA1_Update(&ctx.sha1, bytes, len);
     else if (ht == htSHA256) SHA256_Update(&ctx.sha256, bytes, len);
+    else if (ht == htSHA512) SHA512_Update(&ctx.sha512, bytes, len);
 }
 
 
@@ -224,6 +233,7 @@ static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
     if (ht == htMD5) MD5_Final(hash, &ctx.md5);
     else if (ht == htSHA1) SHA1_Final(hash, &ctx.sha1);
     else if (ht == htSHA256) SHA256_Final(hash, &ctx.sha256);
+    else if (ht == htSHA512) SHA512_Final(hash, &ctx.sha512);
 }
 
 
@@ -321,6 +331,7 @@ HashType parseHashType(const string & s)
     if (s == "md5") return htMD5;
     else if (s == "sha1") return htSHA1;
     else if (s == "sha256") return htSHA256;
+    else if (s == "sha512") return htSHA512;
     else return htUnknown;
 }
 
@@ -330,7 +341,8 @@ string printHashType(HashType ht)
     if (ht == htMD5) return "md5";
     else if (ht == htSHA1) return "sha1";
     else if (ht == htSHA256) return "sha256";
-    else throw Error("cannot print unknown hash type");
+    else if (ht == htSHA512) return "sha512";
+    else abort();
 }