Index: sys/crypto/openssl/ossl.h =================================================================== --- sys/crypto/openssl/ossl.h +++ sys/crypto/openssl/ossl.h @@ -73,5 +73,6 @@ extern struct auth_hash ossl_hash_sha512; extern struct ossl_cipher ossl_cipher_aes_cbc; +extern struct ossl_cipher ossl_cipher_chacha20; #endif /* !__OSSL_H__ */ Index: sys/crypto/openssl/ossl.c =================================================================== --- sys/crypto/openssl/ossl.c +++ sys/crypto/openssl/ossl.c @@ -157,6 +157,9 @@ case CRYPTO_AES_CBC: cipher = &ossl_cipher_aes_cbc; break; + case CRYPTO_CHACHA20: + cipher = &ossl_cipher_chacha20; + break; default: return (NULL); } @@ -182,15 +185,9 @@ return (EINVAL); break; case CSP_MODE_CIPHER: - switch (csp->csp_cipher_alg) { - case CRYPTO_CHACHA20: - if (csp->csp_cipher_klen != CHACHA_KEY_SIZE) - return (EINVAL); - break; - default: - if (!sc->has_aes || ossl_lookup_cipher(csp) == NULL) - return (EINVAL); - } + if ((!sc->has_aes && csp->csp_cipher_alg != CRYPTO_CHACHA20) || + ossl_lookup_cipher(csp) == NULL) + return (EINVAL); break; case CSP_MODE_ETA: if ((!sc->has_aes && csp->csp_cipher_alg != CRYPTO_CHACHA20) || @@ -253,9 +250,6 @@ struct ossl_cipher *cipher; int error; - if (csp->csp_cipher_alg == CRYPTO_CHACHA20) - return (0); - cipher = ossl_lookup_cipher(csp); if (cipher == NULL) return (EINVAL); @@ -389,10 +383,6 @@ int blocklen, error; bool encrypt; - /* CHACHA20 is handled separately for now. */ - if (csp->csp_cipher_alg == CRYPTO_CHACHA20) - return (ossl_chacha20(crp, csp)); - cipher = s->cipher.cipher; encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); plen = crp->crp_payload_length; Index: sys/crypto/openssl/ossl_chacha20.c =================================================================== --- sys/crypto/openssl/ossl_chacha20.c +++ sys/crypto/openssl/ossl_chacha20.c @@ -36,62 +36,71 @@ #include #include +#include #include #include +ossl_cipher_setkey_t ossl_chacha20_setkey; +ossl_cipher_setkey_t ossl_chacha20_setiv; +ossl_cipher_encrypt_t ossl_chacha20_encrypt; + +struct ossl_cipher ossl_cipher_chacha20 = { + .type = CRYPTO_CHACHA20, + .minkeysize = CHACHA_KEY_SIZE, + .maxkeysize = CHACHA_KEY_SIZE, + .blocksize = CHACHA_BLK_SIZE, + .ivsize = CHACHA_CTR_SIZE, + .stream_cipher = true, + + .set_encrypt_key = ossl_chacha20_setkey, + .set_decrypt_key = ossl_chacha20_setkey, + .set_iv = ossl_chacha20_setiv, + .encrypt = ossl_chacha20_encrypt +}; + int -ossl_chacha20(struct cryptop *crp, const struct crypto_session_params *csp) +ossl_chacha20_setiv(const unsigned char *in, int size, void *out) { - _Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4]; - unsigned int counter[CHACHA_CTR_SIZE / 4]; - unsigned char block[CHACHA_BLK_SIZE]; - struct crypto_buffer_cursor cc_in, cc_out; - const unsigned char *in, *inseg, *cipher_key; - unsigned char *out, *outseg; - size_t resid, todo, inlen, outlen; - uint32_t next_counter; - u_int i; + const unsigned int *user_counter; + unsigned int *counter; + int i; - if (crp->crp_cipher_key != NULL) - cipher_key = crp->crp_cipher_key; - else - cipher_key = csp->csp_cipher_key; - for (i = 0; i < nitems(key); i++) - key[i] = CHACHA_U8TOU32(cipher_key + i * 4); - crypto_read_iv(crp, counter); - for (i = 0; i < nitems(counter); i++) - counter[i] = le32toh(counter[i]); + user_counter = (const unsigned int *)in; + counter = (unsigned int *)out; - resid = crp->crp_payload_length; - crypto_cursor_init(&cc_in, &crp->crp_buf); - crypto_cursor_advance(&cc_in, crp->crp_payload_start); - inseg = crypto_cursor_segment(&cc_in, &inlen); - if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { - crypto_cursor_init(&cc_out, &crp->crp_obuf); - crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); - } else - cc_out = cc_in; - outseg = crypto_cursor_segment(&cc_out, &outlen); - while (resid >= CHACHA_BLK_SIZE) { - if (inlen < CHACHA_BLK_SIZE) { - crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block); - in = block; - inlen = CHACHA_BLK_SIZE; - } else - in = inseg; - if (outlen < CHACHA_BLK_SIZE) { - out = block; - outlen = CHACHA_BLK_SIZE; - } else - out = outseg; + for (i = 0; i < size / sizeof(unsigned int); i++) + counter[i] = le32toh(user_counter[i]); - /* Figure out how many blocks we can encrypt/decrypt at once. */ - todo = rounddown(MIN(resid, MIN(inlen, outlen)), - CHACHA_BLK_SIZE); + return (0); +} + +int +ossl_chacha20_setkey(const unsigned char *in, int size, void *out) +{ + int i; + uint32_t *key = (uint32_t *)out; + + for (i = 0; i < CHACHA_KEY_SIZE / 4; i++) + key[i] = CHACHA_U8TOU32(in + i * 4); + + return (0); +} + +void +ossl_chacha20_encrypt(const unsigned char *in, unsigned char *out, size_t length, + const void *key, unsigned char *iv, int encrypt) +{ + unsigned int *counter = (unsigned int *) iv; + uint32_t next_counter; + size_t todo; + + while (length > 0) { #ifdef __LP64__ /* ChaCha20_ctr32() assumes length is <= 4GB. */ - todo = (uint32_t)todo; + todo = (uint32_t)length; +#else + todo = length; #endif /* Truncate if the 32-bit counter would roll over. */ @@ -107,35 +116,8 @@ if (counter[0] == 0) counter[1]++; - if (out == block) { - crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block); - outseg = crypto_cursor_segment(&cc_out, &outlen); - } else { - crypto_cursor_advance(&cc_out, todo); - outseg += todo; - outlen -= todo; - } - if (in == block) { - inseg = crypto_cursor_segment(&cc_in, &inlen); - } else { - crypto_cursor_advance(&cc_in, todo); - inseg += todo; - inlen -= todo; - } - resid -= todo; + length -= todo; } - - if (resid > 0) { - memset(block, 0, sizeof(block)); - crypto_cursor_copydata(&cc_in, resid, block); - ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter); - crypto_cursor_copyback(&cc_out, resid, block); - } - - explicit_bzero(block, sizeof(block)); - explicit_bzero(counter, sizeof(counter)); - explicit_bzero(key, sizeof(key)); - return (0); } int @@ -436,3 +418,6 @@ explicit_bzero(key, sizeof(key)); return (error); } + +_Static_assert(CHACHA_KEY_SIZE <= sizeof(struct ossl_context), + "ossl_context too small");