Esempio n. 1
0
/**
 * \brief Reseeds the random number generator from operating system entropy.
 *
 * \param state The RandState object.
 *
 * \return NOISE_ERROR_NONE on success.
 * \return NOISE_ERROR_INVALID_PARAM if \a state is NULL.
 *
 * This function forces the random number generator to fetch fresh entropy
 * from the operating system.  Normally this isn't necessary because
 * noise_randstate_generate() will reseed automatically when necessary.
 *
 * If the application needs to generate a highly critical value such as a
 * new keypair then it may want to force a reseed.  Even this isn't necessary
 * for \ref dhstate "DHState" and \ref signstate "SignState" which already
 * seek fresh operating system entropy when generating keypairs.
 *
 * \sa noise_randstate_generate()
 */
int noise_randstate_reseed(NoiseRandState *state)
{
    uint8_t data[40];

    /* Validate the parameter */
    if (!state)
        return NOISE_ERROR_INVALID_PARAM;

    /* Get new random data from the operating system, encrypt it
       with the previous key/IV, and then replace the key/IV */
    noise_rand_bytes(data, sizeof(data));
    chacha_encrypt_bytes(&(state->chacha), data, data, sizeof(data));
    chacha_keysetup(&(state->chacha), data, 256);
    chacha_ivsetup(&(state->chacha), data + 32, 0);
    state->left = NOISE_RAND_RESEED_COUNT;

    /* And force a rekey as well for good measure */
    memset(data, 0, sizeof(data));
    chacha_encrypt_bytes(&(state->chacha), data, data, sizeof(data));
    chacha_keysetup(&(state->chacha), data, 256);
    chacha_ivsetup(&(state->chacha), data + 32, 0);
    noise_clean(data, sizeof(data));

    /* Ready to go */
    return NOISE_ERROR_NONE;
}
Esempio n. 2
0
/*
 * chachapoly_crypt() operates as following:
 * En/decrypt with header key 'aadlen' bytes from 'src', storing result
 * to 'dest'. The ciphertext here is treated as additional authenticated
 * data for MAC calculation.
 * En/decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. Use
 * POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the authentication
 * tag. This tag is written on encryption and verified on decryption.
 */
int
chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
    const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt)
{
	u_char seqbuf[8];
	const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
	u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
	int r = SSH_ERR_INTERNAL_ERROR;

	/*
	 * Run ChaCha20 once to generate the Poly1305 key. The IV is the
	 * packet sequence number.
	 */
	memset(poly_key, 0, sizeof(poly_key));
	POKE_U64(seqbuf, seqnr);
	chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
	chacha_encrypt_bytes(&ctx->main_ctx,
	    poly_key, poly_key, sizeof(poly_key));

	/* If decrypting, check tag before anything else */
	if (!do_encrypt) {
		const u_char *tag = src + aadlen + len;

		poly1305_auth(expected_tag, src, aadlen + len, poly_key);
		if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
			r = SSH_ERR_MAC_INVALID;
			goto out;
		}
	}

	/* Crypt additional data */
	if (aadlen) {
		chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
		chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen);
	}

	/* Set Chacha's block counter to 1 */
	chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
	chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen,
	    dest + aadlen, len);

	/* If encrypting, calculate and append tag */
	if (do_encrypt) {
		poly1305_auth(dest + aadlen + len, dest, aadlen + len,
		    poly_key);
	}
	r = 0;
 out:
	explicit_bzero(expected_tag, sizeof(expected_tag));
	explicit_bzero(seqbuf, sizeof(seqbuf));
	explicit_bzero(poly_key, sizeof(poly_key));
	return r;
}
static void
_rs_rekey(unsigned char *dat, size_t datlen)
{
#ifndef KEYSTREAM_ONLY
    pure_memzero(rs_buf, RSBUFSZ);
#endif
    /* fill rs_buf with the keystream */
    chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
    /* mix in optional user provided data */
    if (dat != NULL) {
        size_t i, m;

        if (datlen < KEYSZ + IVSZ) {
            m = datlen;
        } else {
            m = KEYSZ + IVSZ;
        }
        for (i = 0; i < m; i++) {
            rs_buf[i] ^= dat[i];
        }
    }
    /* immediately reinit for backtracking resistance */
    _rs_init(rs_buf, KEYSZ + IVSZ);
    pure_memzero(rs_buf, KEYSZ + IVSZ);
    rs_have = RSBUFSZ - KEYSZ - IVSZ;
}
Esempio n. 4
0
/**
 * \brief Forces a rekey on the random number generator.
 *
 * \param state The state of the random number generator.
 */
static void noise_randstate_rekey(NoiseRandState *state)
{
    uint8_t data[40];
    memset(data, 0, sizeof(data));
    chacha_encrypt_bytes(&(state->chacha), data, data, sizeof(data));
    chacha_keysetup(&(state->chacha), data, 256);
    chacha_ivsetup(&(state->chacha), data + 32, 0);
    noise_clean(data, sizeof(data));
}
Esempio n. 5
0
/* Decrypt and extract the encrypted packet length */
int
chachapoly_get_length(struct chachapoly_ctx *ctx,
    u_int *plenp, u_int seqnr, const u_char *cp, u_int len)
{
	u_char buf[4], seqbuf[8];

	if (len < 4)
		return SSH_ERR_MESSAGE_INCOMPLETE;
	POKE_U64(seqbuf, seqnr);
	chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
	chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4);
	*plenp = PEEK_U32(buf);
	return 0;
}
Esempio n. 6
0
/**
 * \brief Generates random bytes for use by the application.
 *
 * \param state The RandState object.
 * \param buffer The buffer to fill with random bytes.
 * \param len The number of random bytes to generate.
 *
 * \return NOISE_ERROR_NONE on success.
 * \return NOISE_ERROR_INVALID_PARAM if \a state or \a buffer is NULL.
 *
 * This function will periodically reseed the random number generator
 * from operating system entropy.  The application can force a reseed
 * at any time by calling noise_randstate_reseed(), but it is usually
 * better to let the RandState API decide when to reseed on its own.
 *
 * \sa noise_randstate_pad(), noise_randstate_reseed()
 */
int noise_randstate_generate
    (NoiseRandState *state, uint8_t *buffer, size_t len)
{
    size_t blocks;
    size_t temp_len;

    /* Validate the parameters.  We make sure to set the contents of
       the buffer to zero before proceeding just in case this function
       bails out before it can actually generate data.  We don't want
       to accidentally leak the previous contents in the buffer. */
    if (!buffer)
        return NOISE_ERROR_INVALID_PARAM;
    memset(buffer, 0, len);
    if (!state)
        return NOISE_ERROR_INVALID_PARAM;

    /* Force a reseed if necessary */
    if (state->left < len)
        noise_randstate_reseed(state);

    /* Generate the random data in ChaCha20 block-sized chunks */
    blocks = 0;
    while (len > 0) {
        temp_len = len;
        if (temp_len > 64)
            temp_len = 64;
        if (state->left >= 64) {
            /* One less block before we need to force a reseed */
            state->left -= 64;
        } else {
            /* Too much random data generated.  Force a reseed now */
            noise_randstate_reseed(state);
            blocks = 0;
        }
        if (blocks++ >= NOISE_RAND_REKEY_COUNT) {
            /* Too many blocks in the current request.  Force a rekey now */
            noise_randstate_rekey(state);
            blocks = 0;
        }
        chacha_encrypt_bytes(&(state->chacha), buffer, buffer, temp_len);
        buffer += temp_len;
        len -= temp_len;
    }

    /* Force a rekey after every request to destroy the input that
       was used to generate the random data for this request.
       This prevents the state from being rolled backwards. */
    noise_randstate_rekey(state);
    return NOISE_ERROR_NONE;
}
Esempio n. 7
0
/* Decrypt and extract the encrypted packet length */
int
chachapoly_get_length(struct chachapoly_ctx *ctx,
    u_int *plenp, u_int seqnr, const u_char *cp, u_int len)
{
	u_char buf[4], seqbuf[8];

	if (len < 4)
		return -1; /* Insufficient length */
	put_u64(seqbuf, seqnr);
	chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
	chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4);
	*plenp = get_u32(buf);
	return 0;
}
Esempio n. 8
0
void
ChaCha(ChaCha_ctx *ctx, unsigned char *out, const unsigned char *in, size_t len)
{
	unsigned char *k;
	int i, l;

	/* Consume remaining keystream, if any exists. */
	if (ctx->unused > 0) {
		k = ctx->ks + 64 - ctx->unused;
		l = (len > ctx->unused) ? ctx->unused : len;
		for (i = 0; i < l; i++)
			*(out++) = *(in++) ^ *(k++);
		ctx->unused -= l;
		len -= l;
	}

	chacha_encrypt_bytes((chacha_ctx *)ctx, in, out, (uint32_t)len);
}
Esempio n. 9
0
static inline void
_rs_rekey(unsigned char *dat, size_t datlen)
{
#ifndef KEYSTREAM_ONLY
	memset(rs_buf, 0, RSBUFSZ);
#endif
	/* fill rs_buf with the keystream */
	chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
	/* mix in optional user provided data */
	if (dat) {
		size_t i, m;

		m = MIN(datlen, KEYSZ + IVSZ);
		for (i = 0; i < m; i++)
			rs_buf[i] ^= dat[i];
	}
	/* immediately reinit for backtracking resistance */
	_rs_init(rs_buf, KEYSZ + IVSZ);
	memset(rs_buf, 0, KEYSZ + IVSZ);
	rs_have = RSBUFSZ - KEYSZ - IVSZ;
}
Esempio n. 10
0
/*
 * Create a psuedorandom output stream of 'blockcount' blocks using a CTR-mode
 * cipher or similar.  The 128-bit counter is supplied in the in-out parmeter
 * 'ctr.'  The output stream goes to 'd_out.'  'blockcount' RANDOM_BLOCKSIZE
 * bytes are generated.
 */
void
randomdev_keystream(union randomdev_key *context, uint128_t *ctr,
    void *d_out, u_int blockcount)
{
	u_int i;

	if (random_chachamode) {
		uint128_t lectr;

		/*
		 * Chacha always encodes and increments the counter little
		 * endian.  So on BE machines, we must provide a swapped
		 * counter to chacha, and swap the output too.
		 */
		le128enc(&lectr, *ctr);

		chacha_ivsetup(&context->chacha, NULL, (const void *)&lectr);
		chacha_encrypt_bytes(&context->chacha, NULL, d_out,
		    RANDOM_BLOCKSIZE * blockcount);

		/*
		 * Decode Chacha-updated LE counter to native endian and store
		 * it back in the caller's in-out parameter.
		 */
		chacha_ctrsave(&context->chacha, (void *)&lectr);
		*ctr = le128dec(&lectr);
	} else {
		for (i = 0; i < blockcount; i++) {
			/*-
			 * FS&K - r = r|E(K,C)
			 *      - C = C + 1
			 */
			rijndael_blockEncrypt(&context->cipher, &context->key,
			    (void *)ctr, RANDOM_BLOCKSIZE * 8, d_out);
			d_out = (char *)d_out + RANDOM_BLOCKSIZE;
			uint128_increment(ctr);
		}
	}
}
Esempio n. 11
0
void
ChaCha(ChaCha_ctx *ctx, unsigned char *out, const unsigned char *in, size_t len)
{
	chacha_encrypt_bytes((chacha_ctx *)ctx, in, out, (uint32_t)len);
}
Esempio n. 12
0
void chacha_keystream_bytes(u32 *x,byte *stream,u32 bytes)
{
  u32 i;
  for (i = 0;i < bytes;++i) stream[i] = 0;
  chacha_encrypt_bytes(x,stream,stream,bytes);
}