Browse Source

[trac781] create hmac class to add update() functionality

Jelte Jansen 14 years ago
parent
commit
24aa99548a
2 changed files with 94 additions and 58 deletions
  1. 81 58
      src/lib/crypto/crypto.cc
  2. 13 0
      src/lib/crypto/crypto.h

+ 81 - 58
src/lib/crypto/crypto.cc

@@ -29,18 +29,17 @@
 
 #include <string>
 
-using namespace Botan;
 using namespace std;
 using namespace isc::dns;
 
 namespace {
-HashFunction* getHash(const Name& hash_name) {
+Botan::HashFunction* getHash(const Name& hash_name) {
     if (hash_name == TSIGKey::HMACMD5_NAME()) {
-        return get_hash("MD5");
+        return Botan::get_hash("MD5");
     } else if (hash_name == TSIGKey::HMACSHA1_NAME()) {
-        return get_hash("SHA-1");
+        return Botan::get_hash("SHA-1");
     } else if (hash_name == TSIGKey::HMACSHA256_NAME()) {
-        return get_hash("SHA-256");
+        return Botan::get_hash("SHA-256");
     } else {
         isc_throw(isc::crypto::UnsupportedAlgorithm,
                   "Unknown Hash type " + hash_name.toText());
@@ -50,76 +49,100 @@ HashFunction* getHash(const Name& hash_name) {
 // Library needs to have been inited during the entire program
 // should we make this a singleton? (for hsm we'll need more
 // initialization, and dynamic loading)
-LibraryInitializer init;
+Botan::LibraryInitializer init;
 
 } // local namespace
 
 namespace isc {
 namespace crypto {
 
-void
-signHMAC(const OutputBuffer& data, TSIGKey key,
-         isc::dns::OutputBuffer& result)
-{
-    // get algorithm from key, then 'translate' to Botan-specific algo
-    HashFunction* hash = getHash(key.getAlgorithmName());
-    HMAC::HMAC hmac(hash);
-
-    // Take the 'secret' from the key
-    // If the key length is larger than the block size, we hash the
-    // key itself first.
-    try {
-        if (key.getSecretLength() > hash->HASH_BLOCK_SIZE) {
-            SecureVector<byte> hashed_key =
-                hash->process(static_cast<const byte*>(key.getSecret()),
-                              key.getSecretLength());
-            hmac.set_key(hashed_key.begin(), hashed_key.size());
-        } else {
-            hmac.set_key(static_cast<const byte*>(key.getSecret()),
-                         key.getSecretLength());
+class HMACImpl {
+public:
+    explicit HMACImpl(const TSIGKey& key) {
+        Botan::HashFunction* hash = getHash(key.getAlgorithmName());
+        hmac_ = new Botan::HMAC::HMAC(hash);
+
+        // Take the 'secret' from the key
+        // If the key length is larger than the block size, we hash the
+        // key itself first.
+        try {
+            if (key.getSecretLength() > hash->HASH_BLOCK_SIZE) {
+                Botan::SecureVector<Botan::byte> hashed_key =
+                    hash->process(static_cast<const Botan::byte*>(key.getSecret()),
+                                  key.getSecretLength());
+                hmac_->set_key(hashed_key.begin(), hashed_key.size());
+            } else {
+                hmac_->set_key(static_cast<const Botan::byte*>(key.getSecret()),
+                             key.getSecretLength());
+            }
+        } catch (Botan::Invalid_Key_Length ikl) {
+            isc_throw(BadKey, ikl.what());
         }
-    } catch (Invalid_Key_Length ikl) {
-        isc_throw(BadKey, ikl.what());
     }
 
-    // update the data from whatever we get (probably as a buffer)
-    hmac.update(static_cast<const byte*>(data.getData()),
-                data.getLength());
+    ~HMACImpl() { delete hmac_; }
+
+    void update(const void* data, size_t len) {
+        // update the data from whatever we get (probably as a buffer)
+        hmac_->update(static_cast<const Botan::byte*>(data), len);
+    }
+
+    void sign(isc::dns::OutputBuffer& result) {
+        // And generate the mac
+        Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+    
+        // write mac to result
+        result.writeData(b_result.begin(), b_result.size());
+    }
+    
+    bool verify(const void* sig, size_t len) {
+        return hmac_->verify_mac(static_cast<const Botan::byte*>(sig), len);
+    }
+
+private:
+    Botan::HMAC* hmac_;
+};
+
+HMAC::HMAC(const TSIGKey& key) {
+    impl_ = new HMACImpl(key);
+}
 
-    // And generate the mac
-    SecureVector<byte> b_result(hmac.final());
+HMAC::~HMAC() {
+    delete impl_;
+}
 
-    // write mac to result
-    result.writeData(b_result.begin(), b_result.size());
+void
+HMAC::update(const void* data, size_t len) {
+    impl_->update(data, len);
+}
+
+void
+HMAC::sign(isc::dns::OutputBuffer& result) {
+    impl_->sign(result);
 }
 
 bool
-verifyHMAC(const OutputBuffer& data, TSIGKey key,
-           const isc::dns::OutputBuffer& result)
+HMAC::verify(const void* sig, size_t len) {
+    return impl_->verify(sig, len);
+}
+
+void
+signHMAC(const OutputBuffer& data, TSIGKey key,
+         isc::dns::OutputBuffer& result)
 {
-    HashFunction* hash = getHash(key.getAlgorithmName());
-    HMAC::HMAC hmac(hash);
-    // If the key length is larger than the block size, we hash the
-    // key itself first.
-    try {
-        if (key.getSecretLength() > hash->HASH_BLOCK_SIZE) {
-            SecureVector<byte> hashed_key =
-                hash->process(static_cast<const byte*>(key.getSecret()),
-                              key.getSecretLength());
-            hmac.set_key(hashed_key.begin(), hashed_key.size());
-        } else {
-            hmac.set_key(static_cast<const byte*>(key.getSecret()),
-                         key.getSecretLength());
-        }
-    } catch (Invalid_Key_Length ikl) {
-        isc_throw(BadKey, ikl.what());
-    }
+    HMAC hmac(key);
+    hmac.update(data.getData(), data.getLength());
+    hmac.sign(result);
+}
 
-    hmac.update(static_cast<const byte*>(data.getData()),
-                data.getLength());
 
-    return hmac.verify_mac(static_cast<const byte*>(result.getData()),
-                           result.getLength());
+bool
+verifyHMAC(const OutputBuffer& data, TSIGKey key,
+           const isc::dns::OutputBuffer& result)
+{
+    HMAC hmac(key);
+    hmac.update(data.getData(), data.getLength());
+    return hmac.verify(result.getData(), result.getLength());
 }
 
 } // namespace crypto

+ 13 - 0
src/lib/crypto/crypto.h

@@ -60,6 +60,19 @@ public:
         CryptoError(file, line, what) {}
 };
 
+class HMACImpl;
+
+class HMAC {
+public:
+    explicit HMAC(const isc::dns::TSIGKey& key);
+    ~HMAC();
+    void update(const void* data, size_t len);
+    void sign(isc::dns::OutputBuffer& result);
+    bool verify(const void* sig, size_t len);
+private:
+    HMACImpl* impl_;
+};
+
 /// \brief Create an HMAC signature for the given data
 ///
 /// Raises an UnsupportedAlgorithm if we do not support the given