summaryrefslogtreecommitdiff
path: root/cipher/cipher.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2017-01-06 12:48:17 +0200
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2017-01-06 12:48:17 +0200
commit232a129b1f915fc54881506e4b07c89cf84932e6 (patch)
tree21830feb80af49e2ab2ff344a647d0a0ec10aac5 /cipher/cipher.c
parentaada604594fd42224d366d3cb98f67fd3b989cd6 (diff)
downloadlibgcrypt-232a129b1f915fc54881506e4b07c89cf84932e6.tar.gz
Add XTS cipher mode
* cipher/Makefile.am: Add 'cipher-xts.c'. * cipher/cipher-internal.h (gcry_cipher_handle): Add 'bulk.xts_crypt' and 'u_mode.xts' members. (_gcry_cipher_xts_crypt): New prototype. * cipher/cipher-xts.c: New. * cipher/cipher.c (_gcry_cipher_open_internal, cipher_setkey) (cipher_reset, cipher_encrypt, cipher_decrypt): Add XTS mode handling. * doc/gcrypt.texi: Add XTS mode to documentation. * src/gcrypt.h.in (GCRY_CIPHER_MODE_XTS, GCRY_XTS_BLOCK_LEN): New. * tests/basic.c (do_check_xts_cipher, check_xts_cipher): New. (check_bulk_cipher_modes): Add XTS test-vectors. (check_one_cipher_core, check_one_cipher, check_ciphers): Add XTS testing support. (check_cipher_modes): Add XTS test. * tests/bench-slope.c (bench_xts_encrypt_init) (bench_xts_encrypt_do_bench, bench_xts_decrypt_do_bench) (xts_encrypt_ops, xts_decrypt_ops): New. (cipher_modes, cipher_bench_one): Add XTS. * tests/benchmark.c (cipher_bench): Add XTS testing. -- Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'cipher/cipher.c')
-rw-r--r--cipher/cipher.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 55853da9..06ce1dad 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -405,6 +405,13 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
err = GPG_ERR_INV_CIPHER_MODE;
break;
+ case GCRY_CIPHER_MODE_XTS:
+ if (spec->blocksize != GCRY_XTS_BLOCK_LEN)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ if (!spec->encrypt || !spec->decrypt)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ break;
+
case GCRY_CIPHER_MODE_ECB:
case GCRY_CIPHER_MODE_CBC:
case GCRY_CIPHER_MODE_CFB:
@@ -468,6 +475,18 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/
);
+ /* Space needed per mode. */
+ switch (mode)
+ {
+ case GCRY_CIPHER_MODE_XTS:
+ /* Additional cipher context for tweak. */
+ size += 2 * spec->contextsize + 15;
+ break;
+
+ default:
+ break;
+ }
+
if (secure)
h = xtrycalloc_secure (1, size);
else
@@ -478,6 +497,7 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
else
{
size_t off = 0;
+ char *tc;
#ifdef NEED_16BYTE_ALIGNED_CONTEXT
if ( ((uintptr_t)h & 0x0f) )
@@ -578,6 +598,13 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
h->u_mode.ocb.taglen = 16; /* Bytes. */
break;
+ case GCRY_CIPHER_MODE_XTS:
+ tc = h->context.c + spec->contextsize * 2;
+ tc += (16 - (uintptr_t)tc % 16) % 16;
+ h->u_mode.xts.tweak_context = tc;
+
+ break;
+
default:
break;
}
@@ -630,6 +657,23 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
{
gcry_err_code_t rc;
+ if (c->mode == GCRY_CIPHER_MODE_XTS)
+ {
+ /* XTS uses two keys. */
+ if (keylen % 2)
+ return GPG_ERR_INV_KEYLEN;
+ keylen /= 2;
+
+ if (fips_mode ())
+ {
+ /* Reject key if subkeys Key_1 and Key_2 are equal.
+ See "Implementation Guidance for FIPS 140-2, A.9 XTS-AES
+ Key Generation Requirements" for details. */
+ if (buf_eq_const (key, key + keylen, keylen))
+ return GPG_ERR_WEAK_KEY;
+ }
+ }
+
rc = c->spec->setkey (&c->context.c, key, keylen);
if (!rc)
{
@@ -653,6 +697,20 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
_gcry_cipher_poly1305_setkey (c);
break;
+ case GCRY_CIPHER_MODE_XTS:
+ /* Setup tweak cipher with second part of XTS key. */
+ rc = c->spec->setkey (c->u_mode.xts.tweak_context, key + keylen,
+ keylen);
+ if (!rc)
+ {
+ /* Duplicate initial tweak context. */
+ memcpy (c->u_mode.xts.tweak_context + c->spec->contextsize,
+ c->u_mode.xts.tweak_context, c->spec->contextsize);
+ }
+ else
+ c->marks.key = 0;
+ break;
+
default:
break;
};
@@ -751,6 +809,12 @@ cipher_reset (gcry_cipher_hd_t c)
c->u_mode.ocb.taglen = 16;
break;
+ case GCRY_CIPHER_MODE_XTS:
+ memcpy (c->u_mode.xts.tweak_context,
+ c->u_mode.xts.tweak_context + c->spec->contextsize,
+ c->spec->contextsize);
+ break;
+
default:
break; /* u_mode unused by other modes. */
}
@@ -872,6 +936,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
rc = _gcry_cipher_ocb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_XTS:
+ rc = _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 1);
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stencrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);
@@ -995,6 +1063,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
rc = _gcry_cipher_ocb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_XTS:
+ rc = _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 0);
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stdecrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);