BIND 10 trac781, updated. 246e56b3bb7792789b3aa891e21e580976d9e7be [trac781] catch all (unexpected) Botan errors and rethrow them as LibraryError

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Apr 20 14:45:50 UTC 2011


The branch, trac781 has been updated
       via  246e56b3bb7792789b3aa891e21e580976d9e7be (commit)
       via  168bed01625dd25fc2c40bd6b402763849e840ec (commit)
       via  e831ffa2129fc5e013a0217f004896f6f40f258e (commit)
       via  4eda7bbc802b24730eb8ef9e5716fc47f19d5a00 (commit)
       via  122d477847f80c7d77bec087a849b9e6743c17d3 (commit)
       via  e74f6d5e8f9abb081bde606bc46319488c7e546b (commit)
       via  f137e0fa3a387fcc13898ea6da6b61dcd80dc8ef (commit)
       via  cf456aa1546145ac403e75535e555d773b39ff20 (commit)
       via  006b2ea9dabd869bc05682b73b083ea815d520db (commit)
       via  c34d8eb763ceb840f65de77a22eb67c8b1ab6392 (commit)
       via  2aa47d167c58b6718706f8e037927b824ff0cf00 (commit)
      from  604e90d1e0c928cc8d94146beea6e24fe2252eec (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 246e56b3bb7792789b3aa891e21e580976d9e7be
Author: Jelte Jansen <jelte at isc.org>
Date:   Wed Apr 20 16:45:28 2011 +0200

    [trac781] catch all (unexpected) Botan errors and rethrow them as LibraryError

commit 168bed01625dd25fc2c40bd6b402763849e840ec
Author: Jelte Jansen <jelte at isc.org>
Date:   Wed Apr 20 16:29:44 2011 +0200

    [trac781] move signHMAC and verifyHMAC to hmac files

commit e831ffa2129fc5e013a0217f004896f6f40f258e
Author: Jelte Jansen <jelte at isc.org>
Date:   Wed Apr 20 15:30:45 2011 +0200

    [trac781] bit of cleanup

commit 4eda7bbc802b24730eb8ef9e5716fc47f19d5a00
Author: Jelte Jansen <jelte at isc.org>
Date:   Wed Apr 20 15:12:12 2011 +0200

    [trac781] rename 'crypto' to cryptolink
    
    renamed the directory, libname, namespace and main class

commit 122d477847f80c7d77bec087a849b9e6743c17d3
Author: Jelte Jansen <jelte at isc.org>
Date:   Wed Apr 20 12:20:11 2011 +0200

    [trac781] make HMAC constructor private

commit e74f6d5e8f9abb081bde606bc46319488c7e546b
Author: Jelte Jansen <jelte at isc.org>
Date:   Wed Apr 20 11:05:15 2011 +0200

    [trac781] make a singleton entry point, moved hmac into own source file

commit f137e0fa3a387fcc13898ea6da6b61dcd80dc8ef
Author: Jelte Jansen <jelte at isc.org>
Date:   Wed Apr 20 09:26:00 2011 +0200

    [trac781] renamed test and refactored duplicate initialization code

commit cf456aa1546145ac403e75535e555d773b39ff20
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Apr 19 16:09:30 2011 +0200

    [trac781] apply proposed patch

commit 006b2ea9dabd869bc05682b73b083ea815d520db
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Apr 19 15:49:07 2011 +0200

    [trac781] constify

commit c34d8eb763ceb840f65de77a22eb67c8b1ab6392
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Apr 19 15:22:10 2011 +0200

    [trac781] better way to test (both vector and buffer)

commit 2aa47d167c58b6718706f8e037927b824ff0cf00
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Apr 19 15:16:39 2011 +0200

    [trac781] some additional tests

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                       |    4 +-
 doc/Doxyfile                                       |    2 +-
 src/lib/Makefile.am                                |    2 +-
 src/lib/crypto/tests/crypto_unittests.cc           |  426 ----------------
 src/lib/{crypto => cryptolink}/Makefile.am         |    5 +-
 src/lib/cryptolink/crypto.cc                       |   84 ++++
 src/lib/cryptolink/crypto.h                        |  165 +++++++
 .../crypto.cc => cryptolink/crypto_hmac.cc}        |  162 +++----
 .../{crypto/crypto.h => cryptolink/crypto_hmac.h}  |  113 ++---
 src/lib/{crypto => cryptolink}/tests/Makefile.am   |    2 +-
 src/lib/cryptolink/tests/crypto_unittests.cc       |  513 ++++++++++++++++++++
 .../{crypto => cryptolink}/tests/run_unittests.cc  |    3 +-
 src/lib/dns/tests/tsigkey_unittest.cc              |    2 +-
 src/lib/dns/tsigkey.cc                             |   59 ++-
 src/lib/dns/tsigkey.h                              |    2 +-
 15 files changed, 929 insertions(+), 615 deletions(-)
 delete mode 100644 src/lib/crypto/tests/crypto_unittests.cc
 rename src/lib/{crypto => cryptolink}/Makefile.am (56%)
 create mode 100644 src/lib/cryptolink/crypto.cc
 create mode 100644 src/lib/cryptolink/crypto.h
 rename src/lib/{crypto/crypto.cc => cryptolink/crypto_hmac.cc} (51%)
 rename src/lib/{crypto/crypto.h => cryptolink/crypto_hmac.h} (75%)
 rename src/lib/{crypto => cryptolink}/tests/Makefile.am (89%)
 create mode 100644 src/lib/cryptolink/tests/crypto_unittests.cc
 rename src/lib/{crypto => cryptolink}/tests/run_unittests.cc (94%)

-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index dce081d..ac60c97 100644
--- a/configure.ac
+++ b/configure.ac
@@ -699,8 +699,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/config/tests/testdata/Makefile
-                 src/lib/crypto/Makefile
-                 src/lib/crypto/tests/Makefile
+                 src/lib/cryptolink/Makefile
+                 src/lib/cryptolink/tests/Makefile
                  src/lib/dns/Makefile
                  src/lib/dns/tests/Makefile
                  src/lib/dns/tests/testdata/Makefile
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 6cb4174..28a0885 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -568,7 +568,7 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/crypto ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/
+INPUT                  = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/cryptolink ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index c3323c0..0d8c494 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,2 @@
-SUBDIRS = exceptions dns crypto cc config python xfr bench log \
+SUBDIRS = exceptions dns cryptolink cc config python xfr bench log \
           asiolink nsas cache resolve testutils datasrc server_common
diff --git a/src/lib/crypto/Makefile.am b/src/lib/crypto/Makefile.am
deleted file mode 100644
index e953284..0000000
--- a/src/lib/crypto/Makefile.am
+++ /dev/null
@@ -1,11 +0,0 @@
-SUBDIRS = . tests
-
-AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CXXFLAGS = $(B10_CXXFLAGS)
-
-CLEANFILES = *.gcno *.gcda
-
-lib_LTLIBRARIES = libb10crypto.la
-
-libb10crypto_la_SOURCES = crypto.h crypto.cc
diff --git a/src/lib/crypto/crypto.cc b/src/lib/crypto/crypto.cc
deleted file mode 100644
index 2319874..0000000
--- a/src/lib/crypto/crypto.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include "crypto.h"
-
-#include <botan/botan.h>
-#include <botan/hmac.h>
-#include <botan/hash.h>
-#include <botan/types.h>
-
-#include <dns/buffer.h>
-#include <dns/name.h>
-#include <dns/util/base64.h>
-
-#include <string>
-
-using namespace std;
-using namespace isc::dns;
-
-namespace {
-const char*
-getBotanHashAlgorithmName(isc::crypto::HMAC::HashAlgorithm algorithm) {
-    switch (algorithm) {
-    case isc::crypto::HMAC::MD5:
-        return ("MD5");
-        break;
-    case isc::crypto::HMAC::SHA1:
-        return ("SHA-1");
-        break;
-    case isc::crypto::HMAC::SHA256:
-        return ("SHA-256");
-        break;
-    case isc::crypto::HMAC::UNKNOWN:
-        return ("Unknown");
-        break;
-    }
-    // compiler should have prevented us to reach this, since we have
-    // no default. But we need a return value anyway
-    return ("Unknown");
-}
-
-} // local namespace
-
-namespace isc {
-namespace crypto {
-
-// For Botan, we use the Crypto class object in RAII style
-class CryptoImpl {
-public:
-    CryptoImpl() {}
-    ~CryptoImpl() {};
-
-private:
-    Botan::LibraryInitializer _botan_init;
-};
-
-Crypto::Crypto() {
-    try {
-        impl_ = new CryptoImpl();
-    } catch (const Botan::Exception& ex) {
-        isc_throw(InitializationError, ex.what());
-    }
-}
-
-Crypto::~Crypto() {
-    delete impl_;
-}
-
-
-class HMACImpl {
-public:
-    explicit HMACImpl(const void* secret, size_t secret_len,
-                      const HMAC::HashAlgorithm hash_algorithm) {
-        Botan::HashFunction* hash;
-        try {
-            hash = Botan::get_hash(
-                getBotanHashAlgorithmName(hash_algorithm));
-        } catch (const Botan::Algorithm_Not_Found&) {
-            isc_throw(isc::crypto::UnsupportedAlgorithm,
-                      "Unknown hash algorithm: " + hash_algorithm);
-        }
-
-        hmac_ = new Botan::HMAC::HMAC(hash);
-
-        // If the key length is larger than the block size, we hash the
-        // key itself first.
-        try {
-            if (secret_len > hash->HASH_BLOCK_SIZE) {
-                Botan::SecureVector<Botan::byte> hashed_key =
-                    hash->process(static_cast<const Botan::byte*>(secret),
-                                  secret_len);
-                hmac_->set_key(hashed_key.begin(), hashed_key.size());
-            } else {
-                hmac_->set_key(static_cast<const Botan::byte*>(secret),
-                               secret_len);
-            }
-        } catch (const Botan::Invalid_Key_Length& ikl) {
-            delete hmac_;
-            isc_throw(BadKey, ikl.what());
-        }
-    }
-
-    ~HMACImpl() { delete hmac_; }
-
-    size_t getOutputLength() const {
-        return (hmac_->OUTPUT_LENGTH);
-    }
-
-    void update(const void* data, const size_t len) {
-        hmac_->update(static_cast<const Botan::byte*>(data), len);
-    }
-
-    void sign(isc::dns::OutputBuffer& result, size_t len) {
-        Botan::SecureVector<Botan::byte> b_result(hmac_->final());
-
-        if (len == 0 || len > b_result.size()) {
-            len = b_result.size();
-        }
-        result.writeData(b_result.begin(), len);
-    }
-
-    void sign(void* result, size_t len) {
-        Botan::SecureVector<Botan::byte> b_result(hmac_->final());
-        size_t output_size = getOutputLength();
-        if (output_size > len) {
-            output_size = len;
-        }
-        memcpy(result, b_result.begin(), output_size);
-    }
-
-    std::vector<uint8_t> sign(size_t len) {
-        Botan::SecureVector<Botan::byte> b_result(hmac_->final());
-        if (len == 0 || len > b_result.size()) {
-            return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
-        } else {
-            return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
-        }
-    }
-
-
-    bool verify(const void* sig, size_t len) {
-        // Botan's verify_mac checks if len matches the output_length,
-        // which causes it to fail for truncated signatures, so we do
-        // the check ourselves
-        Botan::SecureVector<Botan::byte> our_mac = hmac_->final();
-        if (len == 0 || len > getOutputLength()) {
-            len = getOutputLength();
-        }
-        return (Botan::same_mem(&our_mac[0],
-                                static_cast<const unsigned char*>(sig),
-                                len));
-    }
-
-private:
-    Botan::HMAC* hmac_;
-};
-
-HMAC::HMAC(const void* secret, size_t secret_length,
-           const HashAlgorithm hash_algorithm)
-{
-    impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
-}
-
-HMAC::~HMAC() {
-    delete impl_;
-}
-
-size_t
-HMAC::getOutputLength() const {
-    return (impl_->getOutputLength());
-}
-
-void
-HMAC::update(const void* data, const size_t len) {
-    impl_->update(data, len);
-}
-
-void
-HMAC::sign(isc::dns::OutputBuffer& result, size_t len) {
-    impl_->sign(result, len);
-}
-
-void
-HMAC::sign(void* result, size_t len) {
-    impl_->sign(result, len);
-}
-
-std::vector<uint8_t>
-HMAC::sign(size_t len) {
-    return impl_->sign(len);
-}
-
-bool
-HMAC::verify(const void* sig, const size_t len) {
-    return (impl_->verify(sig, len));
-}
-
-void
-signHMAC(const void* data, size_t data_len, const void* secret,
-         size_t secret_len, const HMAC::HashAlgorithm hash_algorithm,
-         isc::dns::OutputBuffer& result, size_t len)
-{
-    HMAC hmac(secret, secret_len, hash_algorithm);
-    hmac.update(data, data_len);
-    hmac.sign(result, len);
-}
-
-
-bool
-verifyHMAC(const void* data, const size_t data_len, const void* secret,
-           size_t secret_len, const HMAC::HashAlgorithm hash_algorithm,
-           const void* sig, const size_t sig_len)
-{
-    HMAC hmac(secret, secret_len, hash_algorithm);
-    hmac.update(data, data_len);
-    return (hmac.verify(sig, sig_len));
-}
-
-} // namespace crypto
-} // namespace isc
-
diff --git a/src/lib/crypto/crypto.h b/src/lib/crypto/crypto.h
deleted file mode 100644
index b5d4b2c..0000000
--- a/src/lib/crypto/crypto.h
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <string>
-#include <dns/buffer.h>
-#include <exceptions/exceptions.h>
-
-#include <boost/noncopyable.hpp>
-
-#ifndef _ISC_CRYPTO_H
-#define _ISC_CRYPTO_H
-
-namespace isc {
-namespace crypto {
-
-/// General exception class that is the base for all crypto-related
-/// exceptions
-class CryptoError : public Exception {
-public:
-    CryptoError(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-/// This exception is thrown if there was a problem initializing the
-/// crypto library
-class InitializationError : public CryptoError {
-public:
-    InitializationError(const char* file, size_t line, const char* what) :
-        CryptoError(file, line, what) {}
-};
-
-/// This exception is thrown when a cryptographic action is requested
-/// for an algorithm that is not supported by the underlying algorithm.
-class UnsupportedAlgorithm : public CryptoError {
-public:
-    UnsupportedAlgorithm(const char* file, size_t line, const char* what) :
-        CryptoError(file, line, what) {}
-};
-
-/// This exception is thrown when the underlying library could not
-/// handle this key
-class BadKey : public CryptoError {
-public:
-    BadKey(const char* file, size_t line, const char* what) :
-        CryptoError(file, line, what) {}
-};
-
-class CryptoImpl;
-
-/// \brief Initializer object
-///
-/// This object represents 'global' state for the backend crypto
-/// library, and must be initialized before any cryptographic calls
-/// are made. It may not be destroyed until all cryptographic objects
-/// are.
-/// Preferably, this object is created in the program's main() function
-// Internal note: we can use this class later to initialize and manage
-// dynamic (PKCS#11) libs
-class Crypto {
-public:
-    Crypto();
-    ~Crypto();
-private:
-    CryptoImpl* impl_;
-};
-
-/// Forward declaration, pimpl style
-class HMACImpl;
-
-/// \brief HMAC support
-///
-/// This class is used to create and verify HMAC signatures
-///
-class HMAC : public boost::noncopyable {
-public:
-    enum HashAlgorithm {
-        MD5 = 0,
-        SHA1 = 1,
-        SHA256 = 2,
-        UNKNOWN = 3
-    };
-
-    /// \brief Constructor from a secret and a hash algorithm
-    ///
-    /// \exception UnsupportedAlgorithmException if the given algorithm
-    ///            is unknown or not supported by the underlying library
-    /// \exception InvalidKeyLength if the given key secret_len is bad
-    ///
-    /// Notes: if the secret is longer than the block size of its
-    /// algorithm, the constructor will run it through the hash
-    /// algorithm, and use the digest as the secret for this HMAC
-    /// operation
-    ///
-    /// \param secret The secret to sign with
-    /// \param len The length of the secret
-    /// \param hash_algorithm The hash algorithm
-    explicit HMAC(const void* secret, size_t secret_len,
-                  const HashAlgorithm hash_algorithm);
-
-    /// \brief Destructor
-    ~HMAC();
-
-    /// \brief Returns the output size of the digest
-    ///
-    /// \return output size of the digest
-    size_t getOutputLength() const;
-
-    /// \brief Add data to digest
-    ///
-    /// \param data The data to add
-    /// \param len The size of the data
-    void update(const void* data, const size_t len);
-
-    /// \brief Calculate the final signature
-    ///
-    /// The result will be appended to the given outputbuffer
-    ///
-    /// \param result The OutputBuffer to append the result to
-    /// \param len The number of bytes from the result to copy. If this
-    ///        value is smaller than the algorithms output size, the
-    ///        result will be truncated. If this value is larger, or 0
-    ///        (the default), it will be ignored
-    void sign(isc::dns::OutputBuffer& result, size_t len = 0);
-
-    /// \brief Calculate the final signature
-    ///
-    /// len bytes of data from the result will be copied to *result
-    /// If len is larger than the output size, only output_size bytes
-    /// will be copied. If it is smaller, the output will be truncated
-    ///
-    /// At least len bytes of data must be available for writing at
-    /// result
-    void sign(void* result, size_t len);
-
-    /// \brief Calculate the final signatre
-    ///
-    /// The result will be returned as a std::vector<uint8_t>
-    ///
-    /// \param len The number of bytes from the result to copy. If this
-    ///        value is smaller than the algorithms output size, the
-    ///        result will be truncated. If this value is larger, or 0
-    ///        (the default), it will be ignored
-    /// \return a vector containing the signature
-    std::vector<uint8_t> sign(size_t len = 0);
-
-    /// \brief Verify an existing signature
-    ///
-    /// \param sig The signature to verify
-    /// \param len The length of the signature. If this is non-zero,
-    ///            and smaller than the output length of the algorithm,
-    ///            only len bytes will be checked
-    /// \return true if the signature is correct, false otherwise
-    bool verify(const void* sig, size_t len);
-
-private:
-    HMACImpl* impl_;
-};
-
-/// \brief Create an HMAC signature for the given data
-///
-/// This is a convenience function that calculates the hmac signature,
-/// given a fixed amount of data. Internally it does the same as
-/// creating an HMAC object, feeding it the data, and calculating the
-/// resulting signature.
-///
-/// \exception UnsupportedAlgorithm if the given algorithm is unknown
-///            or not supported by the underlying library
-/// \exception BadKey if the given key secret_len is bad
-///
-/// Notes: if the secret is longer than the block size of its
-/// algorithm, the constructor will run it through the hash
-/// algorithm, and use the digest as the secret for this HMAC
-/// operation
-///
-/// \param data The data to sign
-/// \param data_len The length of the data
-/// \param secret The secret to sign with
-/// \param secret_len The length of the secret
-/// \param hash_algorithm The hash algorithm
-/// \param result The signature will be appended to this buffer
-/// \param len If this is non-zero and less than the output size,
-///            the result will be truncated to len bytes
-void signHMAC(const void* data,
-              const size_t data_len,
-              const void* secret,
-              size_t secret_len,
-              const HMAC::HashAlgorithm hash_algorithm,
-              isc::dns::OutputBuffer& result,
-              size_t len = 0);
-
-/// \brief Verify an HMAC signature for the given data
-///
-/// This is a convenience function that verifies an hmac signature,
-/// given a fixed amount of data. Internally it does the same as
-/// creating an HMAC object, feeding it the data, and checking the
-/// resulting signature.
-///
-/// \exception UnsupportedAlgorithm if the given algorithm is unknown
-///            or not supported by the underlying library
-/// \exception BadKey if the given key secret_len is bad
-///
-/// Notes: if the secret is longer than the block size of its
-/// algorithm, the constructor will run it through the hash
-/// algorithm, and use the digest as the secret for this HMAC
-/// operation
-///
-/// \param data The data to verify
-/// \param data_len The length of the data
-/// \param secret The secret to sign with
-/// \param secret_len The length of the secret
-/// \param hash_algorithm The hash algorithm
-/// \param sig The signature to verify
-/// \param sig_len The length of the signature
-/// \return True if the signature verifies, false if not
-bool verifyHMAC(const void* data,
-                const size_t data_len,
-                const void* secret,
-                size_t secret_len,
-                const HMAC::HashAlgorithm hash_algorithm,
-                const void* sig,
-                const size_t sig_len);
-
-} // namespace crypto
-} // namespace isc
-
-#endif // _ISC_CRYPTO_H
diff --git a/src/lib/crypto/tests/Makefile.am b/src/lib/crypto/tests/Makefile.am
deleted file mode 100644
index 1777f2b..0000000
--- a/src/lib/crypto/tests/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-SUBDIRS = .
-
-AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
-AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CXXFLAGS = $(B10_CXXFLAGS)
-
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-endif
-
-CLEANFILES = *.gcno *.gcda
-
-TESTS =
-if HAVE_GTEST
-TESTS += run_unittests
-run_unittests_SOURCES = run_unittests.cc
-run_unittests_SOURCES += crypto_unittests.cc
-run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/crypto/libb10crypto.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-endif
-
-noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/crypto/tests/crypto_unittests.cc b/src/lib/crypto/tests/crypto_unittests.cc
deleted file mode 100644
index f81c02b..0000000
--- a/src/lib/crypto/tests/crypto_unittests.cc
+++ /dev/null
@@ -1,426 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <gtest/gtest.h>
-
-#include <crypto/crypto.h>
-#include <dns/buffer.h>
-#include <exceptions/exceptions.h>
-
-using namespace isc::dns;
-using namespace isc::crypto;
-
-namespace {
-    void checkData(const uint8_t* data1, const uint8_t* data2, size_t len) {
-        for (size_t i = 0; i < len; ++i) {
-            ASSERT_EQ(data1[i], data2[i]);
-        }
-    }
-
-    void checkBuffer(const OutputBuffer& buf, const uint8_t* data,
-                     size_t len)
-    {
-        ASSERT_EQ(len, buf.getLength());
-        checkData(static_cast<const uint8_t*>(buf.getData()), data, len);
-    }
-
-    // Sign and verify with the convenience functions
-    void doHMACTestConv(const std::string& data,
-                        const void* secret,
-                        size_t secret_len,
-                        const HMAC::HashAlgorithm hash_algorithm,
-                        const uint8_t* expected_hmac,
-                        size_t hmac_len) {
-        OutputBuffer data_buf(data.size());
-        data_buf.writeData(data.c_str(), data.size());
-        OutputBuffer hmac_sig(0);
-
-        // Sign it
-        signHMAC(data_buf.getData(), data_buf.getLength(),
-                 secret, secret_len, hash_algorithm, hmac_sig, hmac_len);
-
-        // Check if the signature is what we expect
-        checkBuffer(hmac_sig, expected_hmac, hmac_len);
-
-        // Check whether we can verify it ourselves
-        EXPECT_TRUE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
-                               secret, secret_len, hash_algorithm,
-                               hmac_sig.getData(),
-                               hmac_sig.getLength()));
-
-        // Change the sig by flipping the first octet, and check
-        // whether verification fails then
-        hmac_sig.writeUint8At(~hmac_sig[0], 0);
-        EXPECT_FALSE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
-                               secret, secret_len, hash_algorithm,
-                               hmac_sig.getData(),
-                               hmac_sig.getLength()));
-    }
-
-    // Sign and verify with an instantiation of an HMAC object
-    void doHMACTestDirect(const std::string& data,
-                          const void* secret,
-                          size_t secret_len,
-                          const HMAC::HashAlgorithm hash_algorithm,
-                          const uint8_t* expected_hmac,
-                          size_t hmac_len) {
-        OutputBuffer data_buf(data.size());
-        data_buf.writeData(data.c_str(), data.size());
-        OutputBuffer hmac_sig(1);
-
-        // Sign it
-        HMAC hmac_sign(secret, secret_len, hash_algorithm);
-        hmac_sign.update(data_buf.getData(), data_buf.getLength());
-        hmac_sign.sign(hmac_sig, hmac_len);
-
-        // Check if the signature is what we expect
-        checkBuffer(hmac_sig, expected_hmac, hmac_len);
-
-        // Check whether we can verify it ourselves
-        HMAC hmac_verify(secret, secret_len, hash_algorithm);
-        hmac_verify.update(data_buf.getData(), data_buf.getLength());
-        EXPECT_TRUE(hmac_verify.verify(hmac_sig.getData(),
-                                       hmac_sig.getLength()));
-
-        // Change the sig by flipping the first octet, and check
-        // whether verification fails then
-        hmac_sig.writeUint8At(~hmac_sig[0], 0);
-        EXPECT_FALSE(hmac_verify.verify(hmac_sig.getData(),
-                                        hmac_sig.getLength()));
-    }
-
-    void doHMACTestVector(const std::string& data,
-                          const void* secret,
-                          size_t secret_len,
-                          const HMAC::HashAlgorithm hash_algorithm,
-                          const uint8_t* expected_hmac,
-                          size_t hmac_len) {
-        HMAC hmac_sign(secret, secret_len, hash_algorithm);
-        hmac_sign.update(data.c_str(), data.size());
-        std::vector<uint8_t> sig = hmac_sign.sign(hmac_len);
-        ASSERT_EQ(hmac_len, sig.size());
-        checkData(&sig[0], expected_hmac, hmac_len);
-
-        HMAC hmac_verify(secret, secret_len, hash_algorithm);
-        hmac_verify.update(data.c_str(), data.size());
-        EXPECT_TRUE(hmac_verify.verify(&sig[0], sig.size()));
-
-        sig[0] = ~sig[0];
-        EXPECT_FALSE(hmac_verify.verify(&sig[0], sig.size()));
-    }
-
-    void doHMACTestArray(const std::string& data,
-                         const void* secret,
-                         size_t secret_len,
-                         const HMAC::HashAlgorithm hash_algorithm,
-                         const uint8_t* expected_hmac,
-                         size_t hmac_len) {
-        HMAC hmac_sign(secret, secret_len, hash_algorithm);
-        hmac_sign.update(data.c_str(), data.size());
-
-        uint8_t sig[hmac_len];
-
-        hmac_sign.sign(sig, hmac_len);
-        checkData(sig, expected_hmac, hmac_len);
-
-        HMAC hmac_verify(secret, secret_len, hash_algorithm);
-        hmac_verify.update(data.c_str(), data.size());
-        EXPECT_TRUE(hmac_verify.verify(sig, hmac_len));
-
-        sig[0] = ~sig[0];
-        EXPECT_FALSE(hmac_verify.verify(sig, hmac_len));
-    }
-
-    void doHMACTest(const std::string& data,
-                    const void* secret,
-                    size_t secret_len,
-                    const HMAC::HashAlgorithm hash_algorithm,
-                    const uint8_t* expected_hmac,
-                    size_t hmac_len) {
-        doHMACTestConv(data, secret, secret_len, hash_algorithm,
-                       expected_hmac, hmac_len);
-        doHMACTestDirect(data, secret, secret_len, hash_algorithm,
-                         expected_hmac, hmac_len);
-        doHMACTestVector(data, secret, secret_len, hash_algorithm,
-                         expected_hmac, hmac_len);
-        doHMACTestArray(data, secret, secret_len, hash_algorithm,
-                        expected_hmac, hmac_len);
-    }
-}
-
-//
-// Test values taken from RFC 2202
-//
-TEST(CryptoTest, HMAC_MD5_RFC2202_SIGN) {
-    uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-                         0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-                         0x0b, 0x0b };
-    uint8_t hmac_expected[] = { 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38,
-                                0xbb, 0x1c, 0x13, 0xf4, 0x8e, 0xf8,
-                                0x15, 0x8b, 0xfc, 0x9d };
-    doHMACTest("Hi There", secret, 16, HMAC::MD5, hmac_expected, 16);
-
-    uint8_t hmac_expected2[] = { 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0,
-                                 0xb5, 0x03, 0xea, 0xa8, 0x6e, 0x31,
-                                 0x0a, 0x5d, 0xb7, 0x38 };
-    doHMACTest("what do ya want for nothing?", "Jefe", 4, HMAC::MD5,
-               hmac_expected2, 16);
-
-    std::string data3;
-    for (int i = 0; i < 50; ++i) {
-        data3.push_back(0xdd);
-    }
-    uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-                          0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-                          0xaa, 0xaa };
-    uint8_t hmac_expected3[] = { 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14,
-                                 0x4c, 0x88, 0xdb, 0xb8, 0xc7, 0x33,
-                                 0xf0, 0xe8, 0xb3, 0xf6};
-    doHMACTest(data3, secret3, 16, HMAC::MD5, hmac_expected3, 16);
-
-    std::string data4;
-    for (int i = 0; i < 50; ++i) {
-        data4.push_back(0xcd);
-    }
-    uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-                          0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-                          0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
-                          0x16, 0x17, 0x18, 0x19 };
-    uint8_t hmac_expected4[] = { 0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a,
-                                 0x3a, 0xea, 0x3a, 0x75, 0x16, 0x47,
-                                 0x46, 0xff, 0xaa, 0x79 };
-    doHMACTest(data4, secret4, 25, HMAC::MD5, hmac_expected4, 16);
-
-    uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-                          0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-                          0x0c, 0x0c };
-    uint8_t hmac_expected5[] = { 0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e,
-                                 0xdc, 0x00, 0xf9, 0xba, 0xb9, 0x95,
-                                 0x69, 0x0e, 0xfd, 0x4c };
-    doHMACTest("Test With Truncation", secret5, 16, HMAC::MD5,
-               hmac_expected5, 16);
-    doHMACTest("Test With Truncation", secret5, 16, HMAC::MD5,
-               hmac_expected5, 12);
-
-    std::string secret6;
-    for (int i = 0; i < 80; ++i) {
-        secret6.push_back(0xaa);
-    }
-    uint8_t hmac_expected6[] = { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7,
-                                 0xbf, 0x8f, 0x0b, 0x62, 0xe6, 0xce,
-                                 0x61, 0xb9, 0xd0, 0xcd };
-    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
-               secret6.c_str(), 80, HMAC::MD5, hmac_expected6, 16);
-
-    // same secret as for test 6
-    uint8_t hmac_expected7[] = { 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd,
-                                 0xa0, 0xee, 0x1f, 0xb1, 0xf5, 0x62,
-                                 0xdb, 0x3a, 0xa5, 0x3e };
-    doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
-               "One Block-Size Data",
-               secret6.c_str(), 80, HMAC::MD5, hmac_expected7, 16);
-}
-
-//
-// Test values taken from RFC 2202
-//
-TEST(CryptoTest, HMAC_SHA1_RFC2202_SIGN) {
-    uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-                         0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-                         0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
-    uint8_t hmac_expected[] = { 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05,
-                                0x72, 0x64, 0xe2, 0x8b, 0xc0, 0xb6,
-                                0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46,
-                                0xbe, 0x00 };
-    doHMACTest("Hi There", secret, 20, HMAC::SHA1, hmac_expected, 20);
-
-    uint8_t hmac_expected2[] = { 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb,
-                                 0x2f, 0xa2, 0xd2, 0x74, 0x16, 0xd5,
-                                 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a,
-                                 0x7c, 0x79 };
-    doHMACTest("what do ya want for nothing?", "Jefe", 4, HMAC::SHA1,
-               hmac_expected2, 20);
-
-    std::string data3;
-    for (int i = 0; i < 50; ++i) {
-        data3.push_back(0xdd);
-    }
-    uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-                          0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-                          0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
-    uint8_t hmac_expected3[] = { 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac,
-                                 0x11, 0xcd, 0x91, 0xa3, 0x9a, 0xf4,
-                                 0x8a, 0xa1, 0x7b, 0x4f, 0x63, 0xf1,
-                                 0x75, 0xd3 };
-    doHMACTest(data3, secret3, 20, HMAC::SHA1, hmac_expected3, 20);
-
-    std::string data4;
-    for (int i = 0; i < 50; ++i) {
-        data4.push_back(0xcd);
-    }
-    uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-                          0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-                          0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
-                          0x16, 0x17, 0x18, 0x19 };
-    uint8_t hmac_expected4[] = { 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62,
-                                 0x50, 0xc6, 0xbc, 0x84, 0x14, 0xf9,
-                                 0xbf, 0x50, 0xc8, 0x6c, 0x2d, 0x72,
-                                 0x35, 0xda };
-    doHMACTest(data4, secret4, 25, HMAC::SHA1, hmac_expected4, 20);
-
-    uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-                          0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-                          0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c };
-    uint8_t hmac_expected5[] = { 0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55,
-                                 0xe0, 0x7f, 0xe7, 0xf2, 0x7b, 0xe1,
-                                 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a,
-                                 0x5a, 0x04 };
-    doHMACTest("Test With Truncation", secret5, 20, HMAC::SHA1,
-               hmac_expected5, 20);
-    doHMACTest("Test With Truncation", secret5, 20, HMAC::SHA1,
-               hmac_expected5, 12);
-
-    std::string secret6;
-    for (int i = 0; i < 80; ++i) {
-        secret6.push_back(0xaa);
-    }
-    uint8_t hmac_expected6[] = { 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72,
-                                 0xd0, 0x0e, 0x95, 0x70, 0x56, 0x37,
-                                 0xce, 0x8a, 0x3b, 0x55, 0xed, 0x40,
-                                 0x21, 0x12 };
-    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
-               secret6.c_str(), 80, HMAC::SHA1, hmac_expected6, 20);
-
-    // same secret as for test 6
-    uint8_t hmac_expected7[] = { 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23,
-                                 0x7d, 0x78, 0x6d, 0x6b, 0xba, 0xa7,
-                                 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff,
-                                 0x1a, 0x91 };
-    doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
-               "One Block-Size Data",
-               secret6.c_str(), 80, HMAC::SHA1, hmac_expected7, 20);
-}
-
-//
-// Test values taken from RFC 4231
-//
-TEST(CryptoTest, HMAC_SHA256_RFC2202_SIGN) {
-    uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-                         0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-                         0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
-    uint8_t hmac_expected[] = { 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb,
-                                0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce,
-                                0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d,
-                                0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
-                                0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32,
-                                0xcf, 0xf7 };
-    doHMACTest("Hi There", secret, 20, HMAC::SHA256, hmac_expected, 32);
-
-    uint8_t hmac_expected2[] = { 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60,
-                                 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26,
-                                 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00,
-                                 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
-                                 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec,
-                                 0x38, 0x43 };
-    doHMACTest("what do ya want for nothing?", "Jefe", 4, HMAC::SHA256,
-               hmac_expected2, 32);
-
-    std::string data3;
-    for (int i = 0; i < 50; ++i) {
-        data3.push_back(0xdd);
-    }
-    uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-                          0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-                          0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
-    uint8_t hmac_expected3[] = { 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80,
-                                 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb,
-                                 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59,
-                                 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
-                                 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5,
-                                 0x65, 0xfe };
-    doHMACTest(data3, secret3, 20, HMAC::SHA256, hmac_expected3, 32);
-
-    std::string data4;
-    for (int i = 0; i < 50; ++i) {
-        data4.push_back(0xcd);
-    }
-    uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-                          0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-                          0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
-                          0x16, 0x17, 0x18, 0x19 };
-    uint8_t hmac_expected4[] = { 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44,
-                                 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98,
-                                 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0,
-                                 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
-                                 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29,
-                                 0x66, 0x5b };
-    doHMACTest(data4, secret4, 25, HMAC::SHA256, hmac_expected4, 32);
-
-    uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-                          0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-                          0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c };
-    uint8_t hmac_expected5[] = { 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10,
-                                 0x0e, 0xe0, 0x6e, 0x0c, 0x79, 0x6c,
-                                 0x29, 0x55, 0x55, 0x2b };
-    doHMACTest("Test With Truncation", secret5, 20, HMAC::SHA256,
-               hmac_expected5, 16);
-
-    std::string secret6;
-    for (int i = 0; i < 131; ++i) {
-        secret6.push_back(0xaa);
-    }
-    uint8_t hmac_expected6[] = { 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0,
-                                 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa,
-                                 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b,
-                                 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
-                                 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3,
-                                 0x7f, 0x54 };
-    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
-               secret6.c_str(), 131, HMAC::SHA256, hmac_expected6, 32);
-
-    // Same secret as test 6
-    uint8_t hmac_expected7[] = { 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94,
-                                 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc,
-                                 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc,
-                                 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
-                                 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a,
-                                 0x35, 0xe2 };
-    doHMACTest("This is a test using a larger than block-size key and a"
-               " larger than block-size data. The key needs to be hashe"
-               "d before being used by the HMAC algorithm.",
-               secret6.c_str(), 131, HMAC::SHA256, hmac_expected7, 32);
-}
-
-TEST(CryptoTest, BadKey) {
-    OutputBuffer data_buf(0);
-    OutputBuffer hmac_sig(0);
-
-    EXPECT_THROW(new HMAC(NULL, 0, HMAC::MD5), BadKey);
-    EXPECT_THROW(new HMAC(NULL, 0, HMAC::UNKNOWN), UnsupportedAlgorithm);
-
-    EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
-                          NULL, 0, HMAC::MD5, hmac_sig), BadKey);
-    EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
-                          NULL, 0, HMAC::UNKNOWN, hmac_sig),
-                          UnsupportedAlgorithm);
-
-    EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
-                            NULL, 0, HMAC::MD5, hmac_sig.getData(),
-                            hmac_sig.getLength()), BadKey);
-    EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
-                            NULL, 0, HMAC::UNKNOWN, hmac_sig.getData(),
-                            hmac_sig.getLength()),
-                            UnsupportedAlgorithm);
-}
diff --git a/src/lib/crypto/tests/run_unittests.cc b/src/lib/crypto/tests/run_unittests.cc
deleted file mode 100644
index b8f0508..0000000
--- a/src/lib/crypto/tests/run_unittests.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <gtest/gtest.h>
-
-#include <dns/tests/unittest_util.h>
-#include <crypto/crypto.h>
-
-int
-main(int argc, char* argv[]) {
-    ::testing::InitGoogleTest(&argc, argv);
-    isc::crypto::Crypto crypto;
-
-    return (RUN_ALL_TESTS());
-}
diff --git a/src/lib/cryptolink/Makefile.am b/src/lib/cryptolink/Makefile.am
new file mode 100644
index 0000000..e12a147
--- /dev/null
+++ b/src/lib/cryptolink/Makefile.am
@@ -0,0 +1,12 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+lib_LTLIBRARIES = libcryptolink.la
+
+libcryptolink_la_SOURCES = crypto.h crypto.cc
+libcryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc
diff --git a/src/lib/cryptolink/crypto.cc b/src/lib/cryptolink/crypto.cc
new file mode 100644
index 0000000..64969e5
--- /dev/null
+++ b/src/lib/cryptolink/crypto.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "crypto.h"
+
+#include <botan/botan.h>
+#include <botan/hmac.h>
+#include <botan/hash.h>
+#include <botan/types.h>
+
+#include <dns/buffer.h>
+#include <dns/name.h>
+#include <dns/util/base64.h>
+
+#include <string>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <iostream>
+
+using namespace std;
+using namespace isc::dns;
+
+
+namespace isc {
+namespace cryptolink {
+
+// For Botan, we use the CryptoLink class object in RAII style
+class CryptoLinkImpl {
+private:
+    Botan::LibraryInitializer _botan_init;
+};
+
+CryptoLink::~CryptoLink() {
+    delete impl_;
+}
+
+CryptoLink&
+CryptoLink::getCryptoLink() {
+    CryptoLink &c = getCryptoLinkInternal();
+    if (!c.impl_) {
+        c.initialize();
+    }
+    return c;
+}
+
+CryptoLink&
+CryptoLink::getCryptoLinkInternal() {
+    static CryptoLink instance;
+    return (instance);
+}
+
+void
+CryptoLink::initialize() {
+    CryptoLink& c = getCryptoLinkInternal();
+    if (!c.impl_) {
+        try {
+            c.impl_ = new CryptoLinkImpl();
+        } catch (const Botan::Exception& ex) {
+            isc_throw(InitializationError, ex.what());
+        }
+    }
+}
+
+HMAC*
+CryptoLink::createHMAC(const void* secret, size_t secret_len,
+                   const HMAC::HashAlgorithm hash_algorithm) {
+    return (new HMAC(secret, secret_len, hash_algorithm));
+}
+
+} // namespace cryptolink
+} // namespace isc
+
diff --git a/src/lib/cryptolink/crypto.h b/src/lib/cryptolink/crypto.h
new file mode 100644
index 0000000..208d37a
--- /dev/null
+++ b/src/lib/cryptolink/crypto.h
@@ -0,0 +1,165 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef _ISC_CRYPTO_H
+#define _ISC_CRYPTO_H
+
+#include <string>
+#include <dns/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <cryptolink/crypto_hmac.h>
+
+
+namespace isc {
+namespace cryptolink {
+
+/// General exception class that is the base for all crypto-related
+/// exceptions
+class CryptoLinkError : public Exception {
+public:
+    CryptoLinkError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// This exception is thrown if there was a problem initializing the
+/// crypto library
+class InitializationError : public CryptoLinkError {
+public:
+    InitializationError(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when a cryptographic action is requested
+/// for an algorithm that is not supported by the underlying library.
+class UnsupportedAlgorithm : public CryptoLinkError {
+public:
+    UnsupportedAlgorithm(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when the underlying library could not
+/// handle the key data.
+class BadKey : public CryptoLinkError {
+public:
+    BadKey(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is raised when a general error that was not
+/// specifically caught is thrown by the underlying library. It
+/// is replaced by this one so as not have 'external' exceptions
+/// bubbling up
+class LibraryError : public CryptoLinkError {
+public:
+    LibraryError(const char* file, size_t line, const char* what) :
+        CryptoLinkError(file, line, what) {}
+};
+
+/// Forward declaration for pimpl
+class CryptoLinkImpl;
+
+/// \brief 
+///
+/// This is singleton class that serves as the entry point to
+/// the underlying cryptography library, and as a factory for objects
+/// within the cryptolink library.
+///
+/// There is only one way to access it, through getCryptoLink(), which
+/// returns a reference to the initialized library. On the first call,
+/// it will be initialized automatically. You can however initialize it
+/// manually through a call to the initalize(), before your first call
+/// to getCryptoLink. Any subsequent call to initialize() will be a
+/// noop.
+///
+/// \note All other classes within cryptolink should have private
+/// constructors as well, and should have a factory function from this
+/// class.
+///
+// Internal note: we can use this class later to initialize and manage
+// dynamic (PKCS#11) libs
+class CryptoLink : private boost::noncopyable {
+public:
+    /// \brief Returns a reference to the singleton instance
+    ///
+    /// If the library has not been initialized yet, it will be
+    /// initialized with some default values.
+    ///
+    /// Since this class is noncopyable, you must use the return
+    /// value directly, or store it in a reference variable.
+    ///
+    /// \exception InitializationError if initialization fails
+    ///
+    /// \return Reference to the singleton instance
+    static CryptoLink& getCryptoLink();
+
+    /// \brief Initialize the library manually
+    ///
+    /// If the library has already been initialized (either by a call
+    /// to initialize() or automatically in getCryptoLink()), this
+    /// function does nothing.
+    ///
+    /// \note A call to initialize() is not strictly necessary with
+    /// the current implementation.
+    ///
+    /// \exception InitializationError if initialization fails
+    ///
+    static void initialize();
+
+    /// \brief Factory function for HMAC objects
+    ///
+    /// CryptoLink objects cannot be constructed directly. This
+    /// function creates a new HMAC object usable for signing or
+    /// verification.
+    ///
+    /// The caller is responsible for deleting the object, and it is
+    /// therefore highly recommended to place the return value of this
+    /// function in a scoped_ptr or shared_ptr.
+    ///
+    /// Notes: if the secret is longer than the block size of its
+    /// algorithm, the constructor will run it through the hash
+    /// algorithm, and use the digest as the secret for this HMAC
+    /// operation
+    ///
+    /// \exception UnsupportedAlgorithmException if the given algorithm
+    ///            is unknown or not supported by the underlying library
+    /// \exception InvalidKeyLength if the given key secret_len is bad
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param secret The secret to sign with
+    /// \param secret_len The length of the secret
+    /// \param hash_algorithm The hash algorithm
+    HMAC* createHMAC(const void* secret, size_t secret_len,
+                     const HMAC::HashAlgorithm hash_algorithm);
+
+private:
+    // To enable us to use an optional explicit initialization call,
+    // the 'real' instance getter is private
+    static CryptoLink& getCryptoLinkInternal();
+
+    // To prevent people constructing their own, we make the constructor
+    // private too.
+    CryptoLink() : impl_(NULL) {};
+    ~CryptoLink();
+
+    CryptoLinkImpl* impl_;
+};
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // _ISC_CRYPTO_H
diff --git a/src/lib/cryptolink/crypto_hmac.cc b/src/lib/cryptolink/crypto_hmac.cc
new file mode 100644
index 0000000..dea8571
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.cc
@@ -0,0 +1,218 @@
+
+#include <crypto.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <botan/botan.h>
+#include <botan/hmac.h>
+#include <botan/hash.h>
+#include <botan/types.h>
+
+namespace {
+const char*
+getBotanHashAlgorithmName(isc::cryptolink::HMAC::HashAlgorithm algorithm) {
+    switch (algorithm) {
+    case isc::cryptolink::HMAC::MD5:
+        return ("MD5");
+        break;
+    case isc::cryptolink::HMAC::SHA1:
+        return ("SHA-1");
+        break;
+    case isc::cryptolink::HMAC::SHA256:
+        return ("SHA-256");
+        break;
+    case isc::cryptolink::HMAC::UNKNOWN:
+        return ("Unknown");
+        break;
+    }
+    // compiler should have prevented us to reach this, since we have
+    // no default. But we need a return value anyway
+    return ("Unknown");
+}
+
+} // local namespace
+
+
+namespace isc {
+namespace cryptolink {
+
+class HMACImpl {
+public:
+    explicit HMACImpl(const void* secret, size_t secret_len,
+                      const HMAC::HashAlgorithm hash_algorithm) {
+        Botan::HashFunction* hash;
+        try {
+            hash = Botan::get_hash(
+                getBotanHashAlgorithmName(hash_algorithm));
+        } catch (const Botan::Algorithm_Not_Found&) {
+            isc_throw(isc::cryptolink::UnsupportedAlgorithm,
+                      "Unknown hash algorithm: " + hash_algorithm);
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+
+        hmac_.reset(new Botan::HMAC::HMAC(hash));
+
+        // If the key length is larger than the block size, we hash the
+        // key itself first.
+        try {
+            if (secret_len > hash->HASH_BLOCK_SIZE) {
+                Botan::SecureVector<Botan::byte> hashed_key =
+                    hash->process(static_cast<const Botan::byte*>(secret),
+                                  secret_len);
+                hmac_->set_key(hashed_key.begin(), hashed_key.size());
+            } else {
+                hmac_->set_key(static_cast<const Botan::byte*>(secret),
+                               secret_len);
+            }
+        } catch (const Botan::Invalid_Key_Length& ikl) {
+            isc_throw(BadKey, ikl.what());
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    ~HMACImpl() { }
+
+    size_t getOutputLength() const {
+        return (hmac_->OUTPUT_LENGTH);
+    }
+
+    void update(const void* data, const size_t len) {
+        try {
+            hmac_->update(static_cast<const Botan::byte*>(data), len);
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    void sign(isc::dns::OutputBuffer& result, size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+    
+            if (len == 0 || len > b_result.size()) {
+                len = b_result.size();
+            }
+            result.writeData(b_result.begin(), len);
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    void sign(void* result, size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+            size_t output_size = getOutputLength();
+            if (output_size > len) {
+                output_size = len;
+            }
+            memcpy(result, b_result.begin(), output_size);
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+    std::vector<uint8_t> sign(size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+            if (len == 0 || len > b_result.size()) {
+                return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
+            } else {
+                return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
+            }
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+
+    bool verify(const void* sig, size_t len) {
+        // Botan's verify_mac checks if len matches the output_length,
+        // which causes it to fail for truncated signatures, so we do
+        // the check ourselves
+        try {
+            Botan::SecureVector<Botan::byte> our_mac = hmac_->final();
+            if (len == 0 || len > getOutputLength()) {
+                len = getOutputLength();
+            }
+            return (Botan::same_mem(&our_mac[0],
+                                    static_cast<const unsigned char*>(sig),
+                                    len));
+        } catch (const Botan::Exception& exc) {
+            isc_throw(isc::cryptolink::LibraryError, exc.what());
+        }
+    }
+
+private:
+    boost::scoped_ptr<Botan::HMAC> hmac_;
+};
+
+HMAC::HMAC(const void* secret, size_t secret_length,
+           const HashAlgorithm hash_algorithm)
+{
+    impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
+}
+
+HMAC::~HMAC() {
+    delete impl_;
+}
+
+size_t
+HMAC::getOutputLength() const {
+    return (impl_->getOutputLength());
+}
+
+void
+HMAC::update(const void* data, const size_t len) {
+    impl_->update(data, len);
+}
+
+void
+HMAC::sign(isc::dns::OutputBuffer& result, size_t len) {
+    impl_->sign(result, len);
+}
+
+void
+HMAC::sign(void* result, size_t len) {
+    impl_->sign(result, len);
+}
+
+std::vector<uint8_t>
+HMAC::sign(size_t len) {
+    return impl_->sign(len);
+}
+
+bool
+HMAC::verify(const void* sig, const size_t len) {
+    return (impl_->verify(sig, len));
+}
+
+void
+signHMAC(const void* data, size_t data_len, const void* secret,
+         size_t secret_len, const HMAC::HashAlgorithm hash_algorithm,
+         isc::dns::OutputBuffer& result, size_t len)
+{
+    boost::scoped_ptr<HMAC> hmac(
+        CryptoLink::getCryptoLink().createHMAC(secret,
+                                               secret_len,
+                                               hash_algorithm));
+    hmac->update(data, data_len);
+    hmac->sign(result, len);
+}
+
+
+bool
+verifyHMAC(const void* data, const size_t data_len, const void* secret,
+           size_t secret_len, const HMAC::HashAlgorithm hash_algorithm,
+           const void* sig, const size_t sig_len)
+{
+    boost::scoped_ptr<HMAC> hmac(
+        CryptoLink::getCryptoLink().createHMAC(secret,
+                                               secret_len,
+                                               hash_algorithm));
+    hmac->update(data, data_len);
+    return (hmac->verify(sig, sig_len));
+}
+
+} // namespace cryptolink
+} // namespace isc
diff --git a/src/lib/cryptolink/crypto_hmac.h b/src/lib/cryptolink/crypto_hmac.h
new file mode 100644
index 0000000..57f6626
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.h
@@ -0,0 +1,222 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string>
+#include <dns/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <cryptolink/crypto.h>
+
+#ifndef _ISC_CRYPTO_HMAC_H
+#define _ISC_CRYPTO_HMAC_H
+
+namespace isc {
+namespace cryptolink {
+
+/// Forward declaration, pimpl style
+class HMACImpl;
+
+/// \brief HMAC support
+///
+/// This class is used to create and verify HMAC signatures. Instances
+/// can be created with CryptoLink::createHMAC()
+///
+class HMAC : private boost::noncopyable {
+public:
+    enum HashAlgorithm {
+        MD5 = 0,            ///< MD5
+        SHA1 = 1,           ///< SHA-1
+        SHA256 = 2,         ///< SHA-256
+        UNKNOWN = 3         ///< This value can be used in conversion
+                            ///  functions, to be returned when the
+                            ///  input is unknown (but a value MUST be
+                            ///  returned), for instance when the input
+                            ///  is a Name or a string, and the return
+                            ///  value is a HashAlgorithm.
+    };
+
+private:
+    /// Since HMAC objects cannot be created directly, the factory
+    /// class CryptoLink is a friend
+    friend class CryptoLink;
+
+    /// \brief Constructor from a secret and a hash algorithm
+    ///
+    /// \exception UnsupportedAlgorithmException if the given algorithm
+    ///            is unknown or not supported by the underlying library
+    /// \exception InvalidKeyLength if the given key secret_len is bad
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// Notes: if the secret is longer than the block size of its
+    /// algorithm, the constructor will run it through the hash
+    /// algorithm, and use the digest as the secret for this HMAC
+    /// operation
+    ///
+    /// \param secret The secret to sign with
+    /// \param len The length of the secret
+    /// \param hash_algorithm The hash algorithm
+    HMAC(const void* secret, size_t secret_len,
+         const HashAlgorithm hash_algorithm);
+
+public:
+    /// \brief Destructor
+    ~HMAC();
+
+    /// \brief Returns the output size of the digest
+    ///
+    /// \return output size of the digest
+    size_t getOutputLength() const;
+
+    /// \brief Add data to digest
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param data The data to add
+    /// \param len The size of the data
+    void update(const void* data, const size_t len);
+
+    /// \brief Calculate the final signature
+    ///
+    /// The result will be appended to the given outputbuffer
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param result The OutputBuffer to append the result to
+    /// \param len The number of bytes from the result to copy. If this
+    ///        value is smaller than the algorithms output size, the
+    ///        result will be truncated. If this value is larger, or 0
+    ///        (the default), it will be ignored
+    void sign(isc::dns::OutputBuffer& result, size_t len = 0);
+
+    /// \brief Calculate the final signature
+    ///
+    /// len bytes of data from the result will be copied to *result
+    /// If len is larger than the output size, only output_size bytes
+    /// will be copied. If it is smaller, the output will be truncated
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// At least len bytes of data must be available for writing at
+    /// result
+    void sign(void* result, size_t len);
+
+    /// \brief Calculate the final signatre
+    ///
+    /// The result will be returned as a std::vector<uint8_t>
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param len The number of bytes from the result to copy. If this
+    ///        value is smaller than the algorithms output size, the
+    ///        result will be truncated. If this value is larger, or 0
+    ///        (the default), it will be ignored
+    /// \return a vector containing the signature
+    std::vector<uint8_t> sign(size_t len = 0);
+
+    /// \brief Verify an existing signature
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param sig The signature to verify
+    /// \param len The length of the signature. If this is non-zero,
+    ///            and smaller than the output length of the algorithm,
+    ///            only len bytes will be checked
+    /// \return true if the signature is correct, false otherwise
+    bool verify(const void* sig, size_t len);
+
+private:
+    HMACImpl* impl_;
+};
+
+/// \brief Create an HMAC signature for the given data
+///
+/// This is a convenience function that calculates the hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and calculating the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+///            or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+///                         in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to sign
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param result The signature will be appended to this buffer
+/// \param len If this is non-zero and less than the output size,
+///            the result will be truncated to len bytes
+void signHMAC(const void* data,
+              const size_t data_len,
+              const void* secret,
+              size_t secret_len,
+              const HMAC::HashAlgorithm hash_algorithm,
+              isc::dns::OutputBuffer& result,
+              size_t len = 0);
+
+/// \brief Verify an HMAC signature for the given data
+///
+/// This is a convenience function that verifies an hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and checking the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+///            or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+///                         in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to verify
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param sig The signature to verify
+/// \param sig_len The length of the signature
+/// \return True if the signature verifies, false if not
+bool verifyHMAC(const void* data,
+                const size_t data_len,
+                const void* secret,
+                size_t secret_len,
+                const HMAC::HashAlgorithm hash_algorithm,
+                const void* sig,
+                const size_t sig_len);
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // __ISC_CRYPTO_HMAC
+
diff --git a/src/lib/cryptolink/tests/Makefile.am b/src/lib/cryptolink/tests/Makefile.am
new file mode 100644
index 0000000..3936072
--- /dev/null
+++ b/src/lib/cryptolink/tests/Makefile.am
@@ -0,0 +1,26 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += crypto_unittests.cc
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libcryptolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/cryptolink/tests/crypto_unittests.cc b/src/lib/cryptolink/tests/crypto_unittests.cc
new file mode 100644
index 0000000..9b2a6af
--- /dev/null
+++ b/src/lib/cryptolink/tests/crypto_unittests.cc
@@ -0,0 +1,513 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <cryptolink/crypto.h>
+#include <dns/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/scoped_ptr.hpp>
+
+using namespace isc::dns;
+using namespace isc::cryptolink;
+
+namespace {
+    void checkData(const uint8_t* data, const uint8_t* expected,
+                   size_t len) {
+        for (size_t i = 0; i < len; ++i) {
+            ASSERT_EQ(expected[i], data[i]);
+        }
+    }
+
+    void checkBuffer(const OutputBuffer& buf, const uint8_t* expected,
+                     size_t len)
+    {
+        ASSERT_EQ(len, buf.getLength());
+        checkData(static_cast<const uint8_t*>(buf.getData()), expected,
+                  len);
+    }
+
+    // Sign and verify with the convenience functions
+    void doHMACTestConv(const std::string& data,
+                        const void* secret,
+                        size_t secret_len,
+                        const HMAC::HashAlgorithm hash_algorithm,
+                        const uint8_t* expected_hmac,
+                        size_t hmac_len) {
+        OutputBuffer data_buf(data.size());
+        data_buf.writeData(data.c_str(), data.size());
+        OutputBuffer hmac_sig(0);
+
+        // Sign it
+        signHMAC(data_buf.getData(), data_buf.getLength(),
+                 secret, secret_len, hash_algorithm, hmac_sig, hmac_len);
+
+        // Check if the signature is what we expect
+        checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+        // Check whether we can verify it ourselves
+        EXPECT_TRUE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                               secret, secret_len, hash_algorithm,
+                               hmac_sig.getData(),
+                               hmac_sig.getLength()));
+
+        // Change the sig by flipping the first octet, and check
+        // whether verification fails then
+        hmac_sig.writeUint8At(~hmac_sig[0], 0);
+        EXPECT_FALSE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                               secret, secret_len, hash_algorithm,
+                               hmac_sig.getData(),
+                               hmac_sig.getLength()));
+    }
+
+    // Sign and verify with an instantiation of an HMAC object
+    void doHMACTestDirect(const std::string& data,
+                          const void* secret,
+                          size_t secret_len,
+                          const HMAC::HashAlgorithm hash_algorithm,
+                          const uint8_t* expected_hmac,
+                          size_t hmac_len) {
+        OutputBuffer data_buf(data.size());
+        data_buf.writeData(data.c_str(), data.size());
+        OutputBuffer hmac_sig(1);
+        CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+        // Sign it
+        boost::scoped_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+                                                            secret_len,
+                                                            hash_algorithm));
+        hmac_sign->update(data_buf.getData(), data_buf.getLength());
+        hmac_sign->sign(hmac_sig, hmac_len);
+
+        // Check if the signature is what we expect
+        checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+        // Check whether we can verify it ourselves
+        boost::scoped_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+                                                              secret_len,
+                                                              hash_algorithm));
+        hmac_verify->update(data_buf.getData(), data_buf.getLength());
+        EXPECT_TRUE(hmac_verify->verify(hmac_sig.getData(),
+                                        hmac_sig.getLength()));
+
+        // Change the sig by flipping the first octet, and check
+        // whether verification fails then
+        hmac_sig.writeUint8At(~hmac_sig[0], 0);
+        EXPECT_FALSE(hmac_verify->verify(hmac_sig.getData(),
+                                        hmac_sig.getLength()));
+    }
+
+    void doHMACTestVector(const std::string& data,
+                          const void* secret,
+                          size_t secret_len,
+                          const HMAC::HashAlgorithm hash_algorithm,
+                          const uint8_t* expected_hmac,
+                          size_t hmac_len) {
+        CryptoLink& crypto = CryptoLink::getCryptoLink();
+        boost::scoped_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+                                                            secret_len,
+                                                            hash_algorithm));
+        hmac_sign->update(data.c_str(), data.size());
+        std::vector<uint8_t> sig = hmac_sign->sign(hmac_len);
+        ASSERT_EQ(hmac_len, sig.size());
+        checkData(&sig[0], expected_hmac, hmac_len);
+
+        boost::scoped_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+                                                              secret_len,
+                                                              hash_algorithm));
+        hmac_verify->update(data.c_str(), data.size());
+        EXPECT_TRUE(hmac_verify->verify(&sig[0], sig.size()));
+
+        sig[0] = ~sig[0];
+        EXPECT_FALSE(hmac_verify->verify(&sig[0], sig.size()));
+    }
+
+    void doHMACTestArray(const std::string& data,
+                         const void* secret,
+                         size_t secret_len,
+                         const HMAC::HashAlgorithm hash_algorithm,
+                         const uint8_t* expected_hmac,
+                         size_t hmac_len) {
+        CryptoLink& crypto = CryptoLink::getCryptoLink();
+        boost::scoped_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+                                                            secret_len,
+                                                            hash_algorithm));
+        hmac_sign->update(data.c_str(), data.size());
+
+        // note: this is not exception-safe, and will leak, but
+        // if there is an unexpected exception in the code below we
+        // have more important things to fix.
+        uint8_t* sig = new uint8_t[hmac_len];
+
+        hmac_sign->sign(sig, hmac_len);
+        checkData(sig, expected_hmac, hmac_len);
+
+        boost::scoped_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+                                                              secret_len,
+                                                              hash_algorithm));
+        hmac_verify->update(data.c_str(), data.size());
+        EXPECT_TRUE(hmac_verify->verify(sig, hmac_len));
+
+        sig[0] = ~sig[0];
+        EXPECT_FALSE(hmac_verify->verify(sig, hmac_len));
+
+        delete[] sig;
+    }
+
+    void doHMACTest(const std::string& data,
+                    const void* secret,
+                    size_t secret_len,
+                    const HMAC::HashAlgorithm hash_algorithm,
+                    const uint8_t* expected_hmac,
+                    size_t hmac_len) {
+        doHMACTestConv(data, secret, secret_len, hash_algorithm,
+                       expected_hmac, hmac_len);
+        doHMACTestDirect(data, secret, secret_len, hash_algorithm,
+                         expected_hmac, hmac_len);
+        doHMACTestVector(data, secret, secret_len, hash_algorithm,
+                         expected_hmac, hmac_len);
+        doHMACTestArray(data, secret, secret_len, hash_algorithm,
+                        expected_hmac, hmac_len);
+    }
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_MD5_RFC2202_SIGN) {
+    const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b };
+    const uint8_t hmac_expected[] = { 0x92, 0x94, 0x72, 0x7a, 0x36,
+                                      0x38, 0xbb, 0x1c, 0x13, 0xf4,
+                                      0x8e, 0xf8, 0x15, 0x8b, 0xfc,
+                                      0x9d };
+    doHMACTest("Hi There", secret, 16, HMAC::MD5, hmac_expected, 16);
+
+    const uint8_t hmac_expected2[] = { 0x75, 0x0c, 0x78, 0x3e, 0x6a,
+                                       0xb0, 0xb5, 0x03, 0xea, 0xa8,
+                                       0x6e, 0x31, 0x0a, 0x5d, 0xb7,
+                                       0x38 };
+    doHMACTest("what do ya want for nothing?", "Jefe", 4, HMAC::MD5,
+               hmac_expected2, 16);
+
+    const std::string data3(50, 0xdd);
+    const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa };
+    const uint8_t hmac_expected3[] = { 0x56, 0xbe, 0x34, 0x52, 0x1d,
+                                       0x14, 0x4c, 0x88, 0xdb, 0xb8,
+                                       0xc7, 0x33, 0xf0, 0xe8, 0xb3,
+                                       0xf6};
+    doHMACTest(data3, secret3, 16, HMAC::MD5, hmac_expected3, 16);
+
+    const std::string data4(50, 0xcd);
+    const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                                0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+                                0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+                                0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                                0x19 };
+    const uint8_t hmac_expected4[] = { 0x69, 0x7e, 0xaf, 0x0a, 0xca,
+                                       0x3a, 0x3a, 0xea, 0x3a, 0x75,
+                                       0x16, 0x47, 0x46, 0xff, 0xaa,
+                                       0x79 };
+    doHMACTest(data4, secret4, 25, HMAC::MD5, hmac_expected4, 16);
+
+    const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c };
+    const uint8_t hmac_expected5[] = { 0x56, 0x46, 0x1e, 0xf2, 0x34,
+                                       0x2e, 0xdc, 0x00, 0xf9, 0xba,
+                                       0xb9, 0x95, 0x69, 0x0e, 0xfd,
+                                       0x4c };
+    doHMACTest("Test With Truncation", secret5, 16, HMAC::MD5,
+               hmac_expected5, 16);
+    doHMACTest("Test With Truncation", secret5, 16, HMAC::MD5,
+               hmac_expected5, 12);
+
+    const std::string secret6(80, 0xaa);
+    const uint8_t hmac_expected6[] = { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b,
+                                       0xd7, 0xbf, 0x8f, 0x0b, 0x62,
+                                       0xe6, 0xce, 0x61, 0xb9, 0xd0,
+                                       0xcd };
+    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+               secret6.c_str(), 80, HMAC::MD5, hmac_expected6, 16);
+
+    // same secret as for test 6
+    const uint8_t hmac_expected7[] = { 0x6f, 0x63, 0x0f, 0xad, 0x67,
+                                       0xcd, 0xa0, 0xee, 0x1f, 0xb1,
+                                       0xf5, 0x62, 0xdb, 0x3a, 0xa5,
+                                       0x3e };
+    doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+               "One Block-Size Data",
+               secret6.c_str(), 80, HMAC::MD5, hmac_expected7, 16);
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_SHA1_RFC2202_SIGN) {
+    const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+    const uint8_t hmac_expected[] = { 0xb6, 0x17, 0x31, 0x86, 0x55,
+                                      0x05, 0x72, 0x64, 0xe2, 0x8b,
+                                      0xc0, 0xb6, 0xfb, 0x37, 0x8c,
+                                      0x8e, 0xf1, 0x46, 0xbe, 0x00 };
+    doHMACTest("Hi There", secret, 20, HMAC::SHA1, hmac_expected, 20);
+
+    const uint8_t hmac_expected2[] = { 0xef, 0xfc, 0xdf, 0x6a, 0xe5,
+                                       0xeb, 0x2f, 0xa2, 0xd2, 0x74,
+                                       0x16, 0xd5, 0xf1, 0x84, 0xdf,
+                                       0x9c, 0x25, 0x9a, 0x7c, 0x79 };
+    doHMACTest("what do ya want for nothing?", "Jefe", 4, HMAC::SHA1,
+               hmac_expected2, 20);
+
+    const std::string data3(50, 0xdd);
+    const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa };
+    const uint8_t hmac_expected3[] = { 0x12, 0x5d, 0x73, 0x42, 0xb9,
+                                       0xac, 0x11, 0xcd, 0x91, 0xa3,
+                                       0x9a, 0xf4, 0x8a, 0xa1, 0x7b,
+                                       0x4f, 0x63, 0xf1, 0x75, 0xd3 };
+    doHMACTest(data3, secret3, 20, HMAC::SHA1, hmac_expected3, 20);
+
+    const std::string data4(50, 0xcd);
+    const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                                0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+                                0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+                                0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                                0x19 };
+    const uint8_t hmac_expected4[] = { 0x4c, 0x90, 0x07, 0xf4, 0x02,
+                                       0x62, 0x50, 0xc6, 0xbc, 0x84,
+                                       0x14, 0xf9, 0xbf, 0x50, 0xc8,
+                                       0x6c, 0x2d, 0x72, 0x35, 0xda };
+    doHMACTest(data4, secret4, 25, HMAC::SHA1, hmac_expected4, 20);
+
+    const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c };
+    const uint8_t hmac_expected5[] = { 0x4c, 0x1a, 0x03, 0x42, 0x4b,
+                                       0x55, 0xe0, 0x7f, 0xe7, 0xf2,
+                                       0x7b, 0xe1, 0xd5, 0x8b, 0xb9,
+                                       0x32, 0x4a, 0x9a, 0x5a, 0x04 };
+    doHMACTest("Test With Truncation", secret5, 20, HMAC::SHA1,
+               hmac_expected5, 20);
+    doHMACTest("Test With Truncation", secret5, 20, HMAC::SHA1,
+               hmac_expected5, 12);
+
+    const std::string secret6(80, 0xaa);
+    const uint8_t hmac_expected6[] = { 0xaa, 0x4a, 0xe5, 0xe1, 0x52,
+                                       0x72, 0xd0, 0x0e, 0x95, 0x70,
+                                       0x56, 0x37, 0xce, 0x8a, 0x3b,
+                                       0x55, 0xed, 0x40, 0x21, 0x12 };
+    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+               secret6.c_str(), 80, HMAC::SHA1, hmac_expected6, 20);
+
+    // same secret as for test 6
+    const uint8_t hmac_expected7[] = { 0xe8, 0xe9, 0x9d, 0x0f, 0x45,
+                                       0x23, 0x7d, 0x78, 0x6d, 0x6b,
+                                       0xba, 0xa7, 0x96, 0x5c, 0x78,
+                                       0x08, 0xbb, 0xff, 0x1a, 0x91 };
+    doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+               "One Block-Size Data",
+               secret6.c_str(), 80, HMAC::SHA1, hmac_expected7, 20);
+}
+
+//
+// Test values taken from RFC 4231
+//
+TEST(CryptoLinkTest, HMAC_SHA256_RFC2202_SIGN) {
+    const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                               0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+    const uint8_t hmac_expected[] = { 0xb0, 0x34, 0x4c, 0x61, 0xd8,
+                                      0xdb, 0x38, 0x53, 0x5c, 0xa8,
+                                      0xaf, 0xce, 0xaf, 0x0b, 0xf1,
+                                      0x2b, 0x88, 0x1d, 0xc2, 0x00,
+                                      0xc9, 0x83, 0x3d, 0xa7, 0x26,
+                                      0xe9, 0x37, 0x6c, 0x2e, 0x32,
+                                      0xcf, 0xf7 };
+    doHMACTest("Hi There", secret, 20, HMAC::SHA256, hmac_expected, 32);
+
+    const uint8_t hmac_expected2[] = { 0x5b, 0xdc, 0xc1, 0x46, 0xbf,
+                                       0x60, 0x75, 0x4e, 0x6a, 0x04,
+                                       0x24, 0x26, 0x08, 0x95, 0x75,
+                                       0xc7, 0x5a, 0x00, 0x3f, 0x08,
+                                       0x9d, 0x27, 0x39, 0x83, 0x9d,
+                                       0xec, 0x58, 0xb9, 0x64, 0xec,
+                                       0x38, 0x43 };
+    doHMACTest("what do ya want for nothing?", "Jefe", 4, HMAC::SHA256,
+               hmac_expected2, 32);
+
+    const std::string data3(50, 0xdd);
+    const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+                                0xaa, 0xaa };
+    const uint8_t hmac_expected3[] = { 0x77, 0x3e, 0xa9, 0x1e, 0x36,
+                                       0x80, 0x0e, 0x46, 0x85, 0x4d,
+                                       0xb8, 0xeb, 0xd0, 0x91, 0x81,
+                                       0xa7, 0x29, 0x59, 0x09, 0x8b,
+                                       0x3e, 0xf8, 0xc1, 0x22, 0xd9,
+                                       0x63, 0x55, 0x14, 0xce, 0xd5,
+                                       0x65, 0xfe };
+    doHMACTest(data3, secret3, 20, HMAC::SHA256, hmac_expected3, 32);
+
+    const std::string data4(50, 0xcd);
+    const uint8_t secret4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                                0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+                                0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+                                0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                                0x19 };
+    const uint8_t hmac_expected4[] = { 0x82, 0x55, 0x8a, 0x38, 0x9a,
+                                       0x44, 0x3c, 0x0e, 0xa4, 0xcc,
+                                       0x81, 0x98, 0x99, 0xf2, 0x08,
+                                       0x3a, 0x85, 0xf0, 0xfa, 0xa3,
+                                       0xe5, 0x78, 0xf8, 0x07, 0x7a,
+                                       0x2e, 0x3f, 0xf4, 0x67, 0x29,
+                                       0x66, 0x5b };
+    doHMACTest(data4, secret4, 25, HMAC::SHA256, hmac_expected4, 32);
+
+    const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+                                0x0c, 0x0c };
+    const uint8_t hmac_expected5[] = { 0xa3, 0xb6, 0x16, 0x74, 0x73,
+                                       0x10, 0x0e, 0xe0, 0x6e, 0x0c,
+                                       0x79, 0x6c, 0x29, 0x55, 0x55,
+                                       0x2b };
+    doHMACTest("Test With Truncation", secret5, 20, HMAC::SHA256,
+               hmac_expected5, 16);
+
+    const std::string secret6(131, 0xaa);
+    const uint8_t hmac_expected6[] = { 0x60, 0xe4, 0x31, 0x59, 0x1e,
+                                       0xe0, 0xb6, 0x7f, 0x0d, 0x8a,
+                                       0x26, 0xaa, 0xcb, 0xf5, 0xb7,
+                                       0x7f, 0x8e, 0x0b, 0xc6, 0x21,
+                                       0x37, 0x28, 0xc5, 0x14, 0x05,
+                                       0x46, 0x04, 0x0f, 0x0e, 0xe3,
+                                       0x7f, 0x54 };
+    doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+               secret6.c_str(), 131, HMAC::SHA256, hmac_expected6, 32);
+
+    // Same secret as test 6
+    const uint8_t hmac_expected7[] = { 0x9b, 0x09, 0xff, 0xa7, 0x1b,
+                                       0x94, 0x2f, 0xcb, 0x27, 0x63,
+                                       0x5f, 0xbc, 0xd5, 0xb0, 0xe9,
+                                       0x44, 0xbf, 0xdc, 0x63, 0x64,
+                                       0x4f, 0x07, 0x13, 0x93, 0x8a,
+                                       0x7f, 0x51, 0x53, 0x5c, 0x3a,
+                                       0x35, 0xe2 };
+    doHMACTest("This is a test using a larger than block-size key and a"
+               " larger than block-size data. The key needs to be hashe"
+               "d before being used by the HMAC algorithm.",
+               secret6.c_str(), 131, HMAC::SHA256, hmac_expected7, 32);
+}
+
+namespace {
+    size_t
+    sigVectorLength(HMAC::HashAlgorithm alg, size_t len) {
+        boost::scoped_ptr<HMAC> hmac_sign(
+            CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg));
+        hmac_sign->update("asdf", 4);
+        const std::vector<uint8_t> sig = hmac_sign->sign(len);
+        return sig.size();
+    }
+
+    size_t
+    sigBufferLength(HMAC::HashAlgorithm alg, size_t len) {
+        boost::scoped_ptr<HMAC> hmac_sign(
+            CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg));
+        hmac_sign->update("asdf", 4);
+        OutputBuffer sig(0);
+        hmac_sign->sign(sig, len);
+        return sig.getLength();
+    }
+}
+
+TEST(CryptoLinkTest, HMACSigLengthArgument)
+{
+    std::vector<uint8_t> sig;
+
+    EXPECT_EQ(16, sigVectorLength(HMAC::MD5, 0));
+    EXPECT_EQ(8, sigVectorLength(HMAC::MD5, 8));
+    EXPECT_EQ(16, sigVectorLength(HMAC::MD5, 16));
+    EXPECT_EQ(16, sigVectorLength(HMAC::MD5, 40));
+    EXPECT_EQ(16, sigVectorLength(HMAC::MD5, 2000));
+
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 0));
+    EXPECT_EQ(8, sigBufferLength(HMAC::SHA1, 8));
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 20));
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 40));
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 2000));
+
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 0));
+    EXPECT_EQ(8, sigBufferLength(HMAC::SHA256, 8));
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 32));
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 40));
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 3200));
+
+    EXPECT_EQ(16, sigBufferLength(HMAC::MD5, 0));
+    EXPECT_EQ(8, sigBufferLength(HMAC::MD5, 8));
+    EXPECT_EQ(16, sigBufferLength(HMAC::MD5, 16));
+    EXPECT_EQ(16, sigBufferLength(HMAC::MD5, 40));
+    EXPECT_EQ(16, sigBufferLength(HMAC::MD5, 2000));
+
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 0));
+    EXPECT_EQ(8, sigBufferLength(HMAC::SHA1, 8));
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 20));
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 40));
+    EXPECT_EQ(20, sigBufferLength(HMAC::SHA1, 2000));
+
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 0));
+    EXPECT_EQ(8, sigBufferLength(HMAC::SHA256, 8));
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 32));
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 40));
+    EXPECT_EQ(32, sigBufferLength(HMAC::SHA256, 3200));
+}
+
+TEST(CryptoLinkTest, BadKey) {
+    OutputBuffer data_buf(0);
+    OutputBuffer hmac_sig(0);
+    CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+    EXPECT_THROW(crypto.createHMAC(NULL, 0, HMAC::MD5), BadKey);
+    EXPECT_THROW(crypto.createHMAC(NULL, 0, HMAC::UNKNOWN), UnsupportedAlgorithm);
+
+    EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+                          NULL, 0, HMAC::MD5, hmac_sig), BadKey);
+    EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+                          NULL, 0, HMAC::UNKNOWN, hmac_sig),
+                          UnsupportedAlgorithm);
+
+    EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                            NULL, 0, HMAC::MD5, hmac_sig.getData(),
+                            hmac_sig.getLength()), BadKey);
+    EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+                            NULL, 0, HMAC::UNKNOWN, hmac_sig.getData(),
+                            hmac_sig.getLength()),
+                            UnsupportedAlgorithm);
+}
+
+TEST(CryptoLinkTest, Singleton) {
+    CryptoLink& c1 = CryptoLink::getCryptoLink();
+    CryptoLink& c2 = CryptoLink::getCryptoLink();
+    ASSERT_EQ(&c1, &c2);
+}
diff --git a/src/lib/cryptolink/tests/run_unittests.cc b/src/lib/cryptolink/tests/run_unittests.cc
new file mode 100644
index 0000000..4b0f27a
--- /dev/null
+++ b/src/lib/cryptolink/tests/run_unittests.cc
@@ -0,0 +1,25 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+#include <cryptolink/crypto.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/dns/tests/tsigkey_unittest.cc b/src/lib/dns/tests/tsigkey_unittest.cc
index 2cb91f8..c10ffe0 100644
--- a/src/lib/dns/tests/tsigkey_unittest.cc
+++ b/src/lib/dns/tests/tsigkey_unittest.cc
@@ -227,7 +227,7 @@ TEST_F(TSIGKeyRingTest, findFromSome) {
               keyring.find(Name("noexist.example")).key);
 }
 
-TEST(TSIGTest, TSIGKeyFromToString) {
+TEST(TSIGStringTest, TSIGKeyFromToString) {
     TSIGKey k1 = TSIGKey("test.example:MSG6Ng==:hmac-md5.sig-alg.reg.int");
     TSIGKey k2 = TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.");
     TSIGKey k3 = TSIGKey("test.example:MSG6Ng==");
diff --git a/src/lib/dns/tsigkey.cc b/src/lib/dns/tsigkey.cc
index 4edeca9..5376c70 100644
--- a/src/lib/dns/tsigkey.cc
+++ b/src/lib/dns/tsigkey.cc
@@ -18,7 +18,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <crypto/crypto.h>
+#include <cryptolink/crypto.h>
 
 #include <dns/name.h>
 #include <dns/util/base64.h>
@@ -26,6 +26,14 @@
 
 using namespace std;
 
+namespace {
+    bool isValidAlgorithmName(const isc::dns::Name& name) {
+        return (name == isc::dns::TSIGKey::HMACMD5_NAME() ||
+                name == isc::dns::TSIGKey::HMACSHA1_NAME() ||
+                name == isc::dns::TSIGKey::HMACSHA256_NAME());
+    }
+}
+
 namespace isc {
 namespace dns {
 struct
@@ -47,9 +55,7 @@ TSIGKey::TSIGKeyImpl {
 TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
                  const void* secret, size_t secret_len) : impl_(NULL)
 {
-    if (algorithm_name != HMACMD5_NAME() &&
-        algorithm_name != HMACSHA1_NAME() &&
-        algorithm_name != HMACSHA256_NAME()) {
+    if (!isValidAlgorithmName(algorithm_name)) {
         isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
                   algorithm_name);
     }
@@ -63,31 +69,32 @@ TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
 }
 
 TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
-    const size_t pos = str.find(':');
-    if (pos == 0 || pos == str.npos || pos == str.size() - 1) {
-        // error
-        isc_throw(InvalidParameter, "Invalid TSIG key string");
-    }
     try {
-        const Name key_name(str.substr(0, pos));
-        Name algo_name("hmac-md5.sig-alg.reg.int");
-
-        // optional algorithm part
-        size_t pos2 = str.find(':', pos + 1);
-        if (pos2 != str.npos) {
-            if (pos2 == pos + 1) {
-                isc_throw(InvalidParameter, "Invalid TSIG key string");
-            }
-            algo_name = Name(str.substr(pos2 + 1));
-        } else {
-            pos2 = str.size() - pos;
+        istringstream iss(str);
+
+        string keyname_str;
+        getline(iss, keyname_str, ':');
+        if (iss.fail() || iss.bad() || iss.eof()) {
+            isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
         }
 
-        const std::string secret_str = str.substr(pos + 1, pos2 - pos - 1);
+        string secret_str;
+        getline(iss, secret_str, ':');
+        if (iss.fail() || iss.bad()) {
+            isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+        }
+
+        string algo_str;
+        if (!iss.eof()) {
+            getline(iss, algo_str);
+        }
+        if (iss.fail() || iss.bad()) {
+            isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+        }
 
-        if (algo_name != HMACMD5_NAME() &&
-            algo_name != HMACSHA1_NAME() &&
-            algo_name != HMACSHA256_NAME()) {
+        const Name algo_name(algo_str.empty() ? "hmac-md5.sig-alg.reg.int" :
+                             algo_str);
+        if (!isValidAlgorithmName(algo_name)) {
             isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
                       algo_name);
         }
@@ -95,7 +102,7 @@ TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
         vector<uint8_t> secret;
         decodeBase64(secret_str, secret);
 
-        impl_ = new TSIGKeyImpl(key_name, algo_name, &secret[0],
+        impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, &secret[0],
                                 secret.size());
     } catch (const Exception& e) {
         // 'reduce' the several types of exceptions name parsing and
diff --git a/src/lib/dns/tsigkey.h b/src/lib/dns/tsigkey.h
index 5936e0f..ca9e9ec 100644
--- a/src/lib/dns/tsigkey.h
+++ b/src/lib/dns/tsigkey.h
@@ -107,7 +107,7 @@ public:
     /// invalid.
     ///
     /// \param str The string to make a TSIGKey from
-    TSIGKey(const std::string& str);
+    explicit TSIGKey(const std::string& str);
 
     /// \brief The copy constructor.
     ///




More information about the bind10-changes mailing list