smuellerDD / acvpparser

ACVP Parser for invocation of cryptographic implementations using the ACVP JSON test vectors
https://www.chronox.de/acvpparser
Other
36 stars 27 forks source link

SHA MCT (or LDT) cipher interface function working example availability #85

Closed dananjayavr closed 2 months ago

dananjayavr commented 2 months ago

Hello,

I am using backends/backend_acvpproxy.c as an example to create a SHA cipher interface function for a Crypto implementation :

static int cyclonecrypto_sha_generate(struct sha_data *data, flags_t parsed_flags)
{
    const HashAlgo *hash;
    int ret;

    (void)parsed_flags;

    CKINT(cyclonecrypto_hash_convert(data->cipher, &hash));

    CKINT(alloc_buf(hash->digestSize, &data->mac));

    hash->compute(data->msg.buf,data->msg.len,data->mac.buf);

out:
    return ret;
}

I have also implemented the relevant hash_convert function:

static int cyclonecrypto_hash_convert(uint64_t cipher, const HashAlgo **ret_hash)
{
    const HashAlgo *hash;

    switch (cipher) {
    case ACVP_SHA256:
    case ACVP_HMACSHA2_256:
        hash = SHA256_HASH_ALGO;
        break;
    case ACVP_SHA512:
    case ACVP_HMACSHA2_512:
        hash = SHA512_HASH_ALGO;
        break;
    case ACVP_SHA3_224:
    case ACVP_HMACSHA3_224:
        hash = SHA3_224_HASH_ALGO;
        break;
    case ACVP_SHA3_256:
    case ACVP_HMACSHA3_256:
        hash = SHA3_256_HASH_ALGO;
        break;
    case ACVP_SHA3_384:
    case ACVP_HMACSHA3_384:
        hash = SHA3_384_HASH_ALGO;
        break;
    case ACVP_SHA3_512:
    case ACVP_HMACSHA3_512:
        hash = SHA3_512_HASH_ALGO;
        break;
    default:
        logger(LOGGER_ERR, "Cipher implementation not found\n");
        return -EOPNOTSUPP;
    }

    *ret_hash = hash;
    return 0;
}

The test vectors for HMAC-SHAXXX functions are all validated on the ACVP Demo environment but not the SHA (SHA2 and SHA3) functions. After some investigations it seems the MCT and LDT vectors are not being processed properly.

I then followed the example on backend_openssl_common.c to implement the hash_inner_loop function and registered the appropriate callback :

static int cyclonecrypto_sha_mct_ldt_generate(struct sha_data *data, flags_t parsed_flags)
{
    const HashAlgo *hash;
    //HashContext ctx;
    BUFFER_INIT(msg_p);
    int mdlen;
    int ret;

    (void)parsed_flags;

    CKINT(sha_ldt_helper(data, &msg_p));

    CKINT(cyclonecrypto_hash_convert(data->cipher, &hash));

    mdlen = hash->digestSize;

    CKINT(alloc_buf((size_t)mdlen, &data->mac));

    //hash->init(&ctx);
    //hash->update(&ctx,msg_p.buf, msg_p.len);
    //hash->final(&ctx,data->mac.buf);
    hash->compute(msg_p.buf,msg_p.len,data->mac.buf);

out:
    sha_ldt_clear_buf(data, &msg_p);
    return ret;
}

static int cyclonecrypto_hash_inner_loop(struct sha_data *data, flags_t parsed_flags)
{
    switch (data->cipher) {
    case ACVP_SHA1:
    case ACVP_SHA224:
    case ACVP_SHA256:
    case ACVP_SHA384:
    case ACVP_SHA512:
        return parser_sha2_inner_loop(data, parsed_flags,
                          cyclonecrypto_sha_mct_ldt_generate);

    case ACVP_SHA3_224:
    case ACVP_SHA3_256:
    case ACVP_SHA3_384:
    case ACVP_SHA3_512:
        return parser_sha3_inner_loop(data, parsed_flags,
                          cyclonecrypto_sha_mct_ldt_generate);
    default:
        return -EOPNOTSUPP;
    }
}

static struct sha_backend cyclonecrypto_sha =
{
    cyclonecrypto_sha_generate,   /* hash_generate */
    cyclonecrypto_hash_inner_loop
};

The result is still the same, meaning HMAC-SHA-XXX vectors are passing but not the SHA functions (probably because HMAC test vectors do not contain MCT or LTD types).

I just wanted to make sure I am not missing something or at least on the right track. By the way, I compiled the included backends/backend_acvpproxy.c example and I obtain the exact same result. Therefore I assume the example code is perhaps not complete?

I am using ACVP Parser version: ACVPParser/2.1.6

Thank you for your help.

Dan

smuellerDD commented 2 months ago

Am Mittwoch, 17. Juli 2024, 17:30:26 MESZ schrieb Dan Ramanayake:

Hi Dan,

Hello,

I am using backends/backend_acvpproxy.c as an example to create a SHA cipher interface function for a Crypto implementation :

static int cyclonecrypto_sha_generate(struct sha_data *data, flags_t
parsed_flags) {
  const HashAlgo *hash;
  int ret;

  (void)parsed_flags;

  CKINT(cyclonecrypto_hash_convert(data->cipher, &hash));

  CKINT(alloc_buf(hash->digestSize, &data->mac));

  hash->compute(data->msg.buf,data->msg.len,data->mac.buf);

out:
  return ret;
}

I have also implemented the relevant hash_convert function:

static int cyclonecrypto_hash_convert(uint64_t cipher, const HashAlgo
**ret_hash) {
  const HashAlgo *hash;

  switch (cipher) {
  case ACVP_SHA256:
  case ACVP_HMACSHA2_256:
      hash = SHA256_HASH_ALGO;
      break;
  case ACVP_SHA512:
  case ACVP_HMACSHA2_512:
      hash = SHA512_HASH_ALGO;
      break;
  case ACVP_SHA3_224:
  case ACVP_HMACSHA3_224:
      hash = SHA3_224_HASH_ALGO;
      break;
  case ACVP_SHA3_256:
  case ACVP_HMACSHA3_256:
      hash = SHA3_256_HASH_ALGO;
      break;
  case ACVP_SHA3_384:
  case ACVP_HMACSHA3_384:
      hash = SHA3_384_HASH_ALGO;
      break;
  case ACVP_SHA3_512:
  case ACVP_HMACSHA3_512:
      hash = SHA3_512_HASH_ALGO;
      break;
  default:
      logger(LOGGER_ERR, "Cipher implementation not found\n");
      return -EOPNOTSUPP;
  }

  *ret_hash = hash;
  return 0;
}

The test vectors for HMAC-SHAXXX functions are all validated on the ACVP Demo environment but not the SHA (SHA2 and SHA3) functions. After some investigations it seems the MCT and LDT vectors are not being processed properly.

If the input and output is set properly by the hash algo implementation, you do not need a specific MCT inner loop. That is only there to reduce the round trips to the IUT from 100.000 to 100 which saves considerable time if you cross system boundaries like user/kernel land.

The LDT support only requires the LDT helper intro/exit code as you implement below.

I then followed the example on backend_openssl_common.c to implement the hash_inner_loop function and registered the appropriate callback :


static int cyclonecrypto_sha_mct_ldt_generate(struct sha_data *data, flags_t
parsed_flags) {
  const HashAlgo *hash;
  //HashContext ctx;
  BUFFER_INIT(msg_p);
  int mdlen;
  int ret;

  (void)parsed_flags;

  CKINT(sha_ldt_helper(data, &msg_p));

  CKINT(cyclonecrypto_hash_convert(data->cipher, &hash));

  mdlen = hash->digestSize;

  CKINT(alloc_buf((size_t)mdlen, &data->mac));

  //hash->init(&ctx);
  //hash->update(&ctx,msg_p.buf, msg_p.len);
  //hash->final(&ctx,data->mac.buf);
  hash->compute(msg_p.buf,msg_p.len,data->mac.buf);

out:
  sha_ldt_clear_buf(data, &msg_p);
  return ret;
}

static int cyclonecrypto_hash_inner_loop(struct sha_data *data, flags_t
parsed_flags) {
  switch (data->cipher) {
  case ACVP_SHA1:
  case ACVP_SHA224:
  case ACVP_SHA256:
  case ACVP_SHA384:
  case ACVP_SHA512:
      return parser_sha2_inner_loop(data, parsed_flags,
                        cyclonecrypto_sha_mct_ldt_generate);

  case ACVP_SHA3_224:
  case ACVP_SHA3_256:
  case ACVP_SHA3_384:
  case ACVP_SHA3_512:
      return parser_sha3_inner_loop(data, parsed_flags,
                        cyclonecrypto_sha_mct_ldt_generate);
  default:
      return -EOPNOTSUPP;
  }
}

This is ok, but see above for the reasons for having an inner loop impl.

static struct sha_backend cyclonecrypto_sha = { cyclonecrypto_sha_generate, / hash_generate / cyclonecrypto_hash_inner_loop };



The result is still the same, meaning HMAC-SHA-XXX vectors are passing but
not the SHA functions (probably because HMAC test vectors do not contain
MCT or LTD types).

I just wanted to make sure I am not missing something or at least on the
right track.

You implement all correctly for the parser logic. Again, the MCT inner loop is not needed, but good if you have it.

That said, for MCT, I presume you keep some state or something in your cipher handle to your IUT, but the MCT requires a complete fresh new message digest for each new loop round.

The LDT requires the one-shot message digest calculation of the 1 to 8 GBytes of linear buffer. Check that your IUT can handle that.

By the way, I compiled the included backends/backend_acvpproxy.c example and I obtain the exact same result. Therefore I assume the example code is perhaps not complete?

Note, the ACVP proxy backend is not intended to handle LDT, because all I need it for is the SHA2 processing for the OTP and other auxiliary logic in the ACVP Proxy. Yet, the MCT ought to work.

I am using ACVP Parser version: ACVPParser/2.1.6

Thank you for your help.

Dan

Ciao Stephan

dananjayavr commented 2 months ago

Stephan,

Thank you for your answers.

Your remarks about LDT types gave me an idea. I think you are spot on about the linear buffer sizes (making sure the IUT can handle 1 - 8 GBytes). I have to check but I don't think this is supported by the IUT as it is primarily intended to be run on embedded (microcontroller) targets. So I will have to check this on my side.

So the problem must lie with LDT instead of MCT (which explains the identical results obtained both by my own crypto backend and ACVP Proxy backend).

Perhaps I should look at ACVP Proxy documentation about requesting test vectors without LDT ? Do you have any pointers about this?

Thanks again, I feel I am on the right track.

Dan

dananjayavr commented 2 months ago

Quick update, I figured out how to ask for non-LDT vectors from ACVP Proxy and with it all the test vectors pass! I'll go ahead and close the 'issue'. Thanks again @smuellerDD for your guidance.