LoginSignup
0
0

More than 3 years have passed since last update.

Linux Kernel for ARMにおける各種crypt実装が呼び出されるまで

Posted at

こちらをベースに、各種crypt実装が呼び出されるまでを簡単にまとめておく。

大前提

ARM archで、SHA1のNEON実装が有効になり、呼び出せる準備ができるまでをまとめる。

なお、 ** NEON/SIMDの実装の中身の議論はしない** です。 

KConfig

arch/arm/crypy/Kconfig に、各種カーネルコンフィグレーションがある。

  • ARMとなっているものは、基本コンパイルできるはず…だけどNEONも使っているものもまざってて、うんわかりにくいな。
  • NEONとついているものは、NEONが有効になっている場合にだけ使える。
  • CEとついているものは、ARM v8 Crypto Extensionsを有効になっている場合にだけ使える
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

<略>

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

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

<略>
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

これは、 sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o の記載から、2つのファイルを結合したものになる。

sha1_neon_glue.c

モジュール組み込み時の、_init/_exit

モジュールを組み込んだ時点で、sha1_neon_mode_[init|fini] が登録される。

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()

sha1_neon_mod_init()では、neon用の実装を登録している。
ここで、 .initsha1_base_initとなって共通実装を使い、その他は、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);

ここで、

  • crypt_simd_usable() は、SIMD実装をcryptで利用できるかどうかを判定する関数。 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/crypto/internal/simd.h#n64 あたりに実装がある。
  • SIMD実装をcryptで使えない場合は、利用できない場合には、普通のsha1_update_arm()からsha1_base_do_update()を呼び出すフォールバック処理がなされる。
  • kernel_neon_begin() と、kernel_neon_end()は、NEON Registerの保護のために行われる関数。
  • 処理の実体は、sha1_base_do_update()の引数で渡された、sha1_transform_neon() で行われる。

sha1_neon_finup() / sha1_neon_final()

終了処理をまとめて説明する。

  • simdがcryptで使えなかったら、通常処理に戻す。
  • kernel_neon_begin() でneon使えるようにする
  • sha1_base_do_update(sha1_trasnfrom_neon) で、処理本体を呼び出す
  • kernel_neon_end() でneon使用状態を戻す
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()

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;

<略>

まとめ

  • XXXX-glue.cというファイルを追加して、module_init()内でtransform関数を登録しよう。
  • transform関数は、callbackとして引き渡す形で使うので、そこを機にしよう。
  • 前提条件を満たさず使えなかった場合のフォールバック処理もちゃんと入れよう。

以上となります。

おまけ:現在(2020/5/30) でLinux Kernelのcrypt実装では、どんなものがサポートされているのか。

ざっくり、ファイル名から見ると下記がサポートされているっポイ。

ARMの場合

(☆ = x86にはなくて、ARMにはある)

  • aes
  • chacha
  • crc32
  • crct10dif
  • curve25519
  • ghash
  • nhpoly1305
  • poly1305
  • sha1
  • sha2 ☆
  • sha256
  • sha512

ARM64の場合

(☆ = x86にはなくて、ARM64にはある)

  • aes
  • chacha
  • crct10dif
  • ghash
  • ngpoly1305
  • poly1305
  • sha1
  • sha2
  • sha3
  • sha256
  • sha512
  • sm3 ☆

x86の場合 

(★= ARMにはなくて、x86にある)

特徴:さすがにみんなが使っていることだけあって、サポートが熱く厚いなあ……

  • aegis128 ★
  • aes
  • blake2s ★
  • blowfish ★
  • camellia ★
  • cast5 ★
  • cast6 ★
  • chacha
  • crc32
  • crct10dif
  • curve25519 ★
  • des3 ★
  • ghash
  • nhpoly1305
  • poly1305
  • serpent ★
  • sha1
  • sha256
  • sha512
  • twofish ★

powerpcの場合

特徴: う、うーん、、、これ、特徴が無いように見える。

  • aes
  • crc32
  • crct10dif
  • md5
  • sha1
  • sha256

sparcの場合

特徴: MD5とかAES,DES,CAMELLIAとか、SHA1,SHA256,SHA512とか、専用命令あるっぽい!

  • camellia
  • crc32c
  • des
  • md5
  • sha1
  • sha256
  • sha512

MIPS

  • chacha
  • crc32
  • poly1305

S390

  • aes
  • RNG
  • crc32
  • des
  • ghash
  • paes
  • sha1
  • sha3
  • sha256
  • sha512

RISC-V

未実装!!ここにcommitすれば、あなたもLinux Kernel Developerとして名前が未来永劫記録されますよ!!やったね!!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0