diff options
author | Werner Koch <wk@gnupg.org> | 2015-01-16 14:55:03 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2015-01-16 14:55:03 +0100 |
commit | 067d7d8752d4d8a98f8e0e5e9b1a5b13e1b7ff9c (patch) | |
tree | 1eab7affe5d24e919a22a5d4a29c8303342cf8db /cipher/cipher.c | |
parent | 9d2a22c94ae99f9301321082c4fb8d73f4085fda (diff) | |
download | libgcrypt-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.c | 83 |
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. */ |