mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto updates from Herbert Xu: "API: - Add 1472-byte test to tcrypt for IPsec - Reintroduced crypto stats interface with numerous changes - Support incremental algorithm dumps Algorithms: - Add xchacha12/20 - Add nhpoly1305 - Add adiantum - Add streebog hash - Mark cts(cbc(aes)) as FIPS allowed Drivers: - Improve performance of arm64/chacha20 - Improve performance of x86/chacha20 - Add NEON-accelerated nhpoly1305 - Add SSE2 accelerated nhpoly1305 - Add AVX2 accelerated nhpoly1305 - Add support for 192/256-bit keys in gcmaes AVX - Add SG support in gcmaes AVX - ESN for inline IPsec tx in chcr - Add support for CryptoCell 703 in ccree - Add support for CryptoCell 713 in ccree - Add SM4 support in ccree - Add SM3 support in ccree - Add support for chacha20 in caam/qi2 - Add support for chacha20 + poly1305 in caam/jr - Add support for chacha20 + poly1305 in caam/qi2 - Add AEAD cipher support in cavium/nitrox" * 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (130 commits) crypto: skcipher - remove remnants of internal IV generators crypto: cavium/nitrox - Fix build with !CONFIG_DEBUG_FS crypto: salsa20-generic - don't unnecessarily use atomic walk crypto: skcipher - add might_sleep() to skcipher_walk_virt() crypto: x86/chacha - avoid sleeping under kernel_fpu_begin() crypto: cavium/nitrox - Added AEAD cipher support crypto: mxc-scc - fix build warnings on ARM64 crypto: api - document missing stats member crypto: user - remove unused dump functions crypto: chelsio - Fix wrong error counter increments crypto: chelsio - Reset counters on cxgb4 Detach crypto: chelsio - Handle PCI shutdown event crypto: chelsio - cleanup:send addr as value in function argument crypto: chelsio - Use same value for both channel in single WR crypto: chelsio - Swap location of AAD and IV sent in WR crypto: chelsio - remove set but not used variable 'kctx_len' crypto: ux500 - Use proper enum in hash_set_dma_transfer crypto: ux500 - Use proper enum in cryp_set_dma_transfer crypto: aesni - Add scatter/gather avx stubs, and use them in C crypto: aesni - Introduce partial block macro ..
This commit is contained in:
commit
b71acb0e37
183 changed files with 16615 additions and 5866 deletions
|
|
@ -430,11 +430,14 @@ config CRYPTO_CTS
|
|||
help
|
||||
CTS: Cipher Text Stealing
|
||||
This is the Cipher Text Stealing mode as described by
|
||||
Section 8 of rfc2040 and referenced by rfc3962.
|
||||
(rfc3962 includes errata information in its Appendix A)
|
||||
Section 8 of rfc2040 and referenced by rfc3962
|
||||
(rfc3962 includes errata information in its Appendix A) or
|
||||
CBC-CS3 as defined by NIST in Sp800-38A addendum from Oct 2010.
|
||||
This mode is required for Kerberos gss mechanism support
|
||||
for AES encryption.
|
||||
|
||||
See: https://csrc.nist.gov/publications/detail/sp/800-38a/addendum/final
|
||||
|
||||
config CRYPTO_ECB
|
||||
tristate "ECB support"
|
||||
select CRYPTO_BLKCIPHER
|
||||
|
|
@ -493,6 +496,50 @@ config CRYPTO_KEYWRAP
|
|||
Support for key wrapping (NIST SP800-38F / RFC3394) without
|
||||
padding.
|
||||
|
||||
config CRYPTO_NHPOLY1305
|
||||
tristate
|
||||
select CRYPTO_HASH
|
||||
select CRYPTO_POLY1305
|
||||
|
||||
config CRYPTO_NHPOLY1305_SSE2
|
||||
tristate "NHPoly1305 hash function (x86_64 SSE2 implementation)"
|
||||
depends on X86 && 64BIT
|
||||
select CRYPTO_NHPOLY1305
|
||||
help
|
||||
SSE2 optimized implementation of the hash function used by the
|
||||
Adiantum encryption mode.
|
||||
|
||||
config CRYPTO_NHPOLY1305_AVX2
|
||||
tristate "NHPoly1305 hash function (x86_64 AVX2 implementation)"
|
||||
depends on X86 && 64BIT
|
||||
select CRYPTO_NHPOLY1305
|
||||
help
|
||||
AVX2 optimized implementation of the hash function used by the
|
||||
Adiantum encryption mode.
|
||||
|
||||
config CRYPTO_ADIANTUM
|
||||
tristate "Adiantum support"
|
||||
select CRYPTO_CHACHA20
|
||||
select CRYPTO_POLY1305
|
||||
select CRYPTO_NHPOLY1305
|
||||
help
|
||||
Adiantum is a tweakable, length-preserving encryption mode
|
||||
designed for fast and secure disk encryption, especially on
|
||||
CPUs without dedicated crypto instructions. It encrypts
|
||||
each sector using the XChaCha12 stream cipher, two passes of
|
||||
an ε-almost-∆-universal hash function, and an invocation of
|
||||
the AES-256 block cipher on a single 16-byte block. On CPUs
|
||||
without AES instructions, Adiantum is much faster than
|
||||
AES-XTS.
|
||||
|
||||
Adiantum's security is provably reducible to that of its
|
||||
underlying stream and block ciphers, subject to a security
|
||||
bound. Unlike XTS, Adiantum is a true wide-block encryption
|
||||
mode, so it actually provides an even stronger notion of
|
||||
security than XTS, subject to the security bound.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
comment "Hash modes"
|
||||
|
||||
config CRYPTO_CMAC
|
||||
|
|
@ -936,6 +983,18 @@ config CRYPTO_SM3
|
|||
http://www.oscca.gov.cn/UpFile/20101222141857786.pdf
|
||||
https://datatracker.ietf.org/doc/html/draft-shen-sm3-hash
|
||||
|
||||
config CRYPTO_STREEBOG
|
||||
tristate "Streebog Hash Function"
|
||||
select CRYPTO_HASH
|
||||
help
|
||||
Streebog Hash Function (GOST R 34.11-2012, RFC 6986) is one of the Russian
|
||||
cryptographic standard algorithms (called GOST algorithms).
|
||||
This setting enables two hash algorithms with 256 and 512 bits output.
|
||||
|
||||
References:
|
||||
https://tc26.ru/upload/iblock/fed/feddbb4d26b685903faa2ba11aea43f6.pdf
|
||||
https://tools.ietf.org/html/rfc6986
|
||||
|
||||
config CRYPTO_TGR192
|
||||
tristate "Tiger digest algorithms"
|
||||
select CRYPTO_HASH
|
||||
|
|
@ -1006,7 +1065,8 @@ config CRYPTO_AES_TI
|
|||
8 for decryption), this implementation only uses just two S-boxes of
|
||||
256 bytes each, and attempts to eliminate data dependent latencies by
|
||||
prefetching the entire table into the cache at the start of each
|
||||
block.
|
||||
block. Interrupts are also disabled to avoid races where cachelines
|
||||
are evicted when the CPU is interrupted to do something else.
|
||||
|
||||
config CRYPTO_AES_586
|
||||
tristate "AES cipher algorithms (i586)"
|
||||
|
|
@ -1387,32 +1447,34 @@ config CRYPTO_SALSA20
|
|||
Bernstein <[email protected]>. See <http://cr.yp.to/snuffle.html>
|
||||
|
||||
config CRYPTO_CHACHA20
|
||||
tristate "ChaCha20 cipher algorithm"
|
||||
tristate "ChaCha stream cipher algorithms"
|
||||
select CRYPTO_BLKCIPHER
|
||||
help
|
||||
ChaCha20 cipher algorithm, RFC7539.
|
||||
The ChaCha20, XChaCha20, and XChaCha12 stream cipher algorithms.
|
||||
|
||||
ChaCha20 is a 256-bit high-speed stream cipher designed by Daniel J.
|
||||
Bernstein and further specified in RFC7539 for use in IETF protocols.
|
||||
This is the portable C implementation of ChaCha20.
|
||||
|
||||
See also:
|
||||
This is the portable C implementation of ChaCha20. See also:
|
||||
<http://cr.yp.to/chacha/chacha-20080128.pdf>
|
||||
|
||||
XChaCha20 is the application of the XSalsa20 construction to ChaCha20
|
||||
rather than to Salsa20. XChaCha20 extends ChaCha20's nonce length
|
||||
from 64 bits (or 96 bits using the RFC7539 convention) to 192 bits,
|
||||
while provably retaining ChaCha20's security. See also:
|
||||
<https://cr.yp.to/snuffle/xsalsa-20081128.pdf>
|
||||
|
||||
XChaCha12 is XChaCha20 reduced to 12 rounds, with correspondingly
|
||||
reduced security margin but increased performance. It can be needed
|
||||
in some performance-sensitive scenarios.
|
||||
|
||||
config CRYPTO_CHACHA20_X86_64
|
||||
tristate "ChaCha20 cipher algorithm (x86_64/SSSE3/AVX2)"
|
||||
tristate "ChaCha stream cipher algorithms (x86_64/SSSE3/AVX2/AVX-512VL)"
|
||||
depends on X86 && 64BIT
|
||||
select CRYPTO_BLKCIPHER
|
||||
select CRYPTO_CHACHA20
|
||||
help
|
||||
ChaCha20 cipher algorithm, RFC7539.
|
||||
|
||||
ChaCha20 is a 256-bit high-speed stream cipher designed by Daniel J.
|
||||
Bernstein and further specified in RFC7539 for use in IETF protocols.
|
||||
This is the x86_64 assembler implementation using SIMD instructions.
|
||||
|
||||
See also:
|
||||
<http://cr.yp.to/chacha/chacha-20080128.pdf>
|
||||
SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20,
|
||||
XChaCha20, and XChaCha12 stream ciphers.
|
||||
|
||||
config CRYPTO_SEED
|
||||
tristate "SEED cipher algorithm"
|
||||
|
|
@ -1812,7 +1874,8 @@ config CRYPTO_USER_API_AEAD
|
|||
cipher algorithms.
|
||||
|
||||
config CRYPTO_STATS
|
||||
bool
|
||||
bool "Crypto usage statistics for User-space"
|
||||
depends on CRYPTO_USER
|
||||
help
|
||||
This option enables the gathering of crypto stats.
|
||||
This will collect:
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ cryptomgr-y := algboss.o testmgr.o
|
|||
|
||||
obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
|
||||
obj-$(CONFIG_CRYPTO_USER) += crypto_user.o
|
||||
crypto_user-y := crypto_user_base.o crypto_user_stat.o
|
||||
crypto_user-y := crypto_user_base.o
|
||||
crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o
|
||||
obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
|
||||
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
|
||||
obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
|
||||
|
|
@ -71,6 +72,7 @@ obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o
|
|||
obj-$(CONFIG_CRYPTO_SHA512) += sha512_generic.o
|
||||
obj-$(CONFIG_CRYPTO_SHA3) += sha3_generic.o
|
||||
obj-$(CONFIG_CRYPTO_SM3) += sm3_generic.o
|
||||
obj-$(CONFIG_CRYPTO_STREEBOG) += streebog_generic.o
|
||||
obj-$(CONFIG_CRYPTO_WP512) += wp512.o
|
||||
CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
|
||||
obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
|
||||
|
|
@ -84,6 +86,8 @@ obj-$(CONFIG_CRYPTO_LRW) += lrw.o
|
|||
obj-$(CONFIG_CRYPTO_XTS) += xts.o
|
||||
obj-$(CONFIG_CRYPTO_CTR) += ctr.o
|
||||
obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o
|
||||
obj-$(CONFIG_CRYPTO_ADIANTUM) += adiantum.o
|
||||
obj-$(CONFIG_CRYPTO_NHPOLY1305) += nhpoly1305.o
|
||||
obj-$(CONFIG_CRYPTO_GCM) += gcm.o
|
||||
obj-$(CONFIG_CRYPTO_CCM) += ccm.o
|
||||
obj-$(CONFIG_CRYPTO_CHACHA20POLY1305) += chacha20poly1305.o
|
||||
|
|
@ -116,7 +120,7 @@ obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
|
|||
obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
|
||||
obj-$(CONFIG_CRYPTO_SEED) += seed.o
|
||||
obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
|
||||
obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
|
||||
obj-$(CONFIG_CRYPTO_CHACHA20) += chacha_generic.o
|
||||
obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
|
||||
obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
|
||||
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
|
||||
|
|
|
|||
|
|
@ -365,23 +365,18 @@ static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_blkcipher rblkcipher;
|
||||
|
||||
strncpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type));
|
||||
strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<default>",
|
||||
sizeof(rblkcipher.geniv));
|
||||
rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0';
|
||||
memset(&rblkcipher, 0, sizeof(rblkcipher));
|
||||
|
||||
strscpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type));
|
||||
strscpy(rblkcipher.geniv, "<default>", sizeof(rblkcipher.geniv));
|
||||
|
||||
rblkcipher.blocksize = alg->cra_blocksize;
|
||||
rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
|
||||
rblkcipher.max_keysize = alg->cra_ablkcipher.max_keysize;
|
||||
rblkcipher.ivsize = alg->cra_ablkcipher.ivsize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER,
|
||||
sizeof(struct crypto_report_blkcipher), &rblkcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER,
|
||||
sizeof(rblkcipher), &rblkcipher);
|
||||
}
|
||||
#else
|
||||
static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
@ -403,7 +398,7 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
|
|||
seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize);
|
||||
seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize);
|
||||
seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize);
|
||||
seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: "<default>");
|
||||
seq_printf(m, "geniv : <default>\n");
|
||||
}
|
||||
|
||||
const struct crypto_type crypto_ablkcipher_type = {
|
||||
|
|
@ -415,78 +410,3 @@ const struct crypto_type crypto_ablkcipher_type = {
|
|||
.report = crypto_ablkcipher_report,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(crypto_ablkcipher_type);
|
||||
|
||||
static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type,
|
||||
u32 mask)
|
||||
{
|
||||
struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher;
|
||||
struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;
|
||||
|
||||
if (alg->ivsize > PAGE_SIZE / 8)
|
||||
return -EINVAL;
|
||||
|
||||
crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ?
|
||||
alg->setkey : setkey;
|
||||
crt->encrypt = alg->encrypt;
|
||||
crt->decrypt = alg->decrypt;
|
||||
crt->base = __crypto_ablkcipher_cast(tfm);
|
||||
crt->ivsize = alg->ivsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_blkcipher rblkcipher;
|
||||
|
||||
strncpy(rblkcipher.type, "givcipher", sizeof(rblkcipher.type));
|
||||
strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<built-in>",
|
||||
sizeof(rblkcipher.geniv));
|
||||
rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0';
|
||||
|
||||
rblkcipher.blocksize = alg->cra_blocksize;
|
||||
rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
|
||||
rblkcipher.max_keysize = alg->cra_ablkcipher.max_keysize;
|
||||
rblkcipher.ivsize = alg->cra_ablkcipher.ivsize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER,
|
||||
sizeof(struct crypto_report_blkcipher), &rblkcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
#else
|
||||
static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg)
|
||||
__maybe_unused;
|
||||
static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg)
|
||||
{
|
||||
struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
|
||||
|
||||
seq_printf(m, "type : givcipher\n");
|
||||
seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
|
||||
"yes" : "no");
|
||||
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
|
||||
seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize);
|
||||
seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize);
|
||||
seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize);
|
||||
seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: "<built-in>");
|
||||
}
|
||||
|
||||
const struct crypto_type crypto_givcipher_type = {
|
||||
.ctxsize = crypto_ablkcipher_ctxsize,
|
||||
.init = crypto_init_givcipher_ops,
|
||||
#ifdef CONFIG_PROC_FS
|
||||
.show = crypto_givcipher_show,
|
||||
#endif
|
||||
.report = crypto_givcipher_report,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(crypto_givcipher_type);
|
||||
|
|
|
|||
|
|
@ -33,15 +33,11 @@ static int crypto_acomp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_acomp racomp;
|
||||
|
||||
strncpy(racomp.type, "acomp", sizeof(racomp.type));
|
||||
memset(&racomp, 0, sizeof(racomp));
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_ACOMP,
|
||||
sizeof(struct crypto_report_acomp), &racomp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
strscpy(racomp.type, "acomp", sizeof(racomp.type));
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_ACOMP, sizeof(racomp), &racomp);
|
||||
}
|
||||
#else
|
||||
static int crypto_acomp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
664
crypto/adiantum.c
Normal file
664
crypto/adiantum.c
Normal file
|
|
@ -0,0 +1,664 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Adiantum length-preserving encryption mode
|
||||
*
|
||||
* Copyright 2018 Google LLC
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adiantum is a tweakable, length-preserving encryption mode designed for fast
|
||||
* and secure disk encryption, especially on CPUs without dedicated crypto
|
||||
* instructions. Adiantum encrypts each sector using the XChaCha12 stream
|
||||
* cipher, two passes of an ε-almost-∆-universal (ε-∆U) hash function based on
|
||||
* NH and Poly1305, and an invocation of the AES-256 block cipher on a single
|
||||
* 16-byte block. See the paper for details:
|
||||
*
|
||||
* Adiantum: length-preserving encryption for entry-level processors
|
||||
* (https://eprint.iacr.org/2018/720.pdf)
|
||||
*
|
||||
* For flexibility, this implementation also allows other ciphers:
|
||||
*
|
||||
* - Stream cipher: XChaCha12 or XChaCha20
|
||||
* - Block cipher: any with a 128-bit block size and 256-bit key
|
||||
*
|
||||
* This implementation doesn't currently allow other ε-∆U hash functions, i.e.
|
||||
* HPolyC is not supported. This is because Adiantum is ~20% faster than HPolyC
|
||||
* but still provably as secure, and also the ε-∆U hash function of HBSH is
|
||||
* formally defined to take two inputs (tweak, message) which makes it difficult
|
||||
* to wrap with the crypto_shash API. Rather, some details need to be handled
|
||||
* here. Nevertheless, if needed in the future, support for other ε-∆U hash
|
||||
* functions could be added here.
|
||||
*/
|
||||
|
||||
#include <crypto/b128ops.h>
|
||||
#include <crypto/chacha.h>
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <crypto/internal/skcipher.h>
|
||||
#include <crypto/nhpoly1305.h>
|
||||
#include <crypto/scatterwalk.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Size of right-hand part of input data, in bytes; also the size of the block
|
||||
* cipher's block size and the hash function's output.
|
||||
*/
|
||||
#define BLOCKCIPHER_BLOCK_SIZE 16
|
||||
|
||||
/* Size of the block cipher key (K_E) in bytes */
|
||||
#define BLOCKCIPHER_KEY_SIZE 32
|
||||
|
||||
/* Size of the hash key (K_H) in bytes */
|
||||
#define HASH_KEY_SIZE (POLY1305_BLOCK_SIZE + NHPOLY1305_KEY_SIZE)
|
||||
|
||||
/*
|
||||
* The specification allows variable-length tweaks, but Linux's crypto API
|
||||
* currently only allows algorithms to support a single length. The "natural"
|
||||
* tweak length for Adiantum is 16, since that fits into one Poly1305 block for
|
||||
* the best performance. But longer tweaks are useful for fscrypt, to avoid
|
||||
* needing to derive per-file keys. So instead we use two blocks, or 32 bytes.
|
||||
*/
|
||||
#define TWEAK_SIZE 32
|
||||
|
||||
struct adiantum_instance_ctx {
|
||||
struct crypto_skcipher_spawn streamcipher_spawn;
|
||||
struct crypto_spawn blockcipher_spawn;
|
||||
struct crypto_shash_spawn hash_spawn;
|
||||
};
|
||||
|
||||
struct adiantum_tfm_ctx {
|
||||
struct crypto_skcipher *streamcipher;
|
||||
struct crypto_cipher *blockcipher;
|
||||
struct crypto_shash *hash;
|
||||
struct poly1305_key header_hash_key;
|
||||
};
|
||||
|
||||
struct adiantum_request_ctx {
|
||||
|
||||
/*
|
||||
* Buffer for right-hand part of data, i.e.
|
||||
*
|
||||
* P_L => P_M => C_M => C_R when encrypting, or
|
||||
* C_R => C_M => P_M => P_L when decrypting.
|
||||
*
|
||||
* Also used to build the IV for the stream cipher.
|
||||
*/
|
||||
union {
|
||||
u8 bytes[XCHACHA_IV_SIZE];
|
||||
__le32 words[XCHACHA_IV_SIZE / sizeof(__le32)];
|
||||
le128 bignum; /* interpret as element of Z/(2^{128}Z) */
|
||||
} rbuf;
|
||||
|
||||
bool enc; /* true if encrypting, false if decrypting */
|
||||
|
||||
/*
|
||||
* The result of the Poly1305 ε-∆U hash function applied to
|
||||
* (bulk length, tweak)
|
||||
*/
|
||||
le128 header_hash;
|
||||
|
||||
/* Sub-requests, must be last */
|
||||
union {
|
||||
struct shash_desc hash_desc;
|
||||
struct skcipher_request streamcipher_req;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Given the XChaCha stream key K_S, derive the block cipher key K_E and the
|
||||
* hash key K_H as follows:
|
||||
*
|
||||
* K_E || K_H || ... = XChaCha(key=K_S, nonce=1||0^191)
|
||||
*
|
||||
* Note that this denotes using bits from the XChaCha keystream, which here we
|
||||
* get indirectly by encrypting a buffer containing all 0's.
|
||||
*/
|
||||
static int adiantum_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
|
||||
struct {
|
||||
u8 iv[XCHACHA_IV_SIZE];
|
||||
u8 derived_keys[BLOCKCIPHER_KEY_SIZE + HASH_KEY_SIZE];
|
||||
struct scatterlist sg;
|
||||
struct crypto_wait wait;
|
||||
struct skcipher_request req; /* must be last */
|
||||
} *data;
|
||||
u8 *keyp;
|
||||
int err;
|
||||
|
||||
/* Set the stream cipher key (K_S) */
|
||||
crypto_skcipher_clear_flags(tctx->streamcipher, CRYPTO_TFM_REQ_MASK);
|
||||
crypto_skcipher_set_flags(tctx->streamcipher,
|
||||
crypto_skcipher_get_flags(tfm) &
|
||||
CRYPTO_TFM_REQ_MASK);
|
||||
err = crypto_skcipher_setkey(tctx->streamcipher, key, keylen);
|
||||
crypto_skcipher_set_flags(tfm,
|
||||
crypto_skcipher_get_flags(tctx->streamcipher) &
|
||||
CRYPTO_TFM_RES_MASK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Derive the subkeys */
|
||||
data = kzalloc(sizeof(*data) +
|
||||
crypto_skcipher_reqsize(tctx->streamcipher), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
data->iv[0] = 1;
|
||||
sg_init_one(&data->sg, data->derived_keys, sizeof(data->derived_keys));
|
||||
crypto_init_wait(&data->wait);
|
||||
skcipher_request_set_tfm(&data->req, tctx->streamcipher);
|
||||
skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
crypto_req_done, &data->wait);
|
||||
skcipher_request_set_crypt(&data->req, &data->sg, &data->sg,
|
||||
sizeof(data->derived_keys), data->iv);
|
||||
err = crypto_wait_req(crypto_skcipher_encrypt(&data->req), &data->wait);
|
||||
if (err)
|
||||
goto out;
|
||||
keyp = data->derived_keys;
|
||||
|
||||
/* Set the block cipher key (K_E) */
|
||||
crypto_cipher_clear_flags(tctx->blockcipher, CRYPTO_TFM_REQ_MASK);
|
||||
crypto_cipher_set_flags(tctx->blockcipher,
|
||||
crypto_skcipher_get_flags(tfm) &
|
||||
CRYPTO_TFM_REQ_MASK);
|
||||
err = crypto_cipher_setkey(tctx->blockcipher, keyp,
|
||||
BLOCKCIPHER_KEY_SIZE);
|
||||
crypto_skcipher_set_flags(tfm,
|
||||
crypto_cipher_get_flags(tctx->blockcipher) &
|
||||
CRYPTO_TFM_RES_MASK);
|
||||
if (err)
|
||||
goto out;
|
||||
keyp += BLOCKCIPHER_KEY_SIZE;
|
||||
|
||||
/* Set the hash key (K_H) */
|
||||
poly1305_core_setkey(&tctx->header_hash_key, keyp);
|
||||
keyp += POLY1305_BLOCK_SIZE;
|
||||
|
||||
crypto_shash_clear_flags(tctx->hash, CRYPTO_TFM_REQ_MASK);
|
||||
crypto_shash_set_flags(tctx->hash, crypto_skcipher_get_flags(tfm) &
|
||||
CRYPTO_TFM_REQ_MASK);
|
||||
err = crypto_shash_setkey(tctx->hash, keyp, NHPOLY1305_KEY_SIZE);
|
||||
crypto_skcipher_set_flags(tfm, crypto_shash_get_flags(tctx->hash) &
|
||||
CRYPTO_TFM_RES_MASK);
|
||||
keyp += NHPOLY1305_KEY_SIZE;
|
||||
WARN_ON(keyp != &data->derived_keys[ARRAY_SIZE(data->derived_keys)]);
|
||||
out:
|
||||
kzfree(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Addition in Z/(2^{128}Z) */
|
||||
static inline void le128_add(le128 *r, const le128 *v1, const le128 *v2)
|
||||
{
|
||||
u64 x = le64_to_cpu(v1->b);
|
||||
u64 y = le64_to_cpu(v2->b);
|
||||
|
||||
r->b = cpu_to_le64(x + y);
|
||||
r->a = cpu_to_le64(le64_to_cpu(v1->a) + le64_to_cpu(v2->a) +
|
||||
(x + y < x));
|
||||
}
|
||||
|
||||
/* Subtraction in Z/(2^{128}Z) */
|
||||
static inline void le128_sub(le128 *r, const le128 *v1, const le128 *v2)
|
||||
{
|
||||
u64 x = le64_to_cpu(v1->b);
|
||||
u64 y = le64_to_cpu(v2->b);
|
||||
|
||||
r->b = cpu_to_le64(x - y);
|
||||
r->a = cpu_to_le64(le64_to_cpu(v1->a) - le64_to_cpu(v2->a) -
|
||||
(x - y > x));
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply the Poly1305 ε-∆U hash function to (bulk length, tweak) and save the
|
||||
* result to rctx->header_hash. This is the calculation
|
||||
*
|
||||
* H_T ← Poly1305_{K_T}(bin_{128}(|L|) || T)
|
||||
*
|
||||
* from the procedure in section 6.4 of the Adiantum paper. The resulting value
|
||||
* is reused in both the first and second hash steps. Specifically, it's added
|
||||
* to the result of an independently keyed ε-∆U hash function (for equal length
|
||||
* inputs only) taken over the left-hand part (the "bulk") of the message, to
|
||||
* give the overall Adiantum hash of the (tweak, left-hand part) pair.
|
||||
*/
|
||||
static void adiantum_hash_header(struct skcipher_request *req)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
|
||||
struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
|
||||
const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
|
||||
struct {
|
||||
__le64 message_bits;
|
||||
__le64 padding;
|
||||
} header = {
|
||||
.message_bits = cpu_to_le64((u64)bulk_len * 8)
|
||||
};
|
||||
struct poly1305_state state;
|
||||
|
||||
poly1305_core_init(&state);
|
||||
|
||||
BUILD_BUG_ON(sizeof(header) % POLY1305_BLOCK_SIZE != 0);
|
||||
poly1305_core_blocks(&state, &tctx->header_hash_key,
|
||||
&header, sizeof(header) / POLY1305_BLOCK_SIZE);
|
||||
|
||||
BUILD_BUG_ON(TWEAK_SIZE % POLY1305_BLOCK_SIZE != 0);
|
||||
poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv,
|
||||
TWEAK_SIZE / POLY1305_BLOCK_SIZE);
|
||||
|
||||
poly1305_core_emit(&state, &rctx->header_hash);
|
||||
}
|
||||
|
||||
/* Hash the left-hand part (the "bulk") of the message using NHPoly1305 */
|
||||
static int adiantum_hash_message(struct skcipher_request *req,
|
||||
struct scatterlist *sgl, le128 *digest)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
|
||||
struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
|
||||
const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
|
||||
struct shash_desc *hash_desc = &rctx->u.hash_desc;
|
||||
struct sg_mapping_iter miter;
|
||||
unsigned int i, n;
|
||||
int err;
|
||||
|
||||
hash_desc->tfm = tctx->hash;
|
||||
hash_desc->flags = 0;
|
||||
|
||||
err = crypto_shash_init(hash_desc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sg_miter_start(&miter, sgl, sg_nents(sgl),
|
||||
SG_MITER_FROM_SG | SG_MITER_ATOMIC);
|
||||
for (i = 0; i < bulk_len; i += n) {
|
||||
sg_miter_next(&miter);
|
||||
n = min_t(unsigned int, miter.length, bulk_len - i);
|
||||
err = crypto_shash_update(hash_desc, miter.addr, n);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
sg_miter_stop(&miter);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return crypto_shash_final(hash_desc, (u8 *)digest);
|
||||
}
|
||||
|
||||
/* Continue Adiantum encryption/decryption after the stream cipher step */
|
||||
static int adiantum_finish(struct skcipher_request *req)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
|
||||
struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
|
||||
const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
|
||||
le128 digest;
|
||||
int err;
|
||||
|
||||
/* If decrypting, decrypt C_M with the block cipher to get P_M */
|
||||
if (!rctx->enc)
|
||||
crypto_cipher_decrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
|
||||
rctx->rbuf.bytes);
|
||||
|
||||
/*
|
||||
* Second hash step
|
||||
* enc: C_R = C_M - H_{K_H}(T, C_L)
|
||||
* dec: P_R = P_M - H_{K_H}(T, P_L)
|
||||
*/
|
||||
err = adiantum_hash_message(req, req->dst, &digest);
|
||||
if (err)
|
||||
return err;
|
||||
le128_add(&digest, &digest, &rctx->header_hash);
|
||||
le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
|
||||
scatterwalk_map_and_copy(&rctx->rbuf.bignum, req->dst,
|
||||
bulk_len, BLOCKCIPHER_BLOCK_SIZE, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adiantum_streamcipher_done(struct crypto_async_request *areq,
|
||||
int err)
|
||||
{
|
||||
struct skcipher_request *req = areq->data;
|
||||
|
||||
if (!err)
|
||||
err = adiantum_finish(req);
|
||||
|
||||
skcipher_request_complete(req, err);
|
||||
}
|
||||
|
||||
static int adiantum_crypt(struct skcipher_request *req, bool enc)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
|
||||
struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
|
||||
const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
|
||||
unsigned int stream_len;
|
||||
le128 digest;
|
||||
int err;
|
||||
|
||||
if (req->cryptlen < BLOCKCIPHER_BLOCK_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
rctx->enc = enc;
|
||||
|
||||
/*
|
||||
* First hash step
|
||||
* enc: P_M = P_R + H_{K_H}(T, P_L)
|
||||
* dec: C_M = C_R + H_{K_H}(T, C_L)
|
||||
*/
|
||||
adiantum_hash_header(req);
|
||||
err = adiantum_hash_message(req, req->src, &digest);
|
||||
if (err)
|
||||
return err;
|
||||
le128_add(&digest, &digest, &rctx->header_hash);
|
||||
scatterwalk_map_and_copy(&rctx->rbuf.bignum, req->src,
|
||||
bulk_len, BLOCKCIPHER_BLOCK_SIZE, 0);
|
||||
le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
|
||||
|
||||
/* If encrypting, encrypt P_M with the block cipher to get C_M */
|
||||
if (enc)
|
||||
crypto_cipher_encrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
|
||||
rctx->rbuf.bytes);
|
||||
|
||||
/* Initialize the rest of the XChaCha IV (first part is C_M) */
|
||||
BUILD_BUG_ON(BLOCKCIPHER_BLOCK_SIZE != 16);
|
||||
BUILD_BUG_ON(XCHACHA_IV_SIZE != 32); /* nonce || stream position */
|
||||
rctx->rbuf.words[4] = cpu_to_le32(1);
|
||||
rctx->rbuf.words[5] = 0;
|
||||
rctx->rbuf.words[6] = 0;
|
||||
rctx->rbuf.words[7] = 0;
|
||||
|
||||
/*
|
||||
* XChaCha needs to be done on all the data except the last 16 bytes;
|
||||
* for disk encryption that usually means 4080 or 496 bytes. But ChaCha
|
||||
* implementations tend to be most efficient when passed a whole number
|
||||
* of 64-byte ChaCha blocks, or sometimes even a multiple of 256 bytes.
|
||||
* And here it doesn't matter whether the last 16 bytes are written to,
|
||||
* as the second hash step will overwrite them. Thus, round the XChaCha
|
||||
* length up to the next 64-byte boundary if possible.
|
||||
*/
|
||||
stream_len = bulk_len;
|
||||
if (round_up(stream_len, CHACHA_BLOCK_SIZE) <= req->cryptlen)
|
||||
stream_len = round_up(stream_len, CHACHA_BLOCK_SIZE);
|
||||
|
||||
skcipher_request_set_tfm(&rctx->u.streamcipher_req, tctx->streamcipher);
|
||||
skcipher_request_set_crypt(&rctx->u.streamcipher_req, req->src,
|
||||
req->dst, stream_len, &rctx->rbuf);
|
||||
skcipher_request_set_callback(&rctx->u.streamcipher_req,
|
||||
req->base.flags,
|
||||
adiantum_streamcipher_done, req);
|
||||
return crypto_skcipher_encrypt(&rctx->u.streamcipher_req) ?:
|
||||
adiantum_finish(req);
|
||||
}
|
||||
|
||||
static int adiantum_encrypt(struct skcipher_request *req)
|
||||
{
|
||||
return adiantum_crypt(req, true);
|
||||
}
|
||||
|
||||
static int adiantum_decrypt(struct skcipher_request *req)
|
||||
{
|
||||
return adiantum_crypt(req, false);
|
||||
}
|
||||
|
||||
static int adiantum_init_tfm(struct crypto_skcipher *tfm)
|
||||
{
|
||||
struct skcipher_instance *inst = skcipher_alg_instance(tfm);
|
||||
struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst);
|
||||
struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
|
||||
struct crypto_skcipher *streamcipher;
|
||||
struct crypto_cipher *blockcipher;
|
||||
struct crypto_shash *hash;
|
||||
unsigned int subreq_size;
|
||||
int err;
|
||||
|
||||
streamcipher = crypto_spawn_skcipher(&ictx->streamcipher_spawn);
|
||||
if (IS_ERR(streamcipher))
|
||||
return PTR_ERR(streamcipher);
|
||||
|
||||
blockcipher = crypto_spawn_cipher(&ictx->blockcipher_spawn);
|
||||
if (IS_ERR(blockcipher)) {
|
||||
err = PTR_ERR(blockcipher);
|
||||
goto err_free_streamcipher;
|
||||
}
|
||||
|
||||
hash = crypto_spawn_shash(&ictx->hash_spawn);
|
||||
if (IS_ERR(hash)) {
|
||||
err = PTR_ERR(hash);
|
||||
goto err_free_blockcipher;
|
||||
}
|
||||
|
||||
tctx->streamcipher = streamcipher;
|
||||
tctx->blockcipher = blockcipher;
|
||||
tctx->hash = hash;
|
||||
|
||||
BUILD_BUG_ON(offsetofend(struct adiantum_request_ctx, u) !=
|
||||
sizeof(struct adiantum_request_ctx));
|
||||
subreq_size = max(FIELD_SIZEOF(struct adiantum_request_ctx,
|
||||
u.hash_desc) +
|
||||
crypto_shash_descsize(hash),
|
||||
FIELD_SIZEOF(struct adiantum_request_ctx,
|
||||
u.streamcipher_req) +
|
||||
crypto_skcipher_reqsize(streamcipher));
|
||||
|
||||
crypto_skcipher_set_reqsize(tfm,
|
||||
offsetof(struct adiantum_request_ctx, u) +
|
||||
subreq_size);
|
||||
return 0;
|
||||
|
||||
err_free_blockcipher:
|
||||
crypto_free_cipher(blockcipher);
|
||||
err_free_streamcipher:
|
||||
crypto_free_skcipher(streamcipher);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void adiantum_exit_tfm(struct crypto_skcipher *tfm)
|
||||
{
|
||||
struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
|
||||
|
||||
crypto_free_skcipher(tctx->streamcipher);
|
||||
crypto_free_cipher(tctx->blockcipher);
|
||||
crypto_free_shash(tctx->hash);
|
||||
}
|
||||
|
||||
static void adiantum_free_instance(struct skcipher_instance *inst)
|
||||
{
|
||||
struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst);
|
||||
|
||||
crypto_drop_skcipher(&ictx->streamcipher_spawn);
|
||||
crypto_drop_spawn(&ictx->blockcipher_spawn);
|
||||
crypto_drop_shash(&ictx->hash_spawn);
|
||||
kfree(inst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a supported set of inner algorithms.
|
||||
* See the comment at the beginning of this file.
|
||||
*/
|
||||
static bool adiantum_supported_algorithms(struct skcipher_alg *streamcipher_alg,
|
||||
struct crypto_alg *blockcipher_alg,
|
||||
struct shash_alg *hash_alg)
|
||||
{
|
||||
if (strcmp(streamcipher_alg->base.cra_name, "xchacha12") != 0 &&
|
||||
strcmp(streamcipher_alg->base.cra_name, "xchacha20") != 0)
|
||||
return false;
|
||||
|
||||
if (blockcipher_alg->cra_cipher.cia_min_keysize > BLOCKCIPHER_KEY_SIZE ||
|
||||
blockcipher_alg->cra_cipher.cia_max_keysize < BLOCKCIPHER_KEY_SIZE)
|
||||
return false;
|
||||
if (blockcipher_alg->cra_blocksize != BLOCKCIPHER_BLOCK_SIZE)
|
||||
return false;
|
||||
|
||||
if (strcmp(hash_alg->base.cra_name, "nhpoly1305") != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
|
||||
{
|
||||
struct crypto_attr_type *algt;
|
||||
const char *streamcipher_name;
|
||||
const char *blockcipher_name;
|
||||
const char *nhpoly1305_name;
|
||||
struct skcipher_instance *inst;
|
||||
struct adiantum_instance_ctx *ictx;
|
||||
struct skcipher_alg *streamcipher_alg;
|
||||
struct crypto_alg *blockcipher_alg;
|
||||
struct crypto_alg *_hash_alg;
|
||||
struct shash_alg *hash_alg;
|
||||
int err;
|
||||
|
||||
algt = crypto_get_attr_type(tb);
|
||||
if (IS_ERR(algt))
|
||||
return PTR_ERR(algt);
|
||||
|
||||
if ((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask)
|
||||
return -EINVAL;
|
||||
|
||||
streamcipher_name = crypto_attr_alg_name(tb[1]);
|
||||
if (IS_ERR(streamcipher_name))
|
||||
return PTR_ERR(streamcipher_name);
|
||||
|
||||
blockcipher_name = crypto_attr_alg_name(tb[2]);
|
||||
if (IS_ERR(blockcipher_name))
|
||||
return PTR_ERR(blockcipher_name);
|
||||
|
||||
nhpoly1305_name = crypto_attr_alg_name(tb[3]);
|
||||
if (nhpoly1305_name == ERR_PTR(-ENOENT))
|
||||
nhpoly1305_name = "nhpoly1305";
|
||||
if (IS_ERR(nhpoly1305_name))
|
||||
return PTR_ERR(nhpoly1305_name);
|
||||
|
||||
inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
|
||||
if (!inst)
|
||||
return -ENOMEM;
|
||||
ictx = skcipher_instance_ctx(inst);
|
||||
|
||||
/* Stream cipher, e.g. "xchacha12" */
|
||||
err = crypto_grab_skcipher(&ictx->streamcipher_spawn, streamcipher_name,
|
||||
0, crypto_requires_sync(algt->type,
|
||||
algt->mask));
|
||||
if (err)
|
||||
goto out_free_inst;
|
||||
streamcipher_alg = crypto_spawn_skcipher_alg(&ictx->streamcipher_spawn);
|
||||
|
||||
/* Block cipher, e.g. "aes" */
|
||||
err = crypto_grab_spawn(&ictx->blockcipher_spawn, blockcipher_name,
|
||||
CRYPTO_ALG_TYPE_CIPHER, CRYPTO_ALG_TYPE_MASK);
|
||||
if (err)
|
||||
goto out_drop_streamcipher;
|
||||
blockcipher_alg = ictx->blockcipher_spawn.alg;
|
||||
|
||||
/* NHPoly1305 ε-∆U hash function */
|
||||
_hash_alg = crypto_alg_mod_lookup(nhpoly1305_name,
|
||||
CRYPTO_ALG_TYPE_SHASH,
|
||||
CRYPTO_ALG_TYPE_MASK);
|
||||
if (IS_ERR(_hash_alg)) {
|
||||
err = PTR_ERR(_hash_alg);
|
||||
goto out_drop_blockcipher;
|
||||
}
|
||||
hash_alg = __crypto_shash_alg(_hash_alg);
|
||||
err = crypto_init_shash_spawn(&ictx->hash_spawn, hash_alg,
|
||||
skcipher_crypto_instance(inst));
|
||||
if (err)
|
||||
goto out_put_hash;
|
||||
|
||||
/* Check the set of algorithms */
|
||||
if (!adiantum_supported_algorithms(streamcipher_alg, blockcipher_alg,
|
||||
hash_alg)) {
|
||||
pr_warn("Unsupported Adiantum instantiation: (%s,%s,%s)\n",
|
||||
streamcipher_alg->base.cra_name,
|
||||
blockcipher_alg->cra_name, hash_alg->base.cra_name);
|
||||
err = -EINVAL;
|
||||
goto out_drop_hash;
|
||||
}
|
||||
|
||||
/* Instance fields */
|
||||
|
||||
err = -ENAMETOOLONG;
|
||||
if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
|
||||
"adiantum(%s,%s)", streamcipher_alg->base.cra_name,
|
||||
blockcipher_alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
|
||||
goto out_drop_hash;
|
||||
if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
|
||||
"adiantum(%s,%s,%s)",
|
||||
streamcipher_alg->base.cra_driver_name,
|
||||
blockcipher_alg->cra_driver_name,
|
||||
hash_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
|
||||
goto out_drop_hash;
|
||||
|
||||
inst->alg.base.cra_flags = streamcipher_alg->base.cra_flags &
|
||||
CRYPTO_ALG_ASYNC;
|
||||
inst->alg.base.cra_blocksize = BLOCKCIPHER_BLOCK_SIZE;
|
||||
inst->alg.base.cra_ctxsize = sizeof(struct adiantum_tfm_ctx);
|
||||
inst->alg.base.cra_alignmask = streamcipher_alg->base.cra_alignmask |
|
||||
hash_alg->base.cra_alignmask;
|
||||
/*
|
||||
* The block cipher is only invoked once per message, so for long
|
||||
* messages (e.g. sectors for disk encryption) its performance doesn't
|
||||
* matter as much as that of the stream cipher and hash function. Thus,
|
||||
* weigh the block cipher's ->cra_priority less.
|
||||
*/
|
||||
inst->alg.base.cra_priority = (4 * streamcipher_alg->base.cra_priority +
|
||||
2 * hash_alg->base.cra_priority +
|
||||
blockcipher_alg->cra_priority) / 7;
|
||||
|
||||
inst->alg.setkey = adiantum_setkey;
|
||||
inst->alg.encrypt = adiantum_encrypt;
|
||||
inst->alg.decrypt = adiantum_decrypt;
|
||||
inst->alg.init = adiantum_init_tfm;
|
||||
inst->alg.exit = adiantum_exit_tfm;
|
||||
inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(streamcipher_alg);
|
||||
inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(streamcipher_alg);
|
||||
inst->alg.ivsize = TWEAK_SIZE;
|
||||
|
||||
inst->free = adiantum_free_instance;
|
||||
|
||||
err = skcipher_register_instance(tmpl, inst);
|
||||
if (err)
|
||||
goto out_drop_hash;
|
||||
|
||||
crypto_mod_put(_hash_alg);
|
||||
return 0;
|
||||
|
||||
out_drop_hash:
|
||||
crypto_drop_shash(&ictx->hash_spawn);
|
||||
out_put_hash:
|
||||
crypto_mod_put(_hash_alg);
|
||||
out_drop_blockcipher:
|
||||
crypto_drop_spawn(&ictx->blockcipher_spawn);
|
||||
out_drop_streamcipher:
|
||||
crypto_drop_skcipher(&ictx->streamcipher_spawn);
|
||||
out_free_inst:
|
||||
kfree(inst);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* adiantum(streamcipher_name, blockcipher_name [, nhpoly1305_name]) */
|
||||
static struct crypto_template adiantum_tmpl = {
|
||||
.name = "adiantum",
|
||||
.create = adiantum_create,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init adiantum_module_init(void)
|
||||
{
|
||||
return crypto_register_template(&adiantum_tmpl);
|
||||
}
|
||||
|
||||
static void __exit adiantum_module_exit(void)
|
||||
{
|
||||
crypto_unregister_template(&adiantum_tmpl);
|
||||
}
|
||||
|
||||
module_init(adiantum_module_init);
|
||||
module_exit(adiantum_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Adiantum length-preserving encryption mode");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Eric Biggers <[email protected]>");
|
||||
MODULE_ALIAS_CRYPTO("adiantum");
|
||||
|
|
@ -119,20 +119,16 @@ static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
struct crypto_report_aead raead;
|
||||
struct aead_alg *aead = container_of(alg, struct aead_alg, base);
|
||||
|
||||
strncpy(raead.type, "aead", sizeof(raead.type));
|
||||
strncpy(raead.geniv, "<none>", sizeof(raead.geniv));
|
||||
memset(&raead, 0, sizeof(raead));
|
||||
|
||||
strscpy(raead.type, "aead", sizeof(raead.type));
|
||||
strscpy(raead.geniv, "<none>", sizeof(raead.geniv));
|
||||
|
||||
raead.blocksize = alg->cra_blocksize;
|
||||
raead.maxauthsize = aead->maxauthsize;
|
||||
raead.ivsize = aead->ivsize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_AEAD,
|
||||
sizeof(struct crypto_report_aead), &raead))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead);
|
||||
}
|
||||
#else
|
||||
static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ static inline u8 byte(const u32 x, const unsigned n)
|
|||
|
||||
static const u32 rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
|
||||
|
||||
__visible const u32 crypto_ft_tab[4][256] = {
|
||||
/* cacheline-aligned to facilitate prefetching into cache */
|
||||
__visible const u32 crypto_ft_tab[4][256] __cacheline_aligned = {
|
||||
{
|
||||
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
|
||||
0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
|
||||
|
|
@ -327,7 +328,7 @@ __visible const u32 crypto_ft_tab[4][256] = {
|
|||
}
|
||||
};
|
||||
|
||||
__visible const u32 crypto_fl_tab[4][256] = {
|
||||
__visible const u32 crypto_fl_tab[4][256] __cacheline_aligned = {
|
||||
{
|
||||
0x00000063, 0x0000007c, 0x00000077, 0x0000007b,
|
||||
0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5,
|
||||
|
|
@ -591,7 +592,7 @@ __visible const u32 crypto_fl_tab[4][256] = {
|
|||
}
|
||||
};
|
||||
|
||||
__visible const u32 crypto_it_tab[4][256] = {
|
||||
__visible const u32 crypto_it_tab[4][256] __cacheline_aligned = {
|
||||
{
|
||||
0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a,
|
||||
0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b,
|
||||
|
|
@ -855,7 +856,7 @@ __visible const u32 crypto_it_tab[4][256] = {
|
|||
}
|
||||
};
|
||||
|
||||
__visible const u32 crypto_il_tab[4][256] = {
|
||||
__visible const u32 crypto_il_tab[4][256] __cacheline_aligned = {
|
||||
{
|
||||
0x00000052, 0x00000009, 0x0000006a, 0x000000d5,
|
||||
0x00000030, 0x00000036, 0x000000a5, 0x00000038,
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ static void aesti_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
|
|||
const u32 *rkp = ctx->key_enc + 4;
|
||||
int rounds = 6 + ctx->key_length / 4;
|
||||
u32 st0[4], st1[4];
|
||||
unsigned long flags;
|
||||
int round;
|
||||
|
||||
st0[0] = ctx->key_enc[0] ^ get_unaligned_le32(in);
|
||||
|
|
@ -276,6 +277,12 @@ static void aesti_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
|
|||
st0[2] = ctx->key_enc[2] ^ get_unaligned_le32(in + 8);
|
||||
st0[3] = ctx->key_enc[3] ^ get_unaligned_le32(in + 12);
|
||||
|
||||
/*
|
||||
* Temporarily disable interrupts to avoid races where cachelines are
|
||||
* evicted when the CPU is interrupted to do something else.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
st0[0] ^= __aesti_sbox[ 0] ^ __aesti_sbox[128];
|
||||
st0[1] ^= __aesti_sbox[32] ^ __aesti_sbox[160];
|
||||
st0[2] ^= __aesti_sbox[64] ^ __aesti_sbox[192];
|
||||
|
|
@ -300,6 +307,8 @@ static void aesti_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
|
|||
put_unaligned_le32(subshift(st1, 1) ^ rkp[5], out + 4);
|
||||
put_unaligned_le32(subshift(st1, 2) ^ rkp[6], out + 8);
|
||||
put_unaligned_le32(subshift(st1, 3) ^ rkp[7], out + 12);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void aesti_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
|
||||
|
|
@ -308,6 +317,7 @@ static void aesti_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
|
|||
const u32 *rkp = ctx->key_dec + 4;
|
||||
int rounds = 6 + ctx->key_length / 4;
|
||||
u32 st0[4], st1[4];
|
||||
unsigned long flags;
|
||||
int round;
|
||||
|
||||
st0[0] = ctx->key_dec[0] ^ get_unaligned_le32(in);
|
||||
|
|
@ -315,6 +325,12 @@ static void aesti_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
|
|||
st0[2] = ctx->key_dec[2] ^ get_unaligned_le32(in + 8);
|
||||
st0[3] = ctx->key_dec[3] ^ get_unaligned_le32(in + 12);
|
||||
|
||||
/*
|
||||
* Temporarily disable interrupts to avoid races where cachelines are
|
||||
* evicted when the CPU is interrupted to do something else.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
st0[0] ^= __aesti_inv_sbox[ 0] ^ __aesti_inv_sbox[128];
|
||||
st0[1] ^= __aesti_inv_sbox[32] ^ __aesti_inv_sbox[160];
|
||||
st0[2] ^= __aesti_inv_sbox[64] ^ __aesti_inv_sbox[192];
|
||||
|
|
@ -339,6 +355,8 @@ static void aesti_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
|
|||
put_unaligned_le32(inv_subshift(st1, 1) ^ rkp[5], out + 4);
|
||||
put_unaligned_le32(inv_subshift(st1, 2) ^ rkp[6], out + 8);
|
||||
put_unaligned_le32(inv_subshift(st1, 3) ^ rkp[7], out + 12);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static struct crypto_alg aes_alg = {
|
||||
|
|
|
|||
|
|
@ -364,20 +364,28 @@ static int crypto_ahash_op(struct ahash_request *req,
|
|||
|
||||
int crypto_ahash_final(struct ahash_request *req)
|
||||
{
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct crypto_alg *alg = tfm->base.__crt_alg;
|
||||
unsigned int nbytes = req->nbytes;
|
||||
int ret;
|
||||
|
||||
crypto_stats_get(alg);
|
||||
ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final);
|
||||
crypto_stat_ahash_final(req, ret);
|
||||
crypto_stats_ahash_final(nbytes, ret, alg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_ahash_final);
|
||||
|
||||
int crypto_ahash_finup(struct ahash_request *req)
|
||||
{
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct crypto_alg *alg = tfm->base.__crt_alg;
|
||||
unsigned int nbytes = req->nbytes;
|
||||
int ret;
|
||||
|
||||
crypto_stats_get(alg);
|
||||
ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup);
|
||||
crypto_stat_ahash_final(req, ret);
|
||||
crypto_stats_ahash_final(nbytes, ret, alg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_ahash_finup);
|
||||
|
|
@ -385,13 +393,16 @@ EXPORT_SYMBOL_GPL(crypto_ahash_finup);
|
|||
int crypto_ahash_digest(struct ahash_request *req)
|
||||
{
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct crypto_alg *alg = tfm->base.__crt_alg;
|
||||
unsigned int nbytes = req->nbytes;
|
||||
int ret;
|
||||
|
||||
crypto_stats_get(alg);
|
||||
if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
|
||||
ret = -ENOKEY;
|
||||
else
|
||||
ret = crypto_ahash_op(req, tfm->digest);
|
||||
crypto_stat_ahash_final(req, ret);
|
||||
crypto_stats_ahash_final(nbytes, ret, alg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_ahash_digest);
|
||||
|
|
@ -498,18 +509,14 @@ static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_hash rhash;
|
||||
|
||||
strncpy(rhash.type, "ahash", sizeof(rhash.type));
|
||||
memset(&rhash, 0, sizeof(rhash));
|
||||
|
||||
strscpy(rhash.type, "ahash", sizeof(rhash.type));
|
||||
|
||||
rhash.blocksize = alg->cra_blocksize;
|
||||
rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_HASH,
|
||||
sizeof(struct crypto_report_hash), &rhash))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash);
|
||||
}
|
||||
#else
|
||||
static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
|
|
@ -30,15 +30,12 @@ static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_akcipher rakcipher;
|
||||
|
||||
strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
|
||||
memset(&rakcipher, 0, sizeof(rakcipher));
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER,
|
||||
sizeof(struct crypto_report_akcipher), &rakcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER,
|
||||
sizeof(rakcipher), &rakcipher);
|
||||
}
|
||||
#else
|
||||
static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
247
crypto/algapi.c
247
crypto/algapi.c
|
|
@ -258,13 +258,7 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
|
|||
list_add(&alg->cra_list, &crypto_alg_list);
|
||||
list_add(&larval->alg.cra_list, &crypto_alg_list);
|
||||
|
||||
atomic_set(&alg->encrypt_cnt, 0);
|
||||
atomic_set(&alg->decrypt_cnt, 0);
|
||||
atomic64_set(&alg->encrypt_tlen, 0);
|
||||
atomic64_set(&alg->decrypt_tlen, 0);
|
||||
atomic_set(&alg->verify_cnt, 0);
|
||||
atomic_set(&alg->cipher_err_cnt, 0);
|
||||
atomic_set(&alg->sign_cnt, 0);
|
||||
crypto_stats_init(alg);
|
||||
|
||||
out:
|
||||
return larval;
|
||||
|
|
@ -1076,6 +1070,245 @@ int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_type_has_alg);
|
||||
|
||||
#ifdef CONFIG_CRYPTO_STATS
|
||||
void crypto_stats_init(struct crypto_alg *alg)
|
||||
{
|
||||
memset(&alg->stats, 0, sizeof(alg->stats));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_init);
|
||||
|
||||
void crypto_stats_get(struct crypto_alg *alg)
|
||||
{
|
||||
crypto_alg_get(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_get);
|
||||
|
||||
void crypto_stats_ablkcipher_encrypt(unsigned int nbytes, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.cipher.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.cipher.encrypt_cnt);
|
||||
atomic64_add(nbytes, &alg->stats.cipher.encrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_ablkcipher_encrypt);
|
||||
|
||||
void crypto_stats_ablkcipher_decrypt(unsigned int nbytes, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.cipher.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.cipher.decrypt_cnt);
|
||||
atomic64_add(nbytes, &alg->stats.cipher.decrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_ablkcipher_decrypt);
|
||||
|
||||
void crypto_stats_aead_encrypt(unsigned int cryptlen, struct crypto_alg *alg,
|
||||
int ret)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.aead.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.aead.encrypt_cnt);
|
||||
atomic64_add(cryptlen, &alg->stats.aead.encrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_aead_encrypt);
|
||||
|
||||
void crypto_stats_aead_decrypt(unsigned int cryptlen, struct crypto_alg *alg,
|
||||
int ret)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.aead.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.aead.decrypt_cnt);
|
||||
atomic64_add(cryptlen, &alg->stats.aead.decrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_aead_decrypt);
|
||||
|
||||
void crypto_stats_akcipher_encrypt(unsigned int src_len, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.akcipher.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.akcipher.encrypt_cnt);
|
||||
atomic64_add(src_len, &alg->stats.akcipher.encrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_akcipher_encrypt);
|
||||
|
||||
void crypto_stats_akcipher_decrypt(unsigned int src_len, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.akcipher.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.akcipher.decrypt_cnt);
|
||||
atomic64_add(src_len, &alg->stats.akcipher.decrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_akcipher_decrypt);
|
||||
|
||||
void crypto_stats_akcipher_sign(int ret, struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY)
|
||||
atomic64_inc(&alg->stats.akcipher.err_cnt);
|
||||
else
|
||||
atomic64_inc(&alg->stats.akcipher.sign_cnt);
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_akcipher_sign);
|
||||
|
||||
void crypto_stats_akcipher_verify(int ret, struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY)
|
||||
atomic64_inc(&alg->stats.akcipher.err_cnt);
|
||||
else
|
||||
atomic64_inc(&alg->stats.akcipher.verify_cnt);
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_akcipher_verify);
|
||||
|
||||
void crypto_stats_compress(unsigned int slen, int ret, struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.compress.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.compress.compress_cnt);
|
||||
atomic64_add(slen, &alg->stats.compress.compress_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_compress);
|
||||
|
||||
void crypto_stats_decompress(unsigned int slen, int ret, struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.compress.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.compress.decompress_cnt);
|
||||
atomic64_add(slen, &alg->stats.compress.decompress_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_decompress);
|
||||
|
||||
void crypto_stats_ahash_update(unsigned int nbytes, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY)
|
||||
atomic64_inc(&alg->stats.hash.err_cnt);
|
||||
else
|
||||
atomic64_add(nbytes, &alg->stats.hash.hash_tlen);
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_ahash_update);
|
||||
|
||||
void crypto_stats_ahash_final(unsigned int nbytes, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.hash.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.hash.hash_cnt);
|
||||
atomic64_add(nbytes, &alg->stats.hash.hash_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_ahash_final);
|
||||
|
||||
void crypto_stats_kpp_set_secret(struct crypto_alg *alg, int ret)
|
||||
{
|
||||
if (ret)
|
||||
atomic64_inc(&alg->stats.kpp.err_cnt);
|
||||
else
|
||||
atomic64_inc(&alg->stats.kpp.setsecret_cnt);
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_kpp_set_secret);
|
||||
|
||||
void crypto_stats_kpp_generate_public_key(struct crypto_alg *alg, int ret)
|
||||
{
|
||||
if (ret)
|
||||
atomic64_inc(&alg->stats.kpp.err_cnt);
|
||||
else
|
||||
atomic64_inc(&alg->stats.kpp.generate_public_key_cnt);
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_kpp_generate_public_key);
|
||||
|
||||
void crypto_stats_kpp_compute_shared_secret(struct crypto_alg *alg, int ret)
|
||||
{
|
||||
if (ret)
|
||||
atomic64_inc(&alg->stats.kpp.err_cnt);
|
||||
else
|
||||
atomic64_inc(&alg->stats.kpp.compute_shared_secret_cnt);
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_kpp_compute_shared_secret);
|
||||
|
||||
void crypto_stats_rng_seed(struct crypto_alg *alg, int ret)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY)
|
||||
atomic64_inc(&alg->stats.rng.err_cnt);
|
||||
else
|
||||
atomic64_inc(&alg->stats.rng.seed_cnt);
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_rng_seed);
|
||||
|
||||
void crypto_stats_rng_generate(struct crypto_alg *alg, unsigned int dlen,
|
||||
int ret)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.rng.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.rng.generate_cnt);
|
||||
atomic64_add(dlen, &alg->stats.rng.generate_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_rng_generate);
|
||||
|
||||
void crypto_stats_skcipher_encrypt(unsigned int cryptlen, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.cipher.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.cipher.encrypt_cnt);
|
||||
atomic64_add(cryptlen, &alg->stats.cipher.encrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_skcipher_encrypt);
|
||||
|
||||
void crypto_stats_skcipher_decrypt(unsigned int cryptlen, int ret,
|
||||
struct crypto_alg *alg)
|
||||
{
|
||||
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
|
||||
atomic64_inc(&alg->stats.cipher.err_cnt);
|
||||
} else {
|
||||
atomic64_inc(&alg->stats.cipher.decrypt_cnt);
|
||||
atomic64_add(cryptlen, &alg->stats.cipher.decrypt_tlen);
|
||||
}
|
||||
crypto_alg_put(alg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_stats_skcipher_decrypt);
|
||||
#endif
|
||||
|
||||
static int __init crypto_algapi_init(void)
|
||||
{
|
||||
crypto_init_proc();
|
||||
|
|
|
|||
|
|
@ -507,23 +507,18 @@ static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_blkcipher rblkcipher;
|
||||
|
||||
strncpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type));
|
||||
strncpy(rblkcipher.geniv, alg->cra_blkcipher.geniv ?: "<default>",
|
||||
sizeof(rblkcipher.geniv));
|
||||
rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0';
|
||||
memset(&rblkcipher, 0, sizeof(rblkcipher));
|
||||
|
||||
strscpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type));
|
||||
strscpy(rblkcipher.geniv, "<default>", sizeof(rblkcipher.geniv));
|
||||
|
||||
rblkcipher.blocksize = alg->cra_blocksize;
|
||||
rblkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
|
||||
rblkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
|
||||
rblkcipher.ivsize = alg->cra_blkcipher.ivsize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER,
|
||||
sizeof(struct crypto_report_blkcipher), &rblkcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER,
|
||||
sizeof(rblkcipher), &rblkcipher);
|
||||
}
|
||||
#else
|
||||
static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
@ -541,8 +536,7 @@ static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
|
|||
seq_printf(m, "min keysize : %u\n", alg->cra_blkcipher.min_keysize);
|
||||
seq_printf(m, "max keysize : %u\n", alg->cra_blkcipher.max_keysize);
|
||||
seq_printf(m, "ivsize : %u\n", alg->cra_blkcipher.ivsize);
|
||||
seq_printf(m, "geniv : %s\n", alg->cra_blkcipher.geniv ?:
|
||||
"<default>");
|
||||
seq_printf(m, "geniv : <default>\n");
|
||||
}
|
||||
|
||||
const struct crypto_type crypto_blkcipher_type = {
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ static int crypto_cfb_decrypt_segment(struct skcipher_walk *walk,
|
|||
|
||||
do {
|
||||
crypto_cfb_encrypt_one(tfm, iv, dst);
|
||||
crypto_xor(dst, iv, bsize);
|
||||
crypto_xor(dst, src, bsize);
|
||||
iv = src;
|
||||
|
||||
src += bsize;
|
||||
|
|
|
|||
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* ChaCha20 256-bit cipher algorithm, RFC7539
|
||||
*
|
||||
* Copyright (C) 2015 Martin Willi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/chacha20.h>
|
||||
#include <crypto/internal/skcipher.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src,
|
||||
unsigned int bytes)
|
||||
{
|
||||
/* aligned to potentially speed up crypto_xor() */
|
||||
u8 stream[CHACHA20_BLOCK_SIZE] __aligned(sizeof(long));
|
||||
|
||||
if (dst != src)
|
||||
memcpy(dst, src, bytes);
|
||||
|
||||
while (bytes >= CHACHA20_BLOCK_SIZE) {
|
||||
chacha20_block(state, stream);
|
||||
crypto_xor(dst, stream, CHACHA20_BLOCK_SIZE);
|
||||
bytes -= CHACHA20_BLOCK_SIZE;
|
||||
dst += CHACHA20_BLOCK_SIZE;
|
||||
}
|
||||
if (bytes) {
|
||||
chacha20_block(state, stream);
|
||||
crypto_xor(dst, stream, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv)
|
||||
{
|
||||
state[0] = 0x61707865; /* "expa" */
|
||||
state[1] = 0x3320646e; /* "nd 3" */
|
||||
state[2] = 0x79622d32; /* "2-by" */
|
||||
state[3] = 0x6b206574; /* "te k" */
|
||||
state[4] = ctx->key[0];
|
||||
state[5] = ctx->key[1];
|
||||
state[6] = ctx->key[2];
|
||||
state[7] = ctx->key[3];
|
||||
state[8] = ctx->key[4];
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_chacha20_init);
|
||||
|
||||
int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
||||
unsigned int keysize)
|
||||
{
|
||||
struct chacha20_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
int i;
|
||||
|
||||
if (keysize != CHACHA20_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
|
||||
ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_chacha20_setkey);
|
||||
|
||||
int crypto_chacha20_crypt(struct skcipher_request *req)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
struct chacha20_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct skcipher_walk walk;
|
||||
u32 state[16];
|
||||
int err;
|
||||
|
||||
err = skcipher_walk_virt(&walk, req, true);
|
||||
|
||||
crypto_chacha20_init(state, ctx, walk.iv);
|
||||
|
||||
while (walk.nbytes > 0) {
|
||||
unsigned int nbytes = walk.nbytes;
|
||||
|
||||
if (nbytes < walk.total)
|
||||
nbytes = round_down(nbytes, walk.stride);
|
||||
|
||||
chacha20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
|
||||
nbytes);
|
||||
err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_chacha20_crypt);
|
||||
|
||||
static struct skcipher_alg alg = {
|
||||
.base.cra_name = "chacha20",
|
||||
.base.cra_driver_name = "chacha20-generic",
|
||||
.base.cra_priority = 100,
|
||||
.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_IV_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);
|
||||
}
|
||||
|
||||
static void __exit chacha20_generic_mod_fini(void)
|
||||
{
|
||||
crypto_unregister_skcipher(&alg);
|
||||
}
|
||||
|
||||
module_init(chacha20_generic_mod_init);
|
||||
module_exit(chacha20_generic_mod_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Martin Willi <[email protected]>");
|
||||
MODULE_DESCRIPTION("chacha20 cipher algorithm");
|
||||
MODULE_ALIAS_CRYPTO("chacha20");
|
||||
MODULE_ALIAS_CRYPTO("chacha20-generic");
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
#include <crypto/internal/hash.h>
|
||||
#include <crypto/internal/skcipher.h>
|
||||
#include <crypto/scatterwalk.h>
|
||||
#include <crypto/chacha20.h>
|
||||
#include <crypto/chacha.h>
|
||||
#include <crypto/poly1305.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -22,8 +22,6 @@
|
|||
|
||||
#include "internal.h"
|
||||
|
||||
#define CHACHAPOLY_IV_SIZE 12
|
||||
|
||||
struct chachapoly_instance_ctx {
|
||||
struct crypto_skcipher_spawn chacha;
|
||||
struct crypto_ahash_spawn poly;
|
||||
|
|
@ -51,7 +49,7 @@ struct poly_req {
|
|||
};
|
||||
|
||||
struct chacha_req {
|
||||
u8 iv[CHACHA20_IV_SIZE];
|
||||
u8 iv[CHACHA_IV_SIZE];
|
||||
struct scatterlist src[1];
|
||||
struct skcipher_request req; /* must be last member */
|
||||
};
|
||||
|
|
@ -91,7 +89,7 @@ static void chacha_iv(u8 *iv, struct aead_request *req, u32 icb)
|
|||
memcpy(iv, &leicb, sizeof(leicb));
|
||||
memcpy(iv + sizeof(leicb), ctx->salt, ctx->saltlen);
|
||||
memcpy(iv + sizeof(leicb) + ctx->saltlen, req->iv,
|
||||
CHACHA20_IV_SIZE - sizeof(leicb) - ctx->saltlen);
|
||||
CHACHA_IV_SIZE - sizeof(leicb) - ctx->saltlen);
|
||||
}
|
||||
|
||||
static int poly_verify_tag(struct aead_request *req)
|
||||
|
|
@ -494,7 +492,7 @@ static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key,
|
|||
struct chachapoly_ctx *ctx = crypto_aead_ctx(aead);
|
||||
int err;
|
||||
|
||||
if (keylen != ctx->saltlen + CHACHA20_KEY_SIZE)
|
||||
if (keylen != ctx->saltlen + CHACHA_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
keylen -= ctx->saltlen;
|
||||
|
|
@ -639,7 +637,7 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb,
|
|||
|
||||
err = -EINVAL;
|
||||
/* Need 16-byte IV size, including Initial Block Counter value */
|
||||
if (crypto_skcipher_alg_ivsize(chacha) != CHACHA20_IV_SIZE)
|
||||
if (crypto_skcipher_alg_ivsize(chacha) != CHACHA_IV_SIZE)
|
||||
goto out_drop_chacha;
|
||||
/* Not a stream cipher? */
|
||||
if (chacha->base.cra_blocksize != 1)
|
||||
|
|
|
|||
217
crypto/chacha_generic.c
Normal file
217
crypto/chacha_generic.c
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* ChaCha and XChaCha stream ciphers, including ChaCha20 (RFC7539)
|
||||
*
|
||||
* Copyright (C) 2015 Martin Willi
|
||||
* Copyright (C) 2018 Google LLC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/chacha.h>
|
||||
#include <crypto/internal/skcipher.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static void chacha_docrypt(u32 *state, u8 *dst, const u8 *src,
|
||||
unsigned int bytes, int nrounds)
|
||||
{
|
||||
/* aligned to potentially speed up crypto_xor() */
|
||||
u8 stream[CHACHA_BLOCK_SIZE] __aligned(sizeof(long));
|
||||
|
||||
if (dst != src)
|
||||
memcpy(dst, src, bytes);
|
||||
|
||||
while (bytes >= CHACHA_BLOCK_SIZE) {
|
||||
chacha_block(state, stream, nrounds);
|
||||
crypto_xor(dst, stream, CHACHA_BLOCK_SIZE);
|
||||
bytes -= CHACHA_BLOCK_SIZE;
|
||||
dst += CHACHA_BLOCK_SIZE;
|
||||
}
|
||||
if (bytes) {
|
||||
chacha_block(state, stream, nrounds);
|
||||
crypto_xor(dst, stream, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
static int chacha_stream_xor(struct skcipher_request *req,
|
||||
struct chacha_ctx *ctx, u8 *iv)
|
||||
{
|
||||
struct skcipher_walk walk;
|
||||
u32 state[16];
|
||||
int err;
|
||||
|
||||
err = skcipher_walk_virt(&walk, req, false);
|
||||
|
||||
crypto_chacha_init(state, ctx, iv);
|
||||
|
||||
while (walk.nbytes > 0) {
|
||||
unsigned int nbytes = walk.nbytes;
|
||||
|
||||
if (nbytes < walk.total)
|
||||
nbytes = round_down(nbytes, walk.stride);
|
||||
|
||||
chacha_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
|
||||
nbytes, ctx->nrounds);
|
||||
err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void crypto_chacha_init(u32 *state, struct chacha_ctx *ctx, u8 *iv)
|
||||
{
|
||||
state[0] = 0x61707865; /* "expa" */
|
||||
state[1] = 0x3320646e; /* "nd 3" */
|
||||
state[2] = 0x79622d32; /* "2-by" */
|
||||
state[3] = 0x6b206574; /* "te k" */
|
||||
state[4] = ctx->key[0];
|
||||
state[5] = ctx->key[1];
|
||||
state[6] = ctx->key[2];
|
||||
state[7] = ctx->key[3];
|
||||
state[8] = ctx->key[4];
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_chacha_init);
|
||||
|
||||
static int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
||||
unsigned int keysize, int nrounds)
|
||||
{
|
||||
struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
int i;
|
||||
|
||||
if (keysize != CHACHA_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
|
||||
ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32));
|
||||
|
||||
ctx->nrounds = nrounds;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
||||
unsigned int keysize)
|
||||
{
|
||||
return chacha_setkey(tfm, key, keysize, 20);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_chacha20_setkey);
|
||||
|
||||
int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
||||
unsigned int keysize)
|
||||
{
|
||||
return chacha_setkey(tfm, key, keysize, 12);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_chacha12_setkey);
|
||||
|
||||
int crypto_chacha_crypt(struct skcipher_request *req)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
|
||||
return chacha_stream_xor(req, ctx, req->iv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_chacha_crypt);
|
||||
|
||||
int crypto_xchacha_crypt(struct skcipher_request *req)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct chacha_ctx subctx;
|
||||
u32 state[16];
|
||||
u8 real_iv[16];
|
||||
|
||||
/* Compute the subkey given the original key and first 128 nonce bits */
|
||||
crypto_chacha_init(state, ctx, req->iv);
|
||||
hchacha_block(state, subctx.key, ctx->nrounds);
|
||||
subctx.nrounds = ctx->nrounds;
|
||||
|
||||
/* Build the real IV */
|
||||
memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */
|
||||
memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */
|
||||
|
||||
/* Generate the stream and XOR it with the data */
|
||||
return chacha_stream_xor(req, &subctx, real_iv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_xchacha_crypt);
|
||||
|
||||
static struct skcipher_alg algs[] = {
|
||||
{
|
||||
.base.cra_name = "chacha20",
|
||||
.base.cra_driver_name = "chacha20-generic",
|
||||
.base.cra_priority = 100,
|
||||
.base.cra_blocksize = 1,
|
||||
.base.cra_ctxsize = sizeof(struct chacha_ctx),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
|
||||
.min_keysize = CHACHA_KEY_SIZE,
|
||||
.max_keysize = CHACHA_KEY_SIZE,
|
||||
.ivsize = CHACHA_IV_SIZE,
|
||||
.chunksize = CHACHA_BLOCK_SIZE,
|
||||
.setkey = crypto_chacha20_setkey,
|
||||
.encrypt = crypto_chacha_crypt,
|
||||
.decrypt = crypto_chacha_crypt,
|
||||
}, {
|
||||
.base.cra_name = "xchacha20",
|
||||
.base.cra_driver_name = "xchacha20-generic",
|
||||
.base.cra_priority = 100,
|
||||
.base.cra_blocksize = 1,
|
||||
.base.cra_ctxsize = sizeof(struct chacha_ctx),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
|
||||
.min_keysize = CHACHA_KEY_SIZE,
|
||||
.max_keysize = CHACHA_KEY_SIZE,
|
||||
.ivsize = XCHACHA_IV_SIZE,
|
||||
.chunksize = CHACHA_BLOCK_SIZE,
|
||||
.setkey = crypto_chacha20_setkey,
|
||||
.encrypt = crypto_xchacha_crypt,
|
||||
.decrypt = crypto_xchacha_crypt,
|
||||
}, {
|
||||
.base.cra_name = "xchacha12",
|
||||
.base.cra_driver_name = "xchacha12-generic",
|
||||
.base.cra_priority = 100,
|
||||
.base.cra_blocksize = 1,
|
||||
.base.cra_ctxsize = sizeof(struct chacha_ctx),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
|
||||
.min_keysize = CHACHA_KEY_SIZE,
|
||||
.max_keysize = CHACHA_KEY_SIZE,
|
||||
.ivsize = XCHACHA_IV_SIZE,
|
||||
.chunksize = CHACHA_BLOCK_SIZE,
|
||||
.setkey = crypto_chacha12_setkey,
|
||||
.encrypt = crypto_xchacha_crypt,
|
||||
.decrypt = crypto_xchacha_crypt,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init chacha_generic_mod_init(void)
|
||||
{
|
||||
return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
|
||||
}
|
||||
|
||||
static void __exit chacha_generic_mod_fini(void)
|
||||
{
|
||||
crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
|
||||
}
|
||||
|
||||
module_init(chacha_generic_mod_init);
|
||||
module_exit(chacha_generic_mod_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Martin Willi <[email protected]>");
|
||||
MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (generic)");
|
||||
MODULE_ALIAS_CRYPTO("chacha20");
|
||||
MODULE_ALIAS_CRYPTO("chacha20-generic");
|
||||
MODULE_ALIAS_CRYPTO("xchacha20");
|
||||
MODULE_ALIAS_CRYPTO("xchacha20-generic");
|
||||
MODULE_ALIAS_CRYPTO("xchacha12");
|
||||
MODULE_ALIAS_CRYPTO("xchacha12-generic");
|
||||
|
|
@ -422,8 +422,6 @@ static int cryptd_create_blkcipher(struct crypto_template *tmpl,
|
|||
inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
|
||||
inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
|
||||
|
||||
inst->alg.cra_ablkcipher.geniv = alg->cra_blkcipher.geniv;
|
||||
|
||||
inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx);
|
||||
|
||||
inst->alg.cra_init = cryptd_blkcipher_init_tfm;
|
||||
|
|
@ -1174,7 +1172,7 @@ struct cryptd_ablkcipher *cryptd_alloc_ablkcipher(const char *alg_name,
|
|||
return ERR_PTR(-EINVAL);
|
||||
type = crypto_skcipher_type(type);
|
||||
mask &= ~CRYPTO_ALG_TYPE_MASK;
|
||||
mask |= (CRYPTO_ALG_GENIV | CRYPTO_ALG_TYPE_BLKCIPHER_MASK);
|
||||
mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK;
|
||||
tfm = crypto_alloc_base(cryptd_alg_name, type, mask);
|
||||
if (IS_ERR(tfm))
|
||||
return ERR_CAST(tfm);
|
||||
|
|
|
|||
|
|
@ -84,87 +84,38 @@ static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_cipher rcipher;
|
||||
|
||||
strncpy(rcipher.type, "cipher", sizeof(rcipher.type));
|
||||
memset(&rcipher, 0, sizeof(rcipher));
|
||||
|
||||
strscpy(rcipher.type, "cipher", sizeof(rcipher.type));
|
||||
|
||||
rcipher.blocksize = alg->cra_blocksize;
|
||||
rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
|
||||
rcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_CIPHER,
|
||||
sizeof(struct crypto_report_cipher), &rcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_CIPHER,
|
||||
sizeof(rcipher), &rcipher);
|
||||
}
|
||||
|
||||
static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_comp rcomp;
|
||||
|
||||
strncpy(rcomp.type, "compression", sizeof(rcomp.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
|
||||
sizeof(struct crypto_report_comp), &rcomp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
memset(&rcomp, 0, sizeof(rcomp));
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
strscpy(rcomp.type, "compression", sizeof(rcomp.type));
|
||||
|
||||
static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_acomp racomp;
|
||||
|
||||
strncpy(racomp.type, "acomp", sizeof(racomp.type));
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_ACOMP,
|
||||
sizeof(struct crypto_report_acomp), &racomp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_akcipher rakcipher;
|
||||
|
||||
strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER,
|
||||
sizeof(struct crypto_report_akcipher), &rakcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_kpp rkpp;
|
||||
|
||||
strncpy(rkpp.type, "kpp", sizeof(rkpp.type));
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_KPP,
|
||||
sizeof(struct crypto_report_kpp), &rkpp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS, sizeof(rcomp), &rcomp);
|
||||
}
|
||||
|
||||
static int crypto_report_one(struct crypto_alg *alg,
|
||||
struct crypto_user_alg *ualg, struct sk_buff *skb)
|
||||
{
|
||||
strncpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
|
||||
strncpy(ualg->cru_driver_name, alg->cra_driver_name,
|
||||
memset(ualg, 0, sizeof(*ualg));
|
||||
|
||||
strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
|
||||
strscpy(ualg->cru_driver_name, alg->cra_driver_name,
|
||||
sizeof(ualg->cru_driver_name));
|
||||
strncpy(ualg->cru_module_name, module_name(alg->cra_module),
|
||||
strscpy(ualg->cru_module_name, module_name(alg->cra_module),
|
||||
sizeof(ualg->cru_module_name));
|
||||
|
||||
ualg->cru_type = 0;
|
||||
|
|
@ -177,9 +128,9 @@ static int crypto_report_one(struct crypto_alg *alg,
|
|||
if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
|
||||
struct crypto_report_larval rl;
|
||||
|
||||
strncpy(rl.type, "larval", sizeof(rl.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL,
|
||||
sizeof(struct crypto_report_larval), &rl))
|
||||
memset(&rl, 0, sizeof(rl));
|
||||
strscpy(rl.type, "larval", sizeof(rl.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL, sizeof(rl), &rl))
|
||||
goto nla_put_failure;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -202,20 +153,6 @@ static int crypto_report_one(struct crypto_alg *alg,
|
|||
goto nla_put_failure;
|
||||
|
||||
break;
|
||||
case CRYPTO_ALG_TYPE_ACOMPRESS:
|
||||
if (crypto_report_acomp(skb, alg))
|
||||
goto nla_put_failure;
|
||||
|
||||
break;
|
||||
case CRYPTO_ALG_TYPE_AKCIPHER:
|
||||
if (crypto_report_akcipher(skb, alg))
|
||||
goto nla_put_failure;
|
||||
|
||||
break;
|
||||
case CRYPTO_ALG_TYPE_KPP:
|
||||
if (crypto_report_kpp(skb, alg))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -294,30 +231,33 @@ drop_alg:
|
|||
|
||||
static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct crypto_alg *alg;
|
||||
const size_t start_pos = cb->args[0];
|
||||
size_t pos = 0;
|
||||
struct crypto_dump_info info;
|
||||
int err;
|
||||
|
||||
if (cb->args[0])
|
||||
goto out;
|
||||
|
||||
cb->args[0] = 1;
|
||||
struct crypto_alg *alg;
|
||||
int res;
|
||||
|
||||
info.in_skb = cb->skb;
|
||||
info.out_skb = skb;
|
||||
info.nlmsg_seq = cb->nlh->nlmsg_seq;
|
||||
info.nlmsg_flags = NLM_F_MULTI;
|
||||
|
||||
down_read(&crypto_alg_sem);
|
||||
list_for_each_entry(alg, &crypto_alg_list, cra_list) {
|
||||
err = crypto_report_alg(alg, &info);
|
||||
if (err)
|
||||
goto out_err;
|
||||
if (pos >= start_pos) {
|
||||
res = crypto_report_alg(alg, &info);
|
||||
if (res == -EMSGSIZE)
|
||||
break;
|
||||
if (res)
|
||||
goto out;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
cb->args[0] = pos;
|
||||
res = skb->len;
|
||||
out:
|
||||
return skb->len;
|
||||
out_err:
|
||||
return err;
|
||||
up_read(&crypto_alg_sem);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int crypto_dump_report_done(struct netlink_callback *cb)
|
||||
|
|
@ -483,9 +423,7 @@ static const struct crypto_link {
|
|||
.dump = crypto_dump_report,
|
||||
.done = crypto_dump_report_done},
|
||||
[CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
|
||||
[CRYPTO_MSG_GETSTAT - CRYPTO_MSG_BASE] = { .doit = crypto_reportstat,
|
||||
.dump = crypto_dump_reportstat,
|
||||
.done = crypto_dump_reportstat_done},
|
||||
[CRYPTO_MSG_GETSTAT - CRYPTO_MSG_BASE] = { .doit = crypto_reportstat},
|
||||
};
|
||||
|
||||
static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
|
|
@ -505,7 +443,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
|
||||
(nlh->nlmsg_flags & NLM_F_DUMP))) {
|
||||
struct crypto_alg *alg;
|
||||
u16 dump_alloc = 0;
|
||||
unsigned long dump_alloc = 0;
|
||||
|
||||
if (link->dump == NULL)
|
||||
return -EINVAL;
|
||||
|
|
@ -513,16 +451,16 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
down_read(&crypto_alg_sem);
|
||||
list_for_each_entry(alg, &crypto_alg_list, cra_list)
|
||||
dump_alloc += CRYPTO_REPORT_MAXSIZE;
|
||||
up_read(&crypto_alg_sem);
|
||||
|
||||
{
|
||||
struct netlink_dump_control c = {
|
||||
.dump = link->dump,
|
||||
.done = link->done,
|
||||
.min_dump_alloc = dump_alloc,
|
||||
.min_dump_alloc = min(dump_alloc, 65535UL),
|
||||
};
|
||||
err = netlink_dump_start(crypto_nlsk, skb, nlh, &c);
|
||||
}
|
||||
up_read(&crypto_alg_sem);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,260 +33,149 @@ struct crypto_dump_info {
|
|||
|
||||
static int crypto_report_aead(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat raead;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_aead raead;
|
||||
|
||||
memset(&raead, 0, sizeof(raead));
|
||||
|
||||
strncpy(raead.type, "aead", sizeof(raead.type));
|
||||
strscpy(raead.type, "aead", sizeof(raead.type));
|
||||
|
||||
v32 = atomic_read(&alg->encrypt_cnt);
|
||||
raead.stat_encrypt_cnt = v32;
|
||||
v64 = atomic64_read(&alg->encrypt_tlen);
|
||||
raead.stat_encrypt_tlen = v64;
|
||||
v32 = atomic_read(&alg->decrypt_cnt);
|
||||
raead.stat_decrypt_cnt = v32;
|
||||
v64 = atomic64_read(&alg->decrypt_tlen);
|
||||
raead.stat_decrypt_tlen = v64;
|
||||
v32 = atomic_read(&alg->aead_err_cnt);
|
||||
raead.stat_aead_err_cnt = v32;
|
||||
raead.stat_encrypt_cnt = atomic64_read(&alg->stats.aead.encrypt_cnt);
|
||||
raead.stat_encrypt_tlen = atomic64_read(&alg->stats.aead.encrypt_tlen);
|
||||
raead.stat_decrypt_cnt = atomic64_read(&alg->stats.aead.decrypt_cnt);
|
||||
raead.stat_decrypt_tlen = atomic64_read(&alg->stats.aead.decrypt_tlen);
|
||||
raead.stat_err_cnt = atomic64_read(&alg->stats.aead.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_AEAD,
|
||||
sizeof(struct crypto_stat), &raead))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead);
|
||||
}
|
||||
|
||||
static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat rcipher;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_cipher rcipher;
|
||||
|
||||
memset(&rcipher, 0, sizeof(rcipher));
|
||||
|
||||
strlcpy(rcipher.type, "cipher", sizeof(rcipher.type));
|
||||
strscpy(rcipher.type, "cipher", sizeof(rcipher.type));
|
||||
|
||||
v32 = atomic_read(&alg->encrypt_cnt);
|
||||
rcipher.stat_encrypt_cnt = v32;
|
||||
v64 = atomic64_read(&alg->encrypt_tlen);
|
||||
rcipher.stat_encrypt_tlen = v64;
|
||||
v32 = atomic_read(&alg->decrypt_cnt);
|
||||
rcipher.stat_decrypt_cnt = v32;
|
||||
v64 = atomic64_read(&alg->decrypt_tlen);
|
||||
rcipher.stat_decrypt_tlen = v64;
|
||||
v32 = atomic_read(&alg->cipher_err_cnt);
|
||||
rcipher.stat_cipher_err_cnt = v32;
|
||||
rcipher.stat_encrypt_cnt = atomic64_read(&alg->stats.cipher.encrypt_cnt);
|
||||
rcipher.stat_encrypt_tlen = atomic64_read(&alg->stats.cipher.encrypt_tlen);
|
||||
rcipher.stat_decrypt_cnt = atomic64_read(&alg->stats.cipher.decrypt_cnt);
|
||||
rcipher.stat_decrypt_tlen = atomic64_read(&alg->stats.cipher.decrypt_tlen);
|
||||
rcipher.stat_err_cnt = atomic64_read(&alg->stats.cipher.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_CIPHER,
|
||||
sizeof(struct crypto_stat), &rcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher);
|
||||
}
|
||||
|
||||
static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat rcomp;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_compress rcomp;
|
||||
|
||||
memset(&rcomp, 0, sizeof(rcomp));
|
||||
|
||||
strlcpy(rcomp.type, "compression", sizeof(rcomp.type));
|
||||
v32 = atomic_read(&alg->compress_cnt);
|
||||
rcomp.stat_compress_cnt = v32;
|
||||
v64 = atomic64_read(&alg->compress_tlen);
|
||||
rcomp.stat_compress_tlen = v64;
|
||||
v32 = atomic_read(&alg->decompress_cnt);
|
||||
rcomp.stat_decompress_cnt = v32;
|
||||
v64 = atomic64_read(&alg->decompress_tlen);
|
||||
rcomp.stat_decompress_tlen = v64;
|
||||
v32 = atomic_read(&alg->cipher_err_cnt);
|
||||
rcomp.stat_compress_err_cnt = v32;
|
||||
strscpy(rcomp.type, "compression", sizeof(rcomp.type));
|
||||
rcomp.stat_compress_cnt = atomic64_read(&alg->stats.compress.compress_cnt);
|
||||
rcomp.stat_compress_tlen = atomic64_read(&alg->stats.compress.compress_tlen);
|
||||
rcomp.stat_decompress_cnt = atomic64_read(&alg->stats.compress.decompress_cnt);
|
||||
rcomp.stat_decompress_tlen = atomic64_read(&alg->stats.compress.decompress_tlen);
|
||||
rcomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_COMPRESS,
|
||||
sizeof(struct crypto_stat), &rcomp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, sizeof(rcomp), &rcomp);
|
||||
}
|
||||
|
||||
static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat racomp;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_compress racomp;
|
||||
|
||||
memset(&racomp, 0, sizeof(racomp));
|
||||
|
||||
strlcpy(racomp.type, "acomp", sizeof(racomp.type));
|
||||
v32 = atomic_read(&alg->compress_cnt);
|
||||
racomp.stat_compress_cnt = v32;
|
||||
v64 = atomic64_read(&alg->compress_tlen);
|
||||
racomp.stat_compress_tlen = v64;
|
||||
v32 = atomic_read(&alg->decompress_cnt);
|
||||
racomp.stat_decompress_cnt = v32;
|
||||
v64 = atomic64_read(&alg->decompress_tlen);
|
||||
racomp.stat_decompress_tlen = v64;
|
||||
v32 = atomic_read(&alg->cipher_err_cnt);
|
||||
racomp.stat_compress_err_cnt = v32;
|
||||
strscpy(racomp.type, "acomp", sizeof(racomp.type));
|
||||
racomp.stat_compress_cnt = atomic64_read(&alg->stats.compress.compress_cnt);
|
||||
racomp.stat_compress_tlen = atomic64_read(&alg->stats.compress.compress_tlen);
|
||||
racomp.stat_decompress_cnt = atomic64_read(&alg->stats.compress.decompress_cnt);
|
||||
racomp.stat_decompress_tlen = atomic64_read(&alg->stats.compress.decompress_tlen);
|
||||
racomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_ACOMP,
|
||||
sizeof(struct crypto_stat), &racomp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_ACOMP, sizeof(racomp), &racomp);
|
||||
}
|
||||
|
||||
static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat rakcipher;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_akcipher rakcipher;
|
||||
|
||||
memset(&rakcipher, 0, sizeof(rakcipher));
|
||||
|
||||
strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
|
||||
v32 = atomic_read(&alg->encrypt_cnt);
|
||||
rakcipher.stat_encrypt_cnt = v32;
|
||||
v64 = atomic64_read(&alg->encrypt_tlen);
|
||||
rakcipher.stat_encrypt_tlen = v64;
|
||||
v32 = atomic_read(&alg->decrypt_cnt);
|
||||
rakcipher.stat_decrypt_cnt = v32;
|
||||
v64 = atomic64_read(&alg->decrypt_tlen);
|
||||
rakcipher.stat_decrypt_tlen = v64;
|
||||
v32 = atomic_read(&alg->sign_cnt);
|
||||
rakcipher.stat_sign_cnt = v32;
|
||||
v32 = atomic_read(&alg->verify_cnt);
|
||||
rakcipher.stat_verify_cnt = v32;
|
||||
v32 = atomic_read(&alg->akcipher_err_cnt);
|
||||
rakcipher.stat_akcipher_err_cnt = v32;
|
||||
strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
|
||||
rakcipher.stat_encrypt_cnt = atomic64_read(&alg->stats.akcipher.encrypt_cnt);
|
||||
rakcipher.stat_encrypt_tlen = atomic64_read(&alg->stats.akcipher.encrypt_tlen);
|
||||
rakcipher.stat_decrypt_cnt = atomic64_read(&alg->stats.akcipher.decrypt_cnt);
|
||||
rakcipher.stat_decrypt_tlen = atomic64_read(&alg->stats.akcipher.decrypt_tlen);
|
||||
rakcipher.stat_sign_cnt = atomic64_read(&alg->stats.akcipher.sign_cnt);
|
||||
rakcipher.stat_verify_cnt = atomic64_read(&alg->stats.akcipher.verify_cnt);
|
||||
rakcipher.stat_err_cnt = atomic64_read(&alg->stats.akcipher.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER,
|
||||
sizeof(struct crypto_stat), &rakcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER,
|
||||
sizeof(rakcipher), &rakcipher);
|
||||
}
|
||||
|
||||
static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat rkpp;
|
||||
u32 v;
|
||||
struct crypto_stat_kpp rkpp;
|
||||
|
||||
memset(&rkpp, 0, sizeof(rkpp));
|
||||
|
||||
strlcpy(rkpp.type, "kpp", sizeof(rkpp.type));
|
||||
strscpy(rkpp.type, "kpp", sizeof(rkpp.type));
|
||||
|
||||
v = atomic_read(&alg->setsecret_cnt);
|
||||
rkpp.stat_setsecret_cnt = v;
|
||||
v = atomic_read(&alg->generate_public_key_cnt);
|
||||
rkpp.stat_generate_public_key_cnt = v;
|
||||
v = atomic_read(&alg->compute_shared_secret_cnt);
|
||||
rkpp.stat_compute_shared_secret_cnt = v;
|
||||
v = atomic_read(&alg->kpp_err_cnt);
|
||||
rkpp.stat_kpp_err_cnt = v;
|
||||
rkpp.stat_setsecret_cnt = atomic64_read(&alg->stats.kpp.setsecret_cnt);
|
||||
rkpp.stat_generate_public_key_cnt = atomic64_read(&alg->stats.kpp.generate_public_key_cnt);
|
||||
rkpp.stat_compute_shared_secret_cnt = atomic64_read(&alg->stats.kpp.compute_shared_secret_cnt);
|
||||
rkpp.stat_err_cnt = atomic64_read(&alg->stats.kpp.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_KPP,
|
||||
sizeof(struct crypto_stat), &rkpp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp);
|
||||
}
|
||||
|
||||
static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat rhash;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_hash rhash;
|
||||
|
||||
memset(&rhash, 0, sizeof(rhash));
|
||||
|
||||
strncpy(rhash.type, "ahash", sizeof(rhash.type));
|
||||
strscpy(rhash.type, "ahash", sizeof(rhash.type));
|
||||
|
||||
v32 = atomic_read(&alg->hash_cnt);
|
||||
rhash.stat_hash_cnt = v32;
|
||||
v64 = atomic64_read(&alg->hash_tlen);
|
||||
rhash.stat_hash_tlen = v64;
|
||||
v32 = atomic_read(&alg->hash_err_cnt);
|
||||
rhash.stat_hash_err_cnt = v32;
|
||||
rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt);
|
||||
rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
|
||||
rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_HASH,
|
||||
sizeof(struct crypto_stat), &rhash))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
|
||||
}
|
||||
|
||||
static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat rhash;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_hash rhash;
|
||||
|
||||
memset(&rhash, 0, sizeof(rhash));
|
||||
|
||||
strncpy(rhash.type, "shash", sizeof(rhash.type));
|
||||
strscpy(rhash.type, "shash", sizeof(rhash.type));
|
||||
|
||||
v32 = atomic_read(&alg->hash_cnt);
|
||||
rhash.stat_hash_cnt = v32;
|
||||
v64 = atomic64_read(&alg->hash_tlen);
|
||||
rhash.stat_hash_tlen = v64;
|
||||
v32 = atomic_read(&alg->hash_err_cnt);
|
||||
rhash.stat_hash_err_cnt = v32;
|
||||
rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt);
|
||||
rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
|
||||
rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_HASH,
|
||||
sizeof(struct crypto_stat), &rhash))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
|
||||
}
|
||||
|
||||
static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_stat rrng;
|
||||
u64 v64;
|
||||
u32 v32;
|
||||
struct crypto_stat_rng rrng;
|
||||
|
||||
memset(&rrng, 0, sizeof(rrng));
|
||||
|
||||
strncpy(rrng.type, "rng", sizeof(rrng.type));
|
||||
strscpy(rrng.type, "rng", sizeof(rrng.type));
|
||||
|
||||
v32 = atomic_read(&alg->generate_cnt);
|
||||
rrng.stat_generate_cnt = v32;
|
||||
v64 = atomic64_read(&alg->generate_tlen);
|
||||
rrng.stat_generate_tlen = v64;
|
||||
v32 = atomic_read(&alg->seed_cnt);
|
||||
rrng.stat_seed_cnt = v32;
|
||||
v32 = atomic_read(&alg->hash_err_cnt);
|
||||
rrng.stat_rng_err_cnt = v32;
|
||||
rrng.stat_generate_cnt = atomic64_read(&alg->stats.rng.generate_cnt);
|
||||
rrng.stat_generate_tlen = atomic64_read(&alg->stats.rng.generate_tlen);
|
||||
rrng.stat_seed_cnt = atomic64_read(&alg->stats.rng.seed_cnt);
|
||||
rrng.stat_err_cnt = atomic64_read(&alg->stats.rng.err_cnt);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_RNG,
|
||||
sizeof(struct crypto_stat), &rrng))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng);
|
||||
}
|
||||
|
||||
static int crypto_reportstat_one(struct crypto_alg *alg,
|
||||
|
|
@ -295,10 +184,10 @@ static int crypto_reportstat_one(struct crypto_alg *alg,
|
|||
{
|
||||
memset(ualg, 0, sizeof(*ualg));
|
||||
|
||||
strlcpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
|
||||
strlcpy(ualg->cru_driver_name, alg->cra_driver_name,
|
||||
strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
|
||||
strscpy(ualg->cru_driver_name, alg->cra_driver_name,
|
||||
sizeof(ualg->cru_driver_name));
|
||||
strlcpy(ualg->cru_module_name, module_name(alg->cra_module),
|
||||
strscpy(ualg->cru_module_name, module_name(alg->cra_module),
|
||||
sizeof(ualg->cru_module_name));
|
||||
|
||||
ualg->cru_type = 0;
|
||||
|
|
@ -309,12 +198,11 @@ static int crypto_reportstat_one(struct crypto_alg *alg,
|
|||
if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
|
||||
goto nla_put_failure;
|
||||
if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
|
||||
struct crypto_stat rl;
|
||||
struct crypto_stat_larval rl;
|
||||
|
||||
memset(&rl, 0, sizeof(rl));
|
||||
strlcpy(rl.type, "larval", sizeof(rl.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL,
|
||||
sizeof(struct crypto_stat), &rl))
|
||||
strscpy(rl.type, "larval", sizeof(rl.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, sizeof(rl), &rl))
|
||||
goto nla_put_failure;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -448,37 +336,4 @@ drop_alg:
|
|||
return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
|
||||
}
|
||||
|
||||
int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct crypto_alg *alg;
|
||||
struct crypto_dump_info info;
|
||||
int err;
|
||||
|
||||
if (cb->args[0])
|
||||
goto out;
|
||||
|
||||
cb->args[0] = 1;
|
||||
|
||||
info.in_skb = cb->skb;
|
||||
info.out_skb = skb;
|
||||
info.nlmsg_seq = cb->nlh->nlmsg_seq;
|
||||
info.nlmsg_flags = NLM_F_MULTI;
|
||||
|
||||
list_for_each_entry(alg, &crypto_alg_list, cra_list) {
|
||||
err = crypto_reportstat_alg(alg, &info);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
out:
|
||||
return skb->len;
|
||||
out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
int crypto_dump_reportstat_done(struct netlink_callback *cb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -233,8 +233,6 @@ static struct crypto_instance *crypto_ctr_alloc(struct rtattr **tb)
|
|||
inst->alg.cra_blkcipher.encrypt = crypto_ctr_crypt;
|
||||
inst->alg.cra_blkcipher.decrypt = crypto_ctr_crypt;
|
||||
|
||||
inst->alg.cra_blkcipher.geniv = "chainiv";
|
||||
|
||||
out:
|
||||
crypto_mod_put(alg);
|
||||
return inst;
|
||||
|
|
|
|||
58
crypto/ecc.c
58
crypto/ecc.c
|
|
@ -842,15 +842,23 @@ static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
|
|||
|
||||
static void ecc_point_mult(struct ecc_point *result,
|
||||
const struct ecc_point *point, const u64 *scalar,
|
||||
u64 *initial_z, u64 *curve_prime,
|
||||
u64 *initial_z, const struct ecc_curve *curve,
|
||||
unsigned int ndigits)
|
||||
{
|
||||
/* R0 and R1 */
|
||||
u64 rx[2][ECC_MAX_DIGITS];
|
||||
u64 ry[2][ECC_MAX_DIGITS];
|
||||
u64 z[ECC_MAX_DIGITS];
|
||||
u64 sk[2][ECC_MAX_DIGITS];
|
||||
u64 *curve_prime = curve->p;
|
||||
int i, nb;
|
||||
int num_bits = vli_num_bits(scalar, ndigits);
|
||||
int num_bits;
|
||||
int carry;
|
||||
|
||||
carry = vli_add(sk[0], scalar, curve->n, ndigits);
|
||||
vli_add(sk[1], sk[0], curve->n, ndigits);
|
||||
scalar = sk[!carry];
|
||||
num_bits = sizeof(u64) * ndigits * 8 + 1;
|
||||
|
||||
vli_set(rx[1], point->x, ndigits);
|
||||
vli_set(ry[1], point->y, ndigits);
|
||||
|
|
@ -904,28 +912,41 @@ static inline void ecc_swap_digits(const u64 *in, u64 *out,
|
|||
out[i] = __swab64(in[ndigits - 1 - i]);
|
||||
}
|
||||
|
||||
static int __ecc_is_key_valid(const struct ecc_curve *curve,
|
||||
const u64 *private_key, unsigned int ndigits)
|
||||
{
|
||||
u64 one[ECC_MAX_DIGITS] = { 1, };
|
||||
u64 res[ECC_MAX_DIGITS];
|
||||
|
||||
if (!private_key)
|
||||
return -EINVAL;
|
||||
|
||||
if (curve->g.ndigits != ndigits)
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure the private key is in the range [2, n-3]. */
|
||||
if (vli_cmp(one, private_key, ndigits) != -1)
|
||||
return -EINVAL;
|
||||
vli_sub(res, curve->n, one, ndigits);
|
||||
vli_sub(res, res, one, ndigits);
|
||||
if (vli_cmp(res, private_key, ndigits) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
|
||||
const u64 *private_key, unsigned int private_key_len)
|
||||
{
|
||||
int nbytes;
|
||||
const struct ecc_curve *curve = ecc_get_curve(curve_id);
|
||||
|
||||
if (!private_key)
|
||||
return -EINVAL;
|
||||
|
||||
nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
|
||||
|
||||
if (private_key_len != nbytes)
|
||||
return -EINVAL;
|
||||
|
||||
if (vli_is_zero(private_key, ndigits))
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure the private key is in the range [1, n-1]. */
|
||||
if (vli_cmp(curve->n, private_key, ndigits) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
return __ecc_is_key_valid(curve, private_key, ndigits);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -971,11 +992,8 @@ int ecc_gen_privkey(unsigned int curve_id, unsigned int ndigits, u64 *privkey)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (vli_is_zero(priv, ndigits))
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure the private key is in the range [1, n-1]. */
|
||||
if (vli_cmp(curve->n, priv, ndigits) != 1)
|
||||
/* Make sure the private key is in the valid range. */
|
||||
if (__ecc_is_key_valid(curve, priv, ndigits))
|
||||
return -EINVAL;
|
||||
|
||||
ecc_swap_digits(priv, privkey, ndigits);
|
||||
|
|
@ -1004,7 +1022,7 @@ int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ecc_point_mult(pk, &curve->g, priv, NULL, curve->p, ndigits);
|
||||
ecc_point_mult(pk, &curve->g, priv, NULL, curve, ndigits);
|
||||
if (ecc_point_is_zero(pk)) {
|
||||
ret = -EAGAIN;
|
||||
goto err_free_point;
|
||||
|
|
@ -1090,7 +1108,7 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
|
|||
goto err_alloc_product;
|
||||
}
|
||||
|
||||
ecc_point_mult(product, pk, priv, rand_z, curve->p, ndigits);
|
||||
ecc_point_mult(product, pk, priv, rand_z, curve, ndigits);
|
||||
|
||||
ecc_swap_digits(product->x, secret, ndigits);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ const char *const hash_algo_name[HASH_ALGO__LAST] = {
|
|||
[HASH_ALGO_TGR_160] = "tgr160",
|
||||
[HASH_ALGO_TGR_192] = "tgr192",
|
||||
[HASH_ALGO_SM3_256] = "sm3-256",
|
||||
[HASH_ALGO_STREEBOG_256] = "streebog256",
|
||||
[HASH_ALGO_STREEBOG_512] = "streebog512",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(hash_algo_name);
|
||||
|
||||
|
|
@ -54,5 +56,7 @@ const int hash_digest_size[HASH_ALGO__LAST] = {
|
|||
[HASH_ALGO_TGR_160] = TGR160_DIGEST_SIZE,
|
||||
[HASH_ALGO_TGR_192] = TGR192_DIGEST_SIZE,
|
||||
[HASH_ALGO_SM3_256] = SM3256_DIGEST_SIZE,
|
||||
[HASH_ALGO_STREEBOG_256] = STREEBOG256_DIGEST_SIZE,
|
||||
[HASH_ALGO_STREEBOG_512] = STREEBOG512_DIGEST_SIZE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(hash_digest_size);
|
||||
|
|
|
|||
10
crypto/kpp.c
10
crypto/kpp.c
|
|
@ -30,15 +30,11 @@ static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_kpp rkpp;
|
||||
|
||||
strncpy(rkpp.type, "kpp", sizeof(rkpp.type));
|
||||
memset(&rkpp, 0, sizeof(rkpp));
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_KPP,
|
||||
sizeof(struct crypto_report_kpp), &rkpp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
strscpy(rkpp.type, "kpp", sizeof(rkpp.type));
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_KPP, sizeof(rkpp), &rkpp);
|
||||
}
|
||||
#else
|
||||
static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ static struct crypto_alg alg_lz4 = {
|
|||
.cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
|
||||
.cra_ctxsize = sizeof(struct lz4_ctx),
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_list = LIST_HEAD_INIT(alg_lz4.cra_list),
|
||||
.cra_init = lz4_init,
|
||||
.cra_exit = lz4_exit,
|
||||
.cra_u = { .compress = {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ static struct crypto_alg alg_lz4hc = {
|
|||
.cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
|
||||
.cra_ctxsize = sizeof(struct lz4hc_ctx),
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_list = LIST_HEAD_INIT(alg_lz4hc.cra_list),
|
||||
.cra_init = lz4hc_init,
|
||||
.cra_exit = lz4hc_exit,
|
||||
.cra_u = { .compress = {
|
||||
|
|
|
|||
254
crypto/nhpoly1305.c
Normal file
254
crypto/nhpoly1305.c
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NHPoly1305 - ε-almost-∆-universal hash function for Adiantum
|
||||
*
|
||||
* Copyright 2018 Google LLC
|
||||
*/
|
||||
|
||||
/*
|
||||
* "NHPoly1305" is the main component of Adiantum hashing.
|
||||
* Specifically, it is the calculation
|
||||
*
|
||||
* H_L ← Poly1305_{K_L}(NH_{K_N}(pad_{128}(L)))
|
||||
*
|
||||
* from the procedure in section 6.4 of the Adiantum paper [1]. It is an
|
||||
* ε-almost-∆-universal (ε-∆U) hash function for equal-length inputs over
|
||||
* Z/(2^{128}Z), where the "∆" operation is addition. It hashes 1024-byte
|
||||
* chunks of the input with the NH hash function [2], reducing the input length
|
||||
* by 32x. The resulting NH digests are evaluated as a polynomial in
|
||||
* GF(2^{130}-5), like in the Poly1305 MAC [3]. Note that the polynomial
|
||||
* evaluation by itself would suffice to achieve the ε-∆U property; NH is used
|
||||
* for performance since it's over twice as fast as Poly1305.
|
||||
*
|
||||
* This is *not* a cryptographic hash function; do not use it as such!
|
||||
*
|
||||
* [1] Adiantum: length-preserving encryption for entry-level processors
|
||||
* (https://eprint.iacr.org/2018/720.pdf)
|
||||
* [2] UMAC: Fast and Secure Message Authentication
|
||||
* (https://fastcrypto.org/umac/umac_proc.pdf)
|
||||
* [3] The Poly1305-AES message-authentication code
|
||||
* (https://cr.yp.to/mac/poly1305-20050329.pdf)
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <crypto/nhpoly1305.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static void nh_generic(const u32 *key, const u8 *message, size_t message_len,
|
||||
__le64 hash[NH_NUM_PASSES])
|
||||
{
|
||||
u64 sums[4] = { 0, 0, 0, 0 };
|
||||
|
||||
BUILD_BUG_ON(NH_PAIR_STRIDE != 2);
|
||||
BUILD_BUG_ON(NH_NUM_PASSES != 4);
|
||||
|
||||
while (message_len) {
|
||||
u32 m0 = get_unaligned_le32(message + 0);
|
||||
u32 m1 = get_unaligned_le32(message + 4);
|
||||
u32 m2 = get_unaligned_le32(message + 8);
|
||||
u32 m3 = get_unaligned_le32(message + 12);
|
||||
|
||||
sums[0] += (u64)(u32)(m0 + key[ 0]) * (u32)(m2 + key[ 2]);
|
||||
sums[1] += (u64)(u32)(m0 + key[ 4]) * (u32)(m2 + key[ 6]);
|
||||
sums[2] += (u64)(u32)(m0 + key[ 8]) * (u32)(m2 + key[10]);
|
||||
sums[3] += (u64)(u32)(m0 + key[12]) * (u32)(m2 + key[14]);
|
||||
sums[0] += (u64)(u32)(m1 + key[ 1]) * (u32)(m3 + key[ 3]);
|
||||
sums[1] += (u64)(u32)(m1 + key[ 5]) * (u32)(m3 + key[ 7]);
|
||||
sums[2] += (u64)(u32)(m1 + key[ 9]) * (u32)(m3 + key[11]);
|
||||
sums[3] += (u64)(u32)(m1 + key[13]) * (u32)(m3 + key[15]);
|
||||
key += NH_MESSAGE_UNIT / sizeof(key[0]);
|
||||
message += NH_MESSAGE_UNIT;
|
||||
message_len -= NH_MESSAGE_UNIT;
|
||||
}
|
||||
|
||||
hash[0] = cpu_to_le64(sums[0]);
|
||||
hash[1] = cpu_to_le64(sums[1]);
|
||||
hash[2] = cpu_to_le64(sums[2]);
|
||||
hash[3] = cpu_to_le64(sums[3]);
|
||||
}
|
||||
|
||||
/* Pass the next NH hash value through Poly1305 */
|
||||
static void process_nh_hash_value(struct nhpoly1305_state *state,
|
||||
const struct nhpoly1305_key *key)
|
||||
{
|
||||
BUILD_BUG_ON(NH_HASH_BYTES % POLY1305_BLOCK_SIZE != 0);
|
||||
|
||||
poly1305_core_blocks(&state->poly_state, &key->poly_key, state->nh_hash,
|
||||
NH_HASH_BYTES / POLY1305_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Feed the next portion of the source data, as a whole number of 16-byte
|
||||
* "NH message units", through NH and Poly1305. Each NH hash is taken over
|
||||
* 1024 bytes, except possibly the final one which is taken over a multiple of
|
||||
* 16 bytes up to 1024. Also, in the case where data is passed in misaligned
|
||||
* chunks, we combine partial hashes; the end result is the same either way.
|
||||
*/
|
||||
static void nhpoly1305_units(struct nhpoly1305_state *state,
|
||||
const struct nhpoly1305_key *key,
|
||||
const u8 *src, unsigned int srclen, nh_t nh_fn)
|
||||
{
|
||||
do {
|
||||
unsigned int bytes;
|
||||
|
||||
if (state->nh_remaining == 0) {
|
||||
/* Starting a new NH message */
|
||||
bytes = min_t(unsigned int, srclen, NH_MESSAGE_BYTES);
|
||||
nh_fn(key->nh_key, src, bytes, state->nh_hash);
|
||||
state->nh_remaining = NH_MESSAGE_BYTES - bytes;
|
||||
} else {
|
||||
/* Continuing a previous NH message */
|
||||
__le64 tmp_hash[NH_NUM_PASSES];
|
||||
unsigned int pos;
|
||||
int i;
|
||||
|
||||
pos = NH_MESSAGE_BYTES - state->nh_remaining;
|
||||
bytes = min(srclen, state->nh_remaining);
|
||||
nh_fn(&key->nh_key[pos / 4], src, bytes, tmp_hash);
|
||||
for (i = 0; i < NH_NUM_PASSES; i++)
|
||||
le64_add_cpu(&state->nh_hash[i],
|
||||
le64_to_cpu(tmp_hash[i]));
|
||||
state->nh_remaining -= bytes;
|
||||
}
|
||||
if (state->nh_remaining == 0)
|
||||
process_nh_hash_value(state, key);
|
||||
src += bytes;
|
||||
srclen -= bytes;
|
||||
} while (srclen);
|
||||
}
|
||||
|
||||
int crypto_nhpoly1305_setkey(struct crypto_shash *tfm,
|
||||
const u8 *key, unsigned int keylen)
|
||||
{
|
||||
struct nhpoly1305_key *ctx = crypto_shash_ctx(tfm);
|
||||
int i;
|
||||
|
||||
if (keylen != NHPOLY1305_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
poly1305_core_setkey(&ctx->poly_key, key);
|
||||
key += POLY1305_BLOCK_SIZE;
|
||||
|
||||
for (i = 0; i < NH_KEY_WORDS; i++)
|
||||
ctx->nh_key[i] = get_unaligned_le32(key + i * sizeof(u32));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_nhpoly1305_setkey);
|
||||
|
||||
int crypto_nhpoly1305_init(struct shash_desc *desc)
|
||||
{
|
||||
struct nhpoly1305_state *state = shash_desc_ctx(desc);
|
||||
|
||||
poly1305_core_init(&state->poly_state);
|
||||
state->buflen = 0;
|
||||
state->nh_remaining = 0;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_nhpoly1305_init);
|
||||
|
||||
int crypto_nhpoly1305_update_helper(struct shash_desc *desc,
|
||||
const u8 *src, unsigned int srclen,
|
||||
nh_t nh_fn)
|
||||
{
|
||||
struct nhpoly1305_state *state = shash_desc_ctx(desc);
|
||||
const struct nhpoly1305_key *key = crypto_shash_ctx(desc->tfm);
|
||||
unsigned int bytes;
|
||||
|
||||
if (state->buflen) {
|
||||
bytes = min(srclen, (int)NH_MESSAGE_UNIT - state->buflen);
|
||||
memcpy(&state->buffer[state->buflen], src, bytes);
|
||||
state->buflen += bytes;
|
||||
if (state->buflen < NH_MESSAGE_UNIT)
|
||||
return 0;
|
||||
nhpoly1305_units(state, key, state->buffer, NH_MESSAGE_UNIT,
|
||||
nh_fn);
|
||||
state->buflen = 0;
|
||||
src += bytes;
|
||||
srclen -= bytes;
|
||||
}
|
||||
|
||||
if (srclen >= NH_MESSAGE_UNIT) {
|
||||
bytes = round_down(srclen, NH_MESSAGE_UNIT);
|
||||
nhpoly1305_units(state, key, src, bytes, nh_fn);
|
||||
src += bytes;
|
||||
srclen -= bytes;
|
||||
}
|
||||
|
||||
if (srclen) {
|
||||
memcpy(state->buffer, src, srclen);
|
||||
state->buflen = srclen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_nhpoly1305_update_helper);
|
||||
|
||||
int crypto_nhpoly1305_update(struct shash_desc *desc,
|
||||
const u8 *src, unsigned int srclen)
|
||||
{
|
||||
return crypto_nhpoly1305_update_helper(desc, src, srclen, nh_generic);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_nhpoly1305_update);
|
||||
|
||||
int crypto_nhpoly1305_final_helper(struct shash_desc *desc, u8 *dst, nh_t nh_fn)
|
||||
{
|
||||
struct nhpoly1305_state *state = shash_desc_ctx(desc);
|
||||
const struct nhpoly1305_key *key = crypto_shash_ctx(desc->tfm);
|
||||
|
||||
if (state->buflen) {
|
||||
memset(&state->buffer[state->buflen], 0,
|
||||
NH_MESSAGE_UNIT - state->buflen);
|
||||
nhpoly1305_units(state, key, state->buffer, NH_MESSAGE_UNIT,
|
||||
nh_fn);
|
||||
}
|
||||
|
||||
if (state->nh_remaining)
|
||||
process_nh_hash_value(state, key);
|
||||
|
||||
poly1305_core_emit(&state->poly_state, dst);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_nhpoly1305_final_helper);
|
||||
|
||||
int crypto_nhpoly1305_final(struct shash_desc *desc, u8 *dst)
|
||||
{
|
||||
return crypto_nhpoly1305_final_helper(desc, dst, nh_generic);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_nhpoly1305_final);
|
||||
|
||||
static struct shash_alg nhpoly1305_alg = {
|
||||
.base.cra_name = "nhpoly1305",
|
||||
.base.cra_driver_name = "nhpoly1305-generic",
|
||||
.base.cra_priority = 100,
|
||||
.base.cra_ctxsize = sizeof(struct nhpoly1305_key),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
.digestsize = POLY1305_DIGEST_SIZE,
|
||||
.init = crypto_nhpoly1305_init,
|
||||
.update = crypto_nhpoly1305_update,
|
||||
.final = crypto_nhpoly1305_final,
|
||||
.setkey = crypto_nhpoly1305_setkey,
|
||||
.descsize = sizeof(struct nhpoly1305_state),
|
||||
};
|
||||
|
||||
static int __init nhpoly1305_mod_init(void)
|
||||
{
|
||||
return crypto_register_shash(&nhpoly1305_alg);
|
||||
}
|
||||
|
||||
static void __exit nhpoly1305_mod_exit(void)
|
||||
{
|
||||
crypto_unregister_shash(&nhpoly1305_alg);
|
||||
}
|
||||
|
||||
module_init(nhpoly1305_mod_init);
|
||||
module_exit(nhpoly1305_mod_exit);
|
||||
|
||||
MODULE_DESCRIPTION("NHPoly1305 ε-almost-∆-universal hash function");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Eric Biggers <[email protected]>");
|
||||
MODULE_ALIAS_CRYPTO("nhpoly1305");
|
||||
MODULE_ALIAS_CRYPTO("nhpoly1305-generic");
|
||||
|
|
@ -394,7 +394,7 @@ static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name)
|
|||
int ret;
|
||||
|
||||
pinst->kobj.kset = pcrypt_kset;
|
||||
ret = kobject_add(&pinst->kobj, NULL, name);
|
||||
ret = kobject_add(&pinst->kobj, NULL, "%s", name);
|
||||
if (!ret)
|
||||
kobject_uevent(&pinst->kobj, KOBJ_ADD);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ int crypto_poly1305_init(struct shash_desc *desc)
|
|||
{
|
||||
struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
|
||||
|
||||
memset(dctx->h, 0, sizeof(dctx->h));
|
||||
poly1305_core_init(&dctx->h);
|
||||
dctx->buflen = 0;
|
||||
dctx->rset = false;
|
||||
dctx->sset = false;
|
||||
|
|
@ -47,23 +47,16 @@ int crypto_poly1305_init(struct shash_desc *desc)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_poly1305_init);
|
||||
|
||||
static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
|
||||
void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key)
|
||||
{
|
||||
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
||||
dctx->r[0] = (get_unaligned_le32(key + 0) >> 0) & 0x3ffffff;
|
||||
dctx->r[1] = (get_unaligned_le32(key + 3) >> 2) & 0x3ffff03;
|
||||
dctx->r[2] = (get_unaligned_le32(key + 6) >> 4) & 0x3ffc0ff;
|
||||
dctx->r[3] = (get_unaligned_le32(key + 9) >> 6) & 0x3f03fff;
|
||||
dctx->r[4] = (get_unaligned_le32(key + 12) >> 8) & 0x00fffff;
|
||||
}
|
||||
|
||||
static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key)
|
||||
{
|
||||
dctx->s[0] = get_unaligned_le32(key + 0);
|
||||
dctx->s[1] = get_unaligned_le32(key + 4);
|
||||
dctx->s[2] = get_unaligned_le32(key + 8);
|
||||
dctx->s[3] = get_unaligned_le32(key + 12);
|
||||
key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff;
|
||||
key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03;
|
||||
key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff;
|
||||
key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff;
|
||||
key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(poly1305_core_setkey);
|
||||
|
||||
/*
|
||||
* Poly1305 requires a unique key for each tag, which implies that we can't set
|
||||
|
|
@ -75,13 +68,16 @@ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
|
|||
{
|
||||
if (!dctx->sset) {
|
||||
if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
|
||||
poly1305_setrkey(dctx, src);
|
||||
poly1305_core_setkey(&dctx->r, src);
|
||||
src += POLY1305_BLOCK_SIZE;
|
||||
srclen -= POLY1305_BLOCK_SIZE;
|
||||
dctx->rset = true;
|
||||
}
|
||||
if (srclen >= POLY1305_BLOCK_SIZE) {
|
||||
poly1305_setskey(dctx, src);
|
||||
dctx->s[0] = get_unaligned_le32(src + 0);
|
||||
dctx->s[1] = get_unaligned_le32(src + 4);
|
||||
dctx->s[2] = get_unaligned_le32(src + 8);
|
||||
dctx->s[3] = get_unaligned_le32(src + 12);
|
||||
src += POLY1305_BLOCK_SIZE;
|
||||
srclen -= POLY1305_BLOCK_SIZE;
|
||||
dctx->sset = true;
|
||||
|
|
@ -91,41 +87,37 @@ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_poly1305_setdesckey);
|
||||
|
||||
static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx,
|
||||
const u8 *src, unsigned int srclen,
|
||||
u32 hibit)
|
||||
static void poly1305_blocks_internal(struct poly1305_state *state,
|
||||
const struct poly1305_key *key,
|
||||
const void *src, unsigned int nblocks,
|
||||
u32 hibit)
|
||||
{
|
||||
u32 r0, r1, r2, r3, r4;
|
||||
u32 s1, s2, s3, s4;
|
||||
u32 h0, h1, h2, h3, h4;
|
||||
u64 d0, d1, d2, d3, d4;
|
||||
unsigned int datalen;
|
||||
|
||||
if (unlikely(!dctx->sset)) {
|
||||
datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
|
||||
src += srclen - datalen;
|
||||
srclen = datalen;
|
||||
}
|
||||
if (!nblocks)
|
||||
return;
|
||||
|
||||
r0 = dctx->r[0];
|
||||
r1 = dctx->r[1];
|
||||
r2 = dctx->r[2];
|
||||
r3 = dctx->r[3];
|
||||
r4 = dctx->r[4];
|
||||
r0 = key->r[0];
|
||||
r1 = key->r[1];
|
||||
r2 = key->r[2];
|
||||
r3 = key->r[3];
|
||||
r4 = key->r[4];
|
||||
|
||||
s1 = r1 * 5;
|
||||
s2 = r2 * 5;
|
||||
s3 = r3 * 5;
|
||||
s4 = r4 * 5;
|
||||
|
||||
h0 = dctx->h[0];
|
||||
h1 = dctx->h[1];
|
||||
h2 = dctx->h[2];
|
||||
h3 = dctx->h[3];
|
||||
h4 = dctx->h[4];
|
||||
|
||||
while (likely(srclen >= POLY1305_BLOCK_SIZE)) {
|
||||
h0 = state->h[0];
|
||||
h1 = state->h[1];
|
||||
h2 = state->h[2];
|
||||
h3 = state->h[3];
|
||||
h4 = state->h[4];
|
||||
|
||||
do {
|
||||
/* h += m[i] */
|
||||
h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff;
|
||||
h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff;
|
||||
|
|
@ -154,16 +146,36 @@ static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx,
|
|||
h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
|
||||
|
||||
src += POLY1305_BLOCK_SIZE;
|
||||
srclen -= POLY1305_BLOCK_SIZE;
|
||||
} while (--nblocks);
|
||||
|
||||
state->h[0] = h0;
|
||||
state->h[1] = h1;
|
||||
state->h[2] = h2;
|
||||
state->h[3] = h3;
|
||||
state->h[4] = h4;
|
||||
}
|
||||
|
||||
void poly1305_core_blocks(struct poly1305_state *state,
|
||||
const struct poly1305_key *key,
|
||||
const void *src, unsigned int nblocks)
|
||||
{
|
||||
poly1305_blocks_internal(state, key, src, nblocks, 1 << 24);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(poly1305_core_blocks);
|
||||
|
||||
static void poly1305_blocks(struct poly1305_desc_ctx *dctx,
|
||||
const u8 *src, unsigned int srclen, u32 hibit)
|
||||
{
|
||||
unsigned int datalen;
|
||||
|
||||
if (unlikely(!dctx->sset)) {
|
||||
datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
|
||||
src += srclen - datalen;
|
||||
srclen = datalen;
|
||||
}
|
||||
|
||||
dctx->h[0] = h0;
|
||||
dctx->h[1] = h1;
|
||||
dctx->h[2] = h2;
|
||||
dctx->h[3] = h3;
|
||||
dctx->h[4] = h4;
|
||||
|
||||
return srclen;
|
||||
poly1305_blocks_internal(&dctx->h, &dctx->r,
|
||||
src, srclen / POLY1305_BLOCK_SIZE, hibit);
|
||||
}
|
||||
|
||||
int crypto_poly1305_update(struct shash_desc *desc,
|
||||
|
|
@ -187,9 +199,9 @@ int crypto_poly1305_update(struct shash_desc *desc,
|
|||
}
|
||||
|
||||
if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
|
||||
bytes = poly1305_blocks(dctx, src, srclen, 1 << 24);
|
||||
src += srclen - bytes;
|
||||
srclen = bytes;
|
||||
poly1305_blocks(dctx, src, srclen, 1 << 24);
|
||||
src += srclen - (srclen % POLY1305_BLOCK_SIZE);
|
||||
srclen %= POLY1305_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if (unlikely(srclen)) {
|
||||
|
|
@ -201,30 +213,18 @@ int crypto_poly1305_update(struct shash_desc *desc,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_poly1305_update);
|
||||
|
||||
int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
|
||||
void poly1305_core_emit(const struct poly1305_state *state, void *dst)
|
||||
{
|
||||
struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
|
||||
u32 h0, h1, h2, h3, h4;
|
||||
u32 g0, g1, g2, g3, g4;
|
||||
u32 mask;
|
||||
u64 f = 0;
|
||||
|
||||
if (unlikely(!dctx->sset))
|
||||
return -ENOKEY;
|
||||
|
||||
if (unlikely(dctx->buflen)) {
|
||||
dctx->buf[dctx->buflen++] = 1;
|
||||
memset(dctx->buf + dctx->buflen, 0,
|
||||
POLY1305_BLOCK_SIZE - dctx->buflen);
|
||||
poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0);
|
||||
}
|
||||
|
||||
/* fully carry h */
|
||||
h0 = dctx->h[0];
|
||||
h1 = dctx->h[1];
|
||||
h2 = dctx->h[2];
|
||||
h3 = dctx->h[3];
|
||||
h4 = dctx->h[4];
|
||||
h0 = state->h[0];
|
||||
h1 = state->h[1];
|
||||
h2 = state->h[2];
|
||||
h3 = state->h[3];
|
||||
h4 = state->h[4];
|
||||
|
||||
h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
|
||||
h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
|
||||
|
|
@ -254,16 +254,40 @@ int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
|
|||
h4 = (h4 & mask) | g4;
|
||||
|
||||
/* h = h % (2^128) */
|
||||
h0 = (h0 >> 0) | (h1 << 26);
|
||||
h1 = (h1 >> 6) | (h2 << 20);
|
||||
h2 = (h2 >> 12) | (h3 << 14);
|
||||
h3 = (h3 >> 18) | (h4 << 8);
|
||||
put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0);
|
||||
put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4);
|
||||
put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8);
|
||||
put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(poly1305_core_emit);
|
||||
|
||||
int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
|
||||
{
|
||||
struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
|
||||
__le32 digest[4];
|
||||
u64 f = 0;
|
||||
|
||||
if (unlikely(!dctx->sset))
|
||||
return -ENOKEY;
|
||||
|
||||
if (unlikely(dctx->buflen)) {
|
||||
dctx->buf[dctx->buflen++] = 1;
|
||||
memset(dctx->buf + dctx->buflen, 0,
|
||||
POLY1305_BLOCK_SIZE - dctx->buflen);
|
||||
poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0);
|
||||
}
|
||||
|
||||
poly1305_core_emit(&dctx->h, digest);
|
||||
|
||||
/* mac = (h + s) % (2^128) */
|
||||
f = (f >> 32) + h0 + dctx->s[0]; put_unaligned_le32(f, dst + 0);
|
||||
f = (f >> 32) + h1 + dctx->s[1]; put_unaligned_le32(f, dst + 4);
|
||||
f = (f >> 32) + h2 + dctx->s[2]; put_unaligned_le32(f, dst + 8);
|
||||
f = (f >> 32) + h3 + dctx->s[3]; put_unaligned_le32(f, dst + 12);
|
||||
f = (f >> 32) + le32_to_cpu(digest[0]) + dctx->s[0];
|
||||
put_unaligned_le32(f, dst + 0);
|
||||
f = (f >> 32) + le32_to_cpu(digest[1]) + dctx->s[1];
|
||||
put_unaligned_le32(f, dst + 4);
|
||||
f = (f >> 32) + le32_to_cpu(digest[2]) + dctx->s[2];
|
||||
put_unaligned_le32(f, dst + 8);
|
||||
f = (f >> 32) + le32_to_cpu(digest[3]) + dctx->s[3];
|
||||
put_unaligned_le32(f, dst + 12);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
16
crypto/rng.c
16
crypto/rng.c
|
|
@ -35,9 +35,11 @@ static int crypto_default_rng_refcnt;
|
|||
|
||||
int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
|
||||
{
|
||||
struct crypto_alg *alg = tfm->base.__crt_alg;
|
||||
u8 *buf = NULL;
|
||||
int err;
|
||||
|
||||
crypto_stats_get(alg);
|
||||
if (!seed && slen) {
|
||||
buf = kmalloc(slen, GFP_KERNEL);
|
||||
if (!buf)
|
||||
|
|
@ -50,7 +52,7 @@ int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
|
|||
}
|
||||
|
||||
err = crypto_rng_alg(tfm)->seed(tfm, seed, slen);
|
||||
crypto_stat_rng_seed(tfm, err);
|
||||
crypto_stats_rng_seed(alg, err);
|
||||
out:
|
||||
kzfree(buf);
|
||||
return err;
|
||||
|
|
@ -74,17 +76,13 @@ static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_rng rrng;
|
||||
|
||||
strncpy(rrng.type, "rng", sizeof(rrng.type));
|
||||
memset(&rrng, 0, sizeof(rrng));
|
||||
|
||||
strscpy(rrng.type, "rng", sizeof(rrng.type));
|
||||
|
||||
rrng.seedsize = seedsize(alg);
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_RNG,
|
||||
sizeof(struct crypto_report_rng), &rrng))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_RNG, sizeof(rrng), &rrng);
|
||||
}
|
||||
#else
|
||||
static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ static int salsa20_crypt(struct skcipher_request *req)
|
|||
u32 state[16];
|
||||
int err;
|
||||
|
||||
err = skcipher_walk_virt(&walk, req, true);
|
||||
err = skcipher_walk_virt(&walk, req, false);
|
||||
|
||||
salsa20_init(state, ctx, walk.iv);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,15 +40,12 @@ static int crypto_scomp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
{
|
||||
struct crypto_report_comp rscomp;
|
||||
|
||||
strncpy(rscomp.type, "scomp", sizeof(rscomp.type));
|
||||
memset(&rscomp, 0, sizeof(rscomp));
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
|
||||
sizeof(struct crypto_report_comp), &rscomp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
strscpy(rscomp.type, "scomp", sizeof(rscomp.type));
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
|
||||
sizeof(rscomp), &rscomp);
|
||||
}
|
||||
#else
|
||||
static int crypto_scomp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
|
|
@ -408,18 +408,14 @@ static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
struct crypto_report_hash rhash;
|
||||
struct shash_alg *salg = __crypto_shash_alg(alg);
|
||||
|
||||
strncpy(rhash.type, "shash", sizeof(rhash.type));
|
||||
memset(&rhash, 0, sizeof(rhash));
|
||||
|
||||
strscpy(rhash.type, "shash", sizeof(rhash.type));
|
||||
|
||||
rhash.blocksize = alg->cra_blocksize;
|
||||
rhash.digestsize = salg->digestsize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_HASH,
|
||||
sizeof(struct crypto_report_hash), &rhash))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash);
|
||||
}
|
||||
#else
|
||||
static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
|
|
@ -474,6 +474,8 @@ int skcipher_walk_virt(struct skcipher_walk *walk,
|
|||
{
|
||||
int err;
|
||||
|
||||
might_sleep_if(req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
|
||||
|
||||
walk->flags &= ~SKCIPHER_WALK_PHYS;
|
||||
|
||||
err = skcipher_walk_skcipher(walk, req);
|
||||
|
|
@ -577,8 +579,7 @@ static unsigned int crypto_skcipher_extsize(struct crypto_alg *alg)
|
|||
if (alg->cra_type == &crypto_blkcipher_type)
|
||||
return sizeof(struct crypto_blkcipher *);
|
||||
|
||||
if (alg->cra_type == &crypto_ablkcipher_type ||
|
||||
alg->cra_type == &crypto_givcipher_type)
|
||||
if (alg->cra_type == &crypto_ablkcipher_type)
|
||||
return sizeof(struct crypto_ablkcipher *);
|
||||
|
||||
return crypto_alg_extsize(alg);
|
||||
|
|
@ -842,8 +843,7 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm)
|
|||
if (tfm->__crt_alg->cra_type == &crypto_blkcipher_type)
|
||||
return crypto_init_skcipher_ops_blkcipher(tfm);
|
||||
|
||||
if (tfm->__crt_alg->cra_type == &crypto_ablkcipher_type ||
|
||||
tfm->__crt_alg->cra_type == &crypto_givcipher_type)
|
||||
if (tfm->__crt_alg->cra_type == &crypto_ablkcipher_type)
|
||||
return crypto_init_skcipher_ops_ablkcipher(tfm);
|
||||
|
||||
skcipher->setkey = skcipher_setkey;
|
||||
|
|
@ -897,21 +897,18 @@ static int crypto_skcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
|||
struct skcipher_alg *skcipher = container_of(alg, struct skcipher_alg,
|
||||
base);
|
||||
|
||||
strncpy(rblkcipher.type, "skcipher", sizeof(rblkcipher.type));
|
||||
strncpy(rblkcipher.geniv, "<none>", sizeof(rblkcipher.geniv));
|
||||
memset(&rblkcipher, 0, sizeof(rblkcipher));
|
||||
|
||||
strscpy(rblkcipher.type, "skcipher", sizeof(rblkcipher.type));
|
||||
strscpy(rblkcipher.geniv, "<none>", sizeof(rblkcipher.geniv));
|
||||
|
||||
rblkcipher.blocksize = alg->cra_blocksize;
|
||||
rblkcipher.min_keysize = skcipher->min_keysize;
|
||||
rblkcipher.max_keysize = skcipher->max_keysize;
|
||||
rblkcipher.ivsize = skcipher->ivsize;
|
||||
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER,
|
||||
sizeof(struct crypto_report_blkcipher), &rblkcipher))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
return nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER,
|
||||
sizeof(rblkcipher), &rblkcipher);
|
||||
}
|
||||
#else
|
||||
static int crypto_skcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
|
|
|
|||
1140
crypto/streebog_generic.c
Normal file
1140
crypto/streebog_generic.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -76,10 +76,12 @@ static char *check[] = {
|
|||
"cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
|
||||
"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt",
|
||||
"camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320",
|
||||
"lzo", "cts", "sha3-224", "sha3-256", "sha3-384", "sha3-512", NULL
|
||||
"lzo", "cts", "sha3-224", "sha3-256", "sha3-384", "sha3-512",
|
||||
"streebog256", "streebog512",
|
||||
NULL
|
||||
};
|
||||
|
||||
static u32 block_sizes[] = { 16, 64, 256, 1024, 8192, 0 };
|
||||
static u32 block_sizes[] = { 16, 64, 256, 1024, 1472, 8192, 0 };
|
||||
static u32 aead_sizes[] = { 16, 64, 256, 512, 1024, 2048, 4096, 8192, 0 };
|
||||
|
||||
#define XBUFSIZE 8
|
||||
|
|
@ -1736,6 +1738,7 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
|
|||
ret += tcrypt_test("ctr(aes)");
|
||||
ret += tcrypt_test("rfc3686(ctr(aes))");
|
||||
ret += tcrypt_test("ofb(aes)");
|
||||
ret += tcrypt_test("cfb(aes)");
|
||||
break;
|
||||
|
||||
case 11:
|
||||
|
|
@ -1913,6 +1916,14 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
|
|||
ret += tcrypt_test("sm3");
|
||||
break;
|
||||
|
||||
case 53:
|
||||
ret += tcrypt_test("streebog256");
|
||||
break;
|
||||
|
||||
case 54:
|
||||
ret += tcrypt_test("streebog512");
|
||||
break;
|
||||
|
||||
case 100:
|
||||
ret += tcrypt_test("hmac(md5)");
|
||||
break;
|
||||
|
|
@ -1969,6 +1980,14 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
|
|||
ret += tcrypt_test("hmac(sha3-512)");
|
||||
break;
|
||||
|
||||
case 115:
|
||||
ret += tcrypt_test("hmac(streebog256)");
|
||||
break;
|
||||
|
||||
case 116:
|
||||
ret += tcrypt_test("hmac(streebog512)");
|
||||
break;
|
||||
|
||||
case 150:
|
||||
ret += tcrypt_test("ansi_cprng");
|
||||
break;
|
||||
|
|
@ -2060,6 +2079,10 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
|
|||
speed_template_16_24_32);
|
||||
test_cipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0,
|
||||
speed_template_16_24_32);
|
||||
test_cipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0,
|
||||
speed_template_16_24_32);
|
||||
test_cipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0,
|
||||
speed_template_16_24_32);
|
||||
break;
|
||||
|
||||
case 201:
|
||||
|
|
@ -2297,6 +2320,18 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
|
|||
test_cipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0,
|
||||
speed_template_16);
|
||||
break;
|
||||
|
||||
case 219:
|
||||
test_cipher_speed("adiantum(xchacha12,aes)", ENCRYPT, sec, NULL,
|
||||
0, speed_template_32);
|
||||
test_cipher_speed("adiantum(xchacha12,aes)", DECRYPT, sec, NULL,
|
||||
0, speed_template_32);
|
||||
test_cipher_speed("adiantum(xchacha20,aes)", ENCRYPT, sec, NULL,
|
||||
0, speed_template_32);
|
||||
test_cipher_speed("adiantum(xchacha20,aes)", DECRYPT, sec, NULL,
|
||||
0, speed_template_32);
|
||||
break;
|
||||
|
||||
case 300:
|
||||
if (alg) {
|
||||
test_hash_speed(alg, sec, generic_hash_speed_template);
|
||||
|
|
@ -2407,6 +2442,16 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
|
|||
test_hash_speed("sm3", sec, generic_hash_speed_template);
|
||||
if (mode > 300 && mode < 400) break;
|
||||
/* fall through */
|
||||
case 327:
|
||||
test_hash_speed("streebog256", sec,
|
||||
generic_hash_speed_template);
|
||||
if (mode > 300 && mode < 400) break;
|
||||
/* fall through */
|
||||
case 328:
|
||||
test_hash_speed("streebog512", sec,
|
||||
generic_hash_speed_template);
|
||||
if (mode > 300 && mode < 400) break;
|
||||
/* fall through */
|
||||
case 399:
|
||||
break;
|
||||
|
||||
|
|
@ -2520,6 +2565,16 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
|
|||
num_mb);
|
||||
if (mode > 400 && mode < 500) break;
|
||||
/* fall through */
|
||||
case 426:
|
||||
test_mb_ahash_speed("streebog256", sec,
|
||||
generic_hash_speed_template, num_mb);
|
||||
if (mode > 400 && mode < 500) break;
|
||||
/* fall through */
|
||||
case 427:
|
||||
test_mb_ahash_speed("streebog512", sec,
|
||||
generic_hash_speed_template, num_mb);
|
||||
if (mode > 400 && mode < 500) break;
|
||||
/* fall through */
|
||||
case 499:
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -2404,6 +2404,18 @@ static int alg_test_null(const struct alg_test_desc *desc,
|
|||
/* Please keep this list sorted by algorithm name. */
|
||||
static const struct alg_test_desc alg_test_descs[] = {
|
||||
{
|
||||
.alg = "adiantum(xchacha12,aes)",
|
||||
.test = alg_test_skcipher,
|
||||
.suite = {
|
||||
.cipher = __VECS(adiantum_xchacha12_aes_tv_template)
|
||||
},
|
||||
}, {
|
||||
.alg = "adiantum(xchacha20,aes)",
|
||||
.test = alg_test_skcipher,
|
||||
.suite = {
|
||||
.cipher = __VECS(adiantum_xchacha20_aes_tv_template)
|
||||
},
|
||||
}, {
|
||||
.alg = "aegis128",
|
||||
.test = alg_test_aead,
|
||||
.suite = {
|
||||
|
|
@ -2690,6 +2702,13 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.dec = __VECS(aes_ccm_dec_tv_template)
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "cfb(aes)",
|
||||
.test = alg_test_skcipher,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.cipher = __VECS(aes_cfb_tv_template)
|
||||
},
|
||||
}, {
|
||||
.alg = "chacha20",
|
||||
.test = alg_test_skcipher,
|
||||
|
|
@ -2805,6 +2824,7 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
}, {
|
||||
.alg = "cts(cbc(aes))",
|
||||
.test = alg_test_skcipher,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.cipher = __VECS(cts_mode_tv_template)
|
||||
}
|
||||
|
|
@ -3184,6 +3204,18 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.suite = {
|
||||
.hash = __VECS(hmac_sha512_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "hmac(streebog256)",
|
||||
.test = alg_test_hash,
|
||||
.suite = {
|
||||
.hash = __VECS(hmac_streebog256_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "hmac(streebog512)",
|
||||
.test = alg_test_hash,
|
||||
.suite = {
|
||||
.hash = __VECS(hmac_streebog512_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "jitterentropy_rng",
|
||||
.fips_allowed = 1,
|
||||
|
|
@ -3291,6 +3323,12 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.dec = __VECS(morus640_dec_tv_template),
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "nhpoly1305",
|
||||
.test = alg_test_hash,
|
||||
.suite = {
|
||||
.hash = __VECS(nhpoly1305_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "ofb(aes)",
|
||||
.test = alg_test_skcipher,
|
||||
|
|
@ -3496,6 +3534,18 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.suite = {
|
||||
.hash = __VECS(sm3_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "streebog256",
|
||||
.test = alg_test_hash,
|
||||
.suite = {
|
||||
.hash = __VECS(streebog256_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "streebog512",
|
||||
.test = alg_test_hash,
|
||||
.suite = {
|
||||
.hash = __VECS(streebog512_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "tgr128",
|
||||
.test = alg_test_hash,
|
||||
|
|
@ -3544,6 +3594,18 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.suite = {
|
||||
.hash = __VECS(aes_xcbc128_tv_template)
|
||||
}
|
||||
}, {
|
||||
.alg = "xchacha12",
|
||||
.test = alg_test_skcipher,
|
||||
.suite = {
|
||||
.cipher = __VECS(xchacha12_tv_template)
|
||||
},
|
||||
}, {
|
||||
.alg = "xchacha20",
|
||||
.test = alg_test_skcipher,
|
||||
.suite = {
|
||||
.cipher = __VECS(xchacha20_tv_template)
|
||||
},
|
||||
}, {
|
||||
.alg = "xts(aes)",
|
||||
.test = alg_test_skcipher,
|
||||
|
|
|
|||
3220
crypto/testmgr.h
3220
crypto/testmgr.h
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue