2007-09-03 21:57:01

by Rik Snel

[permalink] [raw]
Subject: [PATCH] an XTS blockcipher mode implementation without partial blocks

XTS currently considered to be the successor of the LRW mode by the IEEE1619
workgroup. LRW was discarded, because it was not secure if the encyption key
itself is encrypted with LRW.

XTS does not have this problem. The implementation is pretty straightforward,
a new function was added to gf128mul to handle GF(128) elements in ble format.
Four testvectors from the specification
http://grouper.ieee.org/groups/1619/email/pdf00086.pdf
were added, and they verify on my system.

Signed-off-by: Rik Snel <[email protected]>
---
crypto/Kconfig | 11 ++
crypto/Makefile | 1 +
crypto/gf128mul.c | 11 ++
crypto/tcrypt.c | 12 ++
crypto/tcrypt.h | 417 +++++++++++++++++++++++++++++++++++++++++++++
crypto/xts.c | 277 ++++++++++++++++++++++++++++++
include/crypto/gf128mul.h | 2 +
7 files changed, 731 insertions(+), 0 deletions(-)
create mode 100644 crypto/xts.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 3d1a1e2..de94549 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -183,6 +183,17 @@ config CRYPTO_LRW
The first 128, 192 or 256 bits in the key are used for AES and the
rest is used to tie each cipher block to its logical position.

+config CRYPTO_XTS
+ tristate "XTS support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_MANAGER
+ select CRYPTO_GF128MUL
+ help
+ XTS: IEEE1619/D16 narrow block cipher use with aes-xts-plain,
+ key size 256, 384 or 512 bits. This implementation currently
+ can't handle a sectorsize which is not a multiple of 16 bytes.
+
config CRYPTO_CRYPTD
tristate "Software async crypto daemon"
select CRYPTO_ABLKCIPHER
diff --git a/crypto/Makefile b/crypto/Makefile
index 0cf17f1..c4a2bed 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_CRYPTO_ECB) += ecb.o
obj-$(CONFIG_CRYPTO_CBC) += cbc.o
obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
obj-$(CONFIG_CRYPTO_LRW) += lrw.o
+obj-$(CONFIG_CRYPTO_XTS) += xts.o
obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
obj-$(CONFIG_CRYPTO_DES) += des.o
obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
diff --git a/crypto/gf128mul.c b/crypto/gf128mul.c
index 0a2aadf..ecbeaa1 100644
--- a/crypto/gf128mul.c
+++ b/crypto/gf128mul.c
@@ -142,6 +142,17 @@ static void gf128mul_x_bbe(be128 *r, const be128 *x)
r->b = cpu_to_be64((b << 1) ^ _tt);
}

+void gf128mul_x_ble(be128 *r, const be128 *x)
+{
+ u64 a = le64_to_cpu(x->a);
+ u64 b = le64_to_cpu(x->b);
+ u64 _tt = gf128mul_table_bbe[b >> 63];
+
+ r->a = cpu_to_le64((a << 1) ^ _tt);
+ r->b = cpu_to_le64((b << 1) | (a >> 63));
+}
+EXPORT_SYMBOL(gf128mul_x_ble);
+
static void gf128mul_x8_lle(be128 *x)
{
u64 a = be64_to_cpu(x->a);
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 11f9359..d749106 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -955,6 +955,10 @@ static void do_test(void)
AES_LRW_ENC_TEST_VECTORS);
test_cipher("lrw(aes)", DECRYPT, aes_lrw_dec_tv_template,
AES_LRW_DEC_TEST_VECTORS);
+ test_cipher("xts(aes)", ENCRYPT, aes_xts_enc_tv_template,
+ AES_XTS_ENC_TEST_VECTORS);
+ test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
+ AES_XTS_DEC_TEST_VECTORS);

//CAST5
test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
@@ -1132,6 +1136,10 @@ static void do_test(void)
AES_LRW_ENC_TEST_VECTORS);
test_cipher("lrw(aes)", DECRYPT, aes_lrw_dec_tv_template,
AES_LRW_DEC_TEST_VECTORS);
+ test_cipher("xts(aes)", ENCRYPT, aes_xts_enc_tv_template,
+ AES_XTS_ENC_TEST_VECTORS);
+ test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
+ AES_XTS_DEC_TEST_VECTORS);
break;

case 11:
@@ -1307,6 +1315,10 @@ static void do_test(void)
aes_lrw_speed_template);
test_cipher_speed("lrw(aes)", DECRYPT, sec, NULL, 0,
aes_lrw_speed_template);
+ test_cipher_speed("xts(aes)", ENCRYPT, sec, NULL, 0,
+ aes_xts_speed_template);
+ test_cipher_speed("xts(aes)", DECRYPT, sec, NULL, 0,
+ aes_xts_speed_template);
break;

case 201:
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 887527b..03a9445 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -2144,6 +2144,8 @@ static struct cipher_testvec cast6_dec_tv_template[] = {
#define AES_CBC_DEC_TEST_VECTORS 2
#define AES_LRW_ENC_TEST_VECTORS 8
#define AES_LRW_DEC_TEST_VECTORS 8
+#define AES_XTS_ENC_TEST_VECTORS 4
+#define AES_XTS_DEC_TEST_VECTORS 4

static struct cipher_testvec aes_enc_tv_template[] = {
{ /* From FIPS-197 */
@@ -2784,6 +2786,400 @@ static struct cipher_testvec aes_lrw_dec_tv_template[] = {
}
};

+static struct cipher_testvec aes_xts_enc_tv_template[] = {
+ /* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */
+ { /* XTS-AES 1 */
+ .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .klen = 32,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .ilen = 32,
+ .result = { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec,
+ 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92,
+ 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85,
+ 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e },
+ .rlen = 32,
+ }, { /* XTS-AES 2 */
+ .key = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
+ .klen = 32,
+ .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
+ .ilen = 32,
+ .result = { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e,
+ 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b,
+ 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4,
+ 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 },
+ .rlen = 32,
+ }, { /* XTS-AES 3 */
+ .key = { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
+ .klen = 32,
+ .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
+ .ilen = 32,
+ .result = { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a,
+ 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2,
+ 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53,
+ 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 },
+ .rlen = 32,
+ }, { /* XTS-AES 4 */
+ .key = { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
+ 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
+ 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
+ 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 },
+ .klen = 32,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff },
+ .ilen = 512,
+ .result = { 0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
+ 0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
+ 0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
+ 0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
+ 0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
+ 0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
+ 0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
+ 0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
+ 0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5,
+ 0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5,
+ 0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc,
+ 0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce,
+ 0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4,
+ 0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84,
+ 0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a,
+ 0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65,
+ 0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89,
+ 0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51,
+ 0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15,
+ 0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8,
+ 0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed,
+ 0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91,
+ 0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e,
+ 0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34,
+ 0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b,
+ 0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5,
+ 0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4,
+ 0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c,
+ 0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd,
+ 0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3,
+ 0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f,
+ 0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e,
+ 0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91,
+ 0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19,
+ 0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1,
+ 0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc,
+ 0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed,
+ 0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde,
+ 0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98,
+ 0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3,
+ 0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca,
+ 0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6,
+ 0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc,
+ 0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44,
+ 0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0,
+ 0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95,
+ 0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4,
+ 0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd,
+ 0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13,
+ 0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7,
+ 0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a,
+ 0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52,
+ 0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a,
+ 0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38,
+ 0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e,
+ 0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e,
+ 0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad,
+ 0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8,
+ 0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c,
+ 0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d,
+ 0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f,
+ 0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2,
+ 0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea,
+ 0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68 },
+ .rlen = 512,
+ }
+};
+
+static struct cipher_testvec aes_xts_dec_tv_template[] = {
+ /* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */
+ { /* XTS-AES 1 */
+ .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .klen = 32,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec,
+ 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92,
+ 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85,
+ 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e },
+ .ilen = 32,
+ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .rlen = 32,
+ }, { /* XTS-AES 2 */
+ .key = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
+ .klen = 32,
+ .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e,
+ 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b,
+ 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4,
+ 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 },
+ .ilen = 32,
+ .result = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
+ .rlen = 32,
+ }, { /* XTS-AES 3 */
+ .key = { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
+ .klen = 32,
+ .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a,
+ 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2,
+ 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53,
+ 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 },
+ .ilen = 32,
+ .result = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
+ .rlen = 32,
+ }, { /* XTS-AES 4 */
+ .key = { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
+ 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
+ 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
+ 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 },
+ .klen = 32,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
+ 0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
+ 0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
+ 0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
+ 0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
+ 0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
+ 0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
+ 0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
+ 0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5,
+ 0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5,
+ 0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc,
+ 0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce,
+ 0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4,
+ 0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84,
+ 0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a,
+ 0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65,
+ 0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89,
+ 0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51,
+ 0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15,
+ 0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8,
+ 0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed,
+ 0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91,
+ 0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e,
+ 0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34,
+ 0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b,
+ 0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5,
+ 0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4,
+ 0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c,
+ 0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd,
+ 0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3,
+ 0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f,
+ 0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e,
+ 0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91,
+ 0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19,
+ 0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1,
+ 0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc,
+ 0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed,
+ 0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde,
+ 0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98,
+ 0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3,
+ 0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca,
+ 0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6,
+ 0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc,
+ 0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44,
+ 0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0,
+ 0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95,
+ 0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4,
+ 0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd,
+ 0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13,
+ 0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7,
+ 0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a,
+ 0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52,
+ 0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a,
+ 0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38,
+ 0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e,
+ 0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e,
+ 0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad,
+ 0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8,
+ 0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c,
+ 0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d,
+ 0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f,
+ 0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2,
+ 0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea,
+ 0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68 },
+ .ilen = 512,
+ .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff },
+ .rlen = 512,
+ }
+};
+
/* Cast5 test vectors from RFC 2144 */
#define CAST5_ENC_TEST_VECTORS 3
#define CAST5_DEC_TEST_VECTORS 3
@@ -4193,6 +4589,27 @@ static struct cipher_speed aes_lrw_speed_template[] = {
{ .klen = 0, .blen = 0, }
};

+static struct cipher_speed aes_xts_speed_template[] = {
+ { .klen = 32, .blen = 16, },
+ { .klen = 32, .blen = 64, },
+ { .klen = 32, .blen = 256, },
+ { .klen = 32, .blen = 1024, },
+ { .klen = 32, .blen = 8192, },
+ { .klen = 48, .blen = 16, },
+ { .klen = 48, .blen = 64, },
+ { .klen = 48, .blen = 256, },
+ { .klen = 48, .blen = 1024, },
+ { .klen = 48, .blen = 8192, },
+ { .klen = 64, .blen = 16, },
+ { .klen = 64, .blen = 64, },
+ { .klen = 64, .blen = 256, },
+ { .klen = 64, .blen = 1024, },
+ { .klen = 64, .blen = 8192, },
+
+ /* End marker */
+ { .klen = 0, .blen = 0, }
+};
+
static struct cipher_speed des3_ede_speed_template[] = {
{ .klen = 24, .blen = 16, },
{ .klen = 24, .blen = 64, },
diff --git a/crypto/xts.c b/crypto/xts.c
new file mode 100644
index 0000000..7d9a353
--- /dev/null
+++ b/crypto/xts.c
@@ -0,0 +1,277 @@
+/* XTS: as defined in IEEE1619/D16
+ * http://grouper.ieee.org/groups/1619/email/pdf00086.pdf
+ * (sector sizes which are not a multiple of 16 bytes are,
+ * however currently unsupported)
+ *
+ * Copyright (c) 2007 Rik Snel <[email protected]>
+ *
+ * Based om ecb.c
+ * Copyright (c) 2006 Herbert Xu <[email protected]>
+ *
+ * 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 <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+#include <crypto/b128ops.h>
+#include <crypto/gf128mul.h>
+
+struct priv {
+ struct crypto_cipher *child;
+ struct crypto_cipher *tweak;
+};
+
+static int setkey(struct crypto_tfm *parent, const u8 *key,
+ unsigned int keylen)
+{
+ struct priv *ctx = crypto_tfm_ctx(parent);
+ struct crypto_cipher *child = ctx->tweak;
+ u32 *flags = &parent->crt_flags;
+ int err;
+
+ /* key consists of keys of equal size concatenated, therefore
+ * the length must be even */
+ if (keylen % 2) {
+ /* does anyone read this flag, it is not set if key setup
+ * fails below (or is it?) */
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ /* we need two cipher instances: one to compute the inital 'tweak'
+ * by encrypting the IV (usually the 'plain' iv) and the other
+ * one to encrypt and decrypt the data */
+
+ /* tweak cipher, uses Key2 i.e. the second half of *key */
+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ if ((err = crypto_cipher_setkey(child, key + keylen/2, keylen/2)))
+ return err;
+ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
+
+ child = ctx->child;
+
+ /* data cipher, uses Key1 i.e. the first half of *key */
+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ if ((err = crypto_cipher_setkey(child, key, keylen/2)))
+ return err;
+ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
+
+ return 0;
+}
+
+struct sinfo {
+ be128 t;
+ struct crypto_tfm *tfm;
+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
+};
+
+static inline void xts_round(struct sinfo *s, void *dst, const void *src)
+{
+ be128_xor(dst, &s->t, src); /* PP <- T xor P */
+ s->fn(s->tfm, dst, dst); /* CC <- E(Key1,PP) */
+ be128_xor(dst, dst, &s->t); /* C <- T xor CC */
+}
+
+static int crypt(struct blkcipher_desc *d,
+ struct blkcipher_walk *w, struct priv *ctx,
+ void (*tw)(struct crypto_tfm *, u8 *, const u8 *),
+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
+{
+ int err;
+ unsigned int avail;
+ const int bs = crypto_cipher_blocksize(ctx->child);
+ struct sinfo s = {
+ .tfm = crypto_cipher_tfm(ctx->child),
+ .fn = fn
+ };
+ be128 *iv;
+ u8 *wsrc;
+ u8 *wdst;
+
+ err = blkcipher_walk_virt(d, w);
+ if (!(avail = w->nbytes))
+ return err;
+
+ wsrc = w->src.virt.addr;
+ wdst = w->dst.virt.addr;
+
+ /* calculate first value of T */
+ iv = (be128 *)w->iv;
+ tw(crypto_cipher_tfm(ctx->tweak), (void*)&s.t, w->iv);
+
+ goto first;
+
+ for (;;) {
+ do {
+ gf128mul_x_ble(&s.t, &s.t);
+
+first:
+ xts_round(&s, wdst, wsrc);
+
+ wsrc += bs;
+ wdst += bs;
+ } while ((avail -= bs) >= bs);
+
+ err = blkcipher_walk_done(d, w, avail);
+ if (!(avail = w->nbytes))
+ break;
+
+ wsrc = w->src.virt.addr;
+ wdst = w->dst.virt.addr;
+ }
+
+ return err;
+}
+
+static int encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk w;
+
+ blkcipher_walk_init(&w, dst, src, nbytes);
+ return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt,
+ crypto_cipher_alg(ctx->child)->cia_encrypt);
+}
+
+static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk w;
+
+ blkcipher_walk_init(&w, dst, src, nbytes);
+ return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt,
+ crypto_cipher_alg(ctx->child)->cia_decrypt);
+}
+
+static int init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_cipher *cipher;
+ struct crypto_instance *inst = (void *)tfm->__crt_alg;
+ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+ struct priv *ctx = crypto_tfm_ctx(tfm);
+ u32 *flags = &tfm->crt_flags;
+
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ if (crypto_cipher_blocksize(cipher) != 16) {
+ *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
+ return -EINVAL;
+ }
+
+ ctx->child = cipher;
+
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ /* this check isn't really needed */
+ if (crypto_cipher_blocksize(cipher) != 16) {
+ *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
+ return -EINVAL;
+ }
+
+ ctx->tweak = cipher;
+
+ return 0;
+}
+
+static void exit_tfm(struct crypto_tfm *tfm)
+{
+ struct priv *ctx = crypto_tfm_ctx(tfm);
+ crypto_free_cipher(ctx->child);
+ crypto_free_cipher(ctx->tweak);
+}
+
+static struct crypto_instance *alloc(struct rtattr **tb)
+{
+ struct crypto_instance *inst;
+ struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+ if (err)
+ return ERR_PTR(err);
+
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
+ if (IS_ERR(alg))
+ return ERR_PTR(PTR_ERR(alg));
+
+ inst = crypto_alloc_instance("xts", alg);
+ if (IS_ERR(inst))
+ goto out_put_alg;
+
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+ inst->alg.cra_priority = alg->cra_priority;
+ inst->alg.cra_blocksize = alg->cra_blocksize;
+
+ if (alg->cra_alignmask < 7) inst->alg.cra_alignmask = 7;
+ else inst->alg.cra_alignmask = alg->cra_alignmask;
+ inst->alg.cra_type = &crypto_blkcipher_type;
+
+ if (!(alg->cra_blocksize % 4))
+ inst->alg.cra_alignmask |= 3;
+ inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
+ inst->alg.cra_blkcipher.min_keysize = 2*alg->cra_cipher.cia_min_keysize;
+ inst->alg.cra_blkcipher.max_keysize = 2*alg->cra_cipher.cia_max_keysize;
+
+ inst->alg.cra_ctxsize = sizeof(struct priv);
+
+ inst->alg.cra_init = init_tfm;
+ inst->alg.cra_exit = exit_tfm;
+
+ inst->alg.cra_blkcipher.setkey = setkey;
+ inst->alg.cra_blkcipher.encrypt = encrypt;
+ inst->alg.cra_blkcipher.decrypt = decrypt;
+
+out_put_alg:
+ crypto_mod_put(alg);
+ return inst;
+}
+
+static void free(struct crypto_instance *inst)
+{
+ crypto_drop_spawn(crypto_instance_ctx(inst));
+ kfree(inst);
+}
+
+static struct crypto_template crypto_tmpl = {
+ .name = "xts",
+ .alloc = alloc,
+ .free = free,
+ .module = THIS_MODULE,
+};
+
+static int __init crypto_module_init(void)
+{
+ return crypto_register_template(&crypto_tmpl);
+}
+
+static void __exit crypto_module_exit(void)
+{
+ crypto_unregister_template(&crypto_tmpl);
+}
+
+module_init(crypto_module_init);
+module_exit(crypto_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("XTS block cipher mode");
diff --git a/include/crypto/gf128mul.h b/include/crypto/gf128mul.h
index 4fd3152..4086b8e 100644
--- a/include/crypto/gf128mul.h
+++ b/include/crypto/gf128mul.h
@@ -161,6 +161,8 @@ void gf128mul_lle(be128 *a, const be128 *b);

void gf128mul_bbe(be128 *a, const be128 *b);

+/* multiply by x in ble format, needed by XTS */
+void gf128mul_x_ble(be128 *a, const be128 *b);

/* 4k table optimization */

--
1.5.2.5


Subject: Re: [PATCH] an XTS blockcipher mode implementation without partial blocks

* Rik Snel | 2007-09-03 23:45:16 [+0200]:

>diff --git a/crypto/xts.c b/crypto/xts.c
>new file mode 100644
>index 0000000..7d9a353
>--- /dev/null
>+++ b/crypto/xts.c
>@@ -0,0 +1,277 @@
>+/* XTS: as defined in IEEE1619/D16
>+ * http://grouper.ieee.org/groups/1619/email/pdf00086.pdf
>+ * (sector sizes which are not a multiple of 16 bytes are,
>+ * however currently unsupported)
>+ *
>+ * Copyright (c) 2007 Rik Snel <[email protected]>
>+ *
>+ * Based om ecb.c
>+ * Copyright (c) 2006 Herbert Xu <[email protected]>
>+ *
>+ * 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 <crypto/algapi.h>
>+#include <linux/err.h>
>+#include <linux/init.h>
>+#include <linux/kernel.h>
>+#include <linux/module.h>
>+#include <linux/scatterlist.h>
>+#include <linux/slab.h>
>+
>+#include <crypto/b128ops.h>
>+#include <crypto/gf128mul.h>
>+
>+struct priv {
>+ struct crypto_cipher *child;
>+ struct crypto_cipher *tweak;
>+};
>+
>+static int setkey(struct crypto_tfm *parent, const u8 *key,
>+ unsigned int keylen)
>+{
>+ struct priv *ctx = crypto_tfm_ctx(parent);
>+ struct crypto_cipher *child = ctx->tweak;
>+ u32 *flags = &parent->crt_flags;
>+ int err;
>+
>+ /* key consists of keys of equal size concatenated, therefore
>+ * the length must be even */
>+ if (keylen % 2) {
>+ /* does anyone read this flag, it is not set if key setup
>+ * fails below (or is it?) */
>+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
>+ return -EINVAL;
>+ }

A algo user might read this.

>+
>+ /* we need two cipher instances: one to compute the inital 'tweak'
>+ * by encrypting the IV (usually the 'plain' iv) and the other
>+ * one to encrypt and decrypt the data */
>+
>+ /* tweak cipher, uses Key2 i.e. the second half of *key */
>+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
>+ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
>+ CRYPTO_TFM_REQ_MASK);
>+ if ((err = crypto_cipher_setkey(child, key + keylen/2, keylen/2)))
>+ return err;

why not
err = crypto_cipher_setkey(child, key + keylen/2, keylen/2);
if (err)
return err;

>+ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
>+ CRYPTO_TFM_RES_MASK);
>+
>+ child = ctx->child;
>+
>+ /* data cipher, uses Key1 i.e. the first half of *key */
>+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
>+ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
>+ CRYPTO_TFM_REQ_MASK);
>+ if ((err = crypto_cipher_setkey(child, key, keylen/2)))
...

>+ return err;
>+ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
>+ CRYPTO_TFM_RES_MASK);
>+
>+ return 0;
>+}
>+
>+struct sinfo {
>+ be128 t;
>+ struct crypto_tfm *tfm;
>+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
>+};
>+
>+static inline void xts_round(struct sinfo *s, void *dst, const void *src)
>+{
>+ be128_xor(dst, &s->t, src); /* PP <- T xor P */
>+ s->fn(s->tfm, dst, dst); /* CC <- E(Key1,PP) */
>+ be128_xor(dst, dst, &s->t); /* C <- T xor CC */
>+}
>+
>+static int crypt(struct blkcipher_desc *d,
>+ struct blkcipher_walk *w, struct priv *ctx,
>+ void (*tw)(struct crypto_tfm *, u8 *, const u8 *),
>+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
>+{
>+ int err;
>+ unsigned int avail;
>+ const int bs = crypto_cipher_blocksize(ctx->child);
>+ struct sinfo s = {
>+ .tfm = crypto_cipher_tfm(ctx->child),
>+ .fn = fn
>+ };
>+ be128 *iv;
>+ u8 *wsrc;
>+ u8 *wdst;
>+
>+ err = blkcipher_walk_virt(d, w);
>+ if (!(avail = w->nbytes))
...
>+ return err;
>+
>+ wsrc = w->src.virt.addr;
>+ wdst = w->dst.virt.addr;
>+
>+ /* calculate first value of T */
>+ iv = (be128 *)w->iv;
>+ tw(crypto_cipher_tfm(ctx->tweak), (void*)&s.t, w->iv);
>+
>+ goto first;
>+
>+ for (;;) {
>+ do {
>+ gf128mul_x_ble(&s.t, &s.t);
>+
>+first:

why not

int first = 0;
...
do {
if (!first) {
gf128mul_x_ble(&s.t, &s.t);
first = 1;
}

The compiler should generate similar code.

>+ xts_round(&s, wdst, wsrc);
>+
>+ wsrc += bs;
>+ wdst += bs;
>+ } while ((avail -= bs) >= bs);
>+
>+ err = blkcipher_walk_done(d, w, avail);
>+ if (!(avail = w->nbytes))

avail = w->nbytes;
if (!avail)

>+ break;
>+
>+ wsrc = w->src.virt.addr;
>+ wdst = w->dst.virt.addr;
>+ }
>+
>+ return err;
>+}
>+
>+static int encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
>+ struct scatterlist *src, unsigned int nbytes)
>+{
>+ struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
>+ struct blkcipher_walk w;
>+
>+ blkcipher_walk_init(&w, dst, src, nbytes);
>+ return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt,
>+ crypto_cipher_alg(ctx->child)->cia_encrypt);
>+}
>+
>+static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
>+ struct scatterlist *src, unsigned int nbytes)
>+{
>+ struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
>+ struct blkcipher_walk w;
>+
>+ blkcipher_walk_init(&w, dst, src, nbytes);
>+ return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt,
>+ crypto_cipher_alg(ctx->child)->cia_decrypt);
>+}
>+
>+static int init_tfm(struct crypto_tfm *tfm)
>+{
>+ struct crypto_cipher *cipher;
>+ struct crypto_instance *inst = (void *)tfm->__crt_alg;
>+ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
>+ struct priv *ctx = crypto_tfm_ctx(tfm);
>+ u32 *flags = &tfm->crt_flags;
>+
>+ cipher = crypto_spawn_cipher(spawn);
>+ if (IS_ERR(cipher))
>+ return PTR_ERR(cipher);
>+
>+ if (crypto_cipher_blocksize(cipher) != 16) {
>+ *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
>+ return -EINVAL;
>+ }
>+
>+ ctx->child = cipher;
>+
>+ cipher = crypto_spawn_cipher(spawn);
>+ if (IS_ERR(cipher))
>+ return PTR_ERR(cipher);

don't you want to free ctx->child on error?

>+
>+ /* this check isn't really needed */
>+ if (crypto_cipher_blocksize(cipher) != 16) {
>+ *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
>+ return -EINVAL;
>+ }

and here both.
Right now you should get the same algo but I don't thing that a check
will hurt.

>+
>+ ctx->tweak = cipher;
>+
>+ return 0;
>+}
>+
>+static void exit_tfm(struct crypto_tfm *tfm)
>+{
>+ struct priv *ctx = crypto_tfm_ctx(tfm);
>+ crypto_free_cipher(ctx->child);
>+ crypto_free_cipher(ctx->tweak);
>+}
>+
>+static struct crypto_instance *alloc(struct rtattr **tb)
>+{
>+ struct crypto_instance *inst;
>+ struct crypto_alg *alg;
>+ int err;
>+
>+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
>+ if (err)
>+ return ERR_PTR(err);
>+
>+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
>+ CRYPTO_ALG_TYPE_MASK);
>+ if (IS_ERR(alg))
>+ return ERR_PTR(PTR_ERR(alg));
>+
>+ inst = crypto_alloc_instance("xts", alg);
>+ if (IS_ERR(inst))
>+ goto out_put_alg;
>+
>+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
>+ inst->alg.cra_priority = alg->cra_priority;
>+ inst->alg.cra_blocksize = alg->cra_blocksize;
>+
>+ if (alg->cra_alignmask < 7) inst->alg.cra_alignmask = 7;
>+ else inst->alg.cra_alignmask = alg->cra_alignmask;
>+ inst->alg.cra_type = &crypto_blkcipher_type;
>+
>+ if (!(alg->cra_blocksize % 4))
>+ inst->alg.cra_alignmask |= 3;

please do

if (a)
do_on_a();
else
do_on_b();

besides that, what are you trying to do? The if() makes sure that the
alignmask is atleast 7 (0b111). And then, depending on the block size
you might set the lower two bits (3 is 0b11) which are allready set.


>+ inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
>+ inst->alg.cra_blkcipher.min_keysize = 2*alg->cra_cipher.cia_min_keysize;
>+ inst->alg.cra_blkcipher.max_keysize = 2*alg->cra_cipher.cia_max_keysize;

a space between the operator might not be a bad idea.

>+
>+ inst->alg.cra_ctxsize = sizeof(struct priv);
>+
>+ inst->alg.cra_init = init_tfm;
>+ inst->alg.cra_exit = exit_tfm;
>+
>+ inst->alg.cra_blkcipher.setkey = setkey;
>+ inst->alg.cra_blkcipher.encrypt = encrypt;
>+ inst->alg.cra_blkcipher.decrypt = decrypt;
>+
>+out_put_alg:
>+ crypto_mod_put(alg);
>+ return inst;
>+}
>+
>+static void free(struct crypto_instance *inst)
>+{
>+ crypto_drop_spawn(crypto_instance_ctx(inst));
>+ kfree(inst);
>+}
>+
>+static struct crypto_template crypto_tmpl = {
>+ .name = "xts",
>+ .alloc = alloc,
>+ .free = free,
>+ .module = THIS_MODULE,
>+};
>+
>+static int __init crypto_module_init(void)
>+{
>+ return crypto_register_template(&crypto_tmpl);
>+}
>+
>+static void __exit crypto_module_exit(void)
>+{
>+ crypto_unregister_template(&crypto_tmpl);
>+}
>+
>+module_init(crypto_module_init);
>+module_exit(crypto_module_exit);
>+
>+MODULE_LICENSE("GPL");
>+MODULE_DESCRIPTION("XTS block cipher mode");

The other things are looking fine to me. You might want to consider
using ./scripts/checkpatch.pl on your patch the next time :)

Sebastian

2007-09-06 14:59:03

by Rik Snel

[permalink] [raw]
Subject: Re: [PATCH] an XTS blockcipher mode implementation without partial blocks

Hello Sebastian,

Thanks for your review of the patch. I will address your points below.

On Wed, Sep 05, 2007 at 02:29:06AM +0200, Sebastian Siewior wrote:
> >diff --git a/crypto/xts.c b/crypto/xts.c
> [...]
> >+ /* key consists of keys of equal size concatenated, therefore
> >+ * the length must be even */
> >+ if (keylen % 2) {
> >+ /* does anyone read this flag, it is not set if key setup
> >+ * fails below (or is it?) */
> >+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
> >+ return -EINVAL;
> >+ }
>
> A algo user might read this.

Ok. I see that the error flags from the keysetup below are also copied
to the flags..., will update comment.
>
> >+
> >+ /* we need two cipher instances: one to compute the inital 'tweak'
> >+ * by encrypting the IV (usually the 'plain' iv) and the other
> >+ * one to encrypt and decrypt the data */
> >+
> >+ /* tweak cipher, uses Key2 i.e. the second half of *key */
> >+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
> >+ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
> >+ CRYPTO_TFM_REQ_MASK);
> >+ if ((err = crypto_cipher_setkey(child, key + keylen/2, keylen/2)))
> >+ return err;
>
> why not
> err = crypto_cipher_setkey(child, key + keylen/2, keylen/2);
> if (err)
> return err;

Ok, I can see that it probably goes against the 'multiple statements on
a single line' rules in CodingStyle, will change.

> >+ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
> >+ CRYPTO_TFM_RES_MASK);
> >+
> >+ child = ctx->child;
> >+
> >+ /* data cipher, uses Key1 i.e. the first half of *key */
> >+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
> >+ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
> >+ CRYPTO_TFM_REQ_MASK);
> >+ if ((err = crypto_cipher_setkey(child, key, keylen/2)))
> ...

Copypaste from above...

> > [...]
> >+ err = blkcipher_walk_virt(d, w);
> >+ if (!(avail = w->nbytes))
> ...

Ok.

> >+ return err;
> >+
> >+ wsrc = w->src.virt.addr;
> >+ wdst = w->dst.virt.addr;
> >+
> >+ /* calculate first value of T */
> >+ iv = (be128 *)w->iv;
> >+ tw(crypto_cipher_tfm(ctx->tweak), (void*)&s.t, w->iv);
> >+
> >+ goto first;
> >+
> >+ for (;;) {
> >+ do {
> >+ gf128mul_x_ble(&s.t, &s.t);
> >+
> >+first:
>
> why not
>
> int first = 0;
> ...
> do {
> if (!first) {
> gf128mul_x_ble(&s.t, &s.t);
> first = 1;
> }
>
> The compiler should generate similar code.

I'd rather tell the compiler what I want than to introduce a new local
variable and a conditional branch in the hope that the compiler will
optimize it away, just to avoid a goto.

If you insist on getting rid of the goto, I could unroll the first
iteration of the loop by hand. (when is submitted lrw.c it had the first
iteration unrolled; Herbert replaced it with this goto)

> >+ xts_round(&s, wdst, wsrc);
> >+
> >+ wsrc += bs;
> >+ wdst += bs;
> >+ } while ((avail -= bs) >= bs);
> >+
> >+ err = blkcipher_walk_done(d, w, avail);
> >+ if (!(avail = w->nbytes))
>
> avail = w->nbytes;
> if (!avail)
>

Ok.

> > [...]
> >+ if (crypto_cipher_blocksize(cipher) != 16) {
> >+ *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
> >+ return -EINVAL;
> >+ }
> >+
> >+ ctx->child = cipher;
> >+
> >+ cipher = crypto_spawn_cipher(spawn);
> >+ if (IS_ERR(cipher))
> >+ return PTR_ERR(cipher);
>
> don't you want to free ctx->child on error?

Yes, of course. Fixed.

> >+
> >+ /* this check isn't really needed */
> >+ if (crypto_cipher_blocksize(cipher) != 16) {
> >+ *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
> >+ return -EINVAL;
> >+ }
>
> and here both.

Fixed.

> Right now you should get the same algo but I don't thing that a check
> will hurt.

Agree.

> > [...]
> >+ if (alg->cra_alignmask < 7) inst->alg.cra_alignmask = 7;
> >+ else inst->alg.cra_alignmask = alg->cra_alignmask;
> >+ inst->alg.cra_type = &crypto_blkcipher_type;
> >+
> >+ if (!(alg->cra_blocksize % 4))
> >+ inst->alg.cra_alignmask |= 3;
>
> please do
>
> if (a)
> do_on_a();
> else
> do_on_b();

Ok.

> besides that, what are you trying to do? The if() makes sure that the
> alignmask is atleast 7 (0b111). And then, depending on the block size
> you might set the lower two bits (3 is 0b11) which are allready set.

Mmmm, I don't know why I did that. It is probably safe to assume that
alg->cra_alignmask = 2^n - 1 for some n, so I will remove the second if.

> >+ inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
> >+ inst->alg.cra_blkcipher.min_keysize = 2*alg->cra_cipher.cia_min_keysize;
> >+ inst->alg.cra_blkcipher.max_keysize = 2*alg->cra_cipher.cia_max_keysize;
>
> a space between the operator might not be a bad idea.

I wanted it to fit in 80 columns, will change.
>
> > [...]
> >+MODULE_LICENSE("GPL");
> >+MODULE_DESCRIPTION("XTS block cipher mode");
>
> The other things are looking fine to me. You might want to consider
> using ./scripts/checkpatch.pl on your patch the next time :)

I did just that, and it catched a (void*) should be (void *).

Christoph encountered a deadlock after a few hours and 16GB of data (on
an aes-xts-plain partition). Assuming there is an error in xts.c, is
there an obvious way of finding it?

Is my re-usage of *spawn (in init_tfm) the right way to get two
instances of the blockcipher?

A patch which fixes everything except the goto in crypt() will follow.

Greetings,

Rik.

--
Nothing is ever a total loss; it can always serve as a bad example.

2007-09-07 06:19:19

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH] an XTS blockcipher mode implementation without partial blocks

On Thu, Sep 06, 2007 at 04:57:26PM +0200, [email protected] wrote:
>
> I'd rather tell the compiler what I want than to introduce a new local
> variable and a conditional branch in the hope that the compiler will
> optimize it away, just to avoid a goto.

Yes this code looks OK to me.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

Subject: Re: [PATCH] an XTS blockcipher mode implementation without partial blocks

* [email protected] | 2007-09-06 16:57:26 [+0200]:

>> The compiler should generate similar code.
>
>I'd rather tell the compiler what I want than to introduce a new local
>variable and a conditional branch in the hope that the compiler will
>optimize it away, just to avoid a goto.
>
>If you insist on getting rid of the goto, I could unroll the first
>iteration of the loop by hand. (when is submitted lrw.c it had the first
>iteration unrolled; Herbert replaced it with this goto)

I didn't know that Herbert did it the same way. In that case you are
fine :)

>Christoph encountered a deadlock after a few hours and 16GB of data (on
>an aes-xts-plain partition). Assuming there is an error in xts.c, is
>there an obvious way of finding it?

Haven't seen any locks in your code, so your part may be fine. How do I
use this?

cryptsetup -c aes-xts

or?

>Greetings,
>
>Rik.

Sebastian

2007-09-07 19:25:06

by Rik Snel

[permalink] [raw]
Subject: Re: [PATCH] an XTS blockcipher mode implementation without partial blocks

Hello,

On Fri, Sep 07, 2007 at 08:38:32PM +0200, Sebastian Siewior wrote:
> [...]
>
> >Christoph encountered a deadlock after a few hours and 16GB of data (on
> >an aes-xts-plain partition). Assuming there is an error in xts.c, is
> >there an obvious way of finding it?
>
> Haven't seen any locks in your code, so your part may be fine. How do I
> use this?
>
> cryptsetup -c aes-xts
>
> or?

for example:
cryptsetup --hash sha256 -s 256 -c aes-xts-plain create test /dev/some_partition

The 'plain'-iv should give an on-disk format compatible with the
requirements of IEEE1619/D16. Internally the 256-bit key is split in two
128-bit AES keys. Other allowed key sizes for aes-xts-* are 2*192=384
bit and 2*256=512 bit. (you may want to use a hash with more bits (I don't know
what cryptsetup does if the hash gives less than keysize bits))

Christoph, is your testing machine stable if you run the same test with
aes-lrw-plain and the same keysize?

Greetings,

Rik.

--
Nothing is ever a total loss; it can always serve as a bad example.