From patchwork Fri Dec 8 11:55:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 846179 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="gFX19vvs"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="QVNhw17+"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3ytW5F1Glvz9ryT for ; Fri, 8 Dec 2017 22:55:45 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=oEN6gWazmuIuCWZU0Rfh/rNV2pHk4TwacrY4OPOdIUo=; b=gFX 19vvssXcLCuloBQxaBa++FF7G5D6Y+mxB5llUfRDx0UzgS6Zo4T7jYY6SMMBe0tCOypR6EaQCQyHQ 6P/xinM/jl27f8x9N+iKkUGiDAvC4JgFNYQkkXf706l2s6M1RDAwoB0XDvX6hiy8vK4MFkSy9tJTE 08l7yrLm7uvirz4AUda+jQKQgGwFkT/CgfQUkscXsPpbnpiHKYZJzcQcshlYL01uKAD2CxcRkVHvP z8OCgKAhVZCb1vN11A1AgYB1GVntFLQpzZ6Po91AFR4+bA2hmodRYTQ7UERIuxkYYEuC6/JvIbiL3 BziqtPMk2t/IlvGqbSzT8vTZIyZLkJA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1eNHFi-0004Cu-UQ; Fri, 08 Dec 2017 11:55:38 +0000 Received: from mail-wr0-x241.google.com ([2a00:1450:400c:c0c::241]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1eNHFe-0004Ab-1F for linux-mtd@lists.infradead.org; Fri, 08 Dec 2017 11:55:37 +0000 Received: by mail-wr0-x241.google.com with SMTP id a41so10581910wra.6 for ; Fri, 08 Dec 2017 03:55:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=MAkj+1Hbc3gdJL1OingPAE4YW1crGN/Ss4+8MX4UTnk=; b=QVNhw17+TUh/SYe4f/4UEr9kNuGkXrgefay5Fe/sHpBS4uId0+9YnuhD4p7jf9gNje tdrj48Mzryv5sU0Hj66KtGMqzLgN8RaQ9ix3rzq90UxBI9yTpwwLlHcAu/nDYFO7lnZY 5N6kE1DfTbgK5ZJGv6mdAYVbuxKgr+V2BkoTI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=MAkj+1Hbc3gdJL1OingPAE4YW1crGN/Ss4+8MX4UTnk=; b=jJqwkOBVTD/0QWOqgG4VlBu+EF6IO1Yh6Jd5hkp8pUPISgWhJK7w9W4Fm0HOGQk6Hb oQoZJCrnUwgZQtOzbbxtQjbgDSmtJsaULQwLIOcq2bZ7JyfoSGmAzyHCoGneP0PxBGVE 2CK59BLBIjp9VMYAL9FTTcie5S0BGKL0hHmXwhrP7J0i1OeA3pTUKc5O9cYOG5fIv1dV A6NhtVScJ6GZwn3k7zN2dwWWSWsvahR+L4/AG0KIhNRTNdf96lKx/xTYulFaMHzfJbQs eIV6KXKBk6cFS1Zxdkc2bT3IpxcSTqp/l2V/y+I7QN5qkPkpqVFwDsANN0Hk6rz8UzrD Ib3w== X-Gm-Message-State: AJaThX77jD2BsS4q18WtISmCgCJhDxGWpCoCvxKWaiix/MqmHubkeSk2 OR03wnFdCYTtK6SkxqxgWkHKIrNtwTo= X-Google-Smtp-Source: AGs4zMY4mCGHa+BvR0wnzQNrVUYA2Tj054RQDnNDnaE0LvDk+HSf7c0PE4wyYVZn1fgPpmEoXnT6mQ== X-Received: by 10.223.156.133 with SMTP id d5mr28115513wre.43.1512734112030; Fri, 08 Dec 2017 03:55:12 -0800 (PST) Received: from localhost.localdomain ([160.171.158.223]) by smtp.gmail.com with ESMTPSA id h12sm7137196wre.52.2017.12.08.03.55.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 08 Dec 2017 03:55:10 -0800 (PST) From: Ard Biesheuvel To: linux-crypto@vger.kernel.org Subject: [RFC PATCH] crypto: chacha20 - add implementation using 96-bit nonce Date: Fri, 8 Dec 2017 11:55:02 +0000 Message-Id: <20171208115502.21775-1-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20171208_035534_512123_12A69769 X-CRM114-Status: GOOD ( 19.89 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [2a00:1450:400c:c0c:0:0:0:241 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Gstir , Theodore Ts'o , herbert@gondor.apana.org.au, Eric Biggers , Martin Willi , Ard Biesheuvel , Michael Halcrow , "Jason A . Donenfeld" , linux-f2fs-devel@lists.sourceforge.net, Stephan Mueller , linux-fscrypt@vger.kernel.org, linux-mtd@lists.infradead.org, linux-fsdevel@vger.kernel.org, Jaegeuk Kim , linux-ext4@vger.kernel.org, Paul Crowley MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org As pointed out by Eric [0], the way RFC7539 was interpreted when creating our implementation of ChaCha20 creates a risk of IV reuse when using a little endian counter as the IV generator. The reason is that the low end bits of the counter get mapped onto the ChaCha20 block counter, which advances every 64 bytes. This means that the counter value that gets selected as IV for the next input block will collide with the ChaCha20 block counter of the previous block, basically recreating the same keystream but shifted by 64 bytes. RFC7539 describes the inputs of the algorithm as follows: The inputs to ChaCha20 are: o A 256-bit key o A 32-bit initial counter. This can be set to any number, but will usually be zero or one. It makes sense to use one if we use the zero block for something else, such as generating a one-time authenticator key as part of an AEAD algorithm. o A 96-bit nonce. In some protocols, this is known as the Initialization Vector. o An arbitrary-length plaintext The solution is to use a fixed value of 0 for the initial counter, and only expose a 96-bit IV to the upper layers of the crypto API. So introduce a new ChaCha20 flavor called chacha20-iv96, which takes the above into account, and should become the preferred ChaCha20 implementation going forward for general use. [0] https://marc.info/?l=linux-crypto-vger&m=151269722430848&w=2 Cc: Eric Biggers Cc: linux-fscrypt@vger.kernel.org Cc: Theodore Ts'o Cc: linux-ext4@vger.kernel.org Cc: linux-f2fs-devel@lists.sourceforge.net Cc: linux-mtd@lists.infradead.org Cc: linux-fsdevel@vger.kernel.org Cc: linux-crypto@vger.kernel.org Cc: Jaegeuk Kim Cc: Michael Halcrow Cc: Paul Crowley Cc: Martin Willi Cc: David Gstir Cc: "Jason A . Donenfeld" Cc: Stephan Mueller Signed-off-by: Ard Biesheuvel --- arch/arm64/crypto/chacha20-neon-glue.c | 27 +++++++++++--- arch/x86/crypto/chacha20_glue.c | 19 +++++++++- crypto/chacha20_generic.c | 38 ++++++++++++++------ crypto/testmgr.c | 9 +++++ crypto/testmgr.h | 2 +- include/crypto/chacha20.h | 4 ++- 6 files changed, 81 insertions(+), 18 deletions(-) diff --git a/arch/arm64/crypto/chacha20-neon-glue.c b/arch/arm64/crypto/chacha20-neon-glue.c index cbdb75d15cd0..76a570058cc8 100644 --- a/arch/arm64/crypto/chacha20-neon-glue.c +++ b/arch/arm64/crypto/chacha20-neon-glue.c @@ -70,7 +70,7 @@ static int chacha20_neon(struct skcipher_request *req) err = skcipher_walk_virt(&walk, req, true); - crypto_chacha20_init(state, ctx, walk.iv); + crypto_chacha20_init(state, ctx, walk.iv, crypto_skcipher_ivsize(tfm)); kernel_neon_begin(); while (walk.nbytes > 0) { @@ -88,7 +88,7 @@ static int chacha20_neon(struct skcipher_request *req) return err; } -static struct skcipher_alg alg = { +static struct skcipher_alg alg[] = {{ .base.cra_name = "chacha20", .base.cra_driver_name = "chacha20-neon", .base.cra_priority = 300, @@ -104,19 +104,35 @@ static struct skcipher_alg alg = { .setkey = crypto_chacha20_setkey, .encrypt = chacha20_neon, .decrypt = chacha20_neon, -}; +}, { + .base.cra_name = "chacha20-iv96", + .base.cra_driver_name = "chacha20-neon", + .base.cra_priority = 300, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct chacha20_ctx), + .base.cra_module = THIS_MODULE, + + .min_keysize = CHACHA20_KEY_SIZE, + .max_keysize = CHACHA20_KEY_SIZE, + .ivsize = CHACHA20_NONCE_SIZE, + .chunksize = CHACHA20_BLOCK_SIZE, + .walksize = 4 * CHACHA20_BLOCK_SIZE, + .setkey = crypto_chacha20_setkey, + .encrypt = chacha20_neon, + .decrypt = chacha20_neon, +}}; static int __init chacha20_simd_mod_init(void) { if (!(elf_hwcap & HWCAP_ASIMD)) return -ENODEV; - return crypto_register_skcipher(&alg); + return crypto_register_skciphers(alg, ARRAY_SIZE(alg)); } static void __exit chacha20_simd_mod_fini(void) { - crypto_unregister_skcipher(&alg); + crypto_unregister_skciphers(alg, ARRAY_SIZE(alg)); } module_init(chacha20_simd_mod_init); @@ -125,3 +141,4 @@ module_exit(chacha20_simd_mod_fini); MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS_CRYPTO("chacha20"); +MODULE_ALIAS_CRYPTO("chacha20-iv96"); diff --git a/arch/x86/crypto/chacha20_glue.c b/arch/x86/crypto/chacha20_glue.c index dce7c5d39c2f..44c7fe376a1d 100644 --- a/arch/x86/crypto/chacha20_glue.c +++ b/arch/x86/crypto/chacha20_glue.c @@ -79,7 +79,7 @@ static int chacha20_simd(struct skcipher_request *req) err = skcipher_walk_virt(&walk, req, true); - crypto_chacha20_init(state, ctx, walk.iv); + crypto_chacha20_init(state, ctx, walk.iv, crypto_skcipher_ivsize(tfm)); kernel_fpu_begin(); @@ -116,6 +116,22 @@ static struct skcipher_alg alg = { .setkey = crypto_chacha20_setkey, .encrypt = chacha20_simd, .decrypt = chacha20_simd, +}, { + .base.cra_name = "chacha20-iv96", + .base.cra_driver_name = "chacha20-simd", + .base.cra_priority = 300, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct chacha20_ctx), + .base.cra_alignmask = sizeof(u32) - 1, + .base.cra_module = THIS_MODULE, + + .min_keysize = CHACHA20_KEY_SIZE, + .max_keysize = CHACHA20_KEY_SIZE, + .ivsize = CHACHA20_NONCE_SIZE, + .chunksize = CHACHA20_BLOCK_SIZE, + .setkey = crypto_chacha20_setkey, + .encrypt = chacha20_simd, + .decrypt = chacha20_simd, }; static int __init chacha20_simd_mod_init(void) @@ -143,4 +159,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Martin Willi "); MODULE_DESCRIPTION("chacha20 cipher algorithm, SIMD accelerated"); MODULE_ALIAS_CRYPTO("chacha20"); +MODULE_ALIAS_CRYPTO("chacha20-iv96"); MODULE_ALIAS_CRYPTO("chacha20-simd"); diff --git a/crypto/chacha20_generic.c b/crypto/chacha20_generic.c index e451c3cb6a56..943acb92857e 100644 --- a/crypto/chacha20_generic.c +++ b/crypto/chacha20_generic.c @@ -35,7 +35,8 @@ static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src, } } -void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv) +void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv, + int ivsize) { state[0] = 0x61707865; /* "expa" */ state[1] = 0x3320646e; /* "nd 3" */ @@ -49,10 +50,10 @@ void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv) state[9] = ctx->key[5]; state[10] = ctx->key[6]; state[11] = ctx->key[7]; - state[12] = get_unaligned_le32(iv + 0); - state[13] = get_unaligned_le32(iv + 4); - state[14] = get_unaligned_le32(iv + 8); - state[15] = get_unaligned_le32(iv + 12); + state[12] = (ivsize > CHACHA20_NONCE_SIZE) ? get_unaligned_le32(iv) : 0; + state[13] = get_unaligned_le32(iv + ivsize - 12); + state[14] = get_unaligned_le32(iv + ivsize - 8); + state[15] = get_unaligned_le32(iv + ivsize - 4); } EXPORT_SYMBOL_GPL(crypto_chacha20_init); @@ -82,7 +83,7 @@ int crypto_chacha20_crypt(struct skcipher_request *req) err = skcipher_walk_virt(&walk, req, true); - crypto_chacha20_init(state, ctx, walk.iv); + crypto_chacha20_init(state, ctx, walk.iv, crypto_skcipher_ivsize(tfm)); while (walk.nbytes > 0) { unsigned int nbytes = walk.nbytes; @@ -99,7 +100,7 @@ int crypto_chacha20_crypt(struct skcipher_request *req) } EXPORT_SYMBOL_GPL(crypto_chacha20_crypt); -static struct skcipher_alg alg = { +static struct skcipher_alg alg[] = {{ .base.cra_name = "chacha20", .base.cra_driver_name = "chacha20-generic", .base.cra_priority = 100, @@ -114,16 +115,32 @@ static struct skcipher_alg alg = { .setkey = crypto_chacha20_setkey, .encrypt = crypto_chacha20_crypt, .decrypt = crypto_chacha20_crypt, -}; +}, { + .base.cra_name = "chacha20-iv96", + .base.cra_driver_name = "chacha20-generic", + .base.cra_priority = 100, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct chacha20_ctx), + .base.cra_alignmask = sizeof(u32) - 1, + .base.cra_module = THIS_MODULE, + + .min_keysize = CHACHA20_KEY_SIZE, + .max_keysize = CHACHA20_KEY_SIZE, + .ivsize = CHACHA20_NONCE_SIZE, + .chunksize = CHACHA20_BLOCK_SIZE, + .setkey = crypto_chacha20_setkey, + .encrypt = crypto_chacha20_crypt, + .decrypt = crypto_chacha20_crypt, +}}; static int __init chacha20_generic_mod_init(void) { - return crypto_register_skcipher(&alg); + return crypto_register_skciphers(alg, ARRAY_SIZE(alg)); } static void __exit chacha20_generic_mod_fini(void) { - crypto_unregister_skcipher(&alg); + crypto_unregister_skciphers(alg, ARRAY_SIZE(alg)); } module_init(chacha20_generic_mod_init); @@ -133,4 +150,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Martin Willi "); MODULE_DESCRIPTION("chacha20 cipher algorithm"); MODULE_ALIAS_CRYPTO("chacha20"); +MODULE_ALIAS_CRYPTO("chacha20-iv96"); MODULE_ALIAS_CRYPTO("chacha20-generic"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 29d7020b8826..ce87cc4f81b1 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2563,6 +2563,15 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "chacha20-iv96", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { .vecs = chacha20_enc_tv_template, .count = 1 }, + .dec = { .vecs = chacha20_enc_tv_template, .count = 1 }, + } + } + }, { .alg = "cmac(aes)", .fips_allowed = 1, .test = alg_test_hash, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index a714b6293959..4a5e5411e12c 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -32612,7 +32612,7 @@ static const struct cipher_testvec salsa20_stream_enc_tv_template[] = { }; static const struct cipher_testvec chacha20_enc_tv_template[] = { - { /* RFC7539 A.2. Test Vector #1 */ + { /* RFC7539 A.2. Test Vector #1 (shared with chacha20-iv96) */ .key = "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" diff --git a/include/crypto/chacha20.h b/include/crypto/chacha20.h index b83d66073db0..5db09213fe67 100644 --- a/include/crypto/chacha20.h +++ b/include/crypto/chacha20.h @@ -10,6 +10,7 @@ #include #include +#define CHACHA20_NONCE_SIZE 12 #define CHACHA20_IV_SIZE 16 #define CHACHA20_KEY_SIZE 32 #define CHACHA20_BLOCK_SIZE 64 @@ -20,7 +21,8 @@ struct chacha20_ctx { }; void chacha20_block(u32 *state, u32 *stream); -void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv); +void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv, + int ivsize); int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keysize); int crypto_chacha20_crypt(struct skcipher_request *req);