The branch main has been updated by jhb:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=dd2e1352b68aa33f7f6f8c19aaf88cf287013ae8

commit dd2e1352b68aa33f7f6f8c19aaf88cf287013ae8
Author:     John Baldwin <j...@freebsd.org>
AuthorDate: 2021-02-18 17:22:18 +0000
Commit:     John Baldwin <j...@freebsd.org>
CommitDate: 2021-02-18 17:26:23 +0000

    Add an implementation of CHACHA20_POLY1305 to cryptosoft.
    
    This uses the chacha20 IETF and poly1305 implementations from
    libsodium.  A seperate auth_hash is created for the auth side whose
    Setkey method derives the poly1305 key from the AEAD key and nonce as
    described in RFC 8439.
    
    Sponsored by:   Netflix
    Differential Revision:  https://reviews.freebsd.org/D27837
---
 sys/conf/files                           |   3 +-
 sys/modules/crypto/Makefile              |   9 +-
 sys/opencrypto/cryptosoft.c              | 199 +++++++++++++++++++++++++++++++
 sys/opencrypto/xform_auth.h              |   1 +
 sys/opencrypto/xform_chacha20_poly1305.c | 128 +++++++++++++++++++-
 5 files changed, 335 insertions(+), 5 deletions(-)

diff --git a/sys/conf/files b/sys/conf/files
index 8705287e89f1..8501f6fa9c1a 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -4925,7 +4925,8 @@ opencrypto/gfmult.c               optional crypto | ipsec 
| ipsec_support
 opencrypto/rmd160.c            optional crypto | ipsec | ipsec_support
 opencrypto/xform.c             optional crypto | ipsec | ipsec_support
 opencrypto/xform_cbc_mac.c     optional crypto
-opencrypto/xform_chacha20_poly1305.c   optional crypto
+opencrypto/xform_chacha20_poly1305.c   optional crypto \
+       compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include 
-I$S/crypto/libsodium"
 opencrypto/xform_poly1305.c    optional crypto \
        compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include 
-I$S/crypto/libsodium"
 
contrib/libsodium/src/libsodium/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c
 \
diff --git a/sys/modules/crypto/Makefile b/sys/modules/crypto/Makefile
index 89af6ab8fc61..f64ea1f6fc8b 100644
--- a/sys/modules/crypto/Makefile
+++ b/sys/modules/crypto/Makefile
@@ -15,6 +15,8 @@ LIBSODIUM=${SRCTOP}/sys/contrib/libsodium/src/libsodium
 .PATH: ${SRCTOP}/sys/contrib/libb2
 .PATH: ${LIBSODIUM}/crypto_onetimeauth/poly1305
 .PATH: ${LIBSODIUM}/crypto_onetimeauth/poly1305/donna
+.PATH: ${LIBSODIUM}/crypto_stream/chacha20
+.PATH: ${LIBSODIUM}/crypto_stream/chacha20/ref
 .PATH: ${LIBSODIUM}/crypto_verify/sodium
 .PATH: ${SRCTOP}/sys/crypto/libsodium
 
@@ -55,8 +57,14 @@ SRCS += chacha-sw.c
 
 LIBSODIUM_INC=${LIBSODIUM}/include
 LIBSODIUM_COMPAT=${SRCTOP}/sys/crypto/libsodium
+SRCS   += xform_chacha20_poly1305.c
+CFLAGS.xform_chacha20_poly1305.c+= -I${LIBSODIUM_INC} -I${LIBSODIUM_COMPAT}
 SRCS   += xform_poly1305.c
 CFLAGS.xform_poly1305.c                += -I${LIBSODIUM_INC} 
-I${LIBSODIUM_COMPAT}
+SRCS   += stream_chacha20.c
+CFLAGS.stream_chacha20.c       += -I${LIBSODIUM_INC}/sodium 
-I${LIBSODIUM_COMPAT}
+SRCS   += chacha20_ref.c
+CFLAGS.chacha20_ref.c          += -I${LIBSODIUM_INC}/sodium 
-I${LIBSODIUM_COMPAT}
 SRCS   += onetimeauth_poly1305.c
 CFLAGS.onetimeauth_poly1305.c  += -I${LIBSODIUM_INC}/sodium 
-I${LIBSODIUM_COMPAT}
 SRCS   += poly1305_donna.c
@@ -67,7 +75,6 @@ SRCS  += randombytes.c
 CFLAGS.randombytes.c           += -I${LIBSODIUM_INC} -I${LIBSODIUM_COMPAT}
 SRCS   += utils.c
 CFLAGS.utils.c                 += -I${LIBSODIUM_INC} -I${LIBSODIUM_COMPAT}
-SRCS   += xform_chacha20_poly1305.c
 
 SRCS   += opt_param.h cryptodev_if.h bus_if.h device_if.h
 SRCS   += opt_compat.h
diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c
index e5a1139039d0..b92e25e86f76 100644
--- a/sys/opencrypto/cryptosoft.c
+++ b/sys/opencrypto/cryptosoft.c
@@ -867,6 +867,168 @@ out:
        return (error);
 }
 
+static int
+swcr_chacha20_poly1305(struct swcr_session *ses, struct cryptop *crp)
+{
+       const struct crypto_session_params *csp;
+       uint64_t blkbuf[howmany(CHACHA20_NATIVE_BLOCK_LEN, sizeof(uint64_t))];
+       u_char *blk = (u_char *)blkbuf;
+       u_char tag[POLY1305_HASH_LEN];
+       struct crypto_buffer_cursor cc_in, cc_out;
+       const u_char *inblk;
+       u_char *outblk;
+       uint64_t *blkp;
+       union authctx ctx;
+       struct swcr_auth *swa;
+       struct swcr_encdec *swe;
+       struct auth_hash *axf;
+       struct enc_xform *exf;
+       int blksz, error, r, resid;
+
+       swa = &ses->swcr_auth;
+       axf = swa->sw_axf;
+
+       swe = &ses->swcr_encdec;
+       exf = swe->sw_exf;
+       blksz = exf->native_blocksize;
+       KASSERT(blksz <= sizeof(blkbuf), ("%s: blocksize mismatch", __func__));
+
+       if ((crp->crp_flags & CRYPTO_F_IV_SEPARATE) == 0)
+               return (EINVAL);
+
+       csp = crypto_get_params(crp->crp_session);
+
+       /* Generate Poly1305 key. */
+       if (crp->crp_cipher_key != NULL)
+               axf->Setkey(&ctx, crp->crp_cipher_key, csp->csp_cipher_klen);
+       else
+               axf->Setkey(&ctx, csp->csp_cipher_key, csp->csp_cipher_klen);
+       axf->Reinit(&ctx, crp->crp_iv, csp->csp_ivlen);
+
+       /* Supply MAC with AAD */
+       if (crp->crp_aad != NULL)
+               axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
+       else
+               crypto_apply(crp, crp->crp_aad_start,
+                   crp->crp_aad_length, axf->Update, &ctx);
+       if (crp->crp_aad_length % 16 != 0) {
+               /* padding1 */
+               memset(blk, 0, 16);
+               axf->Update(&ctx, blk, 16 - crp->crp_aad_length % 16);
+       }
+
+       if (crp->crp_cipher_key != NULL)
+               exf->setkey(swe->sw_kschedule, crp->crp_cipher_key,
+                   csp->csp_cipher_klen);
+       exf->reinit(swe->sw_kschedule, crp->crp_iv);
+
+       /* Do encryption with MAC */
+       crypto_cursor_init(&cc_in, &crp->crp_buf);
+       crypto_cursor_advance(&cc_in, crp->crp_payload_start);
+       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;
+       for (resid = crp->crp_payload_length; resid >= blksz; resid -= blksz) {
+               if (crypto_cursor_seglen(&cc_in) < blksz) {
+                       crypto_cursor_copydata(&cc_in, blksz, blk);
+                       inblk = blk;
+               } else {
+                       inblk = crypto_cursor_segbase(&cc_in);
+                       crypto_cursor_advance(&cc_in, blksz);
+               }
+               if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
+                       if (crypto_cursor_seglen(&cc_out) < blksz)
+                               outblk = blk;
+                       else
+                               outblk = crypto_cursor_segbase(&cc_out);
+                       exf->encrypt(swe->sw_kschedule, inblk, outblk);
+                       axf->Update(&ctx, outblk, blksz);
+                       if (outblk == blk)
+                               crypto_cursor_copyback(&cc_out, blksz, blk);
+                       else
+                               crypto_cursor_advance(&cc_out, blksz);
+               } else {
+                       axf->Update(&ctx, inblk, blksz);
+               }
+       }
+       if (resid > 0) {
+               crypto_cursor_copydata(&cc_in, resid, blk);
+               if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
+                       exf->encrypt_last(swe->sw_kschedule, blk, blk, resid);
+                       crypto_cursor_copyback(&cc_out, resid, blk);
+               }
+               axf->Update(&ctx, blk, resid);
+               if (resid % 16 != 0) {
+                       /* padding2 */
+                       memset(blk, 0, 16);
+                       axf->Update(&ctx, blk, 16 - resid % 16);
+               }
+       }
+
+       /* lengths */
+       blkp = (uint64_t *)blk;
+       blkp[0] = htole64(crp->crp_aad_length);
+       blkp[1] = htole64(crp->crp_payload_length);
+       axf->Update(&ctx, blk, sizeof(uint64_t) * 2);
+
+       /* Finalize MAC */
+       axf->Final(tag, &ctx);
+
+       /* Validate tag */
+       error = 0;
+       if (!CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
+               u_char tag2[POLY1305_HASH_LEN];
+
+               crypto_copydata(crp, crp->crp_digest_start, swa->sw_mlen, tag2);
+
+               r = timingsafe_bcmp(tag, tag2, swa->sw_mlen);
+               explicit_bzero(tag2, sizeof(tag2));
+               if (r != 0) {
+                       error = EBADMSG;
+                       goto out;
+               }
+
+               /* tag matches, decrypt data */
+               crypto_cursor_init(&cc_in, &crp->crp_buf);
+               crypto_cursor_advance(&cc_in, crp->crp_payload_start);
+               for (resid = crp->crp_payload_length; resid > blksz;
+                    resid -= blksz) {
+                       if (crypto_cursor_seglen(&cc_in) < blksz) {
+                               crypto_cursor_copydata(&cc_in, blksz, blk);
+                               inblk = blk;
+                       } else {
+                               inblk = crypto_cursor_segbase(&cc_in);
+                               crypto_cursor_advance(&cc_in, blksz);
+                       }
+                       if (crypto_cursor_seglen(&cc_out) < blksz)
+                               outblk = blk;
+                       else
+                               outblk = crypto_cursor_segbase(&cc_out);
+                       exf->decrypt(swe->sw_kschedule, inblk, outblk);
+                       if (outblk == blk)
+                               crypto_cursor_copyback(&cc_out, blksz, blk);
+                       else
+                               crypto_cursor_advance(&cc_out, blksz);
+               }
+               if (resid > 0) {
+                       crypto_cursor_copydata(&cc_in, resid, blk);
+                       exf->decrypt_last(swe->sw_kschedule, blk, blk, resid);
+                       crypto_cursor_copyback(&cc_out, resid, blk);
+               }
+       } else {
+               /* Inject the authentication data */
+               crypto_copyback(crp, crp->crp_digest_start, swa->sw_mlen, tag);
+       }
+
+out:
+       explicit_bzero(blkbuf, sizeof(blkbuf));
+       explicit_bzero(tag, sizeof(tag));
+       explicit_bzero(&ctx, sizeof(ctx));
+       return (error);
+}
+
 /*
  * Apply a cipher and a digest to perform EtA.
  */
@@ -1171,6 +1333,33 @@ swcr_setup_ccm(struct swcr_session *ses,
        return (swcr_setup_cipher(ses, csp));
 }
 
+static int
+swcr_setup_chacha20_poly1305(struct swcr_session *ses,
+    const struct crypto_session_params *csp)
+{
+       struct swcr_auth *swa;
+       struct auth_hash *axf;
+
+       if (csp->csp_ivlen != CHACHA20_POLY1305_IV_LEN)
+               return (EINVAL);
+
+       /* First, setup the auth side. */
+       swa = &ses->swcr_auth;
+       axf = &auth_hash_chacha20_poly1305;
+       swa->sw_axf = axf;
+       if (csp->csp_auth_mlen < 0 || csp->csp_auth_mlen > axf->hashsize)
+               return (EINVAL);
+       if (csp->csp_auth_mlen == 0)
+               swa->sw_mlen = axf->hashsize;
+       else
+               swa->sw_mlen = csp->csp_auth_mlen;
+
+       /* The auth state is regenerated for each nonce. */
+
+       /* Second, setup the cipher side. */
+       return (swcr_setup_cipher(ses, csp));
+}
+
 static bool
 swcr_auth_supported(const struct crypto_session_params *csp)
 {
@@ -1258,6 +1447,7 @@ swcr_probesession(device_t dev, const struct 
crypto_session_params *csp)
                switch (csp->csp_cipher_alg) {
                case CRYPTO_AES_NIST_GCM_16:
                case CRYPTO_AES_CCM_16:
+               case CRYPTO_CHACHA20_POLY1305:
                        return (EINVAL);
                default:
                        if (!swcr_cipher_supported(csp))
@@ -1273,6 +1463,7 @@ swcr_probesession(device_t dev, const struct 
crypto_session_params *csp)
                switch (csp->csp_cipher_alg) {
                case CRYPTO_AES_NIST_GCM_16:
                case CRYPTO_AES_CCM_16:
+               case CRYPTO_CHACHA20_POLY1305:
                        break;
                default:
                        return (EINVAL);
@@ -1283,6 +1474,7 @@ swcr_probesession(device_t dev, const struct 
crypto_session_params *csp)
                switch (csp->csp_cipher_alg) {
                case CRYPTO_AES_NIST_GCM_16:
                case CRYPTO_AES_CCM_16:
+               case CRYPTO_CHACHA20_POLY1305:
                        return (EINVAL);
                }
                switch (csp->csp_auth_alg) {
@@ -1343,6 +1535,7 @@ swcr_newsession(device_t dev, crypto_session_t cses,
 #ifdef INVARIANTS
                case CRYPTO_AES_NIST_GCM_16:
                case CRYPTO_AES_CCM_16:
+               case CRYPTO_CHACHA20_POLY1305:
                        panic("bad cipher algo");
 #endif
                default:
@@ -1366,6 +1559,11 @@ swcr_newsession(device_t dev, crypto_session_t cses,
                        if (error == 0)
                                ses->swcr_process = swcr_ccm;
                        break;
+               case CRYPTO_CHACHA20_POLY1305:
+                       error = swcr_setup_chacha20_poly1305(ses, csp);
+                       if (error == 0)
+                               ses->swcr_process = swcr_chacha20_poly1305;
+                       break;
 #ifdef INVARIANTS
                default:
                        panic("bad aead algo");
@@ -1377,6 +1575,7 @@ swcr_newsession(device_t dev, crypto_session_t cses,
                switch (csp->csp_cipher_alg) {
                case CRYPTO_AES_NIST_GCM_16:
                case CRYPTO_AES_CCM_16:
+               case CRYPTO_CHACHA20_POLY1305:
                        panic("bad eta cipher algo");
                }
                switch (csp->csp_auth_alg) {
diff --git a/sys/opencrypto/xform_auth.h b/sys/opencrypto/xform_auth.h
index dbdb278209b5..6427965671d3 100644
--- a/sys/opencrypto/xform_auth.h
+++ b/sys/opencrypto/xform_auth.h
@@ -84,6 +84,7 @@ extern struct auth_hash auth_hash_poly1305;
 extern struct auth_hash auth_hash_ccm_cbc_mac_128;
 extern struct auth_hash auth_hash_ccm_cbc_mac_192;
 extern struct auth_hash auth_hash_ccm_cbc_mac_256;
+extern struct auth_hash auth_hash_chacha20_poly1305;
 
 union authctx {
        SHA1_CTX sha1ctx;
diff --git a/sys/opencrypto/xform_chacha20_poly1305.c 
b/sys/opencrypto/xform_chacha20_poly1305.c
index e568e76cad51..3a72c06f931b 100644
--- a/sys/opencrypto/xform_chacha20_poly1305.c
+++ b/sys/opencrypto/xform_chacha20_poly1305.c
@@ -25,17 +25,139 @@
  * SUCH DAMAGE.
  */
 
-#include <crypto/chacha20/chacha.h>
+#include <opencrypto/xform_auth.h>
 #include <opencrypto/xform_enc.h>
 
+#include <sodium/crypto_onetimeauth_poly1305.h>
+#include <sodium/crypto_stream_chacha20.h>
+
+struct chacha20_poly1305_cipher_ctx {
+       const void *key;
+       uint32_t ic;
+       char nonce[CHACHA20_POLY1305_IV_LEN];
+};
+
+static int
+chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len)
+{
+       struct chacha20_poly1305_cipher_ctx *ctx = vctx;
+
+       if (len != CHACHA20_POLY1305_KEY)
+               return (EINVAL);
+
+       ctx->key = key;
+       return (0);
+}
+
+static void
+chacha20_poly1305_reinit(void *vctx, const uint8_t *iv)
+{
+       struct chacha20_poly1305_cipher_ctx *ctx = vctx;
+
+       /* Block 0 is used for the poly1305 key. */
+       memcpy(ctx->nonce, iv, sizeof(ctx->nonce));
+       ctx->ic = 1;
+}
+
+static void
+chacha20_poly1305_crypt(void *vctx, const uint8_t *in, uint8_t *out)
+{
+       struct chacha20_poly1305_cipher_ctx *ctx = vctx;
+       int error;
+
+       error = crypto_stream_chacha20_ietf_xor_ic(out, in,
+           CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
+       KASSERT(error == 0, ("%s failed: %d", __func__, error));
+       ctx->ic++;
+}
+
+static void
+chacha20_poly1305_crypt_last(void *vctx, const uint8_t *in, uint8_t *out,
+    size_t len)
+{
+       struct chacha20_poly1305_cipher_ctx *ctx = vctx;
+
+       int error;
+
+       error = crypto_stream_chacha20_ietf_xor_ic(out, in, len, ctx->nonce,
+           ctx->ic, ctx->key);
+       KASSERT(error == 0, ("%s failed: %d", __func__, error));
+}
+
 struct enc_xform enc_xform_chacha20_poly1305 = {
        .type = CRYPTO_CHACHA20_POLY1305,
        .name = "ChaCha20-Poly1305",
-       .ctxsize = sizeof(struct chacha_ctx),
+       .ctxsize = sizeof(struct chacha20_poly1305_cipher_ctx),
        .blocksize = 1,
-       .native_blocksize = CHACHA_BLOCKLEN,
+       .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN,
        .ivsize = CHACHA20_POLY1305_IV_LEN,
        .minkey = CHACHA20_POLY1305_KEY,
        .maxkey = CHACHA20_POLY1305_KEY,
+       .encrypt = chacha20_poly1305_crypt,
+       .decrypt = chacha20_poly1305_crypt,
+       .setkey = chacha20_poly1305_setkey,
+       .reinit = chacha20_poly1305_reinit,
+       .encrypt_last = chacha20_poly1305_crypt_last,
+       .decrypt_last = chacha20_poly1305_crypt_last,
 };
 
+struct chacha20_poly1305_auth_ctx {
+       struct crypto_onetimeauth_poly1305_state state;
+       const void *key;
+};
+CTASSERT(sizeof(union authctx) >= sizeof(struct chacha20_poly1305_auth_ctx));
+
+static void
+chacha20_poly1305_Init(void *vctx)
+{
+}
+
+static void
+chacha20_poly1305_Setkey(void *vctx, const uint8_t *key, u_int klen)
+{
+       struct chacha20_poly1305_auth_ctx *ctx = vctx;
+
+       ctx->key = key;
+}
+
+static void
+chacha20_poly1305_Reinit(void *vctx, const uint8_t *nonce, u_int noncelen)
+{
+       struct chacha20_poly1305_auth_ctx *ctx = vctx;
+       char block[CHACHA20_NATIVE_BLOCK_LEN];
+
+       crypto_stream_chacha20_ietf(block, sizeof(block), nonce, ctx->key);
+       crypto_onetimeauth_poly1305_init(&ctx->state, block);
+       explicit_bzero(block, sizeof(block));
+}
+
+static int
+chacha20_poly1305_Update(void *vctx, const void *data, u_int len)
+{
+       struct chacha20_poly1305_auth_ctx *ctx = vctx;
+
+       crypto_onetimeauth_poly1305_update(&ctx->state, data, len);
+       return (0);
+}
+
+static void
+chacha20_poly1305_Final(uint8_t *digest, void *vctx)
+{
+       struct chacha20_poly1305_auth_ctx *ctx = vctx;
+
+       crypto_onetimeauth_poly1305_final(&ctx->state, digest);
+}
+
+struct auth_hash auth_hash_chacha20_poly1305 = {
+       .type = CRYPTO_POLY1305,
+       .name = "ChaCha20-Poly1305",
+       .keysize = POLY1305_KEY_LEN,
+       .hashsize = POLY1305_HASH_LEN,
+       .ctxsize = sizeof(struct chacha20_poly1305_auth_ctx),
+       .blocksize = crypto_onetimeauth_poly1305_BYTES,
+       .Init = chacha20_poly1305_Init,
+       .Setkey = chacha20_poly1305_Setkey,
+       .Reinit = chacha20_poly1305_Reinit,
+       .Update = chacha20_poly1305_Update,
+       .Final = chacha20_poly1305_Final,
+};
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to