Until various crypt implementations in Linux Kernel for ARM are called

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm/crypto

Based on this, I will briefly summarize until various crypt implementations are called.

Major premise

In ARM arch, the NEON implementation of SHA1 is enabled and it is ready to be called.

In addition, ** I will not discuss the contents of NEON / SIMD implementation **.

KConfig

There are various kernel configurations in arch / arm / crypy / Kconfig.

--The ones that are ARM should be able to be basically compiled ... But the ones that NEON is also using are mixed, so it's hard to understand. --The ones with NEON can be used only when NEON is enabled. --CE is only available if ARM v8 Crypto Extensions is enabled

arch/arm/crypto/Kconfig



menuconfig ARM_CRYPTO
	bool "ARM Accelerated Cryptographic Algorithms"
	depends on ARM
	help
	  Say Y here to choose from a selection of cryptographic algorithms
	  implemented using ARM specific CPU features or instructions.

if ARM_CRYPTO

<Omitted>

config CRYPTO_SHA1_ARM_NEON
	tristate "SHA1 digest algorithm (ARM NEON)"
	depends on KERNEL_MODE_NEON
	select CRYPTO_SHA1_ARM
	select CRYPTO_SHA1
	select CRYPTO_HASH
	help
	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented
	  using optimized ARM NEON assembly, when NEON instructions are
	  available.

Makefile

It is the usual description to import the necessary files according to the settings enabled in KConfig.

arch/arm/crypto/Makefile



obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o
obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o
obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o
obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o

<Omitted>
aes-arm-y	:= aes-cipher-core.o aes-cipher-glue.o
aes-arm-bs-y	:= aes-neonbs-core.o aes-neonbs-glue.o
sha1-arm-y	:= sha1-armv4-large.o sha1_glue.o
sha1-arm-neon-y	:= sha1-armv7-neon.o sha1_neon_glue.o
sha256-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha256_neon_glue.o

sha1-arm-neon.o

This is a combination of the two files from the description sha1-arm-neon-y: = sha1-armv7-neon.o sha1_neon_glue.o.

sha1_neon_glue.c

_Init / _exit when the module is installed

When the module is installed, sha1_neon_mode_ [init | fini] is registered.

arch/arm/crypto/sha1_neon_glue.c


module_init(sha1_neon_mod_init);
module_exit(sha1_neon_mod_fini);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, NEON accelerated");
MODULE_ALIAS_CRYPTO("sha1");

sha1_neon_mod_init()

In sha1_neon_mod_init (), the implementation for neon is registered. Note that .init becomes sha1_base_init and uses the common implementation, and the others are uniquely implemented as sha1_neon_ *.

arch/arm/crypto/sha1_neon_glue.c



static struct shash_alg alg = {
	.digestsize	=	SHA1_DIGEST_SIZE,
	.init		=	sha1_base_init,
	.update		=	sha1_neon_update,
	.final		=	sha1_neon_final,
	.finup		=	sha1_neon_finup,
	.descsize	=	sizeof(struct sha1_state),
	.base		=	{
		.cra_name		= "sha1",
		.cra_driver_name	= "sha1-neon",
		.cra_priority		= 250,
		.cra_blocksize		= SHA1_BLOCK_SIZE,
		.cra_module		= THIS_MODULE,
	}
};

static int __init sha1_neon_mod_init(void)
{
	if (!cpu_has_neon())
		return -ENODEV;

	return crypto_register_shash(&alg);
}

sha1_neon_update()

arch/arm/crypto/sha1_neon_glue.c


static int sha1_neon_update(struct shash_desc *desc, const u8 *data,
			  unsigned int len)
{
	struct sha1_state *sctx = shash_desc_ctx(desc);

	if (!crypto_simd_usable() ||
	    (sctx->count % SHA1_BLOCK_SIZE) + len < SHA1_BLOCK_SIZE)
		return sha1_update_arm(desc, data, len);

	kernel_neon_begin();
	sha1_base_do_update(desc, data, len,
			    (sha1_block_fn *)sha1_transform_neon);
	kernel_neon_end();

	return 0;
}

arch/arm/crypto/sha1_glue.c


int sha1_update_arm(struct shash_desc *desc, const u8 *data,
		    unsigned int len)
{
	/* make sure casting to sha1_block_fn() is safe */
	BUILD_BUG_ON(offsetof(struct sha1_state, state) != 0);

	return sha1_base_do_update(desc, data, len,
				   (sha1_block_fn *)sha1_block_data_order);
}
EXPORT_SYMBOL_GPL(sha1_update_arm);

here,

--crypt_simd_usable () is a function that determines if a SIMD implementation is available in crypt. There is an implementation around https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/crypto/internal/simd.h#n64. --If the SIMD implementation cannot be used with crypt, if it is not available, a fallback process is performed that calls sha1_base_do_update () from the normal sha1_update_arm (). --kernel_neon_begin () and kernel_neon_end () are functions used to protect the NEON Register. --The substance of the process is sha1_transform_neon () passed as an argument of sha1_base_do_update ().

sha1_neon_finup() / sha1_neon_final()

The end processing will be described collectively.

--If simd cannot be used with crypt, return to normal processing. --Enable neon with kernel_neon_begin () --Call the processing body with sha1_base_do_update (sha1_trasnfrom_neon) --Return neon usage with kernel_neon_end ()

sha1_neon_glue.c


static int sha1_neon_finup(struct shash_desc *desc, const u8 *data,
			   unsigned int len, u8 *out)
{
	if (!crypto_simd_usable())
		return sha1_finup_arm(desc, data, len, out);

	kernel_neon_begin();
	if (len)
		sha1_base_do_update(desc, data, len,
				    (sha1_block_fn *)sha1_transform_neon);
	sha1_base_do_finalize(desc, (sha1_block_fn *)sha1_transform_neon);
	kernel_neon_end();

	return sha1_base_finish(desc, out);
}

static int sha1_neon_final(struct shash_desc *desc, u8 *out)
{
	return sha1_neon_finup(desc, NULL, 0, out);
}

sha1-armv7-neon.S

sha1_transform_neon()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm/crypto/sha1-armv7-neon.S#n292

sha1-armv7-neon.S



/*
 * Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
 *
 * unsigned int
 * sha1_transform_neon (void *ctx, const unsigned char *data,
 *                      unsigned int nblks)
 */
.align 3
ENTRY(sha1_transform_neon)
  /* input:
   *	r0: ctx, CTX
   *	r1: data (64*nblks bytes)
   *	r2: nblks
   */

  cmp RNBLKS, #0;
  beq .Ldo_nothing;

<Omitted>

Summary

--Add a file called XXXX-glue.c and register the transform function in module_init (). --The transform function is used in the form of passing it as a callback, so let's take that as an opportunity. ――Let's properly include fallback processing when the prerequisites are not met and cannot be used.

That is all.

Bonus: What is currently supported by the crypt implementation of the Linux Kernel (May 30, 2020)?

Roughly speaking from the file name, the following are supported.

For ARM

(☆ = not on x86, but on ARM)

For ARM64

(☆ = not on x86, but on ARM64)

For x86

(★ = not on ARM, but on x86)

Characteristic: As expected, everyone is using it, so the support is hot and thick ...

For powerpc

Features: Hmmm ... this looks like it has no features.

For sparc

Features: MD5, AES, DES, CAMELLIA, SHA1, SHA256, SHA512, etc. It seems that there are special instructions!

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/sparc/crypto/opcodes.h

MIPS

S390

RISC-V

Unimplemented! !! If you commit here, your name will be recorded as a Linux Kernel Developer for a long time in the future! !! You did it! !! !!

Recommended Posts

Until various crypt implementations in Linux Kernel for ARM are called
For Debian users who are having trouble with a bug in the Linux kernel 5.10
Linux Kernel Build for DE10nano
[Work memo] Until matplotlib and numpy are installed in Amazon Linux
Until Windows Subsystem for Linux (WSL) is installed in Windows and fish is installed
Consider streamlining crypt / xor.c implementation in risc-v linux kernel (discussion only)
[Linux] [kernel module] Create kthread in kernel module