Hi, I'm implementing a new cipher block within the kernel and I'm stuck into a problem. My algorithm works pretty well, it can cipher and decipher a block. The algorithm also works with ECB, CBC, and CTR modes, however when I try to use the modes such as XTS or LRW I have the following errors which are attached. Did I need to add more code to make it work with XTS and other modes ? Cheers, -- Jonathan "Coldshell" Thieuleux Mail : jonathan.thieuleux@xxxxxxxxx IRC : coldshell [Freenode, OFTC] Shaarli : https://links.stdcall.me/ "If you write interfaces with more than 4 or 5 function arguments, it's possible that you and I cannot be friends." -- David Miller
-----------------------------Cryptsetup---------------------------- $sudo cryptsetup luksFormat --debug --cipher gost-xts-plain64 ~/test # cryptsetup 1.6.6 processing "cryptsetup luksFormat --debug --cipher gost-xts-plain64 /home/coldshell/test" # Running command luksFormat. # Locking memory. # Installing SIGINT/SIGTERM handler. # Unblocking interruption on signal. WARNING! ======== This will overwrite data on /home/coldshell/test irrevocably. Are you sure? (Type uppercase yes): YES # Allocating crypt device /home/coldshell/test context. # Trying to open and read device /home/coldshell/test. # Initialising device-mapper backend library. # Timeout set to 0 miliseconds. # Iteration time set to 1000 miliseconds. # Interactive passphrase entry requested. Enter passphrase: Verify passphrase: # Formatting device /home/coldshell/test as type LUKS1. # Crypto backend (gcrypt 1.6.3) initialized. # Detected kernel Linux 3.19.3-3-ARCH x86_64. # Topology info for /home/coldshell/test not supported, using default offset 1048576 bytes. # Checking if cipher gost-xts-plain64 is usable. # Userspace crypto wrapper cannot use gost-xts-plain64 (-2). # Using dmcrypt to access keyslot area. # Allocating a free loop device. # Trying to open and read device /dev/loop0. # Calculated device size is 8 sectors (RW), offset 0. # dm version OF [16384] (*1) # dm versions OF [16384] (*1) # Detected dm-crypt version 1.13.0, dm-ioctl version 4.29.0. # Device-mapper backend running with UDEV support enabled. # DM-UUID is CRYPT-TEMP-temporary-cryptsetup-1570 # Udev cookie 0xd4dffcb (semid 11042818) created # Udev cookie 0xd4dffcb (semid 11042818) incremented to 1 # Udev cookie 0xd4dffcb (semid 11042818) incremented to 2 # Udev cookie 0xd4dffcb (semid 11042818) assigned to CREATE task(0) with flags DISABLE_SUBSYSTEM_RULES DISABLE_DISK_RULES DISABLE_OTHER_RULES (0xe) # dm create temporary-cryptsetup-1570 CRYPT-TEMP-temporary-cryptsetup-1570 OF [16384] (*1) # dm reload temporary-cryptsetup-1570 OFRW [16384] (*1) device-mapper: reload ioctl on failed: Invalid argument # Udev cookie 0xd4dffcb (semid 11042818) decremented to 1 # Udev cookie 0xd4dffcb (semid 11042818) incremented to 2 # Udev cookie 0xd4dffcb (semid 11042818) assigned to REMOVE task(2) with flags DISABLE_SUBSYSTEM_RULES DISABLE_DISK_RULES DISABLE_OTHER_RULES (0xe) # dm remove temporary-cryptsetup-1570 OFRW [16384] (*1) # temporary-cryptsetup-1570: Stacking NODE_DEL [verify_udev] # Udev cookie 0xd4dffcb (semid 11042818) decremented to 0 # Udev cookie 0xd4dffcb (semid 11042818) waiting for zero # Udev cookie 0xd4dffcb (semid 11042818) destroyed # temporary-cryptsetup-1570: Processing NODE_DEL [verify_udev] Failed to setup dm-crypt key mapping for device /home/coldshell/test. Check that kernel supports gost-xts-plain64 cipher (check syslog for more info). # Releasing crypt device /home/coldshell/test context. # Releasing device-mapper backend. # Closed loop /dev/loop0 (/home/coldshell/test). # Unlocking memory. Command failed with code 5: Failed to setup dm-crypt key mapping for device /home/coldshell/test. Check that kernel supports gost-xts-plain64 cipher (check syslog for more info). -----------------------------------Dmesg--------------------------------- $dmesg [159333.709726] device-mapper: table: 254:0: crypt: Error allocating crypto tfm [159333.709734] device-mapper: ioctl: error adding target to table -----------------------------------Debug--------------------------------- When I debug, it fails at the function crypto_alloc_ablkcipher(), see below: file : /drivers/md/dm-crypt.c 1399│ static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode) 1400│ { 1401│ unsigned i; 1402│ int err; 1403│ 1404│ cc->tfms = kmalloc(cc->tfms_count * sizeof(struct crypto_ablkcipher *), 1405│ GFP_KERNEL); 1406│ if (!cc->tfms) 1407│ return -ENOMEM; 1408│ 1409│ for (i = 0; i < cc->tfms_count; i++) { 1410│ cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0); 1411├───────────────> if (IS_ERR(cc->tfms[i])) { 1412│ err = PTR_ERR(cc->tfms[i]); 1413│ crypt_free_tfms(cc); 1414│ return err; 1415│ } 1416│ } 1417│ 1418│ return 0; 1419│ } 1420│ (gdb) p/x cc->tfms[i] $1 = 0xffffffffffffffea Input of the function : crypto_alloc_ablkcipher (alg_name=0xffff880039607cc0 "xts(gost)", type=0, mask=0) at crypto/ablkcipher.c:676
name : xts(gost) driver : xts(gost-generic) module : kernel priority : 100 refcnt : 1 selftest : passed type : givcipher async : no blocksize : 8 min keysize : 64 max keysize : 64 ivsize : 8 geniv : eseqiv name : xts(gost) driver : xts(gost-generic) module : kernel priority : 100 refcnt : 1 selftest : passed type : blkcipher blocksize : 8 min keysize : 64 max keysize : 64 ivsize : 8 geniv : <default> name : xts(aes) driver : xts(aes-generic) module : kernel priority : 100 refcnt : 1 selftest : passed type : givcipher async : no blocksize : 16 min keysize : 32 max keysize : 64 ivsize : 16 geniv : eseqiv name : xts(aes) driver : xts(aes-generic) module : kernel priority : 100 refcnt : 1 selftest : passed type : blkcipher blocksize : 16 min keysize : 32 max keysize : 64 ivsize : 16 geniv : <default> name : gost driver : gost-generic module : kernel priority : 100 refcnt : 1 selftest : passed type : cipher blocksize : 8 min keysize : 32 max keysize : 32 name : stribog-256 driver : stribog-256-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 32 name : stribog-512 driver : stribog-512-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 64 name : ghash driver : ghash-generic module : kernel priority : 100 refcnt : 1 selftest : passed type : shash blocksize : 16 digestsize : 16 name : stdrng driver : krng module : kernel priority : 200 refcnt : 2 selftest : passed type : rng seedsize : 0 name : crc32c driver : crc32c-generic module : kernel priority : 100 refcnt : 2 selftest : passed type : shash blocksize : 1 digestsize : 4 name : ecb(arc4) driver : ecb(arc4)-generic module : kernel priority : 100 refcnt : 1 selftest : passed type : blkcipher blocksize : 1 min keysize : 1 max keysize : 256 ivsize : 0 geniv : <default> name : arc4 driver : arc4-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : cipher blocksize : 1 min keysize : 1 max keysize : 256 name : cast5 driver : cast5-generic module : kernel priority : 100 refcnt : 1 selftest : passed type : cipher blocksize : 8 min keysize : 5 max keysize : 16 name : aes driver : aes-generic module : kernel priority : 100 refcnt : 1 selftest : passed type : cipher blocksize : 16 min keysize : 16 max keysize : 32 name : des3_ede driver : des3_ede-generic module : kernel priority : 100 refcnt : 1 selftest : passed type : cipher blocksize : 8 min keysize : 24 max keysize : 24 name : des driver : des-generic module : kernel priority : 100 refcnt : 1 selftest : passed type : cipher blocksize : 8 min keysize : 8 max keysize : 8 name : tgr128 driver : tgr128-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 16 name : tgr160 driver : tgr160-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 20 name : tgr192 driver : tgr192-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 24 name : wp256 driver : wp256-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 32 name : wp384 driver : wp384-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 48 name : wp512 driver : wp512-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 64 name : sha384 driver : sha384-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 128 digestsize : 48 name : sha512 driver : sha512-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 128 digestsize : 64 name : sha224 driver : sha224-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 28 name : sha256 driver : sha256-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 32 name : sha1 driver : sha1-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 20 name : md5 driver : md5-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 64 digestsize : 16 name : digest_null driver : digest_null-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : shash blocksize : 1 digestsize : 0 name : compress_null driver : compress_null-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : compression name : ecb(cipher_null) driver : ecb-cipher_null module : kernel priority : 100 refcnt : 1 selftest : passed type : blkcipher blocksize : 1 min keysize : 0 max keysize : 0 ivsize : 0 geniv : <default> name : cipher_null driver : cipher_null-generic module : kernel priority : 0 refcnt : 1 selftest : passed type : cipher blocksize : 1 min keysize : 0 max keysize : 0
/* * * * Based on "Applied Cryptography" book * Dev: * Me */ #include <linux/init.h> #include <linux/module.h> #include <linux/scatterlist.h> #include <linux/crypto.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/errno.h> #include <crypto/gost28147-89.h> int gost_expand_key(struct gost_ctx *CTX, const u8 *key, unsigned int keylen) { if(unlikely(keylen != GOST_MAX_KEY_SIZE)) goto gost_expand_keysize_err; memset(CTX, 0, sizeof(struct gost_ctx)); /* Copy of the cipher key */ memcpy(CTX->key_enc, key, keylen); if(IS_ERR(CTX->key_dec)) goto gost_expand_copy_err; /* Copy of the decipher key */ memcpy(CTX->key_dec, key, keylen); if(IS_ERR(CTX->key_dec)) goto gost_expand_copy_err; CTX->key_length = keylen; CTX->sbox = &gost_sboxes[0]; return 0; gost_expand_keysize_err: pr_err("An error occurred with the key size, key size is %u," "expected size is %u\n", keylen, GOST_MAX_KEY_SIZE); return -1; gost_expand_copy_err: pr_err("An error occurred during the copy of the structure\n"); return -2; } inline void split_in_two(const u8 *src, u32 block[2]) { /* MSB */ block[0] = *(u32 *) src; /* LSB */ block[1] = *(u32 *) (src + sizeof(u32)); } inline void merge_in_one(u32 block[2], u8 *dst) { dst[0] = block[0] & 0xFF; dst[1] = block[0] >> 8 & 0xFF; dst[2] = block[0] >> 16 & 0xFF; dst[3] = block[0] >> 24 & 0xFF; dst[4] = block[1] & 0xFF; dst[5] = block[1] >> 8 & 0xFF; dst[6] = block[1] >> 16 & 0xFF; dst[7] = block[1] >> 24 & 0xFF; } inline u32 transform(u32 cm1, struct gost_ctx *CTX){ cm1 = (uint32_t) (CTX->sbox->sbox[7][(cm1>>28) & 0xF]<< 28 | CTX->sbox->sbox[6][cm1>>24 & 0xF] << 24 | CTX->sbox->sbox[5][cm1>>20 & 0xF] << 20 | CTX->sbox->sbox[4][cm1>>16 & 0xF] << 16 | CTX->sbox->sbox[3][cm1>>12 & 0xF] << 12 | CTX->sbox->sbox[2][cm1>> 8 & 0xF] << 8 | CTX->sbox->sbox[1][cm1>> 4 & 0xF] << 4 | CTX->sbox->sbox[0][cm1 & 0xF]); return (cm1 << 11) | (cm1 >> 21); } int gost_setkey(struct crypto_tfm * tfm, const u8 * key, unsigned int keylen) { int ret; struct gost_ctx *CTX = crypto_tfm_ctx(tfm); ret = gost_expand_key(CTX, key, keylen); if(unlikely(ret != 0)) goto gost_expand_err; return 0; gost_expand_err: pr_err("An error occurred during initialization of the key\n"); return -1; } EXPORT_SYMBOL(gost_setkey); void gost_encrypt(struct crypto_tfm * tfm, u8 * dst, const u8 * src) { u32 in[2], out[2]; register u32 n1, n2; /* see rfc5830 */ struct gost_ctx *CTX = crypto_tfm_ctx(tfm); split_in_two(src, in); n1 = in[1]; /* R_{i-1} (lsb)*/ n2 = in[0]; /* L_{i-1} (msb) */ n2 ^= transform(n1+CTX->key_enc[0], CTX);/* n2 = R_{i}; n1 = R_{i-1} = L_{i} */ n1 ^= transform(n2+CTX->key_enc[1], CTX);/* n1 = R{i+1}; n2 = R_{i} = L_{i+1} */ n2 ^= transform(n1+CTX->key_enc[2], CTX); n1 ^= transform(n2+CTX->key_enc[3], CTX); n2 ^= transform(n1+CTX->key_enc[4], CTX); n1 ^= transform(n2+CTX->key_enc[5], CTX); n2 ^= transform(n1+CTX->key_enc[6], CTX); n1 ^= transform(n2+CTX->key_enc[7], CTX); n2 ^= transform(n1+CTX->key_enc[0], CTX); n1 ^= transform(n2+CTX->key_enc[1], CTX); n2 ^= transform(n1+CTX->key_enc[2], CTX); n1 ^= transform(n2+CTX->key_enc[3], CTX); n2 ^= transform(n1+CTX->key_enc[4], CTX); n1 ^= transform(n2+CTX->key_enc[5], CTX); n2 ^= transform(n1+CTX->key_enc[6], CTX); n1 ^= transform(n2+CTX->key_enc[7], CTX); n2 ^= transform(n1+CTX->key_enc[0], CTX); n1 ^= transform(n2+CTX->key_enc[1], CTX); n2 ^= transform(n1+CTX->key_enc[2], CTX); n1 ^= transform(n2+CTX->key_enc[3], CTX); n2 ^= transform(n1+CTX->key_enc[4], CTX); n1 ^= transform(n2+CTX->key_enc[5], CTX); n2 ^= transform(n1+CTX->key_enc[6], CTX); n1 ^= transform(n2+CTX->key_enc[7], CTX); n2 ^= transform(n1+CTX->key_enc[7], CTX); n1 ^= transform(n2+CTX->key_enc[6], CTX); n2 ^= transform(n1+CTX->key_enc[5], CTX); n1 ^= transform(n2+CTX->key_enc[4], CTX); n2 ^= transform(n1+CTX->key_enc[3], CTX); n1 ^= transform(n2+CTX->key_enc[2], CTX); n2 ^= transform(n1+CTX->key_enc[1], CTX); n1 ^= transform(n2+CTX->key_enc[0], CTX); /* In the RFC order - N1, then N2 */ out[0] = n2; out[1] = n1; merge_in_one(out, dst); } EXPORT_SYMBOL(gost_encrypt); void gost_decrypt(struct crypto_tfm * tfm, u8 * dst, const u8 * src) { u32 in[2], out[2]; register u32 n1, n2; /* see rfc5830 */ struct gost_ctx *CTX = crypto_tfm_ctx(tfm); split_in_two(src, in); n1 = in[0]; /* R_{i-1} (lsb)*/ n2 = in[1]; /* L_{i-1} (msb) */ n2 ^= transform(n1+CTX->key_dec[0], CTX); /* n2 = R_{i}; n1 = R_{i-1} = L_{i} */ n1 ^= transform(n2+CTX->key_dec[1], CTX); /* n1 = R_{i+1}; n2 = R_{i} = L_{i+1} */ n2 ^= transform(n1+CTX->key_dec[2], CTX); n1 ^= transform(n2+CTX->key_dec[3], CTX); n2 ^= transform(n1+CTX->key_dec[4], CTX); n1 ^= transform(n2+CTX->key_dec[5], CTX); n2 ^= transform(n1+CTX->key_dec[6], CTX); n1 ^= transform(n2+CTX->key_dec[7], CTX); n2 ^= transform(n1+CTX->key_dec[7], CTX); n1 ^= transform(n2+CTX->key_dec[6], CTX); n2 ^= transform(n1+CTX->key_dec[5], CTX); n1 ^= transform(n2+CTX->key_dec[4], CTX); n2 ^= transform(n1+CTX->key_dec[3], CTX); n1 ^= transform(n2+CTX->key_dec[2], CTX); n2 ^= transform(n1+CTX->key_dec[1], CTX); n1 ^= transform(n2+CTX->key_dec[0], CTX); n2 ^= transform(n1+CTX->key_dec[7], CTX); n1 ^= transform(n2+CTX->key_dec[6], CTX); n2 ^= transform(n1+CTX->key_dec[5], CTX); n1 ^= transform(n2+CTX->key_dec[4], CTX); n2 ^= transform(n1+CTX->key_dec[3], CTX); n1 ^= transform(n2+CTX->key_dec[2], CTX); n2 ^= transform(n1+CTX->key_dec[1], CTX); n1 ^= transform(n2+CTX->key_dec[0], CTX); n2 ^= transform(n1+CTX->key_dec[7], CTX); n1 ^= transform(n2+CTX->key_dec[6], CTX); n2 ^= transform(n1+CTX->key_dec[5], CTX); n1 ^= transform(n2+CTX->key_dec[4], CTX); n2 ^= transform(n1+CTX->key_dec[3], CTX); n1 ^= transform(n2+CTX->key_dec[2], CTX); n2 ^= transform(n1+CTX->key_dec[1], CTX); n1 ^= transform(n2+CTX->key_dec[0], CTX); out[0] = n1; out[1] = n2; merge_in_one(out, dst); } EXPORT_SYMBOL(gost_decrypt); static struct crypto_alg gost_alg = { .cra_name = "gost", .cra_driver_name = "gost-generic", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = GOST_BLOCK_SIZE, .cra_ctxsize = sizeof(struct gost_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, .cra_u = { .cipher = { .cia_min_keysize = GOST_MIN_KEY_SIZE, .cia_max_keysize = GOST_MAX_KEY_SIZE, .cia_setkey = gost_setkey, .cia_encrypt = gost_encrypt, .cia_decrypt = gost_decrypt } } }; static int __init gost_init(void) { pr_info("Initialization : GOST 28147-89 module\n"); return crypto_register_alg(&gost_alg); } static void __exit gost_exit(void) { pr_info("Exit : GOST 28147-89 module\n"); crypto_unregister_alg(&gost_alg); } module_init(gost_init); module_exit(gost_exit); MODULE_DESCRIPTION("GOST 28147-89 cipher algorithm"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CRYPTO("gost28147-89"); MODULE_ALIAS_CRYPTO("gost89");
#ifndef GOST28147_89 #define GOST28147_89 #include <linux/types.h> #define GOST_BLOCK_SIZE 8 #define GOST_MIN_KEY_SIZE 32 #define GOST_MAX_KEY_SIZE 32 struct gost_s_box { char *name; char *oid; u8 sbox[8][16]; u8 sbox_opti[4][256]; }; struct gost_ctx { u8 key_enc[GOST_MAX_KEY_SIZE]; u8 key_dec[GOST_MAX_KEY_SIZE]; u8 key_length; struct gost_s_box *sbox; }; static struct gost_s_box gost_sboxes[] = { /*Russian Central Bank*/ { "test_3411", "1.2.643.2.2.30.0", { {0x4, 0xA, 0x9, 0x2, 0xD, 0x8, 0x0, 0xE, 0x6, 0xB, 0x1, 0xC, 0x7, 0xF, 0x5, 0x3}, {0xE, 0xB, 0x4, 0xC, 0x6, 0xD, 0xF, 0xA, 0x2, 0x3, 0x8, 0x1, 0x0, 0x7, 0x5, 0x9}, {0x5, 0x8, 0x1, 0xD, 0xA, 0x3, 0x4, 0x2, 0xE, 0xF, 0xC, 0x7, 0x6, 0x0, 0x9, 0xB}, {0x7, 0xD, 0xA, 0x1, 0x0, 0x8, 0x9, 0xF, 0xE, 0x4, 0x6, 0xC, 0xB, 0x2, 0x5, 0x3}, {0x6, 0xC, 0x7, 0x1, 0x5, 0xF, 0xD, 0x8, 0x4, 0xA, 0x9, 0xE, 0x0, 0x3, 0xB, 0x2}, {0x4, 0xB, 0xA, 0x0, 0x7, 0x2, 0x1, 0xD, 0x3, 0x6, 0x8, 0x5, 0x9, 0xC, 0xF, 0xE}, {0xD, 0xB, 0x4, 0x1, 0x3, 0xF, 0x5, 0x9, 0x0, 0xA, 0xE, 0x7, 0x6, 0x8, 0x2, 0xC}, {0x1, 0xF, 0xD, 0x0, 0x5, 0x7, 0xA, 0x4, 0x9, 0x2, 0x3, 0xE, 0x6, 0xB, 0x8, 0xC} }, { {0},{0},{0},{0} } } }; #endif /* GOST28147_89 */