Esempio n. 1
0
static int aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
                                       size_t *out_len, size_t max_out_len,
                                       const uint8_t *nonce, size_t nonce_len,
                                       const uint8_t *in, size_t in_len,
                                       const uint8_t *ad, size_t ad_len) {
  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
  uint8_t mac[POLY1305_TAG_LEN];
  uint8_t poly1305_key[32] ALIGNED;
  size_t plaintext_len;
  poly1305_state poly1305;
  const uint64_t in_len_64 = in_len;

  if (in_len < c20_ctx->tag_len) {
    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  /* The underlying ChaCha implementation may not overflow the block
   * counter into the second counter word. Therefore we disallow
   * individual operations that work on more than 256GB at a time.
   * |in_len_64| is needed because, on 32-bit platforms, size_t is only
   * 32-bits and this produces a warning because it's always false.
   * Casting to uint64_t inside the conditional is not sufficient to stop
   * the warning. */
  if (in_len_64 >= (1ull << 32) * 64 - 64) {
    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_TOO_LARGE);
    return 0;
  }

  if (nonce_len != CHACHA20_NONCE_LEN) {
    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_IV_TOO_LARGE);
    return 0;
  }

  plaintext_len = in_len - c20_ctx->tag_len;

  if (max_out_len < plaintext_len) {
    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open,
                      CIPHER_R_BUFFER_TOO_SMALL);
    return 0;
  }

  memset(poly1305_key, 0, sizeof(poly1305_key));
  CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
                   c20_ctx->key, nonce, 0);

  CRYPTO_poly1305_init(&poly1305, poly1305_key);
  poly1305_update_with_length(&poly1305, ad, ad_len);
  poly1305_update_with_length(&poly1305, in, plaintext_len);
  CRYPTO_poly1305_finish(&poly1305, mac);

  if (CRYPTO_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1);
  *out_len = plaintext_len;
  return 1;
}
Esempio n. 2
0
static ssize_t aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx,
	unsigned char *out, size_t max_out_len,
	const unsigned char *nonce, size_t nonce_len,
	const unsigned char *in, size_t in_len,
	const unsigned char *ad, size_t ad_len)
	{
	const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
	unsigned char poly1305_key[32] ALIGNED;
	poly1305_state poly1305;
	const uint64_t in_len_64 = in_len;

	/* The underlying ChaCha implementation may not overflow the block
	 * counter into the second counter word. Therefore we disallow
	 * individual operations that work on more than 2TB at a time.
	 * |in_len_64| is needed because, on 32-bit platforms, size_t is only
	 * 32-bits and this produces a warning because it's always false.
	 * Casting to uint64_t inside the conditional is not sufficient to stop
	 * the warning. */
	if (in_len_64 >= (1ull << 32)*64-64)
		{
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_TOO_LARGE);
		return -1;
		}

	if (max_out_len < in_len + c20_ctx->tag_len)
		{
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_BUFFER_TOO_SMALL);
		return -1;
		}

	if (nonce_len != CHACHA20_NONCE_LEN)
		{
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_IV_TOO_LARGE);
		return -1;
		}

	memset(poly1305_key, 0, sizeof(poly1305_key));
	CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), c20_ctx->key, nonce, 0);

	CRYPTO_poly1305_init(&poly1305, poly1305_key);
	poly1305_update_with_length(&poly1305, ad, ad_len);
	CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
	poly1305_update_with_length(&poly1305, out, in_len);

	if (c20_ctx->tag_len != POLY1305_TAG_LEN)
		{
		unsigned char tag[POLY1305_TAG_LEN];
		CRYPTO_poly1305_finish(&poly1305, tag);
		memcpy(out + in_len, tag, c20_ctx->tag_len);
		return in_len + c20_ctx->tag_len;
		}

	CRYPTO_poly1305_finish(&poly1305, out + in_len);
	return in_len + POLY1305_TAG_LEN;
	}
Esempio n. 3
0
// calc_tag fills |tag| with the authentication tag for the given inputs.
static void calc_tag(uint8_t tag[POLY1305_TAG_LEN], const uint8_t *key,
                     const uint8_t nonce[12], const uint8_t *ad, size_t ad_len,
                     const uint8_t *ciphertext, size_t ciphertext_len,
                     const uint8_t *ciphertext_extra,
                     size_t ciphertext_extra_len) {
  alignas(16) uint8_t poly1305_key[32];
  OPENSSL_memset(poly1305_key, 0, sizeof(poly1305_key));
  CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), key, nonce,
                   0);

  static const uint8_t padding[16] = { 0 };  // Padding is all zeros.
  poly1305_state ctx;
  CRYPTO_poly1305_init(&ctx, poly1305_key);
  CRYPTO_poly1305_update(&ctx, ad, ad_len);
  if (ad_len % 16 != 0) {
    CRYPTO_poly1305_update(&ctx, padding, sizeof(padding) - (ad_len % 16));
  }
  CRYPTO_poly1305_update(&ctx, ciphertext, ciphertext_len);
  CRYPTO_poly1305_update(&ctx, ciphertext_extra, ciphertext_extra_len);
  const size_t ciphertext_total = ciphertext_len + ciphertext_extra_len;
  if (ciphertext_total % 16 != 0) {
    CRYPTO_poly1305_update(&ctx, padding,
                           sizeof(padding) - (ciphertext_total % 16));
  }
  poly1305_update_length(&ctx, ad_len);
  poly1305_update_length(&ctx, ciphertext_total);
  CRYPTO_poly1305_finish(&ctx, tag);
}
Esempio n. 4
0
static int aead_chacha20_poly1305_seal(aead_poly1305_update poly1305_update,
                                       const void *ctx_buf, uint8_t *out,
                                       size_t *out_len, size_t max_out_len,
                                       const uint8_t nonce[12],
                                       const uint8_t *in, size_t in_len,
                                       const uint8_t *ad, size_t ad_len) {
  aead_assert_open_seal_preconditions(alignof(struct aead_chacha20_poly1305_ctx),
                                      ctx_buf, out, out_len, nonce, in, in_len,
                                      ad, ad_len);

  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx_buf;

  if (!aead_seal_out_max_out_in_tag_len(out_len, max_out_len, in_len,
                                        POLY1305_TAG_LEN)) {
    /* |aead_seal_out_max_out_in_tag_len| already called |OPENSSL_PUT_ERROR|. */
    return 0;
  }

  CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);

  uint8_t tag[POLY1305_TAG_LEN] ALIGNED;
  aead_poly1305(poly1305_update, tag, c20_ctx, nonce, ad, ad_len, out, in_len);

  /* TODO: Does |tag| really need to be |ALIGNED|? If not, we can avoid this
   * call to |memcpy|. */
  memcpy(out + in_len, tag, POLY1305_TAG_LEN);

  return 1;
}
Esempio n. 5
0
static int aead_chacha20_poly1305_open(aead_poly1305_update poly1305_update,
                                       const void *ctx_buf, uint8_t *out,
                                       size_t *out_len, size_t max_out_len,
                                       const uint8_t nonce[12],
                                       const uint8_t *in, size_t in_len,
                                       const uint8_t *ad, size_t ad_len) {
  aead_assert_open_seal_preconditions(alignof(struct aead_chacha20_poly1305_ctx),
                                      ctx_buf, out, out_len, nonce, in, in_len,
                                      ad, ad_len);

  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx_buf;

  if (!aead_open_out_max_out_in_tag_len(out_len, max_out_len, in_len,
                                        POLY1305_TAG_LEN)) {
    /* |aead_open_out_max_out_in_tag_len| already called
     * |OPENSSL_PUT_ERROR|. */
    return 0;
  }

  size_t plaintext_len;

  plaintext_len = in_len - POLY1305_TAG_LEN;
  uint8_t tag[POLY1305_TAG_LEN] ALIGNED;
  aead_poly1305(poly1305_update, tag, c20_ctx, nonce, ad, ad_len, in,
                plaintext_len);
  if (CRYPTO_memcmp(tag, in + plaintext_len, POLY1305_TAG_LEN) != 0) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1);
  *out_len = plaintext_len;
  return 1;
}
Esempio n. 6
0
void CRYPTO_sysrand(uint8_t *out, size_t requested) {
  static const uint8_t kZeroKey[32];

  uint8_t nonce[12];
  OPENSSL_memset(nonce, 0, sizeof(nonce));
  OPENSSL_memcpy(nonce, &g_num_calls, sizeof(g_num_calls));

  OPENSSL_memset(out, 0, requested);
  CRYPTO_chacha_20(out, out, requested, kZeroKey, nonce, 0);
  g_num_calls++;
}
/* aead_poly1305 fills |tag| with the authentication tag for the given
 * inputs, using |update| to control the order and format that the inputs are
 * signed/authenticated. */
static void aead_poly1305(aead_poly1305_update update,
                          uint8_t tag[POLY1305_TAG_LEN],
                          const struct aead_chacha20_poly1305_ctx *c20_ctx,
                          const uint8_t nonce[12], const uint8_t *ad,
                          size_t ad_len, const uint8_t *ciphertext,
                          size_t ciphertext_len) {
  uint8_t poly1305_key[32] ALIGNED;
  memset(poly1305_key, 0, sizeof(poly1305_key));
  CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
                   c20_ctx->key, nonce, 0);
  poly1305_state ctx;
  CRYPTO_poly1305_init(&ctx, poly1305_key);
  update(&ctx, ad, ad_len, ciphertext, ciphertext_len);
  CRYPTO_poly1305_finish(&ctx, tag);
}
static int aead_chacha20_poly1305_open_gather(
    const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
    size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;

  if (nonce_len != 12) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
    return 0;
  }

  if (in_tag_len != ctx->tag_len) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  // |CRYPTO_chacha_20| uses a 32-bit block counter. Therefore we disallow
  // individual operations that work on more than 256GB at a time.
  // |in_len_64| is needed because, on 32-bit platforms, size_t is only
  // 32-bits and this produces a warning because it's always false.
  // Casting to uint64_t inside the conditional is not sufficient to stop
  // the warning.
  const uint64_t in_len_64 = in_len;
  if (in_len_64 >= (UINT64_C(1) << 32) * 64 - 64) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
    return 0;
  }

  union open_data data;
  if (asm_capable()) {
    OPENSSL_memcpy(data.in.key, c20_ctx->key, 32);
    data.in.counter = 0;
    OPENSSL_memcpy(data.in.nonce, nonce, 12);
    chacha20_poly1305_open(out, in, in_len, ad, ad_len, &data);
  } else {
    calc_tag(data.out.tag, c20_ctx, nonce, ad, ad_len, in, in_len, NULL, 0);
    CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
  }

  if (CRYPTO_memcmp(data.out.tag, in_tag, ctx->tag_len) != 0) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  return 1;
}
static int open_impl(aead_poly1305_update poly1305_update,
                     const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
                     size_t max_out_len, const uint8_t nonce[12],
                     const uint8_t *in, size_t in_len, const uint8_t *ad,
                     size_t ad_len) {
  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
  size_t plaintext_len;
  const uint64_t in_len_64 = in_len;

  if (in_len < c20_ctx->tag_len) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  /* |CRYPTO_chacha_20| uses a 32-bit block counter. Therefore we disallow
   * individual operations that work on more than 256GB at a time.
   * |in_len_64| is needed because, on 32-bit platforms, size_t is only
   * 32-bits and this produces a warning because it's always false.
   * Casting to uint64_t inside the conditional is not sufficient to stop
   * the warning. */
  if (in_len_64 >= (1ull << 32) * 64 - 64) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
    return 0;
  }

  plaintext_len = in_len - c20_ctx->tag_len;
  uint8_t tag[POLY1305_TAG_LEN] ALIGNED;
  aead_poly1305(poly1305_update, tag, c20_ctx, nonce, ad, ad_len, in,
                plaintext_len);
  if (CRYPTO_memcmp(tag, in + plaintext_len, c20_ctx->tag_len) != 0) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1);
  *out_len = plaintext_len;
  return 1;
}
Esempio n. 10
0
static int
aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
    size_t *out_len, size_t max_out_len, const unsigned char *nonce,
    size_t nonce_len, const unsigned char *in, size_t in_len,
    const unsigned char *ad, size_t ad_len)
{
	const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
	unsigned char mac[POLY1305_TAG_LEN];
	unsigned char poly1305_key[32];
	const unsigned char *iv = nonce;
	poly1305_state poly1305;
	const uint64_t in_len_64 = in_len;
	size_t plaintext_len;
	uint64_t ctr = 0;

	if (in_len < c20_ctx->tag_len) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
		return 0;
	}

	/* The underlying ChaCha implementation may not overflow the block
	 * counter into the second counter word. Therefore we disallow
	 * individual operations that work on more than 2TB at a time.
	 * in_len_64 is needed because, on 32-bit platforms, size_t is only
	 * 32-bits and this produces a warning because it's always false.
	 * Casting to uint64_t inside the conditional is not sufficient to stop
	 * the warning. */
	if (in_len_64 >= (1ULL << 32) * 64 - 64) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_TOO_LARGE);
		return 0;
	}

	if (nonce_len != ctx->aead->nonce_len) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE);
		return 0;
	}

	plaintext_len = in_len - c20_ctx->tag_len;

	if (max_out_len < plaintext_len) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN,
		    EVP_R_BUFFER_TOO_SMALL);
		return 0;
	}

	if (nonce_len == CHACHA20_NONCE_LEN_OLD) {
		/* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */

		memset(poly1305_key, 0, sizeof(poly1305_key));
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
		    sizeof(poly1305_key), c20_ctx->key, nonce, 0);

		CRYPTO_poly1305_init(&poly1305, poly1305_key);
		poly1305_update_with_length(&poly1305, ad, ad_len);
		poly1305_update_with_length(&poly1305, in, plaintext_len);
	} else if (nonce_len == CHACHA20_NONCE_LEN) {
		/* RFC 7539, May 2015 */

		ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
		    nonce[2] << 16 | nonce[3] << 24) << 32;
		iv = nonce + CHACHA20_CONSTANT_LEN;

		memset(poly1305_key, 0, sizeof(poly1305_key));
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
		    sizeof(poly1305_key), c20_ctx->key, iv, ctr);

		CRYPTO_poly1305_init(&poly1305, poly1305_key);
		poly1305_update_with_pad16(&poly1305, ad, ad_len);
		poly1305_update_with_pad16(&poly1305, in, plaintext_len);
		poly1305_update_with_length(&poly1305, NULL, ad_len);
		poly1305_update_with_length(&poly1305, NULL, plaintext_len);
	}

	CRYPTO_poly1305_finish(&poly1305, mac);

	if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
		return 0;
	}

	CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1);
	*out_len = plaintext_len;
	return 1;
}
Esempio n. 11
0
/* Single-shot ChaCha20 using CRYPTO_chacha_20 interface. */
static void
crypto_chacha_20_test(struct chacha_tv *tv, unsigned char *out,
    unsigned char *in)
{
	CRYPTO_chacha_20(out, in, tv->len, tv->key, tv->iv, 0);
}
Esempio n. 12
0
int RAND_bytes(uint8_t *buf, size_t len) {
  if (len == 0) {
    return 1;
  }

  if (!CRYPTO_have_hwrand() ||
      !CRYPTO_hwrand(buf, len)) {
    /* Without a hardware RNG to save us from address-space duplication, the OS
     * entropy is used directly. */
    CRYPTO_sysrand(buf, len);
    return 1;
  }

  struct rand_thread_state *state =
      CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND);
  if (state == NULL) {
    state = OPENSSL_malloc(sizeof(struct rand_thread_state));
    if (state == NULL ||
        !CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_RAND, state,
                                 rand_thread_state_free)) {
      CRYPTO_sysrand(buf, len);
      return 1;
    }

    memset(state->partial_block, 0, sizeof(state->partial_block));
    state->calls_used = kMaxCallsPerRefresh;
  }

  if (state->calls_used >= kMaxCallsPerRefresh ||
      state->bytes_used >= kMaxBytesPerRefresh) {
    CRYPTO_sysrand(state->key, sizeof(state->key));
    state->calls_used = 0;
    state->bytes_used = 0;
    state->partial_block_used = sizeof(state->partial_block);
  }

  if (len >= sizeof(state->partial_block)) {
    size_t remaining = len;
    while (remaining > 0) {
      // kMaxBytesPerCall is only 2GB, while ChaCha can handle 256GB. But this
      // is sufficient and easier on 32-bit.
      static const size_t kMaxBytesPerCall = 0x80000000;
      size_t todo = remaining;
      if (todo > kMaxBytesPerCall) {
        todo = kMaxBytesPerCall;
      }
      CRYPTO_chacha_20(buf, buf, todo, state->key,
                       (uint8_t *)&state->calls_used, 0);
      buf += todo;
      remaining -= todo;
      state->calls_used++;
    }
  } else {
    if (sizeof(state->partial_block) - state->partial_block_used < len) {
      CRYPTO_chacha_20(state->partial_block, state->partial_block,
                       sizeof(state->partial_block), state->key,
                       (uint8_t *)&state->calls_used, 0);
      state->partial_block_used = 0;
    }

    unsigned i;
    for (i = 0; i < len; i++) {
      buf[i] ^= state->partial_block[state->partial_block_used++];
    }
    state->calls_used++;
  }
  state->bytes_used += len;

  return 1;
}
Esempio n. 13
0
static int chacha20_poly1305_seal_scatter(
    const uint8_t *key, uint8_t *out, uint8_t *out_tag,
    size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
    size_t extra_in_len, const uint8_t *ad, size_t ad_len, size_t tag_len) {
  if (extra_in_len + tag_len < tag_len) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
    return 0;
  }
  if (max_out_tag_len < tag_len + extra_in_len) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
    return 0;
  }
  if (nonce_len != 12) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
    return 0;
  }

  // |CRYPTO_chacha_20| uses a 32-bit block counter. Therefore we disallow
  // individual operations that work on more than 256GB at a time.
  // |in_len_64| is needed because, on 32-bit platforms, size_t is only
  // 32-bits and this produces a warning because it's always false.
  // Casting to uint64_t inside the conditional is not sufficient to stop
  // the warning.
  const uint64_t in_len_64 = in_len;
  if (in_len_64 >= (UINT64_C(1) << 32) * 64 - 64) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
    return 0;
  }

  if (max_out_tag_len < tag_len) {
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
    return 0;
  }

  // The the extra input is given, it is expected to be very short and so is
  // encrypted byte-by-byte first.
  if (extra_in_len) {
    static const size_t kChaChaBlockSize = 64;
    uint32_t block_counter = 1 + (in_len / kChaChaBlockSize);
    size_t offset = in_len % kChaChaBlockSize;
    uint8_t block[64 /* kChaChaBlockSize */];

    for (size_t done = 0; done < extra_in_len; block_counter++) {
      memset(block, 0, sizeof(block));
      CRYPTO_chacha_20(block, block, sizeof(block), key, nonce,
                       block_counter);
      for (size_t i = offset; i < sizeof(block) && done < extra_in_len;
           i++, done++) {
        out_tag[done] = extra_in[done] ^ block[i];
      }
      offset = 0;
    }
  }

  union seal_data data;
  if (asm_capable()) {
    OPENSSL_memcpy(data.in.key, key, 32);
    data.in.counter = 0;
    OPENSSL_memcpy(data.in.nonce, nonce, 12);
    data.in.extra_ciphertext = out_tag;
    data.in.extra_ciphertext_len = extra_in_len;
    chacha20_poly1305_seal(out, in, in_len, ad, ad_len, &data);
  } else {
    CRYPTO_chacha_20(out, in, in_len, key, nonce, 1);
    calc_tag(data.out.tag, key, nonce, ad, ad_len, out, in_len, out_tag,
             extra_in_len);
  }

  OPENSSL_memcpy(out_tag + extra_in_len, data.out.tag, tag_len);
  *out_tag_len = extra_in_len + tag_len;
  return 1;
}
Esempio n. 14
0
int main(void)
{
    static const unsigned num_tests = sizeof(chacha_tests) / sizeof(struct chacha_test);
    unsigned i;
    uint8_t key_bytes[32 + 16];
    uint8_t nonce_bytes[12 + 16] = { 0 };

    uint8_t *key = misalign(key_bytes);
    uint8_t *nonce = misalign(nonce_bytes);

    for (i = 0; i < num_tests; i++) {
        const struct chacha_test *test = &chacha_tests[i];
        uint8_t *expected, *out_bytes, *zero_bytes, *out, *zeros;
        size_t len = strlen(test->outhex);

        if (strlen(test->keyhex) != 32 * 2 || strlen(test->noncehex) != 12 * 2 || (len & 1) == 1)
            return 1;

        len /= 2;

        hex_decode(key, test->keyhex);
        hex_decode(nonce, test->noncehex);

        expected = malloc(len);
        out_bytes = malloc(len + 16);
        zero_bytes = malloc(len + 16);
        /* Attempt to test unaligned inputs. */
        out = misalign(out_bytes);
        zeros = misalign(zero_bytes);
        memset(zeros, 0, len);

        hex_decode(expected, test->outhex);
        CRYPTO_chacha_20(out, zeros, len, key, nonce, 0);

        if (memcmp(out, expected, len) != 0) {
            printf("ChaCha20 test #%d failed.\n", i);
            printf("got:      ");
            hexdump(out, len);
            printf("\nexpected: ");
            hexdump(expected, len);
            printf("\n");
            return 1;
        }

        /*
         * The last test has a large output. We test whether the
         * counter works as expected by skipping the first 64 bytes of
         * it.
         */
        if (i == num_tests - 1) {
            CRYPTO_chacha_20(out, zeros, len - 64, key, nonce, 1);
            if (memcmp(out, expected + 64, len - 64) != 0) {
                printf("ChaCha20 skip test failed.\n");
                return 1;
            }
        }

        free(expected);
        free(zero_bytes);
        free(out_bytes);
    }

    printf("PASS\n");
    return 0;
}