security: add HMAC support to SignerFilter and VerifierFilter

Introduce HmacKeyParams
Add HMAC support to transform::PrivateKey
Deprecate HmacFilter

Refs: #3075
Change-Id: I16e24c1c4f278b08c7f51c91e9317b7820943536
diff --git a/tests/unit/security/key-params.t.cpp b/tests/unit/security/key-params.t.cpp
index 0fc6cd5..336520d 100644
--- a/tests/unit/security/key-params.t.cpp
+++ b/tests/unit/security/key-params.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -36,20 +36,20 @@
   RsaKeyParams params;
   BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::RSA);
   BOOST_CHECK_EQUAL(params.getKeySize(), 2048);
-  BOOST_CHECK(params.getKeyIdType() == KeyIdType::RANDOM);
+  BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::RANDOM);
 
   RsaKeyParams params2(4096, KeyIdType::SHA256);
   BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::RSA);
   BOOST_CHECK_EQUAL(params2.getKeySize(), 4096);
-  BOOST_CHECK(params2.getKeyIdType() == KeyIdType::SHA256);
+  BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::SHA256);
 
   BOOST_CHECK_THROW(RsaKeyParams(1024), KeyParams::Error);
 
   name::Component keyId("keyId");
   RsaKeyParams params4(keyId);
-  BOOST_CHECK(params4.getKeyType() == KeyType::RSA);
+  BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::RSA);
   BOOST_CHECK_EQUAL(params4.getKeySize(), 2048);
-  BOOST_CHECK(params4.getKeyIdType() == KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::USER_SPECIFIED);
   BOOST_CHECK_EQUAL(params4.getKeyId(), keyId);
 }
 
@@ -58,20 +58,20 @@
   EcKeyParams params;
   BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::EC);
   BOOST_CHECK_EQUAL(params.getKeySize(), 256);
-  BOOST_CHECK(params.getKeyIdType() == KeyIdType::RANDOM);
+  BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::RANDOM);
 
   EcKeyParams params2(384, KeyIdType::SHA256);
   BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::EC);
   BOOST_CHECK_EQUAL(params2.getKeySize(), 384);
-  BOOST_CHECK(params2.getKeyIdType() == KeyIdType::SHA256);
+  BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::SHA256);
 
-  BOOST_CHECK_THROW(EcKeyParams(3), KeyParams::Error);
+  BOOST_CHECK_THROW(EcKeyParams(64), KeyParams::Error);
 
   name::Component keyId("keyId");
   EcKeyParams params4(keyId);
-  BOOST_CHECK(params4.getKeyType() == KeyType::EC);
+  BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::EC);
   BOOST_CHECK_EQUAL(params4.getKeySize(), 256);
-  BOOST_CHECK(params4.getKeyIdType() == KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::USER_SPECIFIED);
   BOOST_CHECK_EQUAL(params4.getKeyId(), keyId);
 }
 
@@ -82,32 +82,73 @@
   BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::AES);
   BOOST_CHECK_EQUAL(params.getKeySize(), 128);
   BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params.getKeyId(), keyId);
 
   AesKeyParams params2(keyId, 192);
-  BOOST_CHECK(params2.getKeyType() == KeyType::AES);
+  BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::AES);
   BOOST_CHECK_EQUAL(params2.getKeySize(), 192);
-  BOOST_CHECK(params.getKeyIdType() == KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params2.getKeyId(), keyId);
 
   AesKeyParams params3(keyId, 256);
   BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::AES);
   BOOST_CHECK_EQUAL(params3.getKeySize(), 256);
-  BOOST_CHECK(params.getKeyIdType() == KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params3.getKeyIdType(), KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params3.getKeyId(), keyId);
 
-  BOOST_CHECK_THROW(AesKeyParams(keyId, 4), KeyParams::Error);
+  BOOST_CHECK_THROW(AesKeyParams(keyId, 64), KeyParams::Error);
 
-  AesKeyParams params5(keyId);
+  AesKeyParams params4;
+  BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::AES);
+  BOOST_CHECK_EQUAL(params4.getKeySize(), 128);
+  BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::RANDOM);
+
+  AesKeyParams params5(192);
   BOOST_CHECK_EQUAL(params5.getKeyType(), KeyType::AES);
-  BOOST_CHECK_EQUAL(params5.getKeySize(), 128);
-  BOOST_CHECK_EQUAL(params5.getKeyIdType(), KeyIdType::USER_SPECIFIED);
-  BOOST_CHECK_EQUAL(params5.getKeyId(), keyId);
-
-  AesKeyParams params6(192);
-  BOOST_CHECK(params6.getKeyType() == KeyType::AES);
-  BOOST_CHECK_EQUAL(params6.getKeySize(), 192);
-  BOOST_CHECK(params6.getKeyIdType() == KeyIdType::RANDOM);
+  BOOST_CHECK_EQUAL(params5.getKeySize(), 192);
+  BOOST_CHECK_EQUAL(params5.getKeyIdType(), KeyIdType::RANDOM);
 }
 
-BOOST_AUTO_TEST_CASE(KeyIdTypeInfo)
+BOOST_AUTO_TEST_CASE(Hmac)
+{
+  name::Component keyId("keyId");
+  HmacKeyParams params(keyId);
+  BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::HMAC);
+  BOOST_CHECK_EQUAL(params.getKeySize(), 256);
+  BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params.getKeyId(), keyId);
+
+  HmacKeyParams params2(keyId, 384);
+  BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::HMAC);
+  BOOST_CHECK_EQUAL(params2.getKeySize(), 384);
+  BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params2.getKeyId(), keyId);
+
+  BOOST_CHECK_THROW(HmacKeyParams(keyId, 192), KeyParams::Error); // too short
+  BOOST_CHECK_THROW(HmacKeyParams(keyId, 300), KeyParams::Error); // not a multiple of 8
+
+  HmacKeyParams params3;
+  BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::HMAC);
+  BOOST_CHECK_EQUAL(params3.getKeySize(), 256);
+  BOOST_CHECK_EQUAL(params3.getKeyIdType(), KeyIdType::RANDOM);
+
+  HmacKeyParams params4(1024);
+  BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::HMAC);
+  BOOST_CHECK_EQUAL(params4.getKeySize(), 1024);
+  BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::RANDOM);
+}
+
+BOOST_AUTO_TEST_CASE(KeyTypeToString)
+{
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyType::NONE), "NONE");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyType::RSA), "RSA");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyType::EC), "EC");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyType::AES), "AES");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyType::HMAC), "HMAC");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<KeyType>(12345)), "12345");
+}
+
+BOOST_AUTO_TEST_CASE(KeyIdTypeToString)
 {
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyIdType::USER_SPECIFIED), "USER_SPECIFIED");
   BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyIdType::SHA256), "SHA256");
diff --git a/tests/unit/security/transform/private-key.t.cpp b/tests/unit/security/transform/private-key.t.cpp
index 0cef079..de1d9b2 100644
--- a/tests/unit/security/transform/private-key.t.cpp
+++ b/tests/unit/security/transform/private-key.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,8 +22,15 @@
 #include "ndn-cxx/security/transform/private-key.hpp"
 
 #include "ndn-cxx/encoding/buffer-stream.hpp"
+#include "ndn-cxx/security/impl/openssl.hpp"
 #include "ndn-cxx/security/key-params.hpp"
-#include "ndn-cxx/security/transform.hpp"
+#include "ndn-cxx/security/transform/base64-decode.hpp"
+#include "ndn-cxx/security/transform/bool-sink.hpp"
+#include "ndn-cxx/security/transform/buffer-source.hpp"
+#include "ndn-cxx/security/transform/public-key.hpp"
+#include "ndn-cxx/security/transform/signer-filter.hpp"
+#include "ndn-cxx/security/transform/stream-sink.hpp"
+#include "ndn-cxx/security/transform/verifier-filter.hpp"
 
 #include "tests/boost-test.hpp"
 
@@ -144,7 +151,7 @@
 checkPkcs8Encoding(ConstBufferPtr encoding, const std::string& password, ConstBufferPtr pkcs1)
 {
   PrivateKey sKey;
-  sKey.loadPkcs8(encoding->data(), encoding->size(), password.c_str(), password.size());
+  sKey.loadPkcs8(encoding->data(), encoding->size(), password.data(), password.size());
   OBufferStream os;
   sKey.savePkcs1(os);
   BOOST_CHECK_EQUAL_COLLECTIONS(pkcs1->begin(), pkcs1->end(),
@@ -163,7 +170,7 @@
 {
   T dataSet;
 
-  const uint8_t* sKeyPkcs1Base64 = reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str());
+  const uint8_t* sKeyPkcs1Base64 = reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.data());
   size_t sKeyPkcs1Base64Len = dataSet.privateKeyPkcs1.size();
   OBufferStream os;
   bufferSource(sKeyPkcs1Base64, sKeyPkcs1Base64Len) >> base64Decode() >> streamSink(os);
@@ -200,7 +207,7 @@
   BOOST_CHECK_EQUAL_COLLECTIONS(sKeyPkcs1, sKeyPkcs1 + sKeyPkcs1Len,
                                 os3.buf()->begin(), os3.buf()->end());
 
-  const uint8_t* sKeyPkcs8Base64 = reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs8.c_str());
+  const uint8_t* sKeyPkcs8Base64 = reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs8.data());
   size_t sKeyPkcs8Base64Len = dataSet.privateKeyPkcs8.size();
   OBufferStream os4;
   bufferSource(sKeyPkcs8Base64, sKeyPkcs8Base64Len) >> base64Decode() >> streamSink(os4);
@@ -218,14 +225,14 @@
   // load key in base64-encoded pkcs8 format
   PrivateKey sKey5;
   BOOST_CHECK_NO_THROW(sKey5.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len,
-                                             password.c_str(), password.size()));
+                                             password.data(), password.size()));
 
   PrivateKey sKey6;
   BOOST_CHECK_NO_THROW(sKey6.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, pwCallback));
 
   std::stringstream ss7(dataSet.privateKeyPkcs8);
   PrivateKey sKey7;
-  BOOST_CHECK_NO_THROW(sKey7.loadPkcs8Base64(ss7, password.c_str(), password.size()));
+  BOOST_CHECK_NO_THROW(sKey7.loadPkcs8Base64(ss7, password.data(), password.size()));
 
   std::stringstream ss8(dataSet.privateKeyPkcs8);
   PrivateKey sKey8;
@@ -233,7 +240,7 @@
 
   // load key in pkcs8 format
   PrivateKey sKey9;
-  BOOST_CHECK_NO_THROW(sKey9.loadPkcs8(sKeyPkcs8, sKeyPkcs8Len, password.c_str(), password.size()));
+  BOOST_CHECK_NO_THROW(sKey9.loadPkcs8(sKeyPkcs8, sKeyPkcs8Len, password.data(), password.size()));
 
   PrivateKey sKey10;
   BOOST_CHECK_NO_THROW(sKey10.loadPkcs8(sKeyPkcs8, sKeyPkcs8Len, pwCallback));
@@ -241,7 +248,7 @@
   std::stringstream ss11;
   ss11.write(reinterpret_cast<const char*>(sKeyPkcs8), sKeyPkcs8Len);
   PrivateKey sKey11;
-  BOOST_CHECK_NO_THROW(sKey11.loadPkcs8(ss11, password.c_str(), password.size()));
+  BOOST_CHECK_NO_THROW(sKey11.loadPkcs8(ss11, password.data(), password.size()));
 
   std::stringstream ss12;
   ss12.write(reinterpret_cast<const char*>(sKeyPkcs8), sKeyPkcs8Len);
@@ -250,12 +257,12 @@
 
   // load key using wrong password, Error is expected
   PrivateKey sKey13;
-  BOOST_CHECK_THROW(sKey13.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, wrongpw.c_str(), wrongpw.size()),
+  BOOST_CHECK_THROW(sKey13.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, wrongpw.data(), wrongpw.size()),
                     PrivateKey::Error);
 
   // save key in base64-encoded pkcs8 format
   OBufferStream os14;
-  BOOST_REQUIRE_NO_THROW(sKey.savePkcs8Base64(os14, password.c_str(), password.size()));
+  BOOST_REQUIRE_NO_THROW(sKey.savePkcs8Base64(os14, password.data(), password.size()));
   checkPkcs8Base64Encoding(os14.buf(), password, sKeyPkcs1Buf);
 
   OBufferStream os15;
@@ -264,7 +271,7 @@
 
   // save key in pkcs8 format
   OBufferStream os16;
-  BOOST_REQUIRE_NO_THROW(sKey.savePkcs8(os16, password.c_str(), password.size()));
+  BOOST_REQUIRE_NO_THROW(sKey.savePkcs8(os16, password.data(), password.size()));
   checkPkcs8Encoding(os16.buf(), password, sKeyPkcs1Buf);
 
   OBufferStream os17;
@@ -276,7 +283,7 @@
 {
   T dataSet;
 
-  const uint8_t* sKeyPkcs1Base64 = reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str());
+  const uint8_t* sKeyPkcs1Base64 = reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.data());
   size_t sKeyPkcs1Base64Len = dataSet.privateKeyPkcs1.size();
   PrivateKey sKey;
   sKey.loadPkcs1Base64(sKeyPkcs1Base64, sKeyPkcs1Base64Len);
@@ -294,7 +301,7 @@
   RsaKeyTestData dataSet;
 
   PrivateKey sKey;
-  sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str()),
+  sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.data()),
                        dataSet.privateKeyPkcs1.size());
   BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::RSA);
 
@@ -320,12 +327,12 @@
   RsaKeyTestData dataSet;
 
   PublicKey pKey;
-  pKey.loadPkcs8Base64(reinterpret_cast<const uint8_t*>(dataSet.publicKeyPkcs8.c_str()),
+  pKey.loadPkcs8Base64(reinterpret_cast<const uint8_t*>(dataSet.publicKeyPkcs8.data()),
                        dataSet.publicKeyPkcs8.size());
   BOOST_CHECK_EQUAL(pKey.getKeyType(), KeyType::RSA);
 
   PrivateKey sKey;
-  sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str()),
+  sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.data()),
                        dataSet.privateKeyPkcs1.size());
   BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::RSA);
 
@@ -337,57 +344,94 @@
                                 decrypted->begin(), decrypted->end());
 }
 
-BOOST_AUTO_TEST_CASE(UnsupportedEcDecryption)
+BOOST_AUTO_TEST_CASE(UnsupportedDecryption)
 {
-  EcKeyTestData dataSet;
-
-  PrivateKey sKey;
-  sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(dataSet.privateKeyPkcs1.c_str()),
-                       dataSet.privateKeyPkcs1.size());
-  BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::EC);
-
   OBufferStream os;
   bufferSource("Y2lhbyFob2xhIWhlbGxvIQ==") >> base64Decode() >> streamSink(os);
 
-  BOOST_CHECK_THROW(sKey.decrypt(os.buf()->data(), os.buf()->size()), PrivateKey::Error);
+  auto ecKey = generatePrivateKey(EcKeyParams());
+  BOOST_CHECK_THROW(ecKey->decrypt(os.buf()->data(), os.buf()->size()), PrivateKey::Error);
+
+  auto hmacKey = generatePrivateKey(HmacKeyParams());
+  BOOST_CHECK_THROW(hmacKey->decrypt(os.buf()->data(), os.buf()->size()), PrivateKey::Error);
 }
 
-using KeyParams = boost::mpl::vector<RsaKeyParams, EcKeyParams>;
-
-BOOST_AUTO_TEST_CASE_TEMPLATE(GenerateKey, T, KeyParams)
+struct RsaKeyGenParams
 {
-  unique_ptr<PrivateKey> sKey = generatePrivateKey(T());
-  PublicKey pKey;
-  ConstBufferPtr pKeyBits = sKey->derivePublicKey();
-  pKey.loadPkcs8(pKeyBits->data(), pKeyBits->size());
+  using Params = RsaKeyParams;
+  using hasPublicKey = std::true_type;
+  using canSavePkcs1 = std::true_type;
+};
+
+struct EcKeyGenParams
+{
+  using Params = EcKeyParams;
+  using hasPublicKey = std::true_type;
+  using canSavePkcs1 = std::true_type;
+};
+
+struct HmacKeyGenParams
+{
+  using Params = HmacKeyParams;
+  using hasPublicKey = std::false_type;
+  using canSavePkcs1 = std::false_type;
+};
+
+using KeyGenParams = boost::mpl::vector<RsaKeyGenParams,
+                                        EcKeyGenParams,
+                                        HmacKeyGenParams>;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(GenerateKey, T, KeyGenParams)
+{
+  unique_ptr<PrivateKey> sKey = generatePrivateKey(typename T::Params());
+  BOOST_CHECK_NE(sKey->getKeyType(), KeyType::NONE);
+  BOOST_CHECK_GT(sKey->getKeySize(), 0);
 
   const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
   OBufferStream os;
   BOOST_REQUIRE_NO_THROW(bufferSource(data, sizeof(data)) >>
                          signerFilter(DigestAlgorithm::SHA256, *sKey) >>
                          streamSink(os));
+  auto sig = os.buf();
 
-  ConstBufferPtr sig = os.buf();
   bool result = false;
-  BOOST_REQUIRE_NO_THROW(bufferSource(data, sizeof(data)) >>
+  if (typename T::hasPublicKey()) {
+    auto pKeyBits = sKey->derivePublicKey();
+    PublicKey pKey;
+    pKey.loadPkcs8(pKeyBits->data(), pKeyBits->size());
+    BOOST_CHECK_NO_THROW(bufferSource(data, sizeof(data)) >>
                          verifierFilter(DigestAlgorithm::SHA256, pKey, sig->data(), sig->size()) >>
                          boolSink(result));
+  }
+  else {
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
+    BOOST_CHECK_THROW(sKey->derivePublicKey(), PrivateKey::Error);
+#endif
+    BOOST_CHECK_NO_THROW(bufferSource(data, sizeof(data)) >>
+                         verifierFilter(DigestAlgorithm::SHA256, *sKey, sig->data(), sig->size()) >>
+                         boolSink(result));
+  }
   BOOST_CHECK(result);
 
-  unique_ptr<PrivateKey> sKey2 = generatePrivateKey(T());
+  if (typename T::canSavePkcs1()) {
+    unique_ptr<PrivateKey> sKey2 = generatePrivateKey(typename T::Params());
 
-  OBufferStream os1;
-  sKey->savePkcs1(os1);
-  ConstBufferPtr key1Pkcs1 = os1.buf();
+    OBufferStream os1;
+    sKey->savePkcs1(os1);
+    OBufferStream os2;
+    sKey2->savePkcs1(os2);
 
-  OBufferStream os2;
-  sKey2->savePkcs1(os2);
-  ConstBufferPtr key2Pkcs1 = os2.buf();
-
-  BOOST_CHECK(*key1Pkcs1 != *key2Pkcs1);
+    BOOST_CHECK(*os1.buf() != *os2.buf());
+  }
+  else {
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
+    OBufferStream os1;
+    BOOST_CHECK_THROW(sKey->savePkcs1(os1), PrivateKey::Error);
+#endif
+  }
 }
 
-BOOST_AUTO_TEST_CASE(UnsupportedKeyType)
+BOOST_AUTO_TEST_CASE(GenerateKeyUnsupportedType)
 {
   BOOST_CHECK_THROW(generatePrivateKey(AesKeyParams()), std::invalid_argument);
 }
diff --git a/tests/unit/security/transform/signer-filter.t.cpp b/tests/unit/security/transform/signer-filter.t.cpp
index aa6f6e3..4c75204 100644
--- a/tests/unit/security/transform/signer-filter.t.cpp
+++ b/tests/unit/security/transform/signer-filter.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,6 +22,7 @@
 #include "ndn-cxx/security/transform/signer-filter.hpp"
 
 #include "ndn-cxx/encoding/buffer-stream.hpp"
+#include "ndn-cxx/security/key-params.hpp"
 #include "ndn-cxx/security/transform/base64-decode.hpp"
 #include "ndn-cxx/security/transform/buffer-source.hpp"
 #include "ndn-cxx/security/transform/private-key.hpp"
@@ -39,6 +40,8 @@
 BOOST_AUTO_TEST_SUITE(Transform)
 BOOST_AUTO_TEST_SUITE(TestSignerFilter)
 
+const uint8_t DATA[] = {0x01, 0x02, 0x03, 0x04};
+
 BOOST_AUTO_TEST_CASE(Rsa)
 {
   const std::string publicKeyPkcs8 =
@@ -75,7 +78,6 @@
     "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n"
     "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n"
     "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n";
-  const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
 
   OBufferStream os1;
   bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1);
@@ -87,10 +89,10 @@
   BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, sKey), Error);
 
   OBufferStream os2;
-  bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
+  bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
   auto sig = os2.buf();
 
-  BOOST_CHECK(verifySignature(data, sizeof(data), sig->data(), sig->size(), pubKey->data(), pubKey->size()));
+  BOOST_CHECK(verifySignature(DATA, sizeof(DATA), sig->data(), sig->size(), pubKey->data(), pubKey->size()));
 }
 
 BOOST_AUTO_TEST_CASE(Ecdsa)
@@ -112,7 +114,6 @@
     "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n"
     "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n"
     "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n";
-  const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
 
   OBufferStream os1;
   bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1);
@@ -124,10 +125,34 @@
   BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, sKey), Error);
 
   OBufferStream os2;
-  bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
+  bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
   auto sig = os2.buf();
 
-  BOOST_CHECK(verifySignature(data, sizeof(data), sig->data(), sig->size(), pubKey->data(), pubKey->size()));
+  BOOST_CHECK(verifySignature(DATA, sizeof(DATA), sig->data(), sig->size(), pubKey->data(), pubKey->size()));
+}
+
+BOOST_AUTO_TEST_CASE(Hmac)
+{
+  auto sKey = generatePrivateKey(HmacKeyParams());
+
+  BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, *sKey), Error);
+
+  OBufferStream os;
+  bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, *sKey) >> streamSink(os);
+  auto sig = os.buf();
+
+  BOOST_CHECK_EQUAL(sig->size(), 32);
+}
+
+BOOST_AUTO_TEST_CASE(HmacKeyTooShort)
+{
+  auto sKey = generatePrivateKey(HmacKeyParams(256));
+
+  OBufferStream os;
+  BOOST_CHECK_THROW(bufferSource(DATA, sizeof(DATA)) >>
+                    signerFilter(DigestAlgorithm::SHA512, *sKey) >>
+                    streamSink(os),
+                    Error);
 }
 
 BOOST_AUTO_TEST_CASE(InvalidKey)
diff --git a/tests/unit/security/transform/verifier-filter.t.cpp b/tests/unit/security/transform/verifier-filter.t.cpp
index ef38276..8d733d3 100644
--- a/tests/unit/security/transform/verifier-filter.t.cpp
+++ b/tests/unit/security/transform/verifier-filter.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,6 +22,7 @@
 #include "ndn-cxx/security/transform/verifier-filter.hpp"
 
 #include "ndn-cxx/encoding/buffer-stream.hpp"
+#include "ndn-cxx/security/key-params.hpp"
 #include "ndn-cxx/security/transform/base64-decode.hpp"
 #include "ndn-cxx/security/transform/bool-sink.hpp"
 #include "ndn-cxx/security/transform/buffer-source.hpp"
@@ -41,6 +42,8 @@
 BOOST_AUTO_TEST_SUITE(Transform)
 BOOST_AUTO_TEST_SUITE(TestVerifierFilter)
 
+const uint8_t DATA[] = {0x01, 0x02, 0x03, 0x04};
+
 BOOST_AUTO_TEST_CASE(Rsa)
 {
   const std::string publicKeyPkcs8 =
@@ -78,7 +81,6 @@
     "/YnHJC50/dIKbZakaapXOFFgiep5q1jmxR2U8seb+nvtFPsTLFAdOXCfwUk+4z/h\n"
     "kfWtB3+8H5jyoC1gkJ7EMyxu8tb4mz5U6+SPB4QLSetwvfWP2YXS/PkTq19G7iGE\n"
     "novjJ9azSBJ6OyR5UH/DxBji\n";
-  const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
 
   OBufferStream os1;
   bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1);
@@ -91,13 +93,14 @@
   sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privateKeyPkcs1.data()), privateKeyPkcs1.size());
 
   OBufferStream os2;
-  bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
+  bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
   auto sig = os2.buf();
 
   BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::NONE, pKey, sig->data(), sig->size()), Error);
+  BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, sKey, sig->data(), sig->size()), Error);
 
   bool result = false;
-  bufferSource(data, sizeof(data)) >>
+  bufferSource(DATA, sizeof(DATA)) >>
     verifierFilter(DigestAlgorithm::SHA256, pKey, sig->data(), sig->size()) >>
     boolSink(result);
 
@@ -123,7 +126,6 @@
     "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n"
     "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n"
     "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n";
-  const uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
 
   OBufferStream os1;
   bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1);
@@ -136,23 +138,44 @@
   sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privateKeyPkcs1.data()), privateKeyPkcs1.size());
 
   OBufferStream os2;
-  bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
+  bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2);
   auto sig = os2.buf();
 
   BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::NONE, pKey, sig->data(), sig->size()), Error);
+  BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, sKey, sig->data(), sig->size()), Error);
 
   bool result = false;
-  bufferSource(data, sizeof(data)) >>
+  bufferSource(DATA, sizeof(DATA)) >>
     verifierFilter(DigestAlgorithm::SHA256, pKey, sig->data(), sig->size()) >>
     boolSink(result);
 
   BOOST_CHECK_EQUAL(result, true);
 }
 
+BOOST_AUTO_TEST_CASE(Hmac)
+{
+  auto sKey = generatePrivateKey(HmacKeyParams());
+
+  OBufferStream os;
+  bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, *sKey) >> streamSink(os);
+  auto sig = os.buf();
+
+  BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::NONE, *sKey, sig->data(), sig->size()), Error);
+
+  bool result = false;
+  bufferSource(DATA, sizeof(DATA)) >>
+    verifierFilter(DigestAlgorithm::SHA256, *sKey, sig->data(), sig->size()) >>
+    boolSink(result);
+
+  BOOST_CHECK_EQUAL(result, true);
+}
+
 BOOST_AUTO_TEST_CASE(InvalidKey)
 {
-  PublicKey pKey;
-  BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, pKey, nullptr, 0), Error);
+  PublicKey pubKey;
+  BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, pubKey, nullptr, 0), Error);
+  PrivateKey privKey;
+  BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, privKey, nullptr, 0), Error);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // TestVerifierFilter