HMAC harness¶
Test digest¶
crypto-condor tests HMAC implementations through a single digest function that is
equivalent to the following pseudo-code:
def digest(key: bytes, msg: bytes) -> bytes:
    h = hmac.init(key)
    h.update(msg)
    return h.final()
Naming convention¶
The function must conform to the following convention:
CC_HMAC_digest_<hash function>
Where hash function is one of:
- sha1,- sha224,- sha256,- sha384,- sha512.
- sha3_224,- sha3_256,- sha3_384,- sha3_512.
Function signature¶
Its signature must be:
- int HMAC_digest(
- uint8_t *mac,
- const size_t mac_size,
- const uint8_t *key,
- const size_t key_size,
- const uint8_t *msg,
- const size_t msg_size,
- Generates HMAC tags. - Parameters:
- mac – [Out] An allocated buffer to return the MAC tag. 
- mac_size – [In] The size of the allocated buffer in bytes. 
- key – [In] The secret key. 
- key_size – [In] The size of the secret key in bytes. 
- msg – [In] The message to authenticate. 
- msg_size – [In] The size of the message in bytes. 
 
- Returns:
- A status value. 
- Return values:
- 1 – OK 
- 0 – An error occurred. 
 
 
Example¶
To test the harness for this function, we use the following OpenSSL harness:
#include <openssl/err.h>
#include <openssl/evp.h>
#include <stdint.h>
#include <stdlib.h>
int generic_digest(const char *hash, uint8_t *mac, const size_t mac_size,
                   const uint8_t *key, const size_t key_size,
                   const uint8_t *msg, const size_t msg_size);
int CC_HMAC_digest_sha256(uint8_t *mac, const size_t mac_size,
                          const uint8_t *key, const size_t key_size,
                          const uint8_t *msg, const size_t msg_size) {
  return generic_digest("SHA-256", mac, mac_size, key, key_size, msg, msg_size);
}
int CC_HMAC_digest_sha384(uint8_t *mac, const size_t mac_size,
                          const uint8_t *key, const size_t key_size,
                          const uint8_t *msg, const size_t msg_size) {
  return generic_digest("SHA-384", mac, mac_size, key, key_size, msg, msg_size);
}
int CC_HMAC_digest_sha512(uint8_t *mac, const size_t mac_size,
                          const uint8_t *key, const size_t key_size,
                          const uint8_t *msg, const size_t msg_size) {
  return generic_digest("SHA-512", mac, mac_size, key, key_size, msg, msg_size);
}
int CC_HMAC_digest_sha3_256(uint8_t *mac, const size_t mac_size,
                          const uint8_t *key, const size_t key_size,
                          const uint8_t *msg, const size_t msg_size) {
  return generic_digest("SHA3-256", mac, mac_size, key, key_size, msg, msg_size);
}
int CC_HMAC_digest_sha3_384(uint8_t *mac, const size_t mac_size,
                          const uint8_t *key, const size_t key_size,
                          const uint8_t *msg, const size_t msg_size) {
  return generic_digest("SHA3-384", mac, mac_size, key, key_size, msg, msg_size);
}
int CC_HMAC_digest_sha3_512(uint8_t *mac, const size_t mac_size,
                          const uint8_t *key, const size_t key_size,
                          const uint8_t *msg, const size_t msg_size) {
  return generic_digest("SHA3-512", mac, mac_size, key, key_size, msg, msg_size);
}
int generic_digest(const char *hash, uint8_t *mac, const size_t mac_size,
                   const uint8_t *key, const size_t key_size,
                   const uint8_t *msg, const size_t msg_size) {
  EVP_MD_CTX *mdctx = NULL;
  const EVP_MD *md = NULL;
  EVP_PKEY *pkey = NULL;
  size_t req_size = 0;
  mdctx = EVP_MD_CTX_new();
  if (mdctx == NULL) {
    fprintf(stderr, "EVP_MD_CTX_new failed, error 0x%lx\n", ERR_get_error());
    return -1;
  }
  md = EVP_get_digestbyname(hash);
  if (md == NULL) {
    fprintf(stderr, "Failed to get digest %s by name\n", hash);
    EVP_MD_CTX_free(mdctx);
    return -1;
  }
  pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, key_size);
  if (pkey == NULL) {
    fprintf(stderr, "Failed to create HMAC key\n");
    EVP_MD_CTX_free(mdctx);
    return -1;
  }
  if (!EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey)) {
    fprintf(stderr, "Failed to DigestSignInit\n");
    goto error;
  }
  if (!EVP_DigestSignUpdate(mdctx, msg, msg_size)) {
    fprintf(stderr, "Failed to DigestSignUpdate\n");
    goto error;
  }
  if (!EVP_DigestSignFinal(mdctx, NULL, &req_size)) {
    fprintf(stderr, "Failed first call to DigestSignFinal\n");
    goto error;
  }
  if (req_size != mac_size) {
    fprintf(stderr, "Required size %zu does not match given size %zu\n",
            req_size, mac_size);
    goto error;
  }
  if (!EVP_DigestSignFinal(mdctx, mac, &req_size)) {
    fprintf(stderr, "Failed to DigestSignFinal\n");
    goto error;
  }
  EVP_MD_CTX_free(mdctx);
  EVP_PKEY_free(pkey);
  return 1;
error:
  EVP_MD_CTX_free(mdctx);
  EVP_PKEY_free(pkey);
  return -1;
}
Compile the shared library with the -lssl -lcrypto options:
gcc -fPIC -shared hmac_digest_harness.c -o hmac_digest.so -lssl -lcrypto
Then test the harness.
crypto-condor-cli test harness hmac_digest.so
Test verify¶
HMAC tag verification requires computing the tag again to compare it with the given value.
Naming convention¶
The function must conform to the following convention:
CC_HMAC_verify_<hash function
Where hash function is one of:
- sha1,- sha224,- sha256,- sha384,- sha512.
- sha3_224,- sha3_256,- sha3_384,- sha3_512.
Function signature¶
Attention
The tags used by crypto-condor may be truncated, meaning that comparing the entire MAC to
the tag passed by crypto-condor may fail. The size of the regular MAC tag is equal to the
output size of the underlying hash function. This is given through the md_size
parameter.
Its signature must be:
- int HMAC_verify(
- const uint8_t *mac,
- const size_t mac_size,
- const size_t md_size,
- const uint8_t *key,
- const size_t key_size,
- const uint8_t *msg,
- const size_t msg_size,
- Verifies HMAC tags. - Parameters:
- mac – [In] The MAC tag. 
- mac_size – [In] The size of the MAC tag in bytes. Note that the tag may be truncated, so the size may differ from - md_size.
- md_size – [In] The output size of the hash function in bytes. This is the size of a full MAC tag and may differ from - mac_size.
- key – [In] The secret key. 
- key_size – [In] The size of the secret key in bytes. 
- msg – [In] The message to authenticate. 
- msg_size – [In] The size of the message in bytes. 
 
- Returns:
- A status value. 
- Return values:
- 1 – Tag is valid. 
- 0 – Tag is invalid. 
- -1 – An error occurred. 
 
 
Example¶
To test the harness for this function, we use the following OpenSSL harness:
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <stdint.h>
#include <stdlib.h>
int generic_verify(const char *hash, const uint8_t *mac, const size_t mac_size,
                   const size_t md_size, const uint8_t *key,
                   const size_t key_size, const uint8_t *msg,
                   const size_t msg_size);
int CC_HMAC_verify_sha256(const uint8_t *mac, const size_t mac_size,
                          const size_t md_size, const uint8_t *key,
                          const size_t key_size, const uint8_t *msg,
                          const size_t msg_size) {
  return generic_verify("SHA-256", mac, mac_size, md_size, key, key_size, msg,
                        msg_size);
}
int CC_HMAC_verify_sha384(const uint8_t *mac, const size_t mac_size,
                          const size_t md_size, const uint8_t *key,
                          const size_t key_size, const uint8_t *msg,
                          const size_t msg_size) {
  return generic_verify("SHA-384", mac, mac_size, md_size, key, key_size, msg,
                        msg_size);
}
int CC_HMAC_verify_sha512(const uint8_t *mac, const size_t mac_size,
                          const size_t md_size, const uint8_t *key,
                          const size_t key_size, const uint8_t *msg,
                          const size_t msg_size) {
  return generic_verify("SHA-512", mac, mac_size, md_size, key, key_size, msg,
                        msg_size);
}
int CC_HMAC_verify_sha3_256(const uint8_t *mac, const size_t mac_size,
                            const size_t md_size, const uint8_t *key,
                            const size_t key_size, const uint8_t *msg,
                            const size_t msg_size) {
  return generic_verify("SHA3-256", mac, mac_size, md_size, key, key_size, msg,
                        msg_size);
}
int CC_HMAC_verify_sha3_384(const uint8_t *mac, const size_t mac_size,
                            const size_t md_size, const uint8_t *key,
                            const size_t key_size, const uint8_t *msg,
                            const size_t msg_size) {
  return generic_verify("SHA3-384", mac, mac_size, md_size, key, key_size, msg,
                        msg_size);
}
int CC_HMAC_verify_sha3_512(const uint8_t *mac, const size_t mac_size,
                            const size_t md_size, const uint8_t *key,
                            const size_t key_size, const uint8_t *msg,
                            const size_t msg_size) {
  return generic_verify("SHA3-512", mac, mac_size, md_size, key, key_size, msg,
                        msg_size);
}
int generic_verify(const char *hash, const uint8_t *mac, const size_t mac_size,
                   const size_t md_size, const uint8_t *key,
                   const size_t key_size, const uint8_t *msg,
                   const size_t msg_size) {
  EVP_MD_CTX *mdctx = NULL;
  const EVP_MD *md = NULL;
  EVP_PKEY *pkey = NULL;
  uint8_t buf[EVP_MAX_MD_SIZE];
  size_t buf_size = md_size;
  mdctx = EVP_MD_CTX_new();
  if (mdctx == NULL) {
    fprintf(stderr, "EVP_MD_CTX_new failed, error 0x%lx\n", ERR_get_error());
    return -1;
  }
  md = EVP_get_digestbyname(hash);
  if (md == NULL) {
    fprintf(stderr, "Failed to get digest %s by name\n", hash);
    EVP_MD_CTX_free(mdctx);
    return -1;
  }
  pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, key_size);
  if (pkey == NULL) {
    fprintf(stderr, "Failed to create HMAC key\n");
    EVP_MD_CTX_free(mdctx);
    return -1;
  }
  if (!EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey)) {
    fprintf(stderr, "Failed to DigestSignInit\n");
    goto error;
  }
  if (!EVP_DigestSignUpdate(mdctx, msg, msg_size)) {
    fprintf(stderr, "Failed to DigestSignUpdate\n");
    goto error;
  }
  if (!EVP_DigestSignFinal(mdctx, buf, &buf_size)) {
    fprintf(stderr, "Failed to DigestSignFinal, error 0x%lx\n",
            ERR_get_error());
    goto error;
  }
  EVP_MD_CTX_free(mdctx);
  EVP_PKEY_free(pkey);
  return (CRYPTO_memcmp(mac, buf, mac_size) == 0);
error:
  EVP_MD_CTX_free(mdctx);
  EVP_PKEY_free(pkey);
  return -1;
}
Compile the shared library with the -lssl -lcrypto options:
gcc -fPIC -shared hmac_verify_harness.c -o hmac_verify.so -lssl -lcrypto
Then test the harness.
crypto-condor-cli test harness hmac_verify.so