Exemple #1
0
int cf_ccm_decrypt(const cf_prp *prp, void *prpctx,
                   const uint8_t *cipher, size_t ncipher, size_t L,
                   const uint8_t *header, size_t nheader,
                   const uint8_t *nonce, size_t nnonce,
                   const uint8_t *tag, size_t ntag,
                   uint8_t *plain)
{
    uint8_t block[CF_MAXBLOCK];

    assert(ntag >= 4 && ntag <= 16 && ntag % 2 == 0);
    assert(L >= 2 && L <= 8);
    assert(nnonce == prp->blocksz - L - 1);

    uint8_t ctr_nonce[CF_MAXBLOCK];
    build_ctr_nonce(ctr_nonce, L, nonce, nnonce);

    cf_ctr ctr;
    cf_ctr_init(&ctr, prp, prpctx, ctr_nonce);
    cf_ctr_custom_counter(&ctr, prp->blocksz - L, L);

    /* Decrypt tag. */
    uint8_t plain_tag[CF_MAXBLOCK];
    cf_ctr_cipher(&ctr, tag, plain_tag, ntag);
    cf_ctr_discard_block(&ctr);

    /* Decrypt message. */
    cf_ctr_cipher(&ctr, cipher, plain, ncipher);

    cf_cbcmac_stream cm;
    cf_cbcmac_stream_init(&cm, prp, prpctx);

    /* Add first block. */
    add_block0(&cm, block, prp->blocksz,
               nonce, nnonce,
               L, ncipher, nheader, ntag);

    if (nheader)
        add_aad(&cm, block, header, nheader);

    cf_cbcmac_stream_update(&cm, plain, ncipher);
    zero_pad(&cm);

    /* Finish tag. */
    cf_cbcmac_stream_nopad_final(&cm, block);

    int err = 0;

    if (!mem_eq(block, plain_tag, ntag))
    {
        err = 1;
        mem_clean(plain, ncipher);
    }

    mem_clean(block, sizeof block);
    mem_clean(plain_tag, sizeof plain_tag);
    return err;
}
Exemple #2
0
static int process(const uint8_t key[32],
                   const uint8_t nonce[12],
                   const uint8_t *header, size_t nheader,
                   const uint8_t *input, size_t nbytes,
                   uint8_t *output,
                   int mode,
                   uint8_t tag[16])
{
  /* First, generate the Poly1305 key by running ChaCha20 with the
   * given key and a zero counter.  The first half of the
   * 64-byte output is the key. */
  uint8_t fullnonce[16] = { 0 };
  memcpy(fullnonce + 4, nonce, 12);

  uint8_t polykey[32] = { 0 };
  cf_chacha20_ctx chacha;
  cf_chacha20_init_custom(&chacha, key, 32, fullnonce, 4);
  cf_chacha20_cipher(&chacha, polykey, polykey, sizeof polykey);

  /* Now initialise Poly1305. */
  cf_poly1305 poly;
  cf_poly1305_init(&poly, polykey, polykey + 16);
  mem_clean(polykey, sizeof polykey);

  /* Discard next 32 bytes of chacha20 key stream. */
  cf_chacha20_cipher(&chacha, polykey, polykey, sizeof polykey);
  mem_clean(polykey, sizeof polykey);

  /* The input to Poly1305 is:
   * AAD || pad(AAD) || cipher || pad(cipher) || len_64(aad) || len_64(cipher) */
  uint8_t padbuf[16] = { 0 };

#define PADLEN(x) (16 - ((x) & 0xf))

  /* AAD || pad(AAD) */
  cf_poly1305_update(&poly, header, nheader);
  cf_poly1305_update(&poly, padbuf, PADLEN(nheader));

  /* || cipher */
  if (mode == ENCRYPT)
  {
    /* If we're encrypting, we compute the ciphertext
     * before inputting it into the MAC. */
    cf_chacha20_cipher(&chacha, input, output, nbytes);
    cf_poly1305_update(&poly, output, nbytes);
  } else {
    /* Otherwise: decryption -- input the ciphertext.
     * Delay actual decryption until we checked the MAC. */
    cf_poly1305_update(&poly, input, nbytes);
  }

  /* || pad(cipher) */
  cf_poly1305_update(&poly, padbuf, PADLEN(nbytes));

  /* || len_64(aad) || len_64(cipher) */
  write64_le(nheader, padbuf);
  write64_le(nbytes, padbuf + 8);
  cf_poly1305_update(&poly, padbuf, sizeof padbuf);

  /* MAC computation is now complete. */

  if (mode == ENCRYPT)
  {
    cf_poly1305_finish(&poly, tag);
    mem_clean(&chacha, sizeof chacha);
    return SUCCESS;
  }

  /* Decrypt mode: calculate tag, and check it.
   * If it's correct, proceed with decryption. */
  uint8_t checktag[16];
  cf_poly1305_finish(&poly, checktag);

  if (mem_eq(checktag, tag, sizeof checktag))
  {
    cf_chacha20_cipher(&chacha, input, output, nbytes);
    mem_clean(&chacha, sizeof chacha);
    mem_clean(checktag, sizeof checktag);
    return SUCCESS;
  } else {
    mem_clean(output, nbytes);
    mem_clean(&chacha, sizeof chacha);
    mem_clean(checktag, sizeof checktag);
    return FAILURE;
  }
}