summaryrefslogtreecommitdiff
path: root/cipher/cipher.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2015-01-16 14:55:03 +0100
committerWerner Koch <wk@gnupg.org>2015-01-16 14:55:03 +0100
commit067d7d8752d4d8a98f8e0e5e9b1a5b13e1b7ff9c (patch)
tree1eab7affe5d24e919a22a5d4a29c8303342cf8db /cipher/cipher.c
parent9d2a22c94ae99f9301321082c4fb8d73f4085fda (diff)
downloadlibgcrypt-067d7d8752d4d8a98f8e0e5e9b1a5b13e1b7ff9c.tar.gz
Add OCB cipher mode
* cipher/cipher-ocb.c: New. * cipher/Makefile.am (libcipher_la_SOURCES): Add cipher-ocb.c * cipher/cipher-internal.h (OCB_BLOCK_LEN, OCB_L_TABLE_SIZE): New. (gcry_cipher_handle): Add fields marks.finalize and u_mode.ocb. * cipher/cipher.c (_gcry_cipher_open_internal): Add OCB mode. (_gcry_cipher_open_internal): Setup default taglen of OCB. (cipher_reset): Clear OCB specific data. (cipher_encrypt, cipher_decrypt, _gcry_cipher_authenticate) (_gcry_cipher_gettag, _gcry_cipher_checktag): Call OCB functions. (_gcry_cipher_setiv): Add OCB specific nonce setting. (_gcry_cipher_ctl): Add GCRYCTL_FINALIZE and GCRYCTL_SET_TAGLEN * src/gcrypt.h.in (GCRYCTL_SET_TAGLEN): New. (gcry_cipher_final): New. * cipher/bufhelp.h (buf_xor_1): New. * tests/basic.c (hex2buffer): New. (check_ocb_cipher): New. (main): Call it here. Add option --cipher-modes. * tests/bench-slope.c (bench_aead_encrypt_do_bench): Call gcry_cipher_final. (bench_aead_decrypt_do_bench): Ditto. (bench_aead_authenticate_do_bench): Ditto. Check error code. (bench_ocb_encrypt_do_bench): New. (bench_ocb_decrypt_do_bench): New. (bench_ocb_authenticate_do_bench): New. (ocb_encrypt_ops): New. (ocb_decrypt_ops): New. (ocb_authenticate_ops): New. (cipher_modes): Add them. (cipher_bench_one): Skip wrong block length for OCB. * tests/benchmark.c (cipher_bench): Add field noncelen to MODES. Add OCB support. -- See the comments on top of cipher/cipher-ocb.c for the patent status of the OCB mode. The implementation has not yet been optimized and as such is not faster that the other AEAD modes. A first candidate for optimization is the double_block function. Large improvements can be expected by writing an AES ECB function to work on multiple blocks. Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'cipher/cipher.c')
-rw-r--r--cipher/cipher.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 78cad210..0a13fe61 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -425,6 +425,17 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
err = GPG_ERR_INV_CIPHER_MODE;
break;
+ case GCRY_CIPHER_MODE_OCB:
+ /* Note that our implementation allows only for 128 bit block
+ length algorithms. Lower block lengths would be possible
+ but we do not implement them because they limit the
+ security too much. */
+ if (!spec->encrypt || !spec->decrypt)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ else if (spec->blocksize != (128/8))
+ err = GPG_ERR_INV_CIPHER_MODE;
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
if (!spec->stencrypt || !spec->stdecrypt)
err = GPG_ERR_INV_CIPHER_MODE;
@@ -445,7 +456,8 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
/* Perform selftest here and mark this with a flag in cipher_table?
No, we should not do this as it takes too long. Further it does
not make sense to exclude algorithms with failing selftests at
- runtime: If a selftest fails there is something seriously wrong with the system and thus we better die immediately. */
+ runtime: If a selftest fails there is something seriously wrong
+ with the system and thus we better die immediately. */
if (! err)
{
@@ -551,6 +563,18 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
default:
break;
}
+
+ /* Setup defaults depending on the mode. */
+ switch (mode)
+ {
+ case GCRY_CIPHER_MODE_OCB:
+ h->u_mode.ocb.taglen = 16; /* Bytes. */
+ break;
+
+ default:
+ break;
+ }
+
}
}
@@ -716,6 +740,10 @@ cipher_reset (gcry_cipher_hd_t c)
break;
#endif
+ case GCRY_CIPHER_MODE_OCB:
+ memset (&c->u_mode.ocb, 0, sizeof c->u_mode.ocb);
+ break;
+
default:
break; /* u_mode unused by other modes. */
}
@@ -827,6 +855,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_OCB:
+ rc = _gcry_cipher_ocb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stencrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);
@@ -940,6 +972,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_OCB:
+ rc = _gcry_cipher_ocb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stdecrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);
@@ -1029,6 +1065,10 @@ _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen)
rc = _gcry_cipher_poly1305_setiv (hd, iv, ivlen);
break;
+ case GCRY_CIPHER_MODE_OCB:
+ rc = _gcry_cipher_ocb_set_nonce (hd, iv, ivlen);
+ break;
+
default:
rc = cipher_setiv (hd, iv, ivlen);
break;
@@ -1083,6 +1123,10 @@ _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
rc = _gcry_cipher_poly1305_authenticate (hd, abuf, abuflen);
break;
+ case GCRY_CIPHER_MODE_OCB:
+ rc = _gcry_cipher_ocb_authenticate (hd, abuf, abuflen);
+ break;
+
default:
log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode);
rc = GPG_ERR_INV_CIPHER_MODE;
@@ -1116,6 +1160,10 @@ _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen)
rc = _gcry_cipher_poly1305_get_tag (hd, outtag, taglen);
break;
+ case GCRY_CIPHER_MODE_OCB:
+ rc = _gcry_cipher_ocb_get_tag (hd, outtag, taglen);
+ break;
+
default:
log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode);
rc = GPG_ERR_INV_CIPHER_MODE;
@@ -1149,6 +1197,10 @@ _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen)
rc = _gcry_cipher_poly1305_check_tag (hd, intag, taglen);
break;
+ case GCRY_CIPHER_MODE_OCB:
+ rc = _gcry_cipher_ocb_check_tag (hd, intag, taglen);
+ break;
+
default:
log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode);
rc = GPG_ERR_INV_CIPHER_MODE;
@@ -1170,6 +1222,12 @@ _gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
cipher_reset (h);
break;
+ case GCRYCTL_FINALIZE:
+ if (!h || buffer || buflen)
+ return GPG_ERR_INV_ARG;
+ h->marks.finalize = 1;
+ break;
+
case GCRYCTL_CFB_SYNC:
cipher_sync( h );
break;
@@ -1222,6 +1280,29 @@ _gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
#endif
break;
+ case GCRYCTL_SET_TAGLEN:
+ if (!h || !buffer || buflen != sizeof(int) )
+ return GPG_ERR_INV_ARG;
+ switch (h->mode)
+ {
+ case GCRY_CIPHER_MODE_OCB:
+ switch (*(int*)buffer)
+ {
+ case 8: case 12: case 16:
+ h->u_mode.ocb.taglen = *(int*)buffer;
+ break;
+ default:
+ rc = GPG_ERR_INV_LENGTH; /* Invalid tag length. */
+ break;
+ }
+ break;
+
+ default:
+ rc =GPG_ERR_INV_CIPHER_MODE;
+ break;
+ }
+ break;
+
case GCRYCTL_DISABLE_ALGO:
/* This command expects NULL for H and BUFFER to point to an
integer with the algo number. */