CryptoAPI Linux kernel: development and application of Russian cryptography

imageCryptoAPI is an implementation of cryptographic algorithms with access to them both from the kernel itself and from application software. The most prominent representatives of this software are IPSEC (VPN) and dm-crypt (encrypted file system).

The ultimate goal of this material will be to create an encrypted file system using Russian cryptographic algorithms:

  • The development of the value of the hash function in accordance with the requirements of GOST R 34.11-94 / GOST R 34.11-2012 “Information technology. Cryptographic information security. Hashing Function ”;
  • Encrypting / decrypting data and calculating the insert in accordance with the requirements of GOST 28147-89 “Information processing systems. Cryptographic protection ”;
  • Encryption / decryption of data by encryption algorithms “Grasshopper” (KUZmin, NECHAEV AND COMPANY) and “Magma” in accordance with the requirements of “GOST R 34.12-2015 Information technology. Cryptographic information security. Block Ciphers ”and“ GOST R 34.13-2015 Information Technology. Cryptographic information security. Operating modes of block ciphers. "

You can see which cryptographic algorithms can be used to create an encrypted file system with the following commands:

bash-4.3$ /usr/local/bin64/cryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1       620459 iterations per second
PBKDF2-sha256     541619 iterations per second
PBKDF2-sha512     357144 iterations per second
#  Algorithm | Key |  Encryption |  Decryption
     aes-cbc   128b   467,6 MiB/s  1686,1 MiB/s
 serpent-cbc   128b    74,5 MiB/s   264,4 MiB/s
     aes-cbc   256b   350,1 MiB/s  1333,8 MiB/s
 serpent-cbc   256b    74,2 MiB/s   265,3 MiB/s
bash-4.3$ /usr/local/bin64/cryptsetup  benchmark  -caes-ecb
# Tests are approximate using memory only (no storage IO).
#  Algorithm | Key |  Encryption |  Decryption
     aes-ecb   256b  1422,6 MiB/s  1437,6 MiB/s
bash-4.3$

As can be seen from this example, the AES encryption algorithm in CBC and ECB modes, as well as the hash functions sha1, sha256 and sha512 can be used to create an encrypted file system.

To switch to Russian cryptography, we need to add modules to the Linux kernel that implement a hash according to GOST R 34.11-94, GOST R 34.11-2012 with a hash length of 256 bits (STRIBOG-256) and a hash length of 512 bits (STRIBOG-512).

As encryption algorithms, GOST 28147-89 should be implemented, it is actually the Magma algorithm (GOST R 34.12-2015), as well as the Grasshopper algorithm (GOST R 34.12-2015). For verification, the encryption modes CBC, ECB will be used.

Aes-generic and shaxxx-generic modules are considered as prototypes of these modules. Accordingly, the following modules should be implemented for Russian cryptography:

  • gosthash-generic (GOST K 34.11-94);
  • stribog256-generic (GOST R 34.11-2012 with a hash length of 256 bits);
  • stribog512-generic (GOST R 34.11-2012 with a hash length of 512 bits);
  • gost-generic (GOST 28147-89, Magma);
  • kuznyechik-generic ("Grasshopper").

The main question is where to get the implementation of Russian cryptographic algorithms? One option is OpenSSL and support for GOST algorithms in engine gost. However, to date, the implementation of only GOST 28147-89 and GOST R 34.11-94 is supported. More acceptable is the support of Russian cryptographic algorithms in the GCrypt-1.7.0 project , which already has support for the Magma algorithm (GOST R 34.12-2015) and GOST R 34.11-2012 with a hash length of 256 bits (STRIBOG-256) and a length 512 bit hash (STRIBOG-512).

As for Grasshopper, the article on Habrahabr “GOST R 34.12-15 on SSE2, or Grasshopper Is Not So Bad” will help here .

The modules were assembled for the following Linux kernel:

bash-4.3$ uname -sr
Linux 4.4.39-desktop-1.mga5
bash-4.3$

Other kernels may require some changes. We will show the assembly of CryptoAPI modules that implement Russian crypto algorithms using the stribog256-generic module as an example (GOST R 34.11-2012 with a hash length of aaa 256 bits).

So the Makefile:

obj-m := stribog256_generic.o
my-objs := stribog.o
KDIR  := /lib/modules/$(shell uname -r)/build
PWD   := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean
install:
	$(MAKE) -C $(KDIR) M=$(PWD) modules_install

We also list the contents of the stribog256_generic directory:

bash-4.3$ ls 
rypto_mult_table.h
hash_bit.h
Makefile
stribog256_generic.c
stribog256.h
stribog.c
stribog.h
bash-4.3$	

To build the module, just enter the stribog256 directory and run the make command:

bash-4.3$ make
make -C /lib/modules/4.4.39-desktop-1.mga5/build M=/home/a513/DM_CRYPT/dm-crypt/stribog256 modules
make[1]: вход в каталог «/usr/src/kernel-4.4.39-desktop-1.mga5»
  CC [M]  /home/a513/DM_CRYPT/dm-crypt/stribog256/stribog256_generic.o
…
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/a513/DM_CRYPT/dm-crypt/stribog256/stribog256_generic.mod.o
  LD [M]  /home/a513/DM_CRYPT/dm-crypt/stribog256/stribog256_generic.ko
make[1]: выход из каталога «/usr/src/kernel-4.4.39-desktop-1.mga5»
bash-4.3$ 

The code for the stribog256_generic.c module is as follows:

The code for the stribog256_generic.c module is as follows:
bash-4.3$ cat stribog256_generic.c 

/
*
 * Cryptographic API.
 *
 * Stribog256 Secure Hash Algorithm.
 *
 * 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 
#include 
#include 
#include 
#include 
#include "stribog256.h"
#include "stribog.c"
static int stribog256_init(struct shash_desc *desc)
{
        struct stribog_ctx *sctx = shash_desc_ctx(desc);
        GOSTR3411_2012_256_Init(sctx);
        return 0;
}
int crypto_stribog256_update(struct shash_desc *desc, const u8 *data,
                        u32 len)
{
        struct stribog_ctx *sctx = shash_desc_ctx(desc);
        GOSTR3411_2012_Update(sctx, data, len); 
        return 0;
}
EXPORT_SYMBOL(crypto_stribog256_update);
/* Add padding and return the message digest. */
static int stribog256_final(struct shash_desc *desc, u8 *out)
{
        struct stribog_ctx *sctx = shash_desc_ctx(desc);
        GOSTR3411_2012_256_Final(sctx, out);
        // Wipe context 
        memset(sctx, 0, sizeof(*sctx));
        return 0;
}
static int stribog256_export(struct shash_desc *desc, void *out)
{
        struct stribog_ctx *sctx = shash_desc_ctx(desc);
        memcpy(out, sctx, sizeof(*sctx));
        return 0;
}
static int stribog256_import(struct shash_desc *desc, const void *in)
{
        struct stribog_ctx *sctx = shash_desc_ctx(desc);
        memcpy(sctx, in, sizeof(*sctx));
        return 0;
}
static struct shash_alg alg = {
        .digestsize     =       STRIBOG256_DIGEST_SIZE,
        .init           =       stribog256_init,
        .update         =       crypto_stribog256_update,
        .final          =       stribog256_final,
        .export         =       stribog256_export,
        .import         =       stribog256_import,
        .descsize       =       sizeof(struct stribog_ctx),
        .statesize      =       sizeof(struct stribog_ctx),
        .base           =       {
                .cra_name       =       "stribog256",
                .cra_driver_name=       "stribog256-generic",
                .cra_flags      =       CRYPTO_ALG_TYPE_SHASH,
                .cra_blocksize  =       STRIBOG_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
};
static int __init stribog256_generic_mod_init(void)
{
        return crypto_register_shash(&alg);
}
static void __exit stribog256_generic_mod_fini(void)
{
        crypto_unregister_shash(&alg);
}
module_init(stribog256_generic_mod_init);
module_exit(stribog256_generic_mod_fini);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Stribog256 Secure Hash Algorithm");
MODULE_ALIAS_CRYPTO("stribog256");
MODULE_ALIAS_CRYPTO("stribog256-generic");

bash-4.3$


According to a similar scheme, the remaining modules are prepared and assembled:

bash-4.3$ ls -C1
gost_generic.ko
gosthash_generic.ko
kuznyechik_generic.ko
stribog256_generic.ko
stribog512_generic.ko
bash-4.3$

Now they can be loaded into the system:

bash-4.3#insmod ./ stribog256_generic.ko
bash-4.3#

Now let's see what algorithms CryptoAPI supports:

bash-4.3$ /usr/local/bin64/cryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1       679129 iterations per second
PBKDF2-sha256     544431 iterations per second
PBKDF2-sha512     355208 iterations per second
PBKDF2-gosthash   138994 iterations per second
PBKDF2-stribog256  123187 iterations per second
PBKDF2-stribog512   91275 iterations per second
#  Algorithm | Key |  Encryption |  Decryption
     aes-cbc   128b   468,0 MiB/s  1700,7 MiB/s
 serpent-cbc   128b    74,0 MiB/s   266,9 MiB/s
     aes-cbc   256b   349,2 MiB/s  1349,4 MiB/s
 serpent-cbc   256b    72,8 MiB/s   259,1 MiB/s
    gost-cbc   256b    38,3 MiB/s    46,8 MiB/s
kuznyechik-cbc   256b     3,6 MiB/s     3,2 MiB/s
bash-4.3$ 

In order for GOST algorithms to appear during testing (benchmark parameter), it is enough to make changes to the following files in the cryptsetup utility:

1. ./cryptsetup/src/cryptsetup.c (lines are added only for the testing team)

static struct {
		const char *cipher;
		const char *mode;
		size_t key_size;
		size_t iv_size;
	} bciphers[] = {
		{ "aes",     "cbc", 16, 16 },
		{ "serpent", "cbc", 16, 16 },
		{ "aes",     "cbc", 32, 16 },
		{ "serpent", "cbc", 32, 16 },
/*ГОСТ*/
		{ "gost", "cbc", 32, 8 },
		{ "gost", "ecb", 32, 8 },
		{ "gost", "crt", 32, 8 },
		{ "kuznyechik", "cbc", 32, 16 },
		{  NULL, NULL, 0, 0 }
	};

2. ./cryptsetup/lib/crypto_backend/crypto_cipher_kernel.c

static struct cipher_alg cipher_algs[] = {
    { "cipher_null", 16 },
    { "aes",         16 },
    { "serpent",     16 },
    { "twofish",     16 },
    { "anubis",      16 },
    { "blowfish",     8 },
    { "camellia",    16 },
    { "cast5",        8 },
    { "cast6",       16 },
    { "des",          8 },
    { "des3_ede",     8 },
    { "khazad",       8 },
    { "seed",        16 },
    { "tea",          8 },
    { "xtea",         8 },
/*ГОСТ*/
    { "gost",         8 },
    { "kuznyechik",         8 },
    { NULL,           0 }
};

3. ./cryptsetup/lib/crypto_backend/crypto_kernel.c

static struct hash_alg hash_algs[] = {
    { "sha1",      "sha1",   20,  64 },
/*ГОСТ*/
    { "gosthash",      "gosthash",   32,  64 },
    { "stribog256",      "stribog256",   32,  128 },
    { "stribog512",      "stribog512",   64,  128 },
    { "sha256",    "sha256", 32,  64 },
    { "sha512",    "sha512", 64, 128 },
    { "ripemd160", "rmd160", 20,  64 },
    { "whirlpool", "wp512",  64,  64 },
    { NULL,        NULL,      0,   0 }
};

You can not make these changes, but then you need to test the algorithms with an explicit indication of the cipher and mode (mode). Moreover, this is the only and only way we can check the GOST ciphers in ECB mode:

bash-4.3$ /usr/local/bin64/cryptsetup benchmark -cgost-ecb
# Tests are approximate using memory only (no storage IO).
#  Algorithm | Key |  Encryption |  Decryption
    gost-ecb   256b    50,4 MiB/s    49,2 MiB/s
bash-4.3$ /usr/local/bin64/cryptsetup  benchmark  -ckuznyechik-ecb
# Tests are approximate using memory only (no storage IO).
#  Algorithm | Key |  Encryption |  Decryption
kuznyechik-ecb   256b     3,4 MiB/s     3,2 MiB/s
bash-4.3$# Tests are approximate using memory only (no storage IO).
bash-4.3$ 
#  Algorithm | Key |  Encryption |  Decryption
     aes-ecb   256b  1361,8 MiB/s  1381,5 MiB/s
bash-4.3$ 

And so we figured out the modules. Now you can create a secure file system with encryption on GOST. First, create the test.bin file:

# dd if=/dev/zero of=/tmp/test.bin bs=10M count=50
50+0 записей получено
50+0 записей отправлено
 скопировано 524288000 байт (524 MB), 0,44706 c, 1,2 GB/c
[root@VOrlov_64 tmp]#

We will create the encrypted file system in this file:

[root@VOrlov_64 tmp]# /usr/local/bin64/cryptsetup - kuznyechik-ecb -h stribog256 -y luksFormat /tmp/test.bin
WARNING!
========
This will overwrite data on /tmp/test.bin irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase: 01234567
Verify passphrase: 01234567
[root@VOrlov_64 tmp]#

File System Connection:

#cryptsetup luksOpen <устройство/файл> volume1

And so we connect our protected FS to volume1:

[root@VOrlov_64 tmp]# /usr/local/bin64/cryptsetup luksOpen /tmp/test.bin volume1
Enter passphrase for /tmp/test.bin: 
[root@VOrlov_64 tmp]#

Next, we work with the device / dev / mapper / volume1 as with a regular hard disk partition.

View file system options:

root@VOrlov_64 tmp]# /usr/local/bin64/cryptsetup status /dev/mapper/volume1
/dev/mapper/volume1 is active.
  type:    LUKS1
  cipher:  kuznyechik-ecb
  keysize: 256 bits
  device:  /dev/loop0
  loop:    /tmp/test.bin
  offset:  4096 sectors
  size:    1019904 sectors
  mode:    read/write
[root@VOrlov_64 tmp]# 

After that, just create a file system (FS) on the device / dev / mapper / volume1:

#mkfs.ext4 /dev/mapper/volume1
#

We mount the FS and work with it:

#mount /dev/mapper/volume1 /mount/TEST_DM_CRYPT_GOST
#

That's it, now we can create encrypted FS on GOST 28147-89 (aka GOST R 34.12-2015 Magma) and GOST R 34.12-2015 Grasshopper) in CBC, ECB modes. As a hashing algorithm, GOST R 34.11-94), stribog256 (GOST R 34.11-2012 256 bit) and stribog512 (GOST R 34.11-2012 512 bit) can be used.

Also popular now: