From wk at gnupg.org Tue Oct 1 13:31:16 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 01 Oct 2013 13:31:16 +0200 Subject: possible mpi-pow improvement In-Reply-To: <1378456897.3188.14.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Fri, 06 Sep 2013 17:41:37 +0900") References: <1378456897.3188.14.camel@cfw2.gniibe.org> Message-ID: <87a9itb52z.fsf@vigenere.g10code.de> On Fri, 6 Sep 2013 10:41, gniibe at fsij.org said: > ====================== original ===================== > $ ./tests/benchmark rsa > Algorithm generate 100*sign 100*verify > ------------------------------------------------ > RSA 1024 bit 340ms 860ms 30ms > RSA 2048 bit 870ms 5510ms 110ms > RSA 3072 bit 6440ms 16930ms 210ms > RSA 4096 bit 17470ms 37270ms 360ms > My possible change: > ====================== k-ary, MUL instead of SQR ===== > Algorithm generate 100*sign 100*verify > ------------------------------------------------ > RSA 1024 bit 280ms 710ms 30ms > RSA 2048 bit 960ms 4410ms 110ms > RSA 3072 bit 17680ms 12990ms 220ms > RSA 4096 bit 12280ms 29550ms 360ms > > Any comments are appreciated. Thus you change is even an improvement for the general case. Can you please change your patch to conditionally include the k-ary multiply but enable it right away. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Tue Oct 1 13:35:07 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 01 Oct 2013 13:35:07 +0200 Subject: GOST ECC pubkey In-Reply-To: <1379655225.3179.3.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Fri, 20 Sep 2013 14:33:45 +0900") References: <1379653630.3179.2.camel@cfw2.gniibe.org> <1379655225.3179.3.camel@cfw2.gniibe.org> Message-ID: <8761thb4wk.fsf@vigenere.g10code.de> On Fri, 20 Sep 2013 07:33, gniibe at fsij.org said: > I think that it is possible to represent GOST3410 without extending > the structure ecc_domain_parms_t. Just redefine "n" as order of > cyclic subgroup of elliptic curve points group for GOST3410. Anyone else with comments? I haven't read the specs, if it is different to ECDSA we might want to add another signature scheme similar to the (flag eddsa). Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From cvs at cvs.gnupg.org Tue Oct 1 14:34:33 2013 From: cvs at cvs.gnupg.org (by Peter Wu) Date: Tue, 01 Oct 2013 14:34:33 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-283-g738177e Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 738177ec0eae05069ec61bc4f724a69d4e052e42 (commit) from 1d85452412b65e7976bc94969fc513ff6b880ed8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 738177ec0eae05069ec61bc4f724a69d4e052e42 Author: Peter Wu Date: Thu Sep 26 23:20:32 2013 +0200 cipher: Add support for 128-bit keys in RC2 * cipher/rfc2268.c (oids_rfc2268_128): New (_gcry_cipher_spec_rfc2268_128): New. * cipher/cipher.c (cipher_table_entry): Add GCRY_CIPHER_RFC2268_128. -- This patch adds support for decrypting (and encrypting) using 128-bit keys using the RC2 algorithm. Signed-off-by: Peter Wu Actually this is merely enabling that extra ID for 128 bit RFC2268. We should have used one id for that algorithm only, because a second identifier merely for having the OID in the code is a bad idea. My initial fault and thus I better apply this patch to make the id not entirely useless. -wk diff --git a/cipher/cipher.c b/cipher/cipher.c index a17ca9b..23cb99c 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -87,6 +87,8 @@ static struct cipher_table_entry #if USE_RFC2268 { &_gcry_cipher_spec_rfc2268_40, &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 }, + { &_gcry_cipher_spec_rfc2268_128, + &dummy_extra_spec, GCRY_CIPHER_RFC2268_128 }, #endif #if USE_SEED { &_gcry_cipher_spec_seed, diff --git a/cipher/rfc2268.c b/cipher/rfc2268.c index 130be9b..da0b9f4 100644 --- a/cipher/rfc2268.c +++ b/cipher/rfc2268.c @@ -351,8 +351,21 @@ static gcry_cipher_oid_spec_t oids_rfc2268_40[] = { NULL } }; +static gcry_cipher_oid_spec_t oids_rfc2268_128[] = + { + /* pbeWithSHAAnd128BitRC2_CBC */ + { "1.2.840.113549.1.12.1.5", GCRY_CIPHER_MODE_CBC }, + { NULL } + }; + gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 = { "RFC2268_40", NULL, oids_rfc2268_40, RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context), do_setkey, encrypt_block, decrypt_block }; + +gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 = { + "RFC2268_128", NULL, oids_rfc2268_128, + RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context), + do_setkey, encrypt_block, decrypt_block +}; diff --git a/src/cipher.h b/src/cipher.h index ea7a141..70b46fe 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -194,6 +194,7 @@ extern gcry_cipher_spec_t _gcry_cipher_spec_serpent128; extern gcry_cipher_spec_t _gcry_cipher_spec_serpent192; extern gcry_cipher_spec_t _gcry_cipher_spec_serpent256; extern gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40; +extern gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128; extern gcry_cipher_spec_t _gcry_cipher_spec_seed; extern gcry_cipher_spec_t _gcry_cipher_spec_camellia128; extern gcry_cipher_spec_t _gcry_cipher_spec_camellia192; ----------------------------------------------------------------------- Summary of changes: cipher/cipher.c | 2 ++ cipher/rfc2268.c | 13 +++++++++++++ src/cipher.h | 1 + 3 files changed, 16 insertions(+), 0 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From wk at gnupg.org Tue Oct 1 13:59:08 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 01 Oct 2013 13:59:08 +0200 Subject: [PATCH] Add support for 128-bit keys in RC2 In-Reply-To: <1380230432-13431-1-git-send-email-lekensteyn@gmail.com> (Peter Wu's message of "Thu, 26 Sep 2013 23:20:32 +0200") References: <1380230432-13431-1-git-send-email-lekensteyn@gmail.com> Message-ID: <87y56d9p83.fsf@vigenere.g10code.de> On Thu, 26 Sep 2013 23:20, lekensteyn at gmail.com said: > This patch adds support for decrypting (and encrypting) using 128-bit > keys using the RC2 algorithm. Actually our RC2 implementation supports any key size >= 40 bit. I can't remember why I came up with the two identifiers GCRY_CIPHER_RFC2268_40 = 307, /* Ron's Cipher 2 (40 bit). */ GCRY_CIPHER_RFC2268_128 = 308, /* Ron's Cipher 2 (128 bit). */ and didn't implement the second one. Actually GCRY_CIPHER_RFC2268 would have been sufficient because the caller may use any keylength anyway. I added a Changelog entry and pushed it to master. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Tue Oct 1 14:01:11 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 01 Oct 2013 14:01:11 +0200 Subject: Comments on the change: Mitigate a flush+reload cache attack on RSA secret exponents In-Reply-To: <1376008230.3177.2.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Fri, 09 Aug 2013 09:30:30 +0900") References: <1375939200.3172.6.camel@cfw2.gniibe.org> <871u64iqg7.fsf@vigenere.g10code.de> <1375949109.3172.12.camel@cfw2.gniibe.org> <1376008230.3177.2.camel@cfw2.gniibe.org> Message-ID: <87r4c59p4o.fsf@vigenere.g10code.de> On Fri, 9 Aug 2013 02:30, gniibe at fsij.org said: > Given the situation, my opinion is that, it's not good idea, for now, > to share some useful information with git notes (for libgcrypt, gnupg, > etc.). Okay, let's forget about this. Thanks for looking into this. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From nmav at gnutls.org Tue Oct 1 15:24:22 2013 From: nmav at gnutls.org (Nikos Mavrogiannopoulos) Date: Tue, 01 Oct 2013 15:24:22 +0200 Subject: [PATCH] Add support for 128-bit keys in RC2 In-Reply-To: <87y56d9p83.fsf@vigenere.g10code.de> References: <1380230432-13431-1-git-send-email-lekensteyn@gmail.com> <87y56d9p83.fsf@vigenere.g10code.de> Message-ID: <524ACD06.5020000@gnutls.org> On 10/01/2013 01:59 PM, Werner Koch wrote: > On Thu, 26 Sep 2013 23:20, lekensteyn at gmail.com said: >> This patch adds support for decrypting (and encrypting) using 128-bit >> keys using the RC2 algorithm. > > Actually our RC2 implementation supports any key size >= 40 bit. I > can't remember why I came up with the two identifiers It must have been because of the effective key size reduction code used in the 40 bit version. Since RC2-40 is the only version used in PKCS #12, there may have been no incentive to have the "real" RC2. regards, Nikos From lekensteyn at gmail.com Tue Oct 1 15:21:09 2013 From: lekensteyn at gmail.com (Peter Wu) Date: Tue, 01 Oct 2013 15:21:09 +0200 Subject: ../../src/visibility.c:498:3: warning: implicit declaration of function `_gcry_mpi_ec_new' [-Wimplicit-function-declaration] Message-ID: <22656519.CJENjD6aAd@al> Hi Werner, While building the latest git master (libgcrypt-1.5.0-283-g738177e), I got a warning about an implicit declaration of a function. As far as I can see, it was caused by: commit 64a7d347847d606eb5f4c156e24ba060271b8f6b Author: Werner Koch Date: Sat Sep 7 10:06:46 2013 +0200 ecc: Refactor low-level access functions. The declaration was previously done in src/mpi.h which is included by src/visibility.c, but now ec-context.h is not included by any visibility- related file. Regards, Peter From lekensteyn at gmail.com Tue Oct 1 14:59:21 2013 From: lekensteyn at gmail.com (Peter Wu) Date: Tue, 01 Oct 2013 14:59:21 +0200 Subject: [PATCH] Add support for 128-bit keys in RC2 In-Reply-To: <87y56d9p83.fsf@vigenere.g10code.de> References: <1380230432-13431-1-git-send-email-lekensteyn@gmail.com> <87y56d9p83.fsf@vigenere.g10code.de> Message-ID: <1452407.XMrRVjiz6F@al> Hi Werner, Thanks for taking this patch. On Tuesday 01 October 2013 13:59:08 Werner Koch wrote: > On Thu, 26 Sep 2013 23:20, lekensteyn at gmail.com said: > > This patch adds support for decrypting (and encrypting) using 128-bit > > keys using the RC2 algorithm. > > Actually our RC2 implementation supports any key size >= 40 bit. I > can't remember why I came up with the two identifiers > > GCRY_CIPHER_RFC2268_40 = 307, /* Ron's Cipher 2 (40 bit). */ > GCRY_CIPHER_RFC2268_128 = 308, /* Ron's Cipher 2 (128 bit). */ > > and didn't implement the second one. Actually GCRY_CIPHER_RFC2268 would > have been sufficient because the caller may use any keylength anyway. > > I added a Changelog entry and pushed it to master. Can you also update the documentation? In doc/gcrypt.texi from line 1563 it says: Ron's Cipher 2 in the 40 and 128 bit variants. Note, that we currently only support the 40 bit variant. The identifier for 128 is reserved for future use. If keys of any length (ranging from 0 to 1024?) are allowed, it could be specified in there. Regards, Peter From cvs at cvs.gnupg.org Tue Oct 1 22:35:20 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 01 Oct 2013 22:35:20 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-285-g3ca180b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 3ca180b25e8df252fc16f802cfdc27496e307830 (commit) via 4153fa859816e799e506055321a22e6450aacdcc (commit) from 738177ec0eae05069ec61bc4f724a69d4e052e42 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3ca180b25e8df252fc16f802cfdc27496e307830 Author: Werner Koch Date: Tue Oct 1 22:00:50 2013 +0200 cipher: Simplify the cipher dispatcher cipher.c. * src/gcrypt-module.h (gcry_cipher_spec_t): Move to ... * src/cipher-proto.h (gcry_cipher_spec_t): here. Merge with cipher_extra_spec_t. Add fields ALGO and FLAGS. Set these fields in all cipher modules. * cipher/cipher.c: Change most code to replace the former module system by a simpler system to gain information about the algorithms. (disable_pubkey_algo): Simplified. Not anymore thread-safe, though. * cipher/md.c (_gcry_md_selftest): Use correct structure. Not a real problem because both define the same function as their first field. * cipher/pubkey.c (_gcry_pk_selftest): Take care of the disabled flag. Signed-off-by: Werner Koch diff --git a/cipher/arcfour.c b/cipher/arcfour.c index 6ef07fb..dc32b07 100644 --- a/cipher/arcfour.c +++ b/cipher/arcfour.c @@ -150,6 +150,7 @@ selftest(void) gcry_cipher_spec_t _gcry_cipher_spec_arcfour = { + GCRY_CIPHER_ARCFOUR, {0, 0}, "ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context), arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream, }; diff --git a/cipher/blowfish.c b/cipher/blowfish.c index 61042ed..2f739c8 100644 --- a/cipher/blowfish.c +++ b/cipher/blowfish.c @@ -960,6 +960,7 @@ bf_setkey (void *context, const byte *key, unsigned keylen) gcry_cipher_spec_t _gcry_cipher_spec_blowfish = { + GCRY_CIPHER_BLOWFISH, {0, 0}, "BLOWFISH", NULL, NULL, BLOWFISH_BLOCKSIZE, 128, sizeof (BLOWFISH_context), bf_setkey, encrypt_block, decrypt_block diff --git a/cipher/camellia-glue.c b/cipher/camellia-glue.c index 2842c3b..29cb7a5 100644 --- a/cipher/camellia-glue.c +++ b/cipher/camellia-glue.c @@ -691,18 +691,21 @@ static gcry_cipher_oid_spec_t camellia256_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_camellia128 = { + GCRY_CIPHER_CAMELLIA128, {0, 0}, "CAMELLIA128",NULL,camellia128_oids,CAMELLIA_BLOCK_SIZE,128, sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt }; gcry_cipher_spec_t _gcry_cipher_spec_camellia192 = { + GCRY_CIPHER_CAMELLIA192, {0, 0}, "CAMELLIA192",NULL,camellia192_oids,CAMELLIA_BLOCK_SIZE,192, sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt }; gcry_cipher_spec_t _gcry_cipher_spec_camellia256 = { + GCRY_CIPHER_CAMELLIA256, {0, 0}, "CAMELLIA256",NULL,camellia256_oids,CAMELLIA_BLOCK_SIZE,256, sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt }; diff --git a/cipher/cast5.c b/cipher/cast5.c index ae6b509..92d9af8 100644 --- a/cipher/cast5.c +++ b/cipher/cast5.c @@ -983,6 +983,7 @@ cast_setkey (void *context, const byte *key, unsigned keylen ) gcry_cipher_spec_t _gcry_cipher_spec_cast5 = { + GCRY_CIPHER_CAST5, {0, 0}, "CAST5", NULL, NULL, CAST5_BLOCKSIZE, 128, sizeof (CAST5_context), cast_setkey, encrypt_block, decrypt_block }; diff --git a/cipher/cipher-aeswrap.c b/cipher/cipher-aeswrap.c index 931dec1..03b0ea7 100644 --- a/cipher/cipher-aeswrap.c +++ b/cipher/cipher-aeswrap.c @@ -48,7 +48,7 @@ _gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c, #error Invalid block size #endif /* We require a cipher with a 128 bit block length. */ - if (c->cipher->blocksize != 16) + if (c->spec->blocksize != 16) return GPG_ERR_INV_LENGTH; /* The output buffer must be able to hold the input data plus one @@ -90,7 +90,7 @@ _gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c, /* B := AES_k( A | R[i] ) */ memcpy (b, a, 8); memcpy (b+8, r+i*8, 8); - nburn = c->cipher->encrypt (&c->context.c, b, b); + nburn = c->spec->encrypt (&c->context.c, b, b); burn = nburn > burn ? nburn : burn; /* t := t + 1 */ for (x = 7; x >= 0; x--) @@ -130,7 +130,7 @@ _gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c, #error Invalid block size #endif /* We require a cipher with a 128 bit block length. */ - if (c->cipher->blocksize != 16) + if (c->spec->blocksize != 16) return GPG_ERR_INV_LENGTH; /* The output buffer must be able to hold the input data minus one @@ -173,7 +173,7 @@ _gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c, /* B := AES_k^1( (A ^ t)| R[i] ) */ buf_xor(b, a, t, 8); memcpy (b+8, r+(i-1)*8, 8); - nburn = c->cipher->decrypt (&c->context.c, b, b); + nburn = c->spec->decrypt (&c->context.c, b, b); burn = nburn > burn ? nburn : burn; /* t := t - 1 */ for (x = 7; x >= 0; x--) diff --git a/cipher/cipher-cbc.c b/cipher/cipher-cbc.c index 55a1c74..523f5a6 100644 --- a/cipher/cipher-cbc.c +++ b/cipher/cipher-cbc.c @@ -40,15 +40,15 @@ _gcry_cipher_cbc_encrypt (gcry_cipher_hd_t c, unsigned int n; unsigned char *ivp; int i; - size_t blocksize = c->cipher->blocksize; + size_t blocksize = c->spec->blocksize; unsigned nblocks = inbuflen / blocksize; unsigned int burn, nburn; if (outbuflen < ((c->flags & GCRY_CIPHER_CBC_MAC)? blocksize : inbuflen)) return GPG_ERR_BUFFER_TOO_SHORT; - if ((inbuflen % c->cipher->blocksize) - && !(inbuflen > c->cipher->blocksize + if ((inbuflen % c->spec->blocksize) + && !(inbuflen > c->spec->blocksize && (c->flags & GCRY_CIPHER_CBC_CTS))) return GPG_ERR_INV_LENGTH; @@ -73,7 +73,7 @@ _gcry_cipher_cbc_encrypt (gcry_cipher_hd_t c, for (n=0; n < nblocks; n++ ) { buf_xor(outbuf, inbuf, c->u_iv.iv, blocksize); - nburn = c->cipher->encrypt ( &c->context.c, outbuf, outbuf ); + nburn = c->spec->encrypt ( &c->context.c, outbuf, outbuf ); burn = nburn > burn ? nburn : burn; memcpy (c->u_iv.iv, outbuf, blocksize ); inbuf += blocksize; @@ -104,7 +104,7 @@ _gcry_cipher_cbc_encrypt (gcry_cipher_hd_t c, for (; i < blocksize; i++) outbuf[i] = 0 ^ *ivp++; - nburn = c->cipher->encrypt (&c->context.c, outbuf, outbuf); + nburn = c->spec->encrypt (&c->context.c, outbuf, outbuf); burn = nburn > burn ? nburn : burn; memcpy (c->u_iv.iv, outbuf, blocksize); } @@ -123,15 +123,15 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd_t c, { unsigned int n; int i; - size_t blocksize = c->cipher->blocksize; + size_t blocksize = c->spec->blocksize; unsigned int nblocks = inbuflen / blocksize; unsigned int burn, nburn; if (outbuflen < inbuflen) return GPG_ERR_BUFFER_TOO_SHORT; - if ((inbuflen % c->cipher->blocksize) - && !(inbuflen > c->cipher->blocksize + if ((inbuflen % c->spec->blocksize) + && !(inbuflen > c->spec->blocksize && (c->flags & GCRY_CIPHER_CBC_CTS))) return GPG_ERR_INV_LENGTH; @@ -159,12 +159,12 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd_t c, * save the original ciphertext block. We use LASTIV for * this here because it is not used otherwise. */ memcpy (c->lastiv, inbuf, blocksize); - nburn = c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); + nburn = c->spec->decrypt ( &c->context.c, outbuf, inbuf ); burn = nburn > burn ? nburn : burn; buf_xor(outbuf, outbuf, c->u_iv.iv, blocksize); memcpy(c->u_iv.iv, c->lastiv, blocksize ); - inbuf += c->cipher->blocksize; - outbuf += c->cipher->blocksize; + inbuf += c->spec->blocksize; + outbuf += c->spec->blocksize; } } @@ -180,14 +180,14 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd_t c, memcpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ memcpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ - nburn = c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); + nburn = c->spec->decrypt ( &c->context.c, outbuf, inbuf ); burn = nburn > burn ? nburn : burn; buf_xor(outbuf, outbuf, c->u_iv.iv, restbytes); memcpy(outbuf + blocksize, outbuf, restbytes); for(i=restbytes; i < blocksize; i++) c->u_iv.iv[i] = outbuf[i]; - nburn = c->cipher->decrypt (&c->context.c, outbuf, c->u_iv.iv); + nburn = c->spec->decrypt (&c->context.c, outbuf, c->u_iv.iv); burn = nburn > burn ? nburn : burn; buf_xor(outbuf, outbuf, c->lastiv, blocksize); /* c->lastiv is now really lastlastiv, does this matter? */ diff --git a/cipher/cipher-cfb.c b/cipher/cipher-cfb.c index f772280..244f5fd 100644 --- a/cipher/cipher-cfb.c +++ b/cipher/cipher-cfb.c @@ -37,7 +37,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, const unsigned char *inbuf, unsigned int inbuflen) { unsigned char *ivp; - size_t blocksize = c->cipher->blocksize; + size_t blocksize = c->spec->blocksize; size_t blocksize_x_2 = blocksize + blocksize; unsigned int burn, nburn; @@ -48,7 +48,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, { /* Short enough to be encoded by the remaining XOR mask. */ /* XOR the input with the IV and store input into IV. */ - ivp = c->u_iv.iv + c->cipher->blocksize - c->unused; + ivp = c->u_iv.iv + c->spec->blocksize - c->unused; buf_xor_2dst(outbuf, ivp, inbuf, inbuflen); c->unused -= inbuflen; return 0; @@ -83,7 +83,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, while ( inbuflen >= blocksize_x_2 ) { /* Encrypt the IV. */ - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV. */ buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); @@ -97,7 +97,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, { /* Save the current IV and then encrypt the IV. */ memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV */ buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); @@ -109,7 +109,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, { /* Save the current IV and then encrypt the IV. */ memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; c->unused = blocksize; /* Apply the XOR. */ @@ -133,7 +133,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, const unsigned char *inbuf, unsigned int inbuflen) { unsigned char *ivp; - size_t blocksize = c->cipher->blocksize; + size_t blocksize = c->spec->blocksize; size_t blocksize_x_2 = blocksize + blocksize; unsigned int burn, nburn; @@ -179,7 +179,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, while (inbuflen >= blocksize_x_2 ) { /* Encrypt the IV. */ - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV. */ buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); @@ -193,7 +193,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, { /* Save the current IV and then encrypt the IV. */ memcpy ( c->lastiv, c->u_iv.iv, blocksize); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV */ buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); @@ -206,7 +206,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, { /* Save the current IV and then encrypt the IV. */ memcpy ( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; c->unused = blocksize; /* Apply the XOR. */ diff --git a/cipher/cipher-ctr.c b/cipher/cipher-ctr.c index ff1742c..fbc898f 100644 --- a/cipher/cipher-ctr.c +++ b/cipher/cipher-ctr.c @@ -38,7 +38,7 @@ _gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c, { unsigned int n; int i; - unsigned int blocksize = c->cipher->blocksize; + unsigned int blocksize = c->spec->blocksize; unsigned int nblocks; unsigned int burn, nburn; @@ -77,7 +77,7 @@ _gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c, unsigned char tmp[MAX_BLOCKSIZE]; do { - nburn = c->cipher->encrypt (&c->context.c, tmp, c->u_ctr.ctr); + nburn = c->spec->encrypt (&c->context.c, tmp, c->u_ctr.ctr); burn = nburn > burn ? nburn : burn; for (i = blocksize; i > 0; i--) diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index 025bf2e..cabcd1f 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -60,8 +60,7 @@ struct gcry_cipher_handle int magic; size_t actual_handle_size; /* Allocated size of this handle. */ size_t handle_offset; /* Offset to the malloced block. */ - gcry_cipher_spec_t *cipher; - cipher_extra_spec_t *extraspec; + gcry_cipher_spec_t *spec; gcry_module_t module; /* The algorithm id. This is a hack required because the module diff --git a/cipher/cipher-ofb.c b/cipher/cipher-ofb.c index 3fb9b0d..3d9d54c 100644 --- a/cipher/cipher-ofb.c +++ b/cipher/cipher-ofb.c @@ -37,7 +37,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, const unsigned char *inbuf, unsigned int inbuflen) { unsigned char *ivp; - size_t blocksize = c->cipher->blocksize; + size_t blocksize = c->spec->blocksize; unsigned int burn, nburn; if (outbuflen < inbuflen) @@ -47,7 +47,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, { /* Short enough to be encoded by the remaining XOR mask. */ /* XOR the input with the IV */ - ivp = c->u_iv.iv + c->cipher->blocksize - c->unused; + ivp = c->u_iv.iv + c->spec->blocksize - c->unused; buf_xor(outbuf, ivp, inbuf, inbuflen); c->unused -= inbuflen; return 0; @@ -70,7 +70,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, { /* Encrypt the IV (and save the current one). */ memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize); outbuf += blocksize; @@ -80,7 +80,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, if ( inbuflen ) { /* process the remaining bytes */ memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; c->unused = blocksize; c->unused -= inbuflen; @@ -103,7 +103,7 @@ _gcry_cipher_ofb_decrypt (gcry_cipher_hd_t c, const unsigned char *inbuf, unsigned int inbuflen) { unsigned char *ivp; - size_t blocksize = c->cipher->blocksize; + size_t blocksize = c->spec->blocksize; unsigned int burn, nburn; if (outbuflen < inbuflen) @@ -135,7 +135,7 @@ _gcry_cipher_ofb_decrypt (gcry_cipher_hd_t c, { /* Encrypt the IV (and save the current one). */ memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize); outbuf += blocksize; @@ -146,7 +146,7 @@ _gcry_cipher_ofb_decrypt (gcry_cipher_hd_t c, { /* Process the remaining bytes. */ /* Encrypt the IV (and save the current one). */ memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; c->unused = blocksize; c->unused -= inbuflen; diff --git a/cipher/cipher.c b/cipher/cipher.c index 23cb99c..ca61375 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -1,6 +1,7 @@ /* cipher.c - cipher dispatcher * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * @@ -29,355 +30,168 @@ #include "ath.h" #include "./cipher-internal.h" -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static cipher_extra_spec_t dummy_extra_spec; /* This is the list of the default ciphers, which are included in libgcrypt. */ -static struct cipher_table_entry -{ - gcry_cipher_spec_t *cipher; - cipher_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} cipher_table[] = +static gcry_cipher_spec_t *cipher_list[] = { #if USE_BLOWFISH - { &_gcry_cipher_spec_blowfish, - &dummy_extra_spec, GCRY_CIPHER_BLOWFISH }, + &_gcry_cipher_spec_blowfish, #endif #if USE_DES - { &_gcry_cipher_spec_des, - &dummy_extra_spec, GCRY_CIPHER_DES }, - { &_gcry_cipher_spec_tripledes, - &_gcry_cipher_extraspec_tripledes, GCRY_CIPHER_3DES, 1 }, + &_gcry_cipher_spec_des, + &_gcry_cipher_spec_tripledes, #endif #if USE_ARCFOUR - { &_gcry_cipher_spec_arcfour, - &dummy_extra_spec, GCRY_CIPHER_ARCFOUR }, + &_gcry_cipher_spec_arcfour, #endif #if USE_CAST5 - { &_gcry_cipher_spec_cast5, - &dummy_extra_spec, GCRY_CIPHER_CAST5 }, + &_gcry_cipher_spec_cast5, #endif #if USE_AES - { &_gcry_cipher_spec_aes, - &_gcry_cipher_extraspec_aes, GCRY_CIPHER_AES, 1 }, - { &_gcry_cipher_spec_aes192, - &_gcry_cipher_extraspec_aes192, GCRY_CIPHER_AES192, 1 }, - { &_gcry_cipher_spec_aes256, - &_gcry_cipher_extraspec_aes256, GCRY_CIPHER_AES256, 1 }, + &_gcry_cipher_spec_aes, + &_gcry_cipher_spec_aes192, + &_gcry_cipher_spec_aes256, #endif #if USE_TWOFISH - { &_gcry_cipher_spec_twofish, - &dummy_extra_spec, GCRY_CIPHER_TWOFISH }, - { &_gcry_cipher_spec_twofish128, - &dummy_extra_spec, GCRY_CIPHER_TWOFISH128 }, + &_gcry_cipher_spec_twofish, + &_gcry_cipher_spec_twofish128, #endif #if USE_SERPENT - { &_gcry_cipher_spec_serpent128, - &dummy_extra_spec, GCRY_CIPHER_SERPENT128 }, - { &_gcry_cipher_spec_serpent192, - &dummy_extra_spec, GCRY_CIPHER_SERPENT192 }, - { &_gcry_cipher_spec_serpent256, - &dummy_extra_spec, GCRY_CIPHER_SERPENT256 }, + &_gcry_cipher_spec_serpent128, + &_gcry_cipher_spec_serpent192, + &_gcry_cipher_spec_serpent256, #endif #if USE_RFC2268 - { &_gcry_cipher_spec_rfc2268_40, - &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 }, - { &_gcry_cipher_spec_rfc2268_128, - &dummy_extra_spec, GCRY_CIPHER_RFC2268_128 }, + &_gcry_cipher_spec_rfc2268_40, + &_gcry_cipher_spec_rfc2268_128, #endif #if USE_SEED - { &_gcry_cipher_spec_seed, - &dummy_extra_spec, GCRY_CIPHER_SEED }, + &_gcry_cipher_spec_seed, #endif #if USE_CAMELLIA - { &_gcry_cipher_spec_camellia128, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA128 }, - { &_gcry_cipher_spec_camellia192, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA192 }, - { &_gcry_cipher_spec_camellia256, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA256 }, + &_gcry_cipher_spec_camellia128, + &_gcry_cipher_spec_camellia192, + &_gcry_cipher_spec_camellia256, #endif #ifdef USE_IDEA - { &_gcry_cipher_spec_idea, - &dummy_extra_spec, GCRY_CIPHER_IDEA }, + &_gcry_cipher_spec_idea, #endif #if USE_SALSA20 - { &_gcry_cipher_spec_salsa20, - &_gcry_cipher_extraspec_salsa20, GCRY_CIPHER_SALSA20 }, - { &_gcry_cipher_spec_salsa20r12, - &_gcry_cipher_extraspec_salsa20, GCRY_CIPHER_SALSA20R12 }, + &_gcry_cipher_spec_salsa20, + &_gcry_cipher_spec_salsa20r12, #endif #if USE_GOST28147 - { &_gcry_cipher_spec_gost28147, - &dummy_extra_spec, GCRY_CIPHER_GOST28147 }, + &_gcry_cipher_spec_gost28147, #endif - { NULL } + NULL }; -/* List of registered ciphers. */ -static gcry_module_t ciphers_registered; - -/* This is the lock protecting CIPHERS_REGISTERED. It is initialized - by _gcry_cipher_init. */ -static ath_mutex_t ciphers_registered_lock; - -/* Flag to check whether the default ciphers have already been - registered. */ -static int default_ciphers_registered; - -/* Convenient macro for registering the default ciphers. */ -#define REGISTER_DEFAULT_CIPHERS \ - do \ - { \ - ath_mutex_lock (&ciphers_registered_lock); \ - if (! default_ciphers_registered) \ - { \ - cipher_register_default (); \ - default_ciphers_registered = 1; \ - } \ - ath_mutex_unlock (&ciphers_registered_lock); \ - } \ - while (0) -/* These dummy functions are used in case a cipher implementation - refuses to provide it's own functions. */ - -static gcry_err_code_t -dummy_setkey (void *c, const unsigned char *key, unsigned int keylen) +static int +map_algo (int algo) { - (void)c; - (void)key; - (void)keylen; - return GPG_ERR_NO_ERROR; + return algo; } -static unsigned int -dummy_encrypt_block (void *c, - unsigned char *outbuf, const unsigned char *inbuf) -{ - (void)c; - (void)outbuf; - (void)inbuf; - BUG(); - return 0; -} -static unsigned int -dummy_decrypt_block (void *c, - unsigned char *outbuf, const unsigned char *inbuf) +/* Return the spec structure for the cipher algorithm ALGO. For + an unknown algorithm NULL is returned. */ +static gcry_cipher_spec_t * +spec_from_algo (int algo) { - (void)c; - (void)outbuf; - (void)inbuf; - BUG(); - return 0; -} + int idx; + gcry_cipher_spec_t *spec; -static void -dummy_encrypt_stream (void *c, - unsigned char *outbuf, const unsigned char *inbuf, - unsigned int n) -{ - (void)c; - (void)outbuf; - (void)inbuf; - (void)n; - BUG(); -} + algo = map_algo (algo); -static void -dummy_decrypt_stream (void *c, - unsigned char *outbuf, const unsigned char *inbuf, - unsigned int n) -{ - (void)c; - (void)outbuf; - (void)inbuf; - (void)n; - BUG(); + for (idx = 0; (spec = cipher_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; } - -/* Internal function. Register all the ciphers included in - CIPHER_TABLE. Note, that this function gets only used by the macro - REGISTER_DEFAULT_CIPHERS which protects it using a mutex. */ -static void -cipher_register_default (void) + +/* Lookup a cipher's spec by its name. */ +static gcry_cipher_spec_t * +spec_from_name (const char *name) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - int i; + gcry_cipher_spec_t *spec; + int idx; + const char **aliases; - for (i = 0; !err && cipher_table[i].cipher; i++) + for (idx=0; (spec = cipher_list[idx]); idx++) { - if (! cipher_table[i].cipher->setkey) - cipher_table[i].cipher->setkey = dummy_setkey; - if (! cipher_table[i].cipher->encrypt) - cipher_table[i].cipher->encrypt = dummy_encrypt_block; - if (! cipher_table[i].cipher->decrypt) - cipher_table[i].cipher->decrypt = dummy_decrypt_block; - if (! cipher_table[i].cipher->stencrypt) - cipher_table[i].cipher->stencrypt = dummy_encrypt_stream; - if (! cipher_table[i].cipher->stdecrypt) - cipher_table[i].cipher->stdecrypt = dummy_decrypt_stream; - - if ( fips_mode () && !cipher_table[i].fips_allowed ) - continue; - - err = _gcry_module_add (&ciphers_registered, - cipher_table[i].algorithm, - (void *) cipher_table[i].cipher, - (void *) cipher_table[i].extraspec, - NULL); + if (!stricmp (name, spec->name)) + return spec; + if (spec->aliases) + { + for (aliases = spec->aliases; *aliases; aliases++) + if (!stricmp (name, *aliases)) + return spec; + } } - if (err) - BUG (); + return NULL; } -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_cipher_lookup_func_name (void *spec, void *data) -{ - gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; - char *name = (char *) data; - const char **aliases = cipher->aliases; - int i, ret = ! stricmp (name, cipher->name); - - if (aliases) - for (i = 0; aliases[i] && (! ret); i++) - ret = ! stricmp (name, aliases[i]); - - return ret; -} -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_cipher_lookup_func_oid (void *spec, void *data) -{ - gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; - char *oid = (char *) data; - gcry_cipher_oid_spec_t *oid_specs = cipher->oids; - int ret = 0, i; - - if (oid_specs) - for (i = 0; oid_specs[i].oid && (! ret); i++) - if (! stricmp (oid, oid_specs[i].oid)) - ret = 1; - - return ret; -} - -/* Internal function. Lookup a cipher entry by it's name. */ -static gcry_module_t -gcry_cipher_lookup_name (const char *name) -{ - gcry_module_t cipher; - - cipher = _gcry_module_lookup (ciphers_registered, (void *) name, - gcry_cipher_lookup_func_name); - - return cipher; -} - -/* Internal function. Lookup a cipher entry by it's oid. */ -static gcry_module_t -gcry_cipher_lookup_oid (const char *oid) -{ - gcry_module_t cipher; - - cipher = _gcry_module_lookup (ciphers_registered, (void *) oid, - gcry_cipher_lookup_func_oid); - - return cipher; -} - -/* Register a new cipher module whose specification can be found in - CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_cipher_register (gcry_cipher_spec_t *cipher, - cipher_extra_spec_t *extraspec, - int *algorithm_id, - gcry_module_t *module) +/* Lookup a cipher's spec by its OID. */ +static gcry_cipher_spec_t * +spec_from_oid (const char *oid) { - gcry_err_code_t err = 0; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&ciphers_registered_lock); - err = _gcry_module_add (&ciphers_registered, 0, - (void *)cipher, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&ciphers_registered_lock); + gcry_cipher_spec_t *spec; + gcry_cipher_oid_spec_t *oid_specs; + int idx, j; - if (! err) + for (idx=0; (spec = cipher_list[idx]); idx++) { - *module = mod; - *algorithm_id = mod->mod_id; + oid_specs = spec->oids; + if (oid_specs) + { + for (j = 0; oid_specs[j].oid; j++) + if (!stricmp (oid, oid_specs[j].oid)) + return spec; + } } - return gcry_error (err); + return NULL; } -/* Unregister the cipher identified by MODULE, which must have been - registered with gcry_cipher_register. */ -void -_gcry_cipher_unregister (gcry_module_t module) -{ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); -} -/* Locate the OID in the oid table and return the index or -1 when not - found. An opitonal "oid." or "OID." prefix in OID is ignored, the - OID is expected to be in standard IETF dotted notation. The - internal algorithm number is returned in ALGORITHM unless it - ispassed as NULL. A pointer to the specification of the module - implementing this algorithm is return in OID_SPEC unless passed as - NULL.*/ -static int -search_oid (const char *oid, int *algorithm, gcry_cipher_oid_spec_t *oid_spec) +/* Locate the OID in the oid table and return the spec or NULL if not + found. An optional "oid." or "OID." prefix in OID is ignored, the + OID is expected to be in standard IETF dotted notation. A pointer + to the OID specification of the module implementing this algorithm + is return in OID_SPEC unless passed as NULL.*/ +static gcry_cipher_spec_t * +search_oid (const char *oid, gcry_cipher_oid_spec_t *oid_spec) { - gcry_module_t module; - int ret = 0; + gcry_cipher_spec_t *spec; + int i; if (oid && ((! strncmp (oid, "oid.", 4)) || (! strncmp (oid, "OID.", 4)))) oid += 4; - module = gcry_cipher_lookup_oid (oid); - if (module) + spec = spec_from_oid (oid); + if (spec && spec->oids) { - gcry_cipher_spec_t *cipher = module->spec; - int i; - - for (i = 0; cipher->oids[i].oid && !ret; i++) - if (! stricmp (oid, cipher->oids[i].oid)) + for (i = 0; spec->oids[i].oid; i++) + if (!stricmp (oid, spec->oids[i].oid)) { - if (algorithm) - *algorithm = module->mod_id; if (oid_spec) - *oid_spec = cipher->oids[i]; - ret = 1; + *oid_spec = spec->oids[i]; + return spec; } - _gcry_module_release (module); } - return ret; + return NULL; } + /* Map STRING to the cipher algorithm identifier. Returns the algorithm ID of the cipher for the given name or 0 if the name is not known. It is valid to pass NULL for STRING which results in a @@ -385,34 +199,24 @@ search_oid (const char *oid, int *algorithm, gcry_cipher_oid_spec_t *oid_spec) int gcry_cipher_map_name (const char *string) { - gcry_module_t cipher; - int ret, algorithm = 0; + gcry_cipher_spec_t *spec; - if (! string) + if (!string) return 0; - REGISTER_DEFAULT_CIPHERS; - /* If the string starts with a digit (optionally prefixed with either "OID." or "oid."), we first look into our table of ASN.1 object identifiers to figure out the algorithm */ - ath_mutex_lock (&ciphers_registered_lock); - - ret = search_oid (string, &algorithm, NULL); - if (! ret) - { - cipher = gcry_cipher_lookup_name (string); - if (cipher) - { - algorithm = cipher->mod_id; - _gcry_module_release (cipher); - } - } + spec = search_oid (string, NULL); + if (spec) + return spec->algo; - ath_mutex_unlock (&ciphers_registered_lock); + spec = spec_from_name (string); + if (spec) + return spec->algo; - return algorithm; + return 0; } @@ -423,78 +227,46 @@ gcry_cipher_map_name (const char *string) int gcry_cipher_mode_from_oid (const char *string) { + gcry_cipher_spec_t *spec; gcry_cipher_oid_spec_t oid_spec; - int ret = 0, mode = 0; if (!string) return 0; - ath_mutex_lock (&ciphers_registered_lock); - ret = search_oid (string, NULL, &oid_spec); - if (ret) - mode = oid_spec.mode; - ath_mutex_unlock (&ciphers_registered_lock); + spec = search_oid (string, &oid_spec); + if (spec) + return oid_spec.mode; - return mode; + return 0; } -/* Map the cipher algorithm whose ID is contained in ALGORITHM to a - string representation of the algorithm name. For unknown algorithm - IDs this function returns "?". */ -static const char * -cipher_algo_to_string (int algorithm) -{ - gcry_module_t cipher; - const char *name; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - name = ((gcry_cipher_spec_t *) cipher->spec)->name; - _gcry_module_release (cipher); - } - else - name = "?"; - ath_mutex_unlock (&ciphers_registered_lock); - - return name; -} - /* Map the cipher algorithm identifier ALGORITHM to a string representing this algorithm. This string is the default name as - used by Libgcrypt. An pointer to an empty string is returned for - an unknown algorithm. NULL is never returned. */ + used by Libgcrypt. A "?" is returned for an unknown algorithm. + NULL is never returned. */ const char * gcry_cipher_algo_name (int algorithm) { - return cipher_algo_to_string (algorithm); + gcry_cipher_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec? spec->name : "?"; } /* Flag the cipher algorithm with the identifier ALGORITHM as disabled. There is no error return, the function does nothing for - unknown algorithms. Disabled algorithms are vitually not available - in Libgcrypt. */ + unknown algorithms. Disabled algorithms are virtually not + available in Libgcrypt. This is not thread safe and should thus be + called early. */ static void -disable_cipher_algo (int algorithm) +disable_cipher_algo (int algo) { - gcry_module_t cipher; - - REGISTER_DEFAULT_CIPHERS; + gcry_cipher_spec_t *spec = spec_from_algo (algo); - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - if (! (cipher->flags & FLAG_MODULE_DISABLED)) - cipher->flags |= FLAG_MODULE_DISABLED; - _gcry_module_release (cipher); - } - ath_mutex_unlock (&ciphers_registered_lock); + if (spec) + spec->flags.disabled = 1; } @@ -504,24 +276,13 @@ disable_cipher_algo (int algorithm) static gcry_err_code_t check_cipher_algo (int algorithm) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t cipher; - - REGISTER_DEFAULT_CIPHERS; + gcry_cipher_spec_t *spec; - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - if (cipher->flags & FLAG_MODULE_DISABLED) - err = GPG_ERR_CIPHER_ALGO; - _gcry_module_release (cipher); - } - else - err = GPG_ERR_CIPHER_ALGO; - ath_mutex_unlock (&ciphers_registered_lock); + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; - return err; + return GPG_ERR_CIPHER_ALGO; } @@ -530,45 +291,36 @@ check_cipher_algo (int algorithm) static unsigned int cipher_get_keylen (int algorithm) { - gcry_module_t cipher; + gcry_cipher_spec_t *spec; unsigned len = 0; - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) + spec = spec_from_algo (algorithm); + if (spec) { - len = ((gcry_cipher_spec_t *) cipher->spec)->keylen; + len = spec->keylen; if (!len) log_bug ("cipher %d w/o key length\n", algorithm); - _gcry_module_release (cipher); } - ath_mutex_unlock (&ciphers_registered_lock); return len; } + /* Return the block length of the cipher algorithm with the identifier ALGORITHM. This function return 0 for an invalid algorithm. */ static unsigned int cipher_get_blocksize (int algorithm) { - gcry_module_t cipher; + gcry_cipher_spec_t *spec; unsigned len = 0; - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) + spec = spec_from_algo (algorithm); + if (spec) { - len = ((gcry_cipher_spec_t *) cipher->spec)->blocksize; - if (! len) - log_bug ("cipher %d w/o blocksize\n", algorithm); - _gcry_module_release (cipher); + len = spec->blocksize; + if (!len) + log_bug ("cipher %d w/o blocksize\n", algorithm); } - ath_mutex_unlock (&ciphers_registered_lock); return len; } @@ -593,40 +345,21 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, int algo, int mode, unsigned int flags) { int secure = (flags & GCRY_CIPHER_SECURE); - gcry_cipher_spec_t *cipher = NULL; - cipher_extra_spec_t *extraspec = NULL; - gcry_module_t module = NULL; + gcry_cipher_spec_t *spec; gcry_cipher_hd_t h = NULL; - gcry_err_code_t err = 0; + gcry_err_code_t err; /* If the application missed to call the random poll function, we do it here to ensure that it is used once in a while. */ _gcry_fast_random_poll (); - REGISTER_DEFAULT_CIPHERS; - - /* Fetch the according module and check whether the cipher is marked - available for use. */ - ath_mutex_lock (&ciphers_registered_lock); - module = _gcry_module_lookup_id (ciphers_registered, algo); - if (module) - { - /* Found module. */ - - if (module->flags & FLAG_MODULE_DISABLED) - { - /* Not available for use. */ - err = GPG_ERR_CIPHER_ALGO; - } - else - { - cipher = (gcry_cipher_spec_t *) module->spec; - extraspec = module->extraspec; - } - } - else + spec = spec_from_algo (algo); + if (!spec) + err = GPG_ERR_CIPHER_ALGO; + else if (spec->flags.disabled) err = GPG_ERR_CIPHER_ALGO; - ath_mutex_unlock (&ciphers_registered_lock); + else + err = 0; /* check flags */ if ((! err) @@ -648,14 +381,12 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, case GCRY_CIPHER_MODE_OFB: case GCRY_CIPHER_MODE_CTR: case GCRY_CIPHER_MODE_AESWRAP: - if ((cipher->encrypt == dummy_encrypt_block) - || (cipher->decrypt == dummy_decrypt_block)) + if (!spec->encrypt || !spec->decrypt) err = GPG_ERR_INV_CIPHER_MODE; break; case GCRY_CIPHER_MODE_STREAM: - if ((cipher->stencrypt == dummy_encrypt_stream) - || (cipher->stdecrypt == dummy_decrypt_stream)) + if (!spec->stencrypt || !spec->stdecrypt) err = GPG_ERR_INV_CIPHER_MODE; break; @@ -674,13 +405,12 @@ gcry_cipher_open (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) { size_t size = (sizeof (*h) - + 2 * cipher->contextsize + + 2 * spec->contextsize - sizeof (cipher_context_alignment_t) #ifdef NEED_16BYTE_ALIGNED_CONTEXT + 15 /* Space for leading alignment gap. */ @@ -711,9 +441,7 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; h->actual_handle_size = size - off; h->handle_offset = off; - h->cipher = cipher; - h->extraspec = extraspec; - h->module = module; + h->spec = spec; h->algo = algo; h->mode = mode; h->flags = flags; @@ -781,17 +509,6 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, /* Done. */ - if (err) - { - if (module) - { - /* Release module. */ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); - } - } - *handle = err ? NULL : h; return gcry_error (err); @@ -815,11 +532,6 @@ gcry_cipher_close (gcry_cipher_hd_t h) else h->magic = 0; - /* Release module. */ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (h->module); - ath_mutex_unlock (&ciphers_registered_lock); - /* We always want to wipe out the memory even when the context has been allocated in secure memory. The user might have disabled secure memory or is using his own implementation which does not @@ -840,13 +552,13 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen) { gcry_err_code_t ret; - ret = (*c->cipher->setkey) (&c->context.c, key, keylen); + ret = c->spec->setkey (&c->context.c, key, keylen); if (!ret) { /* Duplicate initial context. */ - memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize), + memcpy ((void *) ((char *) &c->context.c + c->spec->contextsize), (void *) &c->context.c, - c->cipher->contextsize); + c->spec->contextsize); c->marks.key = 1; } else @@ -863,23 +575,23 @@ cipher_setiv (gcry_cipher_hd_t c, const byte *iv, unsigned ivlen) { /* If the cipher has its own IV handler, we use only this one. This is currently used for stream ciphers requiring a nonce. */ - if (c->extraspec && c->extraspec->setiv) + if (c->spec->setiv) { - c->extraspec->setiv (&c->context.c, iv, ivlen); + c->spec->setiv (&c->context.c, iv, ivlen); return; } - memset (c->u_iv.iv, 0, c->cipher->blocksize); + memset (c->u_iv.iv, 0, c->spec->blocksize); if (iv) { - if (ivlen != c->cipher->blocksize) + if (ivlen != c->spec->blocksize) { log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n", - ivlen, (unsigned int)c->cipher->blocksize); + ivlen, (unsigned int)c->spec->blocksize); fips_signal_error ("IV length does not match blocklength"); } - if (ivlen > c->cipher->blocksize) - ivlen = c->cipher->blocksize; + if (ivlen > c->spec->blocksize) + ivlen = c->spec->blocksize; memcpy (c->u_iv.iv, iv, ivlen); c->marks.iv = 1; } @@ -895,12 +607,12 @@ static void cipher_reset (gcry_cipher_hd_t c) { memcpy (&c->context.c, - (char *) &c->context.c + c->cipher->contextsize, - c->cipher->contextsize); + (char *) &c->context.c + c->spec->contextsize, + c->spec->contextsize); memset (&c->marks, 0, sizeof c->marks); - memset (c->u_iv.iv, 0, c->cipher->blocksize); - memset (c->lastiv, 0, c->cipher->blocksize); - memset (c->u_ctr.ctr, 0, c->cipher->blocksize); + memset (c->u_iv.iv, 0, c->spec->blocksize); + memset (c->lastiv, 0, c->spec->blocksize); + memset (c->u_ctr.ctr, 0, c->spec->blocksize); } @@ -910,7 +622,7 @@ do_ecb_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, unsigned int outbuflen, const unsigned char *inbuf, unsigned int inbuflen) { - unsigned int blocksize = c->cipher->blocksize; + unsigned int blocksize = c->spec->blocksize; unsigned int n, nblocks; unsigned int burn, nburn; @@ -919,12 +631,12 @@ do_ecb_encrypt (gcry_cipher_hd_t c, if ((inbuflen % blocksize)) return GPG_ERR_INV_LENGTH; - nblocks = inbuflen / c->cipher->blocksize; + nblocks = inbuflen / c->spec->blocksize; burn = 0; for (n=0; n < nblocks; n++ ) { - nburn = c->cipher->encrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf); + nburn = c->spec->encrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf); burn = nburn > burn ? nburn : burn; inbuf += blocksize; outbuf += blocksize; @@ -941,7 +653,7 @@ do_ecb_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, unsigned int outbuflen, const unsigned char *inbuf, unsigned int inbuflen) { - unsigned int blocksize = c->cipher->blocksize; + unsigned int blocksize = c->spec->blocksize; unsigned int n, nblocks; unsigned int burn, nburn; @@ -950,12 +662,12 @@ do_ecb_decrypt (gcry_cipher_hd_t c, if ((inbuflen % blocksize)) return GPG_ERR_INV_LENGTH; - nblocks = inbuflen / c->cipher->blocksize; + nblocks = inbuflen / c->spec->blocksize; burn = 0; for (n=0; n < nblocks; n++ ) { - nburn = c->cipher->decrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf); + nburn = c->spec->decrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf); burn = nburn > burn ? nburn : burn; inbuf += blocksize; outbuf += blocksize; @@ -1007,8 +719,8 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, break; case GCRY_CIPHER_MODE_STREAM: - c->cipher->stencrypt (&c->context.c, - outbuf, (byte*)/*arggg*/inbuf, inbuflen); + c->spec->stencrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen); rc = 0; break; @@ -1100,8 +812,8 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, break; case GCRY_CIPHER_MODE_STREAM: - c->cipher->stdecrypt (&c->context.c, - outbuf, (byte*)/*arggg*/inbuf, inbuflen); + c->spec->stdecrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen); rc = 0; break; @@ -1155,9 +867,9 @@ cipher_sync (gcry_cipher_hd_t c) if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused) { memmove (c->u_iv.iv + c->unused, - c->u_iv.iv, c->cipher->blocksize - c->unused); + c->u_iv.iv, c->spec->blocksize - c->unused); memcpy (c->u_iv.iv, - c->lastiv + c->cipher->blocksize - c->unused, c->unused); + c->lastiv + c->spec->blocksize - c->unused, c->unused); c->unused = 0; } } @@ -1183,14 +895,14 @@ _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) gpg_error_t _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) { - if (ctr && ctrlen == hd->cipher->blocksize) + if (ctr && ctrlen == hd->spec->blocksize) { - memcpy (hd->u_ctr.ctr, ctr, hd->cipher->blocksize); + memcpy (hd->u_ctr.ctr, ctr, hd->spec->blocksize); hd->unused = 0; } else if (!ctr || !ctrlen) { - memset (hd->u_ctr.ctr, 0, hd->cipher->blocksize); + memset (hd->u_ctr.ctr, 0, hd->spec->blocksize); hd->unused = 0; } else @@ -1255,8 +967,8 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) break; case 61: /* Disable weak key detection (private). */ - if (h->extraspec->set_extra_info) - rc = h->extraspec->set_extra_info + if (h->spec->set_extra_info) + rc = h->spec->set_extra_info (&h->context.c, CIPHER_INFO_NO_WEAK_KEY, NULL, 0); else rc = GPG_ERR_NOT_SUPPORTED; @@ -1268,7 +980,7 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) 1 byte Actual length of the block in bytes. n byte The block. If the provided buffer is too short, an error is returned. */ - if (buflen < (1 + h->cipher->blocksize)) + if (buflen < (1 + h->spec->blocksize)) rc = GPG_ERR_TOO_SHORT; else { @@ -1277,10 +989,10 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) int n = h->unused; if (!n) - n = h->cipher->blocksize; - gcry_assert (n <= h->cipher->blocksize); + n = h->spec->blocksize; + gcry_assert (n <= h->spec->blocksize); *dst++ = n; - ivp = h->u_iv.iv + h->cipher->blocksize - n; + ivp = h->u_iv.iv + h->spec->blocksize - n; while (n--) *dst++ = *ivp++; } @@ -1434,15 +1146,7 @@ gcry_cipher_get_algo_blklen (int algo) gcry_err_code_t _gcry_cipher_init (void) { - gcry_err_code_t err; - - err = ath_mutex_init (&ciphers_registered_lock); - if (err) - return gpg_err_code_from_errno (err); - - REGISTER_DEFAULT_CIPHERS; - - return err; + return 0; } @@ -1451,34 +1155,21 @@ _gcry_cipher_init (void) gpg_error_t _gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report) { - gcry_module_t module = NULL; - cipher_extra_spec_t *extraspec = NULL; gcry_err_code_t ec = 0; + gcry_cipher_spec_t *spec; - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - module = _gcry_module_lookup_id (ciphers_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&ciphers_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); else { ec = GPG_ERR_CIPHER_ALGO; if (report) report ("cipher", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? + (spec && !spec->flags.disabled)? "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); + spec? "algorithm disabled" : "algorithm not found"); } - if (module) - { - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); - } return gpg_error (ec); } diff --git a/cipher/des.c b/cipher/des.c index f1550d1..3464d53 100644 --- a/cipher/des.c +++ b/cipher/des.c @@ -1168,6 +1168,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) gcry_cipher_spec_t _gcry_cipher_spec_des = { + GCRY_CIPHER_DES, {0, 0}, "DES", NULL, NULL, 8, 64, sizeof (struct _des_ctx), do_des_setkey, do_des_encrypt, do_des_decrypt }; @@ -1184,12 +1185,10 @@ static gcry_cipher_oid_spec_t oids_tripledes[] = gcry_cipher_spec_t _gcry_cipher_spec_tripledes = { + GCRY_CIPHER_3DES, {0, 1}, "3DES", NULL, oids_tripledes, 8, 192, sizeof (struct _tripledes_ctx), - do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt - }; - -cipher_extra_spec_t _gcry_cipher_extraspec_tripledes = - { + do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt, + NULL, NULL, run_selftests, do_tripledes_set_extra_info }; diff --git a/cipher/gost28147.c b/cipher/gost28147.c index c669148..2bda868 100644 --- a/cipher/gost28147.c +++ b/cipher/gost28147.c @@ -227,6 +227,7 @@ gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf) gcry_cipher_spec_t _gcry_cipher_spec_gost28147 = { + GCRY_CIPHER_GOST28147, {0, 0}, "GOST28147", NULL, NULL, 8, 256, sizeof (GOST28147_context), gost_setkey, diff --git a/cipher/idea.c b/cipher/idea.c index 6e81e84..7d91a9a 100644 --- a/cipher/idea.c +++ b/cipher/idea.c @@ -371,8 +371,9 @@ static struct { gcry_cipher_spec_t _gcry_cipher_spec_idea = -{ + { + GCRY_CIPHER_IDEA, {0, 0}, "IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128, sizeof (IDEA_context), idea_setkey, idea_encrypt, idea_decrypt -}; + }; diff --git a/cipher/md.c b/cipher/md.c index 280c5d5..c65eb70 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -1414,7 +1414,7 @@ gpg_error_t _gcry_md_selftest (int algo, int extended, selftest_report_func_t report) { gcry_module_t module = NULL; - cipher_extra_spec_t *extraspec = NULL; + md_extra_spec_t *extraspec = NULL; gcry_err_code_t ec = 0; REGISTER_DEFAULT_DIGESTS; diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 4738c29..1628467 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -2356,7 +2356,7 @@ _gcry_pk_selftest (int algo, int extended, selftest_report_func_t report) algo = map_algo (algo); spec = spec_from_algo (algo); - if (spec && spec->selftest) + if (spec && !spec->flags.disabled && spec->selftest) ec = spec->selftest (algo, extended, report); else { diff --git a/cipher/rfc2268.c b/cipher/rfc2268.c index da0b9f4..aed8cad 100644 --- a/cipher/rfc2268.c +++ b/cipher/rfc2268.c @@ -358,14 +358,18 @@ static gcry_cipher_oid_spec_t oids_rfc2268_128[] = { NULL } }; -gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 = { - "RFC2268_40", NULL, oids_rfc2268_40, - RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context), - do_setkey, encrypt_block, decrypt_block -}; +gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 = + { + GCRY_CIPHER_RFC2268_40, {0, 0}, + "RFC2268_40", NULL, oids_rfc2268_40, + RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context), + do_setkey, encrypt_block, decrypt_block + }; -gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 = { - "RFC2268_128", NULL, oids_rfc2268_128, - RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context), - do_setkey, encrypt_block, decrypt_block -}; +gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 = + { + GCRY_CIPHER_RFC2268_128, {0, 0}, + "RFC2268_128", NULL, oids_rfc2268_128, + RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context), + do_setkey, encrypt_block, decrypt_block + }; diff --git a/cipher/rijndael.c b/cipher/rijndael.c index 190d0f9..85c1a41 100644 --- a/cipher/rijndael.c +++ b/cipher/rijndael.c @@ -2557,14 +2557,15 @@ static gcry_cipher_oid_spec_t rijndael_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_aes = { - "AES", rijndael_names, rijndael_oids, 16, 128, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; -cipher_extra_spec_t _gcry_cipher_extraspec_aes = - { + GCRY_CIPHER_AES, {0, 1}, + "AES", rijndael_names, rijndael_oids, 16, 128, + sizeof (RIJNDAEL_context), + rijndael_setkey, rijndael_encrypt, rijndael_decrypt, + NULL, NULL, run_selftests }; + static const char *rijndael192_names[] = { "RIJNDAEL192", @@ -2583,14 +2584,15 @@ static gcry_cipher_oid_spec_t rijndael192_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_aes192 = { - "AES192", rijndael192_names, rijndael192_oids, 16, 192, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; -cipher_extra_spec_t _gcry_cipher_extraspec_aes192 = - { + GCRY_CIPHER_AES192, {0, 1}, + "AES192", rijndael192_names, rijndael192_oids, 16, 192, + sizeof (RIJNDAEL_context), + rijndael_setkey, rijndael_encrypt, rijndael_decrypt, + NULL, NULL, run_selftests }; + static const char *rijndael256_names[] = { "RIJNDAEL256", @@ -2609,12 +2611,10 @@ static gcry_cipher_oid_spec_t rijndael256_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_aes256 = { + GCRY_CIPHER_AES256, {0, 1}, "AES256", rijndael256_names, rijndael256_oids, 16, 256, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; - -cipher_extra_spec_t _gcry_cipher_extraspec_aes256 = - { + rijndael_setkey, rijndael_encrypt, rijndael_decrypt, + NULL, NULL, run_selftests }; diff --git a/cipher/salsa20.c b/cipher/salsa20.c index 88f5372..6189bca 100644 --- a/cipher/salsa20.c +++ b/cipher/salsa20.c @@ -373,6 +373,8 @@ selftest (void) gcry_cipher_spec_t _gcry_cipher_spec_salsa20 = { + GCRY_CIPHER_SALSA20, + {0, 0}, /* flags */ "SALSA20", /* name */ NULL, /* aliases */ NULL, /* oids */ @@ -383,11 +385,16 @@ gcry_cipher_spec_t _gcry_cipher_spec_salsa20 = NULL, NULL, salsa20_encrypt_stream, - salsa20_encrypt_stream + salsa20_encrypt_stream, + NULL, + NULL, + salsa20_setiv }; gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12 = { + GCRY_CIPHER_SALSA20R12, + {0, 0}, /* flags */ "SALSA20R12", /* name */ NULL, /* aliases */ NULL, /* oids */ @@ -398,11 +405,7 @@ gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12 = NULL, NULL, salsa20r12_encrypt_stream, - salsa20r12_encrypt_stream - }; - -cipher_extra_spec_t _gcry_cipher_extraspec_salsa20 = - { + salsa20r12_encrypt_stream, NULL, NULL, salsa20_setiv diff --git a/cipher/seed.c b/cipher/seed.c index 474ccba..9f87c05 100644 --- a/cipher/seed.c +++ b/cipher/seed.c @@ -470,6 +470,7 @@ static gcry_cipher_oid_spec_t seed_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_seed = { + GCRY_CIPHER_SEED, {0, 0}, "SEED", NULL, seed_oids, 16, 128, sizeof (SEED_context), seed_setkey, seed_encrypt, seed_decrypt, }; diff --git a/cipher/serpent.c b/cipher/serpent.c index 4720b9c..c0898dc 100644 --- a/cipher/serpent.c +++ b/cipher/serpent.c @@ -1192,6 +1192,7 @@ static const char *cipher_spec_serpent128_aliases[] = gcry_cipher_spec_t _gcry_cipher_spec_serpent128 = { + GCRY_CIPHER_SERPENT128, {0, 0}, "SERPENT128", cipher_spec_serpent128_aliases, NULL, 16, 128, sizeof (serpent_context_t), serpent_setkey, serpent_encrypt, serpent_decrypt @@ -1199,6 +1200,7 @@ gcry_cipher_spec_t _gcry_cipher_spec_serpent128 = gcry_cipher_spec_t _gcry_cipher_spec_serpent192 = { + GCRY_CIPHER_SERPENT192, {0, 0}, "SERPENT192", NULL, NULL, 16, 192, sizeof (serpent_context_t), serpent_setkey, serpent_encrypt, serpent_decrypt @@ -1206,6 +1208,7 @@ gcry_cipher_spec_t _gcry_cipher_spec_serpent192 = gcry_cipher_spec_t _gcry_cipher_spec_serpent256 = { + GCRY_CIPHER_SERPENT256, {0, 0}, "SERPENT256", NULL, NULL, 16, 256, sizeof (serpent_context_t), serpent_setkey, serpent_encrypt, serpent_decrypt diff --git a/cipher/twofish.c b/cipher/twofish.c index 17b3aa3..993ad0f 100644 --- a/cipher/twofish.c +++ b/cipher/twofish.c @@ -1306,12 +1306,14 @@ main() gcry_cipher_spec_t _gcry_cipher_spec_twofish = { + GCRY_CIPHER_TWOFISH, {0, 0}, "TWOFISH", NULL, NULL, 16, 256, sizeof (TWOFISH_context), twofish_setkey, twofish_encrypt, twofish_decrypt }; gcry_cipher_spec_t _gcry_cipher_spec_twofish128 = { + GCRY_CIPHER_TWOFISH128, {0, 0}, "TWOFISH128", NULL, NULL, 16, 128, sizeof (TWOFISH_context), twofish_setkey, twofish_encrypt, twofish_decrypt }; diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 5b152b5..62bc8b9 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -149,6 +149,39 @@ typedef struct gcry_pk_spec +/* + * + * Symmetric cipher related definitions. + * + */ + +/* Type for the cipher_setkey function. */ +typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c, + const unsigned char *key, + unsigned keylen); + +/* Type for the cipher_encrypt function. */ +typedef unsigned int (*gcry_cipher_encrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_decrypt function. */ +typedef unsigned int (*gcry_cipher_decrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_stencrypt function. */ +typedef void (*gcry_cipher_stencrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + +/* Type for the cipher_stdecrypt function. */ +typedef void (*gcry_cipher_stdecrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + /* The type used to convey additional information to a cipher. */ typedef gpg_err_code_t (*cipher_set_extra_info_t) (void *c, int what, const void *buffer, size_t buflen); @@ -157,15 +190,45 @@ typedef gpg_err_code_t (*cipher_set_extra_info_t) typedef void (*cipher_setiv_func_t)(void *c, const byte *iv, unsigned int ivlen); -/* Extra module specification structures. These are used for internal - modules which provide more functions than available through the - public algorithm register APIs. */ -typedef struct cipher_extra_spec +/* A structure to map OIDs to encryption modes. */ +typedef struct gcry_cipher_oid_spec { + const char *oid; + int mode; +} gcry_cipher_oid_spec_t; + + +/* Module specification structure for ciphers. */ +typedef struct gcry_cipher_spec +{ + int algo; + struct { + unsigned int disabled:1; + unsigned int fips:1; + } flags; + const char *name; + const char **aliases; + gcry_cipher_oid_spec_t *oids; + size_t blocksize; + size_t keylen; + size_t contextsize; + gcry_cipher_setkey_t setkey; + gcry_cipher_encrypt_t encrypt; + gcry_cipher_decrypt_t decrypt; + gcry_cipher_stencrypt_t stencrypt; + gcry_cipher_stdecrypt_t stdecrypt; selftest_func_t selftest; cipher_set_extra_info_t set_extra_info; cipher_setiv_func_t setiv; -} cipher_extra_spec_t; +} gcry_cipher_spec_t; + + + +/* + * + * Message digest related definitions. + * + */ typedef struct md_extra_spec { @@ -174,11 +237,8 @@ typedef struct md_extra_spec + /* The private register functions. */ -gcry_error_t _gcry_cipher_register (gcry_cipher_spec_t *cipher, - cipher_extra_spec_t *extraspec, - int *algorithm_id, - gcry_module_t *module); gcry_error_t _gcry_md_register (gcry_md_spec_t *cipher, md_extra_spec_t *extraspec, unsigned int *algorithm_id, diff --git a/src/cipher.h b/src/cipher.h index 70b46fe..d080e72 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -204,12 +204,6 @@ extern gcry_cipher_spec_t _gcry_cipher_spec_salsa20; extern gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12; extern gcry_cipher_spec_t _gcry_cipher_spec_gost28147; -extern cipher_extra_spec_t _gcry_cipher_extraspec_tripledes; -extern cipher_extra_spec_t _gcry_cipher_extraspec_aes; -extern cipher_extra_spec_t _gcry_cipher_extraspec_aes192; -extern cipher_extra_spec_t _gcry_cipher_extraspec_aes256; -extern cipher_extra_spec_t _gcry_cipher_extraspec_salsa20; - /* Declarations for the digest specifications. */ extern gcry_md_spec_t _gcry_digest_spec_crc32; extern gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510; diff --git a/src/gcrypt-module.h b/src/gcrypt-module.h index 9fcb8ab..621a3a4 100644 --- a/src/gcrypt-module.h +++ b/src/gcrypt-module.h @@ -44,59 +44,6 @@ extern "C" { /* This type represents a `module'. */ typedef struct gcry_module *gcry_module_t; -/* Check that the library fulfills the version requirement. */ - -/* Type for the cipher_setkey function. */ -typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c, - const unsigned char *key, - unsigned keylen); - -/* Type for the cipher_encrypt function. */ -typedef unsigned int (*gcry_cipher_encrypt_t) (void *c, - unsigned char *outbuf, - const unsigned char *inbuf); - -/* Type for the cipher_decrypt function. */ -typedef unsigned int (*gcry_cipher_decrypt_t) (void *c, - unsigned char *outbuf, - const unsigned char *inbuf); - -/* Type for the cipher_stencrypt function. */ -typedef void (*gcry_cipher_stencrypt_t) (void *c, - unsigned char *outbuf, - const unsigned char *inbuf, - unsigned int n); - -/* Type for the cipher_stdecrypt function. */ -typedef void (*gcry_cipher_stdecrypt_t) (void *c, - unsigned char *outbuf, - const unsigned char *inbuf, - unsigned int n); - -typedef struct gcry_cipher_oid_spec -{ - const char *oid; - int mode; -} gcry_cipher_oid_spec_t; - -/* Module specification structure for ciphers. */ -typedef struct gcry_cipher_spec -{ - const char *name; - const char **aliases; - gcry_cipher_oid_spec_t *oids; - size_t blocksize; - size_t keylen; - size_t contextsize; - gcry_cipher_setkey_t setkey; - gcry_cipher_encrypt_t encrypt; - gcry_cipher_decrypt_t decrypt; - gcry_cipher_stencrypt_t stencrypt; - gcry_cipher_stdecrypt_t stdecrypt; -} gcry_cipher_spec_t; - - -/* ********************** */ /* ********************** */ commit 4153fa859816e799e506055321a22e6450aacdcc Author: Werner Koch Date: Tue Oct 1 17:47:27 2013 +0200 mpi: Fix gcry_mpi_neg. * mpi/mpiutil.c (_gcry_mpi_neg): Copy U to W. Signed-off-by: Werner Koch diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c index c9e6b31..a82a8e7 100644 --- a/mpi/mpiutil.c +++ b/mpi/mpiutil.c @@ -373,7 +373,9 @@ _gcry_mpi_is_neg (gcry_mpi_t a) void _gcry_mpi_neg (gcry_mpi_t w, gcry_mpi_t u) { - if (mpi_is_immutable (w)) + if (w != u) + mpi_set (w, u); + else if (mpi_is_immutable (w)) { mpi_immutable_failed (); return; ----------------------------------------------------------------------- Summary of changes: cipher/arcfour.c | 1 + cipher/blowfish.c | 1 + cipher/camellia-glue.c | 3 + cipher/cast5.c | 1 + cipher/cipher-aeswrap.c | 8 +- cipher/cipher-cbc.c | 26 +- cipher/cipher-cfb.c | 18 +- cipher/cipher-ctr.c | 4 +- cipher/cipher-internal.h | 3 +- cipher/cipher-ofb.c | 14 +- cipher/cipher.c | 685 +++++++++++++--------------------------------- cipher/des.c | 9 +- cipher/gost28147.c | 1 + cipher/idea.c | 5 +- cipher/md.c | 2 +- cipher/pubkey.c | 2 +- cipher/rfc2268.c | 24 +- cipher/rijndael.c | 30 +- cipher/salsa20.c | 15 +- cipher/seed.c | 1 + cipher/serpent.c | 3 + cipher/twofish.c | 2 + mpi/mpiutil.c | 4 +- src/cipher-proto.h | 78 +++++- src/cipher.h | 6 - src/gcrypt-module.h | 53 ---- 26 files changed, 356 insertions(+), 643 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From gniibe at fsij.org Wed Oct 2 02:41:52 2013 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 02 Oct 2013 09:41:52 +0900 Subject: possible mpi-pow improvement In-Reply-To: <87a9itb52z.fsf@vigenere.g10code.de> References: <1378456897.3188.14.camel@cfw2.gniibe.org> <87a9itb52z.fsf@vigenere.g10code.de> Message-ID: <1380674512.3342.2.camel@cfw2.gniibe.org> On 2013-10-01 at 13:31 +0200, Werner Koch wrote: > Thus you change is even an improvement for the general case. Yes, at least on machine. > Can you please change your patch to conditionally include the k-ary > multiply but enable it right away. Sure. Here is current version, which is ready to push. Since then, I modified the selection of the value W (window size) for 64-bit machine, and added some comments. With compilation option -DUSE_ALGORITHM_SIMPLE_EXPONENTIATION, we can use old implementation. Please test it out. * mpi/mpi-pow.c (gcry_mpi_powm): New implementation of left-to-right k-ary exponentiation. -- Signed-off-by: NIIBE Yutaka For the Yarom/Falkner flush+reload cache side-channel attack, we changed the code so that it always calls the multiplication routine (even if we can skip it to get result). This results some performance regression. This change is for recovering performance with efficient algorithm. --- mpi/mpi-pow.c | 454 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 454 insertions(+) diff --git a/mpi/mpi-pow.c b/mpi/mpi-pow.c index 85d6fd8..469c382 100644 --- a/mpi/mpi-pow.c +++ b/mpi/mpi-pow.c @@ -34,6 +34,14 @@ #include "longlong.h" +/* + * When you need old implementation, please add compilation option + * -DUSE_ALGORITHM_SIMPLE_EXPONENTIATION + * or expose this line: +#define USE_ALGORITHM_SIMPLE_EXPONENTIATION 1 + */ + +#if defined(USE_ALGORITHM_SIMPLE_EXPONENTIATION) /**************** * RES = BASE ^ EXPO mod MOD */ @@ -336,3 +344,449 @@ gcry_mpi_powm (gcry_mpi_t res, if (tspace) _gcry_mpi_free_limb_space( tspace, 0 ); } +#else +/** + * Internal function to compute + * + * X = R * S mod M + * + * and set the size of X at the pointer XSIZE_P. + * Use karatsuba structure at KARACTX_P. + * + * Condition: + * RSIZE >= SSIZE + * Enough space for X is allocated beforehand. + * + * For generic cases, we can/should use gcry_mpi_mulm. + * This function is use for specific internal case. + */ +static void +mul_mod (mpi_ptr_t xp, mpi_size_t *xsize_p, + mpi_ptr_t rp, mpi_size_t rsize, + mpi_ptr_t sp, mpi_size_t ssize, + mpi_ptr_t mp, mpi_size_t msize, + struct karatsuba_ctx *karactx_p) +{ + if( ssize < KARATSUBA_THRESHOLD ) + _gcry_mpih_mul ( xp, rp, rsize, sp, ssize ); + else + _gcry_mpih_mul_karatsuba_case (xp, rp, rsize, sp, ssize, karactx_p); + + if (rsize + ssize > msize) + { + _gcry_mpih_divrem (xp + msize, 0, xp, rsize + ssize, mp, msize); + *xsize_p = msize; + } + else + *xsize_p = rsize + ssize; +} + +#define SIZE_B_2I3 ((1 << (5 - 1)) - 1) + +/**************** + * RES = BASE ^ EXPO mod MOD + * + * To mitigate the Yarom/Falkner flush+reload cache side-channel + * attack on the RSA secret exponent, we don't use the square + * routine but multiplication. + * + * Reference: + * Handbook of Applied Cryptography + * Algorithm 14.83: Modified left-to-right k-ary exponentiation + */ +void +gcry_mpi_powm (gcry_mpi_t res, + gcry_mpi_t base, gcry_mpi_t expo, gcry_mpi_t mod) +{ + /* Pointer to the limbs of the arguments, their size and signs. */ + mpi_ptr_t rp, ep, mp, bp; + mpi_size_t esize, msize, bsize, rsize; + int msign, bsign, rsign; + /* Flags telling the secure allocation status of the arguments. */ + int esec, msec, bsec; + /* Size of the result including space for temporary values. */ + mpi_size_t size; + /* Helper. */ + int mod_shift_cnt; + int negative_result; + mpi_ptr_t mp_marker = NULL; + mpi_ptr_t bp_marker = NULL; + mpi_ptr_t ep_marker = NULL; + mpi_ptr_t xp_marker = NULL; + unsigned int mp_nlimbs = 0; + unsigned int bp_nlimbs = 0; + unsigned int ep_nlimbs = 0; + unsigned int xp_nlimbs = 0; + mpi_ptr_t b_2i3[SIZE_B_2I3]; /* Pre-computed array: BASE^3, ^5, ^7, ... */ + mpi_size_t b_2i3size[SIZE_B_2I3]; + mpi_size_t W; + mpi_ptr_t base_u; + mpi_size_t base_u_size; + + esize = expo->nlimbs; + msize = mod->nlimbs; + size = 2 * msize; + msign = mod->sign; + + if (esize * BITS_PER_MPI_LIMB > 512) + W = 5; + else if (esize * BITS_PER_MPI_LIMB > 256) + W = 4; + else if (esize * BITS_PER_MPI_LIMB > 128) + W = 3; + else if (esize * BITS_PER_MPI_LIMB > 64) + W = 2; + else + W = 1; + + esec = mpi_is_secure(expo); + msec = mpi_is_secure(mod); + bsec = mpi_is_secure(base); + + rp = res->d; + ep = expo->d; + + if (!msize) + _gcry_divide_by_zero(); + + if (!esize) + { + /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 depending + on if MOD equals 1. */ + res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; + if (res->nlimbs) + { + RESIZE_IF_NEEDED (res, 1); + rp = res->d; + rp[0] = 1; + } + res->sign = 0; + goto leave; + } + + /* Normalize MOD (i.e. make its most significant bit set) as + required by mpn_divrem. This will make the intermediate values + in the calculation slightly larger, but the correct result is + obtained after a final reduction using the original MOD value. */ + mp_nlimbs = msec? msize:0; + mp = mp_marker = mpi_alloc_limb_space(msize, msec); + count_leading_zeros (mod_shift_cnt, mod->d[msize-1]); + if (mod_shift_cnt) + _gcry_mpih_lshift (mp, mod->d, msize, mod_shift_cnt); + else + MPN_COPY( mp, mod->d, msize ); + + bsize = base->nlimbs; + bsign = base->sign; + if (bsize > msize) + { + /* The base is larger than the module. Reduce it. + + Allocate (BSIZE + 1) with space for remainder and quotient. + (The quotient is (bsize - msize + 1) limbs.) */ + bp_nlimbs = bsec ? (bsize + 1):0; + bp = bp_marker = mpi_alloc_limb_space( bsize + 1, bsec ); + MPN_COPY ( bp, base->d, bsize ); + /* We don't care about the quotient, store it above the + * remainder, at BP + MSIZE. */ + _gcry_mpih_divrem( bp + msize, 0, bp, bsize, mp, msize ); + bsize = msize; + /* Canonicalize the base, since we are going to multiply with it + quite a few times. */ + MPN_NORMALIZE( bp, bsize ); + } + else + bp = base->d; + + if (!bsize) + { + res->nlimbs = 0; + res->sign = 0; + goto leave; + } + + + /* Make BASE, EXPO and MOD not overlap with RES. */ + if ( rp == bp ) + { + /* RES and BASE are identical. Allocate temp. space for BASE. */ + gcry_assert (!bp_marker); + bp_nlimbs = bsec? bsize:0; + bp = bp_marker = mpi_alloc_limb_space( bsize, bsec ); + MPN_COPY(bp, rp, bsize); + } + if ( rp == ep ) + { + /* RES and EXPO are identical. Allocate temp. space for EXPO. */ + ep_nlimbs = esec? esize:0; + ep = ep_marker = mpi_alloc_limb_space( esize, esec ); + MPN_COPY(ep, rp, esize); + } + if ( rp == mp ) + { + /* RES and MOD are identical. Allocate temporary space for MOD.*/ + gcry_assert (!mp_marker); + mp_nlimbs = msec?msize:0; + mp = mp_marker = mpi_alloc_limb_space( msize, msec ); + MPN_COPY(mp, rp, msize); + } + + /* Copy base to the result. */ + if (res->alloced < size) + { + mpi_resize (res, size); + rp = res->d; + } + + /* Main processing. */ + { + mpi_size_t i, j; + mpi_ptr_t xp; + mpi_size_t xsize; + int c; + mpi_limb_t e; + mpi_limb_t carry_limb; + struct karatsuba_ctx karactx; + mpi_ptr_t tp; + + xp_nlimbs = msec? (2 * (msize + 1)):0; + xp = xp_marker = mpi_alloc_limb_space( 2 * (msize + 1), msec ); + + memset( &karactx, 0, sizeof karactx ); + negative_result = (ep[0] & 1) && bsign; + + /* Precompute B_2I3[], BASE^(2 * i + 3), BASE^3, ^5, ^7, ... */ + if (W > 1) /* X := BASE^2 */ + mul_mod (xp, &xsize, bp, bsize, bp, bsize, mp, msize, &karactx); + for (i = 0; i < (1 << (W - 1)) - 1; i++) + { /* B_2I3[i] = BASE^(2 * i + 3) */ + if (i == 0) + { + base_u = bp; + base_u_size = bsize; + } + else + { + base_u = b_2i3[i-1]; + base_u_size = b_2i3size[i-1]; + } + + if (xsize >= base_u_size) + mul_mod (rp, &rsize, xp, xsize, base_u, base_u_size, + mp, msize, &karactx); + else + mul_mod (rp, &rsize, base_u, base_u_size, xp, xsize, + mp, msize, &karactx); + b_2i3[i] = mpi_alloc_limb_space (rsize, esec); + b_2i3size[i] = rsize; + MPN_COPY (b_2i3[i], rp, rsize); + } + + i = esize - 1; + + /* Main loop. + + Make the result be pointed to alternately by XP and RP. This + helps us avoid block copying, which would otherwise be + necessary with the overlap restrictions of + _gcry_mpih_divmod. With 50% probability the result after this + loop will be in the area originally pointed by RP (==RES->d), + and with 50% probability in the area originally pointed to by XP. */ + rsign = 0; + if (W == 1) + { + rsize = bsize; + } + else + { + rsize = msize; + MPN_ZERO (rp, rsize); + } + MPN_COPY ( rp, bp, bsize ); + + e = ep[i]; + count_leading_zeros (c, e); + e = (e << c) << 1; + c = BITS_PER_MPI_LIMB - 1 - c; + + j = 0; + + for (;;) + if (e == 0) + { + j += c; + i--; + if ( i < 0 ) + { + c = 0; + break; + } + + e = ep[i]; + c = BITS_PER_MPI_LIMB; + } + else + { + int c0; + mpi_limb_t e0; + + count_leading_zeros (c0, e); + e = (e << c0); + c -= c0; + j += c0; + + if (c >= W) + { + e0 = (e >> (BITS_PER_MPI_LIMB - W)); + e = (e << W); + c -= W; + } + else + { + i--; + if ( i < 0 ) + { + e = (e >> (BITS_PER_MPI_LIMB - c)); + break; + } + + c0 = c; + e0 = (e >> (BITS_PER_MPI_LIMB - W)) + | (ep[i] >> (BITS_PER_MPI_LIMB - W + c0)); + e = (ep[i] << (W - c0)); + c = BITS_PER_MPI_LIMB - W + c0; + } + + count_trailing_zeros (c0, e0); + e0 = (e0 >> c0) >> 1; + + for (j += W - c0; j; j--) + { + mul_mod (xp, &xsize, rp, rsize, rp, rsize, mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + } + + if (e0 == 0) + { + base_u = bp; + base_u_size = bsize; + } + else + { + base_u = b_2i3[e0 - 1]; + base_u_size = b_2i3size[e0 -1]; + } + + mul_mod (xp, &xsize, rp, rsize, base_u, base_u_size, + mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + + j = c0; + } + + if (c != 0) + { + j += c; + count_trailing_zeros (c, e); + e = (e >> c); + j -= c; + } + + while (j--) + { + mul_mod (xp, &xsize, rp, rsize, rp, rsize, mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + } + + if (e != 0) + { + if ((e>>1) == 0) + { + base_u = bp; + base_u_size = bsize; + } + else + { + base_u = b_2i3[(e>>1) - 1]; + base_u_size = b_2i3size[(e>>1) -1]; + } + + mul_mod (xp, &xsize, rp, rsize, base_u, base_u_size, + mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + + for (; c; c--) + { + mul_mod (xp, &xsize, rp, rsize, rp, rsize, mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + } + } + + /* We shifted MOD, the modulo reduction argument, left + MOD_SHIFT_CNT steps. Adjust the result by reducing it with the + original MOD. + + Also make sure the result is put in RES->d (where it already + might be, see above). */ + if ( mod_shift_cnt ) + { + carry_limb = _gcry_mpih_lshift( res->d, rp, rsize, mod_shift_cnt); + rp = res->d; + if ( carry_limb ) + { + rp[rsize] = carry_limb; + rsize++; + } + } + else if (res->d != rp) + { + MPN_COPY (res->d, rp, rsize); + rp = res->d; + } + + if ( rsize >= msize ) + { + _gcry_mpih_divrem(rp + msize, 0, rp, rsize, mp, msize); + rsize = msize; + } + + /* Remove any leading zero words from the result. */ + if ( mod_shift_cnt ) + _gcry_mpih_rshift( rp, rp, rsize, mod_shift_cnt); + MPN_NORMALIZE (rp, rsize); + + _gcry_mpih_release_karatsuba_ctx (&karactx ); + for (i = 0; i < (1 << (W - 1)) - 1; i++) + _gcry_mpi_free_limb_space( b_2i3[i], esec ? b_2i3size[i] : 0 ); + } + + /* Fixup for negative results. */ + if ( negative_result && rsize ) + { + if ( mod_shift_cnt ) + _gcry_mpih_rshift( mp, mp, msize, mod_shift_cnt); + _gcry_mpih_sub( rp, mp, msize, rp, rsize); + rsize = msize; + rsign = msign; + MPN_NORMALIZE(rp, rsize); + } + gcry_assert (res->d == rp); + res->nlimbs = rsize; + res->sign = rsign; + + leave: + if (mp_marker) + _gcry_mpi_free_limb_space( mp_marker, mp_nlimbs ); + if (bp_marker) + _gcry_mpi_free_limb_space( bp_marker, bp_nlimbs ); + if (ep_marker) + _gcry_mpi_free_limb_space( ep_marker, ep_nlimbs ); + if (xp_marker) + _gcry_mpi_free_limb_space( xp_marker, xp_nlimbs ); +} +#endif -- 1.7.10.4 From cvs at cvs.gnupg.org Wed Oct 2 14:42:52 2013 From: cvs at cvs.gnupg.org (by Dmitry Eremin-Solenikov) Date: Wed, 02 Oct 2013 14:42:52 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-289-g33757c1 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 33757c1e03f1d885920633edf543cd1c77999455 (commit) from 628ed5ba0ef4b1f04b5a77e29e4bc49a1fe13c07 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 33757c1e03f1d885920633edf543cd1c77999455 Author: Dmitry Eremin-Solenikov Date: Fri Sep 20 01:14:12 2013 +0400 Fix errors when building with Clang on PPC * mpi/longlong.h (add_ssaaaa, sub_ddmmss, count_leading_zeros, umul_ppmm): Do not cast asm output to USItype. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/mpi/longlong.h b/mpi/longlong.h index 4e315df..c2ab9c5 100644 --- a/mpi/longlong.h +++ b/mpi/longlong.h @@ -862,22 +862,22 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); do { \ if (__builtin_constant_p (bh) && (bh) == 0) \ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "%r" ((USItype)(ah)), \ "%r" ((USItype)(al)), \ "rI" ((USItype)(bl))); \ else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "%r" ((USItype)(ah)), \ "%r" ((USItype)(al)), \ "rI" ((USItype)(bl))); \ else \ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "%r" ((USItype)(ah)), \ "r" ((USItype)(bh)), \ "%r" ((USItype)(al)), \ @@ -887,36 +887,36 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); do { \ if (__builtin_constant_p (ah) && (ah) == 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "r" ((USItype)(bh)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "r" ((USItype)(bh)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else if (__builtin_constant_p (bh) && (bh) == 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "r" ((USItype)(ah)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "r" ((USItype)(ah)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else \ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "r" ((USItype)(ah)), \ "r" ((USItype)(bh)), \ "rI" ((USItype)(al)), \ @@ -924,7 +924,7 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); } while (0) #define count_leading_zeros(count, x) \ __asm__ ("{cntlz|cntlzw} %0,%1" \ - : "=r" ((USItype)(count)) \ + : "=r" ((count)) \ : "r" ((USItype)(x))) #define COUNT_LEADING_ZEROS_0 32 #if defined (_ARCH_PPC) @@ -932,7 +932,7 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); do { \ USItype __m0 = (m0), __m1 = (m1); \ __asm__ ("mulhwu %0,%1,%2" \ - : "=r" ((USItype) ph) \ + : "=r" (ph) \ : "%r" (__m0), \ "r" (__m1)); \ (pl) = __m0 * __m1; \ @@ -954,8 +954,8 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); do { \ USItype __m0 = (m0), __m1 = (m1); \ __asm__ ("mul %0,%2,%3" \ - : "=r" ((USItype)(xh)), \ - "=q" ((USItype)(xl)) \ + : "=r" ((xh)), \ + "=q" ((xl)) \ : "r" (__m0), \ "r" (__m1)); \ (xh) += ((((SItype) __m0 >> 31) & __m1) \ ----------------------------------------------------------------------- Summary of changes: mpi/longlong.h | 40 ++++++++++++++++++++-------------------- 1 files changed, 20 insertions(+), 20 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From cvs at cvs.gnupg.org Wed Oct 2 14:52:26 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 02 Oct 2013 14:52:26 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-290-gf04a1db Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via f04a1db22d982627ba87da4e5df52df9b994c779 (commit) from 33757c1e03f1d885920633edf543cd1c77999455 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f04a1db22d982627ba87da4e5df52df9b994c779 Author: Werner Koch Date: Wed Oct 2 14:14:57 2013 +0200 Remove deprecated control codes. * src/gcrypt.h.in (GCRYCTL_SET_KEY): Remove. (GCRYCTL_SET_IV): Remove. (GCRYCTL_SET_CTR): Remove. * cipher/md.c (gcry_md_ctl): Remove deprecated GCRYCTL_SET_KEY. * cipher/cipher.c (gcry_cipher_ctl): Remove deprecated GCRYCTL_SET_KEY, GCRYCTL_SET_IV, GCRYCTL_SET_CTR. -- Real functions are available for a long time now thus there is no more point in supporting the control code hacks. We have an ABI break anyway thus this is a good time to get rid of them. Signed-off-by: Werner Koch diff --git a/NEWS b/NEWS index c232a99..ab326eb 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ Noteworthy changes in version 1.6.0 (unreleased) * The deprecated message digest debug macros have been removed. Use gcry_md_debug instead. + * Removed deprecated control codes. + * Added support for the IDEA cipher algorithm. * Added support for the Salsa20 and reduced Salsa20/12 stream ciphers. @@ -24,10 +26,12 @@ Noteworthy changes in version 1.6.0 (unreleased) * Added support for the SCRYPT algorithm. - * Mitigate the Yarom/Falkner flush+reload side-channel attack on RSA + * Mitigated the Yarom/Falkner flush+reload side-channel attack on RSA secret keys. See [CVE-2013-4242]. - * Support Deterministic DSA as per RFC-6969. + * Added support for Deterministic DSA as per RFC-6969. + + * Added support for curve Ed25519. * Added a scatter gather hash convenience function. @@ -41,20 +45,24 @@ Noteworthy changes in version 1.6.0 (unreleased) * Interface changes relative to the 1.5.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - gcry_ac_* REMOVED. - GCRY_AC_* REMOVED. - gcry_module_t REMOVED. - gcry_cipher_register REMOVED. - gcry_cipher_unregister REMOVED. - gcry_cipher_list REMOVED. - gcry_pk_register REMOVED. - gcry_pk_unregister REMOVED. - gcry_pk_list REMOVED. - gcry_md_register REMOVED. - gcry_md_unregister REMOVED. - gcry_md_list REMOVED. - gcry_md_start_debug REMOVED (macro). - gcry_md_stop_debug REMOVED (macro). + gcry_ac_* REMOVED. + GCRY_AC_* REMOVED. + gcry_module_t REMOVED. + gcry_cipher_register REMOVED. + gcry_cipher_unregister REMOVED. + gcry_cipher_list REMOVED. + gcry_pk_register REMOVED. + gcry_pk_unregister REMOVED. + gcry_pk_list REMOVED. + gcry_md_register REMOVED. + gcry_md_unregister REMOVED. + gcry_md_list REMOVED. + gcry_md_start_debug REMOVED (macro). + gcry_md_stop_debug REMOVED (macro). + GCRYCTL_SET_KEY REMOVED. + GCRYCTL_SET_IV REMOVED. + GCRYCTL_SET_CTR REMOVED. + GCRYCTL_DISABLE_ALGO CHANGED: Not anymore thread-safe. gcry_md_hash_buffers NEW. gcry_buffer_t NEW. GCRYCTL_SET_ENFORCED_FIPS_FLAG NEW. @@ -105,7 +113,6 @@ Noteworthy changes in version 1.6.0 (unreleased) GCRY_MD_GOSTR3411_94 NEW. GCRY_MD_STRIBOG256 NEW. GCRY_MD_STRIBOG512 NEW. - GCRYCTL_DISABLE_ALGO CHANGED: Not anymore thread-safe. GCRY_PK_ECC NEW. gcry_log_debug NEW. gcry_log_debughex NEW. diff --git a/cipher/cipher.c b/cipher/cipher.c index ca61375..75d42d1 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -918,14 +918,6 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) switch (cmd) { - case GCRYCTL_SET_KEY: /* Deprecated; use gcry_cipher_setkey. */ - rc = cipher_setkey( h, buffer, buflen ); - break; - - case GCRYCTL_SET_IV: /* Deprecated; use gcry_cipher_setiv. */ - cipher_setiv( h, buffer, buflen ); - break; - case GCRYCTL_RESET: cipher_reset (h); break; @@ -962,10 +954,6 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) disable_cipher_algo( *(int*)buffer ); break; - case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */ - rc = gpg_err_code (_gcry_cipher_setctr (h, buffer, buflen)); - break; - case 61: /* Disable weak key detection (private). */ if (h->spec->set_extra_info) rc = h->spec->set_extra_info diff --git a/cipher/md.c b/cipher/md.c index e3cc6c6..5c66397 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -717,14 +717,13 @@ gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) { gcry_err_code_t rc = 0; + (void)buflen; /* Currently not used. */ + switch (cmd) { case GCRYCTL_FINALIZE: md_final (hd); break; - case GCRYCTL_SET_KEY: - rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen)); - break; case GCRYCTL_START_DUMP: md_start_debug (hd, buffer); break; diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 8fca52e..719b951 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -257,8 +257,7 @@ const char *gcry_check_version (const char *req_version); /* Codes used with the gcry_control function. */ enum gcry_ctl_cmds { - GCRYCTL_SET_KEY = 1, - GCRYCTL_SET_IV = 2, + /* Note: 1 .. 2 are not anymore used. */ GCRYCTL_CFB_SYNC = 3, GCRYCTL_RESET = 4, /* e.g. for MDs */ GCRYCTL_FINALIZE = 5, @@ -298,7 +297,7 @@ enum gcry_ctl_cmds GCRYCTL_ANY_INITIALIZATION_P = 40, GCRYCTL_SET_CBC_CTS = 41, GCRYCTL_SET_CBC_MAC = 42, - GCRYCTL_SET_CTR = 43, + /* Note: 43 is not anymore used. */ GCRYCTL_ENABLE_QUICK_RANDOM = 44, GCRYCTL_SET_RANDOM_SEED_FILE = 45, GCRYCTL_UPDATE_RANDOM_SEED_FILE = 46, ----------------------------------------------------------------------- Summary of changes: NEWS | 41 ++++++++++++++++++++++++----------------- cipher/cipher.c | 12 ------------ cipher/md.c | 5 ++--- src/gcrypt.h.in | 5 ++--- 4 files changed, 28 insertions(+), 35 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From cvs at cvs.gnupg.org Wed Oct 2 15:32:17 2013 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Wed, 02 Oct 2013 15:32:17 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-291-g6410152 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 6410152338a2b2ac1216e70c153cd16f9199c94e (commit) from f04a1db22d982627ba87da4e5df52df9b994c779 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6410152338a2b2ac1216e70c153cd16f9199c94e Author: Jussi Kivilinna Date: Wed Oct 2 15:59:59 2013 +0300 sha512: fix building on ARM * cipher/sha512.c (transform) [USE_ARM_NEON_ASM]: Fix 'hd' to 'ctx'. -- Signed-off-by: Jussi Kivilinna diff --git a/cipher/sha512.c b/cipher/sha512.c index af30775..97fb203 100644 --- a/cipher/sha512.c +++ b/cipher/sha512.c @@ -488,7 +488,7 @@ transform (void *context, const unsigned char *data) SHA512_CONTEXT *ctx = context; #ifdef USE_ARM_NEON_ASM - if (hd->use_neon) + if (ctx->use_neon) { _gcry_sha512_transform_armv7_neon(&ctx->state, data, k); ----------------------------------------------------------------------- Summary of changes: cipher/sha512.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From dbaryshkov at gmail.com Wed Oct 2 17:09:14 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Wed, 2 Oct 2013 19:09:14 +0400 Subject: GOST ECC pubkey In-Reply-To: <8761thb4wk.fsf@vigenere.g10code.de> References: <1379653630.3179.2.camel@cfw2.gniibe.org> <1379655225.3179.3.camel@cfw2.gniibe.org> <8761thb4wk.fsf@vigenere.g10code.de> Message-ID: On Tue, Oct 1, 2013 at 3:35 PM, Werner Koch wrote: > On Fri, 20 Sep 2013 07:33, gniibe at fsij.org said: > >> I think that it is possible to represent GOST3410 without extending >> the structure ecc_domain_parms_t. Just redefine "n" as order of >> cyclic subgroup of elliptic curve points group for GOST3410. > > Anyone else with comments? > > I haven't read the specs, if it is different to ECDSA we might want to > add another signature scheme similar to the (flag eddsa). I have sent a patch a few days ago. It just adds a (flag gost) to the data and signature s-exps. There is no difference with ECDSA in the keys S-expressions. -- With best wishes Dmitry From cvs at cvs.gnupg.org Wed Oct 2 18:10:40 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 02 Oct 2013 18:10:40 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-292-g2f767f6 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 2f767f6a17f7e99da4075882f7fe3ca597b31bdb (commit) from 6410152338a2b2ac1216e70c153cd16f9199c94e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2f767f6a17f7e99da4075882f7fe3ca597b31bdb Author: Werner Koch Date: Wed Oct 2 16:56:46 2013 +0200 Provide Pth compatiblity for use with GnuPG 2.0. * src/ath.c (ath_install): Call ath_init and declare Pth as compatible. -- GnuPG 2.0 requires GNU Pth which is a plain userland thread implementation. Given that decent versions of GNU Pth seem to work together with pthread, we can declare Pth as compatible. Native pthreads in Libgcrypt are only used internal to Libgcrypt and any internal blocking should be invisible to Pth. Signed-off-by: Werner Koch diff --git a/src/ath.c b/src/ath.c index 1363d9e..7a7035d 100644 --- a/src/ath.c +++ b/src/ath.c @@ -134,8 +134,14 @@ ath_get_model (int *r_model) gpg_err_code_t ath_install (struct ath_ops *ath_ops) { + gpg_err_code_t rc; unsigned int thread_option; + /* Fist call ath_init so that we know our thread model. */ + rc = ath_init (); + if (rc) + return rc; + /* Check if the requested thread option is compatible to the thread option we are already committed to. */ thread_option = ath_ops? GET_OPTION (ath_ops->option) : 0; @@ -149,8 +155,15 @@ ath_install (struct ath_ops *ath_ops) { if (thread_option == ATH_THREAD_OPTION_PTHREAD) return 0; /* Okay - compatible. */ + if (thread_option == ATH_THREAD_OPTION_PTH) + return 0; /* Okay - compatible. */ } #endif /*USE_POSIX_THREADS_WEAK*/ + else if (thread_option == ATH_THREAD_OPTION_PTH) + { + if (thread_model == ath_model_none) + return 0; /* Okay - compatible. */ + } else if (thread_option == ATH_THREAD_OPTION_DEFAULT) return 0; /* No thread support requested. */ ----------------------------------------------------------------------- Summary of changes: src/ath.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From wk at gnupg.org Wed Oct 2 17:39:20 2013 From: wk at gnupg.org (Werner Koch) Date: Wed, 02 Oct 2013 17:39:20 +0200 Subject: [PATCH] Add support for 128-bit keys in RC2 In-Reply-To: <1452407.XMrRVjiz6F@al> (Peter Wu's message of "Tue, 01 Oct 2013 14:59:21 +0200") References: <1380230432-13431-1-git-send-email-lekensteyn@gmail.com> <87y56d9p83.fsf@vigenere.g10code.de> <1452407.XMrRVjiz6F@al> Message-ID: <87txgz7kd3.fsf@vigenere.g10code.de> On Tue, 1 Oct 2013 14:59, lekensteyn at gmail.com said: > Can you also update the documentation? In doc/gcrypt.texi from line 1563 it > says: Will do so. > If keys of any length (ranging from 0 to 1024?) are allowed, it could be > specified in there. Please view that an undocumented features. If we document it we would need to write test cases ;-). Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Wed Oct 2 17:37:26 2013 From: wk at gnupg.org (Werner Koch) Date: Wed, 02 Oct 2013 17:37:26 +0200 Subject: ../../src/visibility.c:498:3: warning: implicit declaration of function `_gcry_mpi_ec_new' [-Wimplicit-function-declaration] In-Reply-To: <22656519.CJENjD6aAd@al> (Peter Wu's message of "Tue, 01 Oct 2013 15:21:09 +0200") References: <22656519.CJENjD6aAd@al> Message-ID: <87y56b7kg9.fsf@vigenere.g10code.de> On Tue, 1 Oct 2013 15:21, lekensteyn at gmail.com said: > While building the latest git master (libgcrypt-1.5.0-283-g738177e), I got a > warning about an implicit declaration of a function. As far as I can see, it Meanwhile fixed. You do not need to report such warnings on standard platforms (i.e. using gcc on a Unix platform). We see them as well and they are usually fixed along with other minor fixes. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From cvs at cvs.gnupg.org Wed Oct 2 18:17:45 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 02 Oct 2013 18:17:45 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-293-g9981040 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 99810404bee86aa55822740ea5ae670848074856 (commit) from 2f767f6a17f7e99da4075882f7fe3ca597b31bdb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 99810404bee86aa55822740ea5ae670848074856 Author: Werner Koch Date: Wed Oct 2 17:45:13 2013 +0200 doc: Remove note that RC2/128 is not yet supported. -- diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 0590a26..c80a6cc 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1560,9 +1560,7 @@ The Serpent cipher from the AES contest. @itemx GCRY_CIPHER_RFC2268_128 @cindex rfc-2268 @cindex RC2 -Ron's Cipher 2 in the 40 and 128 bit variants. Note, that we currently -only support the 40 bit variant. The identifier for 128 is reserved for -future use. +Ron's Cipher 2 in the 40 and 128 bit variants. @item GCRY_CIPHER_SEED @cindex Seed (cipher) ----------------------------------------------------------------------- Summary of changes: doc/gcrypt.texi | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From nmav at gnutls.org Wed Oct 2 18:12:55 2013 From: nmav at gnutls.org (Nikos Mavrogiannopoulos) Date: Wed, 02 Oct 2013 18:12:55 +0200 Subject: [PATCH] Add support for 128-bit keys in RC2 In-Reply-To: <1452407.XMrRVjiz6F@al> References: <1380230432-13431-1-git-send-email-lekensteyn@gmail.com> <87y56d9p83.fsf@vigenere.g10code.de> <1452407.XMrRVjiz6F@al> Message-ID: <524C4607.5020308@gnutls.org> On 10/01/2013 02:59 PM, Peter Wu wrote: > Can you also update the documentation? In doc/gcrypt.texi from line 1563 it > says: > Ron's Cipher 2 in the 40 and 128 bit variants. Note, that we currently > only support the 40 bit variant. The identifier for 128 is reserved for > future use. > If keys of any length (ranging from 0 to 1024?) are allowed, it could be > specified in there. They are allowed, but it isn't the normal RC2 cipher. It is the RC2-40 which uses a different key expansion. There is no point to use this variant with longer keys. regards, Nikos From cvs at cvs.gnupg.org Wed Oct 2 20:21:27 2013 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Wed, 02 Oct 2013 20:21:27 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-294-gd3fa0bc Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via d3fa0bcf62bdb77b70fc96034d86b9f76ba4d4c1 (commit) from 99810404bee86aa55822740ea5ae670848074856 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d3fa0bcf62bdb77b70fc96034d86b9f76ba4d4c1 Author: Jussi Kivilinna Date: Wed Oct 2 20:47:56 2013 +0300 Prevent tail call optimization with _gcry_burn_stack * configure.ac: New check, HAVE_GCC_ASM_VOLATILE_MEMORY. * src/g10lib.h (_gcry_burn_stack): Rename to __gcry_burn_stack. (__gcry_burn_stack_dummy): New. (_gcry_burn_stack): New macro. * src/misc.c (_gcry_burn_stack): Rename to __gcry_burn_stack. (__gcry_burn_stack_dummy): New. -- Tail call optimization can turn _gcry_burn_stack call in to tail jump. When this happens, stack pointer is restored to initial state of current function. This causes problem for _gcry_burn_stack because its callers do not count in current function stack depth. One solution is to prevent gcry_burn_stack being tail optimized by inserting dummy function call behind it. Another would be to add memory barrier 'asm volatile("":::"memory")' behind every _gcry_burn_stack call. This however requires GCC asm support from compiler. Patch adds detection for memory barrier support and when available uses memory barrier to prevent when tail call optimization. If not available dummy function call is used instead. Signed-off-by: Jussi Kivilinna diff --git a/configure.ac b/configure.ac index 2c92028..1460dfd 100644 --- a/configure.ac +++ b/configure.ac @@ -921,7 +921,7 @@ fi # # Check whether the compiler supports 'asm' or '__asm__' keyword for -# assembler blocks +# assembler blocks. # AC_CACHE_CHECK([whether 'asm' assembler keyword is supported], [gcry_cv_have_asm], @@ -945,6 +945,32 @@ fi # +# Check whether the compiler supports inline assembly memory barrier. +# +if test "$gcry_cv_have_asm" = "no" ; then + if test "$gcry_cv_have___asm__" = "yes" ; then + AC_CACHE_CHECK([whether inline assembly memory barrier is supported], + [gcry_cv_have_asm_volatile_memory], + [gcry_cv_have_asm_volatile_memory=no + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [[void a(void) { __asm__ volatile("":::"memory"); }]])], + [gcry_cv_have_asm_volatile_memory=yes])]) + fi +else + AC_CACHE_CHECK([whether inline assembly memory barrier is supported], + [gcry_cv_have_asm_volatile_memory], + [gcry_cv_have_asm_volatile_memory=no + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [[void a(void) { asm volatile("":::"memory"); }]])], + [gcry_cv_have_asm_volatile_memory=yes])]) +fi +if test "$gcry_cv_have_asm_volatile_memory" = "yes" ; then + AC_DEFINE(HAVE_GCC_ASM_VOLATILE_MEMORY,1, + [Define if inline asm memory barrier is supported]) +fi + + +# # Check whether GCC inline assembler supports SSSE3 instructions # This is required for the AES-NI instructions. # diff --git a/src/g10lib.h b/src/g10lib.h index 43281ad..85bd93b 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -254,7 +254,16 @@ int strcasecmp (const char *a, const char *b) _GCRY_GCC_ATTR_PURE; /* Stack burning. */ -void _gcry_burn_stack (unsigned int bytes); +#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY +#define __gcry_burn_stack_dummy() asm volatile ("":::"memory") +#else +void __gcry_burn_stack_dummy (void); +#endif + +void __gcry_burn_stack (unsigned int bytes); +#define _gcry_burn_stack(bytes) \ + do { __gcry_burn_stack (bytes); \ + __gcry_burn_stack_dummy (); } while(0) /* To avoid that a compiler optimizes certain memset calls away, these diff --git a/src/misc.c b/src/misc.c index 912039a..9b30ac3 100644 --- a/src/misc.c +++ b/src/misc.c @@ -438,7 +438,7 @@ _gcry_log_printsxp (const char *text, gcry_sexp_t sexp) void -_gcry_burn_stack (unsigned int bytes) +__gcry_burn_stack (unsigned int bytes) { #ifdef HAVE_VLA /* (bytes == 0 ? 1 : bytes) == (!bytes + bytes) */ @@ -456,6 +456,13 @@ _gcry_burn_stack (unsigned int bytes) #endif } +#ifndef HAVE_GCC_ASM_VOLATILE_MEMORY +void +__gcry_burn_stack_dummy (void) +{ +} +#endif + void _gcry_divide_by_zero (void) { ----------------------------------------------------------------------- Summary of changes: configure.ac | 28 +++++++++++++++++++++++++++- src/g10lib.h | 11 ++++++++++- src/misc.c | 9 ++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From cvs at cvs.gnupg.org Wed Oct 2 14:25:58 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 02 Oct 2013 14:25:58 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-288-g628ed5b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 628ed5ba0ef4b1f04b5a77e29e4bc49a1fe13c07 (commit) via 52783d483293d48cd468143ae6ae2cccbfe17200 (commit) via 0d39997932617ba20656f8bcc230ba744b76c87e (commit) from 3ca180b25e8df252fc16f802cfdc27496e307830 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 628ed5ba0ef4b1f04b5a77e29e4bc49a1fe13c07 Author: Werner Koch Date: Wed Oct 2 13:53:07 2013 +0200 Remove last remains of the former module system. * src/gcrypt-module.h, src/module.c: Remove. * src/visibility.h: Do not include gcrypt-module.h. * src/g10lib.h: Remove all prototypes from module.c (gcry_module): Remove. * cipher/cipher-internal.h (gcry_cipher_handle): Remove unused field. Signed-off-by: Werner Koch diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index cabcd1f..b60ef38 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -61,7 +61,6 @@ struct gcry_cipher_handle size_t actual_handle_size; /* Allocated size of this handle. */ size_t handle_offset; /* Offset to the malloced block. */ gcry_cipher_spec_t *spec; - gcry_module_t module; /* The algorithm id. This is a hack required because the module interface does not easily allow to retrieve this value. */ diff --git a/src/Makefile.am b/src/Makefile.am index 3bc27c8..c020239 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,10 +56,10 @@ endif libgcrypt_la_CFLAGS = $(GPG_ERROR_CFLAGS) libgcrypt_la_SOURCES = \ gcrypt-int.h g10lib.h visibility.c visibility.h types.h \ - cipher.h cipher-proto.h gcrypt-module.h \ + cipher.h cipher-proto.h \ misc.c global.c sexp.c hwfeatures.c hwf-common.h \ stdmem.c stdmem.h secmem.c secmem.h \ - mpi.h missing-string.c module.c fips.c \ + mpi.h missing-string.c fips.c \ hmac256.c hmac256.h context.c context.h \ ec-context.h \ ath.h ath.c diff --git a/src/g10lib.h b/src/g10lib.h index ff7f4b3..43281ad 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -351,52 +351,7 @@ void _gcry_burn_stack (unsigned int bytes); || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) -/* Management for ciphers/digests/pubkey-ciphers. */ - -/* Structure for each registered `module'. */ -struct gcry_module -{ - struct gcry_module *next; /* List pointers. */ - struct gcry_module **prevp; - void *spec; /* Pointer to the subsystem-specific - specification structure. */ - void *extraspec; /* Pointer to the subsystem-specific - extra specification structure. */ - int flags; /* Associated flags. */ - int counter; /* Use counter. */ - unsigned int mod_id; /* ID of this module. */ -}; - -/* Flags for the `flags' member of gcry_module_t. */ -#define FLAG_MODULE_DISABLED (1 << 0) - -gcry_err_code_t _gcry_module_add (gcry_module_t *entries, - unsigned int id, - void *spec, - void *extraspec, - gcry_module_t *module); - -typedef int (*gcry_module_lookup_t) (void *spec, void *data); - -/* Lookup a module specification by it's ID. After a successful - lookup, the module has it's resource counter incremented. */ -gcry_module_t _gcry_module_lookup_id (gcry_module_t entries, - unsigned int id); - -/* Internal function. Lookup a module specification. */ -gcry_module_t _gcry_module_lookup (gcry_module_t entries, void *data, - gcry_module_lookup_t func); - -/* Release a module. In case the use-counter reaches zero, destroy - the module. */ -void _gcry_module_release (gcry_module_t entry); - -/* Add a reference to a module. */ -void _gcry_module_use (gcry_module_t module); - -/* Return a list of module IDs. */ -gcry_err_code_t _gcry_module_list (gcry_module_t modules, - int *list, int *list_length); +/* Init functions. */ gcry_err_code_t _gcry_cipher_init (void); gcry_err_code_t _gcry_md_init (void); diff --git a/src/gcrypt-module.h b/src/gcrypt-module.h deleted file mode 100644 index 35a928c..0000000 --- a/src/gcrypt-module.h +++ /dev/null @@ -1,57 +0,0 @@ -/* gcrypt-module.h - GNU Cryptographic Library Interface - Copyright (C) 2003, 2007 Free Software Foundation, Inc. - - This file is part of Libgcrypt. - - Libgcrypt is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - Libgcrypt is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, see . - */ - -/* - This file contains the necessary declarations/definitions for - working with Libgcrypt modules. Since 1.6 this is an internal - interface and will eventually be merged into another header or - entirely removed. - */ - -#ifndef GCRYPT_MODULE_H -#define GCRYPT_MODULE_H - -#ifdef __cplusplus -extern "C" { -#if 0 /* keep Emacsens's auto-indent happy */ -} -#endif -#endif - -/* The interfaces using the module system reserve a certain range of - IDs for application use. These IDs are not valid within Libgcrypt - but Libgcrypt makes sure never to allocate such a module ID. */ -#define GCRY_MODULE_ID_USER 1024 -#define GCRY_MODULE_ID_USER_LAST 4095 - - -/* This type represents a `module'. */ -typedef struct gcry_module *gcry_module_t; - - -/* ********************** */ - - -#if 0 /* keep Emacsens's auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif -#endif /*GCRYPT_MODULE_H*/ diff --git a/src/module.c b/src/module.c deleted file mode 100644 index 32f668d..0000000 --- a/src/module.c +++ /dev/null @@ -1,212 +0,0 @@ -/* module.c - Module management for libgcrypt. - * Copyright (C) 2003, 2008 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - */ - -#include -#include -#include "g10lib.h" - -/* Please match these numbers with the allocated algorithm - numbers. */ -#define MODULE_ID_MIN 600 -#define MODULE_ID_LAST 65500 -#define MODULE_ID_USER GCRY_MODULE_ID_USER -#define MODULE_ID_USER_LAST GCRY_MODULE_ID_USER_LAST - -#if MODULE_ID_MIN >= MODULE_ID_USER -#error Need to implement a different search strategy -#endif - -/* Internal function. Generate a new, unique module ID for a module - that should be inserted into the module chain starting at - MODULES. */ -static gcry_err_code_t -_gcry_module_id_new (gcry_module_t modules, unsigned int *id_new) -{ - unsigned int mod_id; - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t module; - - /* Search for unused ID. */ - for (mod_id = MODULE_ID_MIN; mod_id < MODULE_ID_LAST; mod_id++) - { - if (mod_id == MODULE_ID_USER) - { - mod_id = MODULE_ID_USER_LAST; - continue; - } - - /* Search for a module with the current ID. */ - for (module = modules; module; module = module->next) - if (mod_id == module->mod_id) - break; - - if (! module) - /* None found -> the ID is available for use. */ - break; - } - - if (mod_id < MODULE_ID_LAST) - /* Done. */ - *id_new = mod_id; - else - /* No free ID found. */ - err = GPG_ERR_INTERNAL; - - return err; -} - -/* Add a module specification to the list ENTRIES. The new module has - it's use-counter set to one. */ -gcry_err_code_t -_gcry_module_add (gcry_module_t *entries, unsigned int mod_id, - void *spec, void *extraspec, gcry_module_t *module) -{ - gcry_err_code_t err = 0; - gcry_module_t entry; - - if (! mod_id) - err = _gcry_module_id_new (*entries, &mod_id); - - if (! err) - { - entry = gcry_malloc (sizeof (struct gcry_module)); - if (! entry) - err = gpg_err_code_from_errno (errno); - } - - if (! err) - { - /* Fill new module entry. */ - entry->flags = 0; - entry->counter = 1; - entry->spec = spec; - entry->extraspec = extraspec; - entry->mod_id = mod_id; - - /* Link it into the list. */ - entry->next = *entries; - entry->prevp = entries; - if (*entries) - (*entries)->prevp = &entry->next; - *entries = entry; - - /* And give it to the caller. */ - if (module) - *module = entry; - } - return err; -} - -/* Internal function. Unlink CIPHER_ENTRY from the list of registered - ciphers and destroy it. */ -static void -_gcry_module_drop (gcry_module_t entry) -{ - *entry->prevp = entry->next; - if (entry->next) - entry->next->prevp = entry->prevp; - - gcry_free (entry); -} - -/* Lookup a module specification by it's ID. After a successful - lookup, the module has it's resource counter incremented. */ -gcry_module_t -_gcry_module_lookup_id (gcry_module_t entries, unsigned int mod_id) -{ - gcry_module_t entry; - - for (entry = entries; entry; entry = entry->next) - if (entry->mod_id == mod_id) - { - entry->counter++; - break; - } - - return entry; -} - -/* Lookup a module specification. After a successful lookup, the - module has it's resource counter incremented. FUNC is a function - provided by the caller, which is responsible for identifying the - wanted module. */ -gcry_module_t -_gcry_module_lookup (gcry_module_t entries, void *data, - gcry_module_lookup_t func) -{ - gcry_module_t entry; - - for (entry = entries; entry; entry = entry->next) - if ((*func) (entry->spec, data)) - { - entry->counter++; - break; - } - - return entry; -} - -/* Release a module. In case the use-counter reaches zero, destroy - the module. Passing MODULE as NULL is a dummy operation (similar - to free()). */ -void -_gcry_module_release (gcry_module_t module) -{ - if (module && ! --module->counter) - _gcry_module_drop (module); -} - -/* Add a reference to a module. */ -void -_gcry_module_use (gcry_module_t module) -{ - ++module->counter; -} - -/* If LIST is zero, write the number of modules identified by MODULES - to LIST_LENGTH and return. If LIST is non-zero, the first - *LIST_LENGTH algorithm IDs are stored in LIST, which must be of - according size. In case there are less cipher modules than - *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ -gcry_err_code_t -_gcry_module_list (gcry_module_t modules, - int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t module; - int length, i; - - for (module = modules, length = 0; module; module = module->next, length++); - - if (list) - { - if (length > *list_length) - length = *list_length; - - for (module = modules, i = 0; i < length; module = module->next, i++) - list[i] = module->mod_id; - - if (length < *list_length) - *list_length = length; - } - else - *list_length = length; - - return err; -} diff --git a/src/visibility.h b/src/visibility.h index 7e7793b..cd2a60f 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -208,7 +208,6 @@ #else # include "gcrypt-int.h" #endif -#include "gcrypt-module.h" /* Prototypes of functions exported but not ready for use. */ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, commit 52783d483293d48cd468143ae6ae2cccbfe17200 Author: Werner Koch Date: Wed Oct 2 13:44:46 2013 +0200 Fix missing prototype warning in visibility.c * src/ec-context.h (_gcry_mpi_ec_new): Move prototype to mpi.h. diff --git a/src/ec-context.h b/src/ec-context.h index ba6bdfc..a118608 100644 --- a/src/ec-context.h +++ b/src/ec-context.h @@ -71,9 +71,6 @@ void _gcry_mpi_ec_get_reset (mpi_ec_t ec); /*-- cipher/ecc-curves.c --*/ -gpg_err_code_t _gcry_mpi_ec_new (gcry_ctx_t *r_ctx, - gcry_sexp_t keyparam, const char *curvename); - gcry_mpi_t _gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy); gcry_mpi_point_t _gcry_ecc_get_point (const char *name, mpi_ec_t ec); gpg_err_code_t _gcry_ecc_set_mpi (const char *name, diff --git a/src/mpi.h b/src/mpi.h index 780d5eb..15fb542 100644 --- a/src/mpi.h +++ b/src/mpi.h @@ -342,6 +342,10 @@ gpg_err_code_t _gcry_mpi_ec_set_point (const char *name, gcry_mpi_point_t newvalue, gcry_ctx_t ctx); +/*-- ecc-curves.c --*/ +gpg_err_code_t _gcry_mpi_ec_new (gcry_ctx_t *r_ctx, + gcry_sexp_t keyparam, const char *curvename); + #endif /*G10_MPI_H*/ commit 0d39997932617ba20656f8bcc230ba744b76c87e Author: Werner Koch Date: Wed Oct 2 13:39:47 2013 +0200 md: Simplify the message digest dispatcher md.c. * src/gcrypt-module.h (gcry_md_spec_t): Move to ... * src/cipher-proto.h: here. Merge with md_extra_spec_t. Add fields ALGO and FLAGS. Set these fields in all digest modules. * cipher/md.c: Change most code to replace the former module system by a simpler system to gain information about the algorithms. Signed-off-by: Werner Koch diff --git a/cipher/crc.c b/cipher/crc.c index 9e406f1..4f72ffb 100644 --- a/cipher/crc.c +++ b/cipher/crc.c @@ -272,8 +272,12 @@ crc24rfc2440_final (void *context) ctx->buf[2] = (ctx->CRC ) & 0xFF; } +/* We allow the CRC algorithms even in FIPS mode because they are + actually no cryptographic primitives. */ + gcry_md_spec_t _gcry_digest_spec_crc32 = { + GCRY_MD_CRC32, {0, 1}, "CRC32", NULL, 0, NULL, 4, crc32_init, crc32_write, crc32_final, crc32_read, sizeof (CRC_CONTEXT) @@ -281,6 +285,7 @@ gcry_md_spec_t _gcry_digest_spec_crc32 = gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510 = { + GCRY_MD_CRC32_RFC1510, {0, 1}, "CRC32RFC1510", NULL, 0, NULL, 4, crc32rfc1510_init, crc32_write, crc32rfc1510_final, crc32_read, @@ -289,6 +294,7 @@ gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510 = gcry_md_spec_t _gcry_digest_spec_crc24_rfc2440 = { + GCRY_MD_CRC24_RFC2440, {0, 1}, "CRC24RFC2440", NULL, 0, NULL, 3, crc24rfc2440_init, crc24rfc2440_write, crc24rfc2440_final, crc32_read, diff --git a/cipher/gostr3411-94.c b/cipher/gostr3411-94.c index 368fc01..1267216 100644 --- a/cipher/gostr3411-94.c +++ b/cipher/gostr3411-94.c @@ -277,6 +277,7 @@ gost3411_read (void *context) } gcry_md_spec_t _gcry_digest_spec_gost3411_94 = { + GCRY_MD_GOSTR3411_94, {0, 0}, "GOSTR3411_94", NULL, 0, NULL, 32, gost3411_init, _gcry_md_block_write, gost3411_final, gost3411_read, sizeof (GOSTR3411_CONTEXT) diff --git a/cipher/md.c b/cipher/md.c index c65eb70..e3cc6c6 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -31,105 +31,64 @@ #include "rmd.h" -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static md_extra_spec_t dummy_extra_spec; - /* This is the list of the digest implementations included in libgcrypt. */ -static struct digest_table_entry -{ - gcry_md_spec_t *digest; - md_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} digest_table[] = +static gcry_md_spec_t *digest_list[] = { #if USE_CRC - /* We allow the CRC algorithms even in FIPS mode because they are - actually no cryptographic primitives. */ - { &_gcry_digest_spec_crc32, - &dummy_extra_spec, GCRY_MD_CRC32, 1 }, - { &_gcry_digest_spec_crc32_rfc1510, - &dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 }, - { &_gcry_digest_spec_crc24_rfc2440, - &dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 }, + &_gcry_digest_spec_crc32, + &_gcry_digest_spec_crc32_rfc1510, + &_gcry_digest_spec_crc24_rfc2440, #endif -#ifdef USE_GOST_R_3411_94 - { &_gcry_digest_spec_gost3411_94, - &dummy_extra_spec, GCRY_MD_GOSTR3411_94 }, -#endif -#ifdef USE_GOST_R_3411_12 - { &_gcry_digest_spec_stribog_256, - &dummy_extra_spec, GCRY_MD_STRIBOG256 }, - { &_gcry_digest_spec_stribog_512, - &dummy_extra_spec, GCRY_MD_STRIBOG512 }, +#if USE_SHA1 + &_gcry_digest_spec_sha1, #endif -#if USE_MD4 - { &_gcry_digest_spec_md4, - &dummy_extra_spec, GCRY_MD_MD4 }, +#if USE_SHA256 + &_gcry_digest_spec_sha256, + &_gcry_digest_spec_sha224, #endif -#if USE_MD5 - { &_gcry_digest_spec_md5, - &dummy_extra_spec, GCRY_MD_MD5, 1 }, +#if USE_SHA512 + &_gcry_digest_spec_sha512, + &_gcry_digest_spec_sha384, #endif -#if USE_RMD160 - { &_gcry_digest_spec_rmd160, - &dummy_extra_spec, GCRY_MD_RMD160 }, +#ifdef USE_GOST_R_3411_94 + &_gcry_digest_spec_gost3411_94, #endif -#if USE_SHA1 - { &_gcry_digest_spec_sha1, - &_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 }, +#ifdef USE_GOST_R_3411_12 + &_gcry_digest_spec_stribog_256, + &_gcry_digest_spec_stribog_512, #endif -#if USE_SHA256 - { &_gcry_digest_spec_sha256, - &_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 }, - { &_gcry_digest_spec_sha224, - &_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 }, +#if USE_WHIRLPOOL + &_gcry_digest_spec_whirlpool, #endif -#if USE_SHA512 - { &_gcry_digest_spec_sha512, - &_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 }, - { &_gcry_digest_spec_sha384, - &_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 }, +#if USE_RMD160 + &_gcry_digest_spec_rmd160, #endif #if USE_TIGER - { &_gcry_digest_spec_tiger, - &dummy_extra_spec, GCRY_MD_TIGER }, - { &_gcry_digest_spec_tiger1, - &dummy_extra_spec, GCRY_MD_TIGER1 }, - { &_gcry_digest_spec_tiger2, - &dummy_extra_spec, GCRY_MD_TIGER2 }, + &_gcry_digest_spec_tiger, + &_gcry_digest_spec_tiger1, + &_gcry_digest_spec_tiger2, #endif -#if USE_WHIRLPOOL - { &_gcry_digest_spec_whirlpool, - &dummy_extra_spec, GCRY_MD_WHIRLPOOL }, +#if USE_MD5 + &_gcry_digest_spec_md5, +#endif +#if USE_MD4 + &_gcry_digest_spec_md4, #endif - { NULL }, + NULL }; -/* List of registered digests. */ -static gcry_module_t digests_registered; - -/* This is the lock protecting DIGESTS_REGISTERED. */ -static ath_mutex_t digests_registered_lock; - -/* Flag to check whether the default ciphers have already been - registered. */ -static int default_digests_registered; typedef struct gcry_md_list { - gcry_md_spec_t *digest; - gcry_module_t module; + gcry_md_spec_t *spec; struct gcry_md_list *next; size_t actual_struct_size; /* Allocated size of this structure. */ PROPERLY_ALIGNED_TYPE context; } GcryDigestEntry; -/* this structure is put right after the gcry_md_hd_t buffer, so that +/* This structure is put right after the gcry_md_hd_t buffer, so that * only one memory block is needed. */ struct gcry_md_context { @@ -147,248 +106,135 @@ struct gcry_md_context #define CTX_MAGIC_NORMAL 0x11071961 #define CTX_MAGIC_SECURE 0x16917011 -/* Convenient macro for registering the default digests. */ -#define REGISTER_DEFAULT_DIGESTS \ - do \ - { \ - ath_mutex_lock (&digests_registered_lock); \ - if (! default_digests_registered) \ - { \ - md_register_default (); \ - default_digests_registered = 1; \ - } \ - ath_mutex_unlock (&digests_registered_lock); \ - } \ - while (0) - - -static const char * digest_algo_to_string( int algo ); -static gcry_err_code_t check_digest_algo (int algo); -static gcry_err_code_t md_open (gcry_md_hd_t *h, int algo, - int secure, int hmac); static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo); -static gcry_err_code_t md_copy (gcry_md_hd_t a, gcry_md_hd_t *b); static void md_close (gcry_md_hd_t a); static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen); -static void md_final(gcry_md_hd_t a); static byte *md_read( gcry_md_hd_t a, int algo ); static int md_get_algo( gcry_md_hd_t a ); static int md_digest_length( int algo ); -static const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ); static void md_start_debug ( gcry_md_hd_t a, const char *suffix ); static void md_stop_debug ( gcry_md_hd_t a ); + +static int +map_algo (int algo) +{ + return algo; +} -/* Internal function. Register all the ciphers included in - CIPHER_TABLE. Returns zero on success or an error code. */ -static void -md_register_default (void) +/* Return the spec structure for the hash algorithm ALGO. For an + unknown algorithm NULL is returned. */ +static gcry_md_spec_t * +spec_from_algo (int algo) { - gcry_err_code_t err = 0; - int i; + int idx; + gcry_md_spec_t *spec; - for (i = 0; !err && digest_table[i].digest; i++) - { - if ( fips_mode ()) - { - if (!digest_table[i].fips_allowed) - continue; - if (digest_table[i].algorithm == GCRY_MD_MD5 - && _gcry_enforced_fips_mode () ) - continue; /* Do not register in enforced fips mode. */ - } + algo = map_algo (algo); - err = _gcry_module_add (&digests_registered, - digest_table[i].algorithm, - (void *) digest_table[i].digest, - (void *) digest_table[i].extraspec, - NULL); - } - - if (err) - BUG (); + for (idx = 0; (spec = digest_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; } -/* Internal callback function. */ -static int -gcry_md_lookup_func_name (void *spec, void *data) -{ - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *name = (char *) data; - return (! stricmp (digest->name, name)); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_md_lookup_func_oid (void *spec, void *data) +/* Lookup a hash's spec by its name. */ +static gcry_md_spec_t * +spec_from_name (const char *name) { - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *oid = (char *) data; - gcry_md_oid_spec_t *oid_specs = digest->oids; - int ret = 0, i; + gcry_md_spec_t *spec; + int idx; - if (oid_specs) + for (idx=0; (spec = digest_list[idx]); idx++) { - for (i = 0; oid_specs[i].oidstring && (! ret); i++) - if (! stricmp (oid, oid_specs[i].oidstring)) - ret = 1; + if (!stricmp (name, spec->name)) + return spec; } - return ret; -} - -/* Internal function. Lookup a digest entry by it's name. */ -static gcry_module_t -gcry_md_lookup_name (const char *name) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) name, - gcry_md_lookup_func_name); - - return digest; + return NULL; } -/* Internal function. Lookup a cipher entry by it's oid. */ -static gcry_module_t -gcry_md_lookup_oid (const char *oid) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) oid, - gcry_md_lookup_func_oid); - - return digest; -} -/* Register a new digest module whose specification can be found in - DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_md_register (gcry_md_spec_t *digest, - md_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module) +/* Lookup a hash's spec by its OID. */ +static gcry_md_spec_t * +spec_from_oid (const char *oid) { - gcry_err_code_t err = 0; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); + gcry_md_spec_t *spec; + gcry_md_oid_spec_t *oid_specs; + int idx, j; - ath_mutex_lock (&digests_registered_lock); - err = _gcry_module_add (&digests_registered, 0, - (void *) digest, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&digests_registered_lock); - - if (! err) + for (idx=0; (spec = digest_list[idx]); idx++) { - *module = mod; - *algorithm_id = mod->mod_id; + oid_specs = spec->oids; + if (oid_specs) + { + for (j = 0; oid_specs[j].oidstring; j++) + if (!stricmp (oid, oid_specs[j].oidstring)) + return spec; + } } - return gcry_error (err); + return NULL; } -static int -search_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec) +static gcry_md_spec_t * +search_oid (const char *oid, gcry_md_oid_spec_t *oid_spec) { - gcry_module_t module; - int ret = 0; + gcry_md_spec_t *spec; + int i; if (oid && ((! strncmp (oid, "oid.", 4)) || (! strncmp (oid, "OID.", 4)))) oid += 4; - module = gcry_md_lookup_oid (oid); - if (module) + spec = spec_from_oid (oid); + if (spec && spec->oids) { - gcry_md_spec_t *digest = module->spec; - int i; - - for (i = 0; digest->oids[i].oidstring && !ret; i++) - if (! stricmp (oid, digest->oids[i].oidstring)) + for (i = 0; spec->oids[i].oidstring; i++) + if (stricmp (oid, spec->oids[i].oidstring)) { - if (algorithm) - *algorithm = module->mod_id; if (oid_spec) - *oid_spec = digest->oids[i]; - ret = 1; + *oid_spec = spec->oids[i]; + return spec; } - _gcry_module_release (module); } - return ret; + return NULL; } + /**************** * Map a string to the digest algo */ int gcry_md_map_name (const char *string) { - gcry_module_t digest; - int ret, algorithm = 0; + gcry_md_spec_t *spec; - if (! string) + if (!string) return 0; - REGISTER_DEFAULT_DIGESTS; - /* If the string starts with a digit (optionally prefixed with either "OID." or "oid."), we first look into our table of ASN.1 object identifiers to figure out the algorithm */ + spec = search_oid (string, NULL); + if (spec) + return spec->algo; - ath_mutex_lock (&digests_registered_lock); + /* Not found, search a matching digest name. */ + spec = spec_from_name (string); + if (spec) + return spec->algo; - ret = search_oid (string, &algorithm, NULL); - if (! ret) - { - /* Not found, search a matching digest name. */ - digest = gcry_md_lookup_name (string); - if (digest) - { - algorithm = digest->mod_id; - _gcry_module_release (digest); - } - } - ath_mutex_unlock (&digests_registered_lock); - - return algorithm; + return 0; } /**************** - * Map a digest algo to a string - */ -static const char * -digest_algo_to_string (int algorithm) -{ - const char *name = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - name = ((gcry_md_spec_t *) digest->spec)->name; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); - - return name; -} - -/**************** * This function simply returns the name of the algorithm or some constant * string when there is no algo. It will never return NULL. * Use the macro gcry_md_test_algo() to check whether the algorithm @@ -397,32 +243,27 @@ digest_algo_to_string (int algorithm) const char * gcry_md_algo_name (int algorithm) { - const char *s = digest_algo_to_string (algorithm); - return s ? s : "?"; + gcry_md_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec ? spec->name : "?"; } static gcry_err_code_t check_digest_algo (int algorithm) { - gcry_err_code_t rc = 0; - gcry_module_t digest; + gcry_md_spec_t *spec; - REGISTER_DEFAULT_DIGESTS; + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - _gcry_module_release (digest); - else - rc = GPG_ERR_DIGEST_ALGO; - ath_mutex_unlock (&digests_registered_lock); + return GPG_ERR_DIGEST_ALGO; - return rc; } - /**************** * Open a message digest handle for use with algorithm ALGO. * More algorithms may be added by md_enable(). The initial algorithm @@ -525,7 +366,7 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) gcry_error_t gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t err; gcry_md_hd_t hd; if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC))) @@ -546,27 +387,20 @@ static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algorithm) { struct gcry_md_context *h = hd->ctx; - gcry_md_spec_t *digest = NULL; + gcry_md_spec_t *spec; GcryDigestEntry *entry; - gcry_module_t module; gcry_err_code_t err = 0; for (entry = h->list; entry; entry = entry->next) - if (entry->module->mod_id == algorithm) - return err; /* already enabled */ + if (entry->spec->algo == algorithm) + return 0; /* Already enabled */ - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algorithm); - ath_mutex_unlock (&digests_registered_lock); - if (! module) + spec = spec_from_algo (algorithm); + if (!spec) { log_debug ("md_enable: algorithm %d not available\n", algorithm); err = GPG_ERR_DIGEST_ALGO; } - else - digest = (gcry_md_spec_t *) module->spec; if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) @@ -583,7 +417,7 @@ md_enable (gcry_md_hd_t hd, int algorithm) if (!err) { size_t size = (sizeof (*entry) - + digest->contextsize + + spec->contextsize - sizeof (entry->context)); /* And allocate a new list entry. */ @@ -596,24 +430,13 @@ md_enable (gcry_md_hd_t hd, int algorithm) err = gpg_err_code_from_errno (errno); else { - entry->digest = digest; - entry->module = module; + entry->spec = spec; entry->next = h->list; entry->actual_struct_size = size; h->list = entry; /* And init this instance. */ - entry->digest->init (&entry->context.c); - } - } - - if (err) - { - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); + entry->spec->init (&entry->context.c); } } @@ -627,10 +450,11 @@ gcry_md_enable (gcry_md_hd_t hd, int algorithm) return gcry_error (md_enable (hd, algorithm)); } + static gcry_err_code_t md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t err = 0; struct gcry_md_context *a = ahd->ctx; struct gcry_md_context *b; GcryDigestEntry *ar, *br; @@ -681,11 +505,11 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) { if (a->secure) br = gcry_malloc_secure (sizeof *br - + ar->digest->contextsize + + ar->spec->contextsize - sizeof(ar->context)); else br = gcry_malloc (sizeof *br - + ar->digest->contextsize + + ar->spec->contextsize - sizeof (ar->context)); if (!br) { @@ -694,15 +518,10 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) break; } - memcpy (br, ar, (sizeof (*br) + ar->digest->contextsize + memcpy (br, ar, (sizeof (*br) + ar->spec->contextsize - sizeof (ar->context))); br->next = b->list; b->list = br; - - /* Add a reference to the module. */ - ath_mutex_lock (&digests_registered_lock); - _gcry_module_use (br->module); - ath_mutex_unlock (&digests_registered_lock); } } @@ -715,6 +534,7 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) return err; } + gcry_error_t gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) { @@ -726,6 +546,7 @@ gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) return gcry_error (err); } + /* * Reset all contexts and discard any buffered stuff. This may be used * instead of a md_close(); md_open(). @@ -741,13 +562,14 @@ gcry_md_reset (gcry_md_hd_t a) for (r = a->ctx->list; r; r = r->next) { - memset (r->context.c, 0, r->digest->contextsize); - (*r->digest->init) (&r->context.c); + memset (r->context.c, 0, r->spec->contextsize); + (*r->spec->init) (&r->context.c); } if (a->ctx->macpads) md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */ } + static void md_close (gcry_md_hd_t a) { @@ -760,9 +582,6 @@ md_close (gcry_md_hd_t a) for (r = a->ctx->list; r; r = r2) { r2 = r->next; - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (r->module); - ath_mutex_unlock (&digests_registered_lock); wipememory (r, r->actual_struct_size); gcry_free (r); } @@ -777,6 +596,7 @@ md_close (gcry_md_hd_t a) gcry_free(a); } + void gcry_md_close (gcry_md_hd_t hd) { @@ -784,6 +604,7 @@ gcry_md_close (gcry_md_hd_t hd) md_close (hd); } + static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) { @@ -800,18 +621,20 @@ md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) for (r = a->ctx->list; r; r = r->next) { if (a->bufpos) - (*r->digest->write) (&r->context.c, a->buf, a->bufpos); - (*r->digest->write) (&r->context.c, inbuf, inlen); + (*r->spec->write) (&r->context.c, a->buf, a->bufpos); + (*r->spec->write) (&r->context.c, inbuf, inlen); } a->bufpos = 0; } + void gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) { md_write (hd, inbuf, inlen); } + static void md_final (gcry_md_hd_t a) { @@ -824,7 +647,7 @@ md_final (gcry_md_hd_t a) md_write (a, NULL, 0); for (r = a->ctx->list; r; r = r->next) - (*r->digest->final) (&r->context.c); + (*r->spec->final) (&r->context.c); a->ctx->finalized = 1; @@ -850,6 +673,7 @@ md_final (gcry_md_hd_t a) } } + static gcry_err_code_t prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) { @@ -884,9 +708,10 @@ prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) } gcry_free (helpkey); - return GPG_ERR_NO_ERROR; + return 0; } + gcry_error_t gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) { @@ -912,10 +737,11 @@ gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) return gcry_error (rc); } + gcry_error_t gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) { - gcry_err_code_t rc = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; if (!hd->ctx->macpads) rc = GPG_ERR_CONFLICT; @@ -929,6 +755,7 @@ gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) return gcry_error (rc); } + /* The new debug interface. If SUFFIX is a string it creates an debug file for the context HD. IF suffix is NULL, the file is closed and debugging is stopped. */ @@ -942,9 +769,9 @@ gcry_md_debug (gcry_md_hd_t hd, const char *suffix) } - /**************** - * if ALGO is null get the digest for the used algo (which should be only one) + * If ALGO is null get the digest for the used algo (which should be + * only one) */ static byte * md_read( gcry_md_hd_t a, int algo ) @@ -958,19 +785,20 @@ md_read( gcry_md_hd_t a, int algo ) { if (r->next) log_debug ("more than one algorithm in md_read(0)\n"); - return r->digest->read (&r->context.c); + return r->spec->read (&r->context.c); } } else { for (r = a->ctx->list; r; r = r->next) - if (r->module->mod_id == algo) - return r->digest->read (&r->context.c); + if (r->spec->algo == algo) + return r->spec->read (&r->context.c); } BUG(); return NULL; } + /* * Read out the complete digest, this function implictly finalizes * the hash. @@ -1133,9 +961,10 @@ md_get_algo (gcry_md_hd_t a) fips_signal_error ("possible usage error"); log_error ("WARNING: more than one algorithm in md_get_algo()\n"); } - return r ? r->module->mod_id : 0; + return r ? r->spec->algo : 0; } + int gcry_md_get_algo (gcry_md_hd_t hd) { @@ -1149,23 +978,13 @@ gcry_md_get_algo (gcry_md_hd_t hd) static int md_digest_length (int algorithm) { - gcry_module_t digest; - int mdlen = 0; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); + gcry_md_spec_t *spec; - return mdlen; + spec = spec_from_algo (algorithm); + return spec? spec->mdlen : 0; } + /**************** * Return the length of the digest in bytes. * This function will return 0 in case of errors. @@ -1182,31 +1001,25 @@ gcry_md_get_algo_dlen (int algorithm) static const byte * md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) { + gcry_md_spec_t *spec; const byte *asnoid = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) + spec = spec_from_algo (algorithm); + if (spec) { if (asnlen) - *asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen; + *asnlen = spec->asnlen; if (mdlen) - *mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid; - _gcry_module_release (digest); + *mdlen = spec->mdlen; + asnoid = spec->asnoid; } else log_bug ("no ASN.1 OID for md algo %d\n", algorithm); - ath_mutex_unlock (&digests_registered_lock); return asnoid; } - /**************** * Return information about the given cipher algorithm * WHAT select the kind of information returned: @@ -1226,7 +1039,7 @@ md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) gcry_error_t gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t err; switch (what) { @@ -1248,10 +1061,10 @@ gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) asn = md_asn_oid (algo, &asnlen, NULL); if (buffer && (*nbytes >= asnlen)) - { - memcpy (buffer, asn, asnlen); - *nbytes = asnlen; - } + { + memcpy (buffer, asn, asnlen); + *nbytes = asnlen; + } else if (!buffer && nbytes) *nbytes = asnlen; else @@ -1264,8 +1077,9 @@ gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) } break; - default: - err = GPG_ERR_INV_OP; + default: + err = GPG_ERR_INV_OP; + break; } return gcry_error (err); @@ -1293,6 +1107,7 @@ md_start_debug ( gcry_md_hd_t md, const char *suffix ) log_debug("md debug: can't open %s\n", buf ); } + static void md_stop_debug( gcry_md_hd_t md ) { @@ -1329,7 +1144,7 @@ md_stop_debug( gcry_md_hd_t md ) gcry_error_t gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t err = 0; switch (cmd) { @@ -1350,7 +1165,7 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) *nbytes = 0; for(r=h->ctx->list; r; r = r->next ) { - if (r->module->mod_id == algo) + if (r->spec->algo == algo) { *nbytes = 1; break; @@ -1372,15 +1187,7 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) gcry_err_code_t _gcry_md_init (void) { - gcry_err_code_t err; - - err = ath_mutex_init (&digests_registered_lock); - if (err) - return gpg_err_code_from_errno (err); - - REGISTER_DEFAULT_DIGESTS; - - return err; + return 0; } @@ -1413,34 +1220,21 @@ gcry_md_is_enabled (gcry_md_hd_t a, int algo) gpg_error_t _gcry_md_selftest (int algo, int extended, selftest_report_func_t report) { - gcry_module_t module = NULL; - md_extra_spec_t *extraspec = NULL; gcry_err_code_t ec = 0; + gcry_md_spec_t *spec; - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&digests_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); else { ec = GPG_ERR_DIGEST_ALGO; if (report) report ("digest", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? + (spec && !spec->flags.disabled)? "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); + spec? "algorithm disabled" : "algorithm not found"); } - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); - } return gpg_error (ec); } diff --git a/cipher/md4.c b/cipher/md4.c index e2d096c..ab32b14 100644 --- a/cipher/md4.c +++ b/cipher/md4.c @@ -261,6 +261,7 @@ static gcry_md_oid_spec_t oid_spec_md4[] = gcry_md_spec_t _gcry_digest_spec_md4 = { + GCRY_MD_MD4, {0, 0}, "MD4", asn, DIM (asn), oid_spec_md4,16, md4_init, _gcry_md_block_write, md4_final, md4_read, sizeof (MD4_CONTEXT) diff --git a/cipher/md5.c b/cipher/md5.c index db0f315..1b6ad48 100644 --- a/cipher/md5.c +++ b/cipher/md5.c @@ -287,6 +287,7 @@ static gcry_md_oid_spec_t oid_spec_md5[] = gcry_md_spec_t _gcry_digest_spec_md5 = { + GCRY_MD_MD5, {0, 1}, "MD5", asn, DIM (asn), oid_spec_md5, 16, md5_init, _gcry_md_block_write, md5_final, md5_read, sizeof (MD5_CONTEXT) diff --git a/cipher/rmd160.c b/cipher/rmd160.c index d156e61..f7430ea 100644 --- a/cipher/rmd160.c +++ b/cipher/rmd160.c @@ -504,6 +504,7 @@ static gcry_md_oid_spec_t oid_spec_rmd160[] = gcry_md_spec_t _gcry_digest_spec_rmd160 = { + GCRY_MD_RMD160, {0, 0}, "RIPEMD160", asn, DIM (asn), oid_spec_rmd160, 20, _gcry_rmd160_init, _gcry_md_block_write, rmd160_final, rmd160_read, sizeof (RMD160_CONTEXT) diff --git a/cipher/sha1.c b/cipher/sha1.c index aef9f05..95591eb 100644 --- a/cipher/sha1.c +++ b/cipher/sha1.c @@ -411,11 +411,9 @@ static gcry_md_oid_spec_t oid_spec_sha1[] = gcry_md_spec_t _gcry_digest_spec_sha1 = { + GCRY_MD_SHA1, {0, 1}, "SHA1", asn, DIM (asn), oid_spec_sha1, 20, sha1_init, _gcry_md_block_write, sha1_final, sha1_read, - sizeof (SHA1_CONTEXT) - }; -md_extra_spec_t _gcry_digest_extraspec_sha1 = - { + sizeof (SHA1_CONTEXT), run_selftests }; diff --git a/cipher/sha256.c b/cipher/sha256.c index ad08cc7..d3917e4 100644 --- a/cipher/sha256.c +++ b/cipher/sha256.c @@ -475,22 +475,18 @@ static gcry_md_oid_spec_t oid_spec_sha256[] = gcry_md_spec_t _gcry_digest_spec_sha224 = { + GCRY_MD_SHA224, {0, 1}, "SHA224", asn224, DIM (asn224), oid_spec_sha224, 28, sha224_init, _gcry_md_block_write, sha256_final, sha256_read, - sizeof (SHA256_CONTEXT) - }; -md_extra_spec_t _gcry_digest_extraspec_sha224 = - { + sizeof (SHA256_CONTEXT), run_selftests }; gcry_md_spec_t _gcry_digest_spec_sha256 = { + GCRY_MD_SHA256, {0, 1}, "SHA256", asn256, DIM (asn256), oid_spec_sha256, 32, sha256_init, _gcry_md_block_write, sha256_final, sha256_read, - sizeof (SHA256_CONTEXT) - }; -md_extra_spec_t _gcry_digest_extraspec_sha256 = - { + sizeof (SHA256_CONTEXT), run_selftests }; diff --git a/cipher/sha512.c b/cipher/sha512.c index 505a1e4..af30775 100644 --- a/cipher/sha512.c +++ b/cipher/sha512.c @@ -731,12 +731,10 @@ static gcry_md_oid_spec_t oid_spec_sha512[] = gcry_md_spec_t _gcry_digest_spec_sha512 = { + GCRY_MD_SHA512, {0, 1}, "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64, sha512_init, _gcry_md_block_write, sha512_final, sha512_read, sizeof (SHA512_CONTEXT), - }; -md_extra_spec_t _gcry_digest_extraspec_sha512 = - { run_selftests }; @@ -759,11 +757,9 @@ static gcry_md_oid_spec_t oid_spec_sha384[] = gcry_md_spec_t _gcry_digest_spec_sha384 = { + GCRY_MD_SHA384, {0, 1}, "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48, sha384_init, _gcry_md_block_write, sha512_final, sha512_read, sizeof (SHA512_CONTEXT), - }; -md_extra_spec_t _gcry_digest_extraspec_sha384 = - { run_selftests }; diff --git a/cipher/stribog.c b/cipher/stribog.c index 61aa222..7dcdfd6 100644 --- a/cipher/stribog.c +++ b/cipher/stribog.c @@ -1387,6 +1387,7 @@ stribog_read_256 (void *context) gcry_md_spec_t _gcry_digest_spec_stribog_256 = { + GCRY_MD_STRIBOG256, {0, 0}, "STRIBOG256", NULL, 0, NULL, 32, stribog_init_256, _gcry_md_block_write, stribog_final, stribog_read_256, sizeof (STRIBOG_CONTEXT) @@ -1394,6 +1395,7 @@ gcry_md_spec_t _gcry_digest_spec_stribog_256 = gcry_md_spec_t _gcry_digest_spec_stribog_512 = { + GCRY_MD_STRIBOG512, {0, 0}, "STRIBOG512", NULL, 0, NULL, 64, stribog_init_512, _gcry_md_block_write, stribog_final, stribog_read_512, sizeof (STRIBOG_CONTEXT) diff --git a/cipher/tiger.c b/cipher/tiger.c index df16098..a70a3f2 100644 --- a/cipher/tiger.c +++ b/cipher/tiger.c @@ -810,6 +810,7 @@ tiger_read( void *context ) an OID anymore because that would not be correct. */ gcry_md_spec_t _gcry_digest_spec_tiger = { + GCRY_MD_TIGER, {0, 0}, "TIGER192", NULL, 0, NULL, 24, tiger_init, _gcry_md_block_write, tiger_final, tiger_read, sizeof (TIGER_CONTEXT) @@ -832,6 +833,7 @@ static gcry_md_oid_spec_t oid_spec_tiger1[] = gcry_md_spec_t _gcry_digest_spec_tiger1 = { + GCRY_MD_TIGER1, {0, 0}, "TIGER", asn1, DIM (asn1), oid_spec_tiger1, 24, tiger1_init, _gcry_md_block_write, tiger_final, tiger_read, sizeof (TIGER_CONTEXT) @@ -842,6 +844,7 @@ gcry_md_spec_t _gcry_digest_spec_tiger1 = /* This is TIGER2 which usues a changed padding algorithm. */ gcry_md_spec_t _gcry_digest_spec_tiger2 = { + GCRY_MD_TIGER2, {0, 0}, "TIGER2", NULL, 0, NULL, 24, tiger2_init, _gcry_md_block_write, tiger_final, tiger_read, sizeof (TIGER_CONTEXT) diff --git a/cipher/whirlpool.c b/cipher/whirlpool.c index fa632f9..168c38f 100644 --- a/cipher/whirlpool.c +++ b/cipher/whirlpool.c @@ -1351,6 +1351,7 @@ whirlpool_read (void *ctx) gcry_md_spec_t _gcry_digest_spec_whirlpool = { + GCRY_MD_WHIRLPOOL, {0, 0}, "WHIRLPOOL", NULL, 0, NULL, 64, whirlpool_init, whirlpool_write, whirlpool_final, whirlpool_read, sizeof (whirlpool_context_t) diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 62bc8b9..f4b9959 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -230,20 +230,46 @@ typedef struct gcry_cipher_spec * */ -typedef struct md_extra_spec +/* Type for the md_init function. */ +typedef void (*gcry_md_init_t) (void *c); + +/* Type for the md_write function. */ +typedef void (*gcry_md_write_t) (void *c, const void *buf, size_t nbytes); + +/* Type for the md_final function. */ +typedef void (*gcry_md_final_t) (void *c); + +/* Type for the md_read function. */ +typedef unsigned char *(*gcry_md_read_t) (void *c); + +typedef struct gcry_md_oid_spec { - selftest_func_t selftest; -} md_extra_spec_t; + const char *oidstring; +} gcry_md_oid_spec_t; +/* Module specification structure for message digests. */ +typedef struct gcry_md_spec +{ + int algo; + struct { + unsigned int disabled:1; + unsigned int fips:1; + } flags; + const char *name; + unsigned char *asnoid; + int asnlen; + gcry_md_oid_spec_t *oids; + int mdlen; + gcry_md_init_t init; + gcry_md_write_t write; + gcry_md_final_t final; + gcry_md_read_t read; + size_t contextsize; /* allocate this amount of context */ + selftest_func_t selftest; +} gcry_md_spec_t; -/* The private register functions. */ -gcry_error_t _gcry_md_register (gcry_md_spec_t *cipher, - md_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module); - /* The selftest functions. */ gcry_error_t _gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report); diff --git a/src/cipher.h b/src/cipher.h index d080e72..3b7744a 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -224,12 +224,6 @@ extern gcry_md_spec_t _gcry_digest_spec_tiger1; extern gcry_md_spec_t _gcry_digest_spec_tiger2; extern gcry_md_spec_t _gcry_digest_spec_whirlpool; -extern md_extra_spec_t _gcry_digest_extraspec_sha1; -extern md_extra_spec_t _gcry_digest_extraspec_sha224; -extern md_extra_spec_t _gcry_digest_extraspec_sha256; -extern md_extra_spec_t _gcry_digest_extraspec_sha384; -extern md_extra_spec_t _gcry_digest_extraspec_sha512; - /* Declarations for the pubkey cipher specifications. */ extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; extern gcry_pk_spec_t _gcry_pubkey_spec_elg; diff --git a/src/gcrypt-module.h b/src/gcrypt-module.h index 621a3a4..35a928c 100644 --- a/src/gcrypt-module.h +++ b/src/gcrypt-module.h @@ -47,37 +47,6 @@ typedef struct gcry_module *gcry_module_t; /* ********************** */ -/* Type for the md_init function. */ -typedef void (*gcry_md_init_t) (void *c); - -/* Type for the md_write function. */ -typedef void (*gcry_md_write_t) (void *c, const void *buf, size_t nbytes); - -/* Type for the md_final function. */ -typedef void (*gcry_md_final_t) (void *c); - -/* Type for the md_read function. */ -typedef unsigned char *(*gcry_md_read_t) (void *c); - -typedef struct gcry_md_oid_spec -{ - const char *oidstring; -} gcry_md_oid_spec_t; - -/* Module specification structure for message digests. */ -typedef struct gcry_md_spec -{ - const char *name; - unsigned char *asnoid; - int asnlen; - gcry_md_oid_spec_t *oids; - int mdlen; - gcry_md_init_t init; - gcry_md_write_t write; - gcry_md_final_t final; - gcry_md_read_t read; - size_t contextsize; /* allocate this amount of context */ -} gcry_md_spec_t; #if 0 /* keep Emacsens's auto-indent happy */ { ----------------------------------------------------------------------- Summary of changes: cipher/cipher-internal.h | 1 - cipher/crc.c | 6 + cipher/gostr3411-94.c | 1 + cipher/md.c | 550 +++++++++++++++------------------------------- cipher/md4.c | 1 + cipher/md5.c | 1 + cipher/rmd160.c | 1 + cipher/sha1.c | 6 +- cipher/sha256.c | 12 +- cipher/sha512.c | 8 +- cipher/stribog.c | 2 + cipher/tiger.c | 3 + cipher/whirlpool.c | 1 + src/Makefile.am | 4 +- src/cipher-proto.h | 44 +++- src/cipher.h | 6 - src/ec-context.h | 3 - src/g10lib.h | 47 +---- src/gcrypt-module.h | 88 -------- src/module.c | 212 ------------------ src/mpi.h | 4 + src/visibility.h | 1 - 22 files changed, 238 insertions(+), 764 deletions(-) delete mode 100644 src/gcrypt-module.h delete mode 100644 src/module.c hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From gniibe at fsij.org Thu Oct 3 06:14:13 2013 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 03 Oct 2013 13:14:13 +0900 Subject: [PATCH 3/3] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> References: <1380197263-750-1-git-send-email-dbaryshkov@gmail.com> <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> Message-ID: <1380773653.32263.2.camel@cfw2.gniibe.org> Hello, Patch looks great. Here is my comment. I think that it's better to add ECC_DIALECT_GOST_R34_10 (or something like that) to ecc_dialects in src/mpi.h. That's because it's a part of a curve definition, and domain parameters (only) make sense with this. -- From dbaryshkov at gmail.com Thu Oct 3 11:43:28 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Thu, 3 Oct 2013 13:43:28 +0400 Subject: [PATCH 3/3] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: <1380773653.32263.2.camel@cfw2.gniibe.org> References: <1380197263-750-1-git-send-email-dbaryshkov@gmail.com> <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> <1380773653.32263.2.camel@cfw2.gniibe.org> Message-ID: Hello, On Thu, Oct 3, 2013 at 8:14 AM, NIIBE Yutaka wrote: > Patch looks great. Here is my comment. > > I think that it's better to add ECC_DIALECT_GOST_R34_10 (or something > like that) to ecc_dialects in src/mpi.h. That's because it's a part > of a curve definition, and domain parameters (only) make sense with > this. Hmm. Interesting suggestion. Maybe I failed to understand the purpose of the domain field. From my understanding it is used only for key generation, isn't it? Does it have any other usecases? I thought about gost r 34.10 signatures as if they are 'just another format' of ecdsa signatures. Thus I added a (flag gost) to data/signature generation. IIUC, there is no any significant difference between ECDSA and GOST curves/keys. What do you think? -- With best wishes Dmitry From gniibe at fsij.org Thu Oct 3 15:11:14 2013 From: gniibe at fsij.org (NIIBE Yutaka) Date: Thu, 03 Oct 2013 22:11:14 +0900 Subject: [PATCH 3/3] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: References: <1380197263-750-1-git-send-email-dbaryshkov@gmail.com> <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> <1380773653.32263.2.camel@cfw2.gniibe.org> Message-ID: <1380805874.3589.0.camel@latx1.gniibe.org> Hello, Let me explain my thought. When I see the portion of your code: --- a/cipher/ecc-curves.c +++ b/cipher/ecc-curves.c @@ -263,6 +263,34 @@ static const ecc_domain_parms_t domain_parms[] = "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111" "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892" }, + { + "GOST2001-test", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000431", /* p */ + "0x0000000000000000000000000000000000000000000000000000000000000007", /* a */ + "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e", /* b */ + "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3", /* q */ + + "0x0000000000000000000000000000000000000000000000000000000000000002", /* x */ + "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8", /* y */ + }, I felt, it's not correct to uses ECC_DIALECT_STANDARD. Then, I thought that if it uses ECC_DIALECT_GOST_R34_10, it will be correct. That is, the interpretation of p, a, b, g (q for GOST R34.10), x, y (of generator) is determined by the combination of curve model and dialect. On 2013-10-03 at 13:43 +0400, Dmitry Eremin-Solenikov wrote: > Hmm. Interesting suggestion. Maybe I failed to understand the purpose > of the domain field. From my understanding it is used only for key generation, > isn't it? Does it have any other usecases? ecc_domain_parms_t is only used internally in ecc-curves.c, but it is the basis of the type elliptic_curve_t (defined in ecc-common.h), which also has model and dialect. > I thought about gost r 34.10 signatures as if they are 'just another format' of > ecdsa signatures. Thus I added a (flag gost) to data/signature generation. > IIUC, there is no any significant difference between ECDSA and GOST > curves/keys. I understand your approach of adding routines for GOST R 34.10. I have no objection for that. I agree about similarity between computation of ECDSA signature and one of GOST signature. My point is that the semantics of a curve definition can be different. Common: p, a, b defines a curve. ECC_DIALECT_STANDARD: g is order of the group. G is the generator, where gG = O ECC_DIALECT_GOST_R34_10: q is order of the subgroup. P is the generator of the subgroup, where qP = O If q = g and P = G for a GOST curve, there is nothing to distinguish ECC_DIALECT_STANDARD and ECC_DIALECT_GOST_R34_10. If q < g and P /= G for a GOST curve, we need to distinguish dialects. If we have optional fields and let GOST curve has g and G too, we can compute ECDSA signature with GOST curve. Usually, with curve for ECDSA, the order g is prime, so, meaningful subgroup is the group itself. We can compute GOST signature with this ECDSA curve with q = g, P = G. -- From wk at gnupg.org Thu Oct 3 17:14:40 2013 From: wk at gnupg.org (Werner Koch) Date: Thu, 03 Oct 2013 17:14:40 +0200 Subject: [PATCH 3/3] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: (Dmitry Eremin-Solenikov's message of "Thu, 3 Oct 2013 13:43:28 +0400") References: <1380197263-750-1-git-send-email-dbaryshkov@gmail.com> <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> <1380773653.32263.2.camel@cfw2.gniibe.org> Message-ID: <87txgy5qu7.fsf@vigenere.g10code.de> On Thu, 3 Oct 2013 11:43, dbaryshkov at gmail.com said: > of the domain field. From my understanding it is used only for key generation, > isn't it? Does it have any other usecases? There are two purposes for the dialect field: - Allow to tweak the computation - for example in the case of EdDSA. - Allow to divert for optimized maths for a specific curve. > ecdsa signatures. Thus I added a (flag gost) to data/signature generation. > IIUC, there is no any significant difference between ECDSA and GOST > curves/keys. Even then it might be useful to flag it as a dialect (e.g. ..DIALECT_SUBGROUP) - might come handy later. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dbaryshkov at gmail.com Thu Oct 3 21:56:22 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Thu, 3 Oct 2013 23:56:22 +0400 Subject: [PATCH 3/3] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: <1380805874.3589.0.camel@latx1.gniibe.org> References: <1380197263-750-1-git-send-email-dbaryshkov@gmail.com> <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> <1380773653.32263.2.camel@cfw2.gniibe.org> <1380805874.3589.0.camel@latx1.gniibe.org> Message-ID: Hello, On Thu, Oct 3, 2013 at 5:11 PM, NIIBE Yutaka wrote: > > If q = g and P = G for a GOST curve, there is nothing to distinguish > ECC_DIALECT_STANDARD and ECC_DIALECT_GOST_R34_10. > > If q < g and P /= G for a GOST curve, we need to distinguish dialects. > > If we have optional fields and let GOST curve has g and G too, we can > compute ECDSA signature with GOST curve. Hmm. It's my fault. In the standard itself, there are two distinct values: m (the group order) and q (the subgroup order). However two facts distracted me. First, in the both curves defined in standard m = q. Second, rfc4357 (which supplements standards with exact parameters, values, etc) defines only q parameter for the curves that are used/defined. It looks like there is a possibility for m and q to differ. Thank you very much for pointing me to it! Even if we verify that queues defined in rfc4357 use m=q, there is absolutely guarantee that in future curves will follow. So it really looks like a separate domain. At least from the 'pure math' perspective. I like the Werner's idea of DIALECT_SUBGROUP. It defines the curve parameters and still leaves enough space for possible standards/curves which decide to use subgroup instead of full group. Werner, would you take first two patches in this serie? -- With best wishes Dmitry From gniibe at fsij.org Fri Oct 4 03:04:18 2013 From: gniibe at fsij.org (NIIBE Yutaka) Date: Fri, 04 Oct 2013 10:04:18 +0900 Subject: [PATCH 3/3] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: References: <1380197263-750-1-git-send-email-dbaryshkov@gmail.com> <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> <1380773653.32263.2.camel@cfw2.gniibe.org> <1380805874.3589.0.camel@latx1.gniibe.org> Message-ID: <1380848658.3346.1.camel@cfw2.gniibe.org> Hello, I withdraw my original suggestion (using DIALECT_*) if we don't have actual curve at hand, where m /= q. On 2013-10-03 at 23:56 +0400, Dmitry Eremin-Solenikov wrote: > First, in the both curves defined in standard m = q. Second, > rfc4357 (which supplements standards with exact parameters, values, > etc) defines only q parameter for the curves that are used/defined. Thank you for your explanation. I misunderstood as if m = q were just an example, and general cases of m /= q should be handled. > So it really looks like a separate domain. I understand. > I like the Werner's idea of DIALECT_SUBGROUP. It defines the curve > parameters and still leaves enough space for possible > standards/curves which decide to use subgroup instead of full group. IIUC, this means: We reserve DIALECT_SUBGROUP for future use (cases of m /= q). A curve with DIALECT_STANDARD will be able to compute GOST signature, as well as ECDSA signature. A curve with DIALECT_SUBGROUP will be able to compute GOST signature, but not to compute ECDSA signature. Let's will do that when we will have a curve m /= q. -- From wk at gnupg.org Mon Oct 7 11:56:00 2013 From: wk at gnupg.org (Werner Koch) Date: Mon, 07 Oct 2013 11:56:00 +0200 Subject: GOST ECC pubkey In-Reply-To: (Dmitry Eremin-Solenikov's message of "Wed, 2 Oct 2013 19:09:14 +0400") References: <1379653630.3179.2.camel@cfw2.gniibe.org> <1379655225.3179.3.camel@cfw2.gniibe.org> <8761thb4wk.fsf@vigenere.g10code.de> Message-ID: <8761t91k27.fsf@vigenere.g10code.de> On Wed, 2 Oct 2013 17:09, dbaryshkov at gmail.com said: > I have sent a patch a few days ago. It just adds a (flag gost) to the data > and signature s-exps. There is no difference with ECDSA in the keys > S-expressions. Please have some patience. I need to restructure the ecc code first and then there is an urgent request from the GNUnet folks to solve an problem with their special needs. Also the git server had a hardware failure and I need some time to migrate it to a new machine. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dbaryshkov at gmail.com Mon Oct 7 12:19:55 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Mon, 7 Oct 2013 14:19:55 +0400 Subject: GOST ECC pubkey In-Reply-To: <8761t91k27.fsf@vigenere.g10code.de> References: <1379653630.3179.2.camel@cfw2.gniibe.org> <1379655225.3179.3.camel@cfw2.gniibe.org> <8761thb4wk.fsf@vigenere.g10code.de> <8761t91k27.fsf@vigenere.g10code.de> Message-ID: On Mon, Oct 7, 2013 at 1:56 PM, Werner Koch wrote: > On Wed, 2 Oct 2013 17:09, dbaryshkov at gmail.com said: > >> I have sent a patch a few days ago. It just adds a (flag gost) to the data >> and signature s-exps. There is no difference with ECDSA in the keys >> S-expressions. > > Please have some patience. I need to restructure the ecc code first and > then there is an urgent request from the GNUnet folks to solve an > problem with their special needs. > > Also the git server had a hardware failure and I need some time to > migrate it to a new machine. No problem with waiting, I was just describing what was done. Hopefully all issues will be sorted out soon. At least this gives me some time to finish GCM :) -- With best wishes Dmitry From wk at gnupg.org Wed Oct 9 23:11:39 2013 From: wk at gnupg.org (Werner Koch) Date: Wed, 09 Oct 2013 23:11:39 +0200 Subject: [admin] Please do not poll the git server Message-ID: <87siwaup2s.fsf@vigenere.g10code.de> Hi, while looking at the new git server I found that someone is polling for changes in libgcrypt. Every minute! Please don't do that - subscribe to the commit list instead. For those who want an immediate notification they my join the Jabber MUC gnupg-devel at conference.jabber.gnupg.org . If you really think that you need to run a poll script please be nice and don't run it more often than every hour or so. The IP address in question seems to be from a Scandinavian shell server provider - please go and fix your cronjob now. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From cvs at cvs.gnupg.org Thu Oct 10 15:00:28 2013 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Thu, 10 Oct 2013 15:00:28 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-300-g150c031 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 150c0313f971bcea62d2802f0389c883e11ebb31 (commit) from 94b652ecb006c29fa2ffb1badc9f02b758581737 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 150c0313f971bcea62d2802f0389c883e11ebb31 Author: Jussi Kivilinna Date: Wed Oct 2 20:47:56 2013 +0300 Prevent tail call optimization with _gcry_burn_stack * configure.ac: New check, HAVE_GCC_ASM_VOLATILE_MEMORY. * src/g10lib.h (_gcry_burn_stack): Rename to __gcry_burn_stack. (__gcry_burn_stack_dummy): New. (_gcry_burn_stack): New macro. * src/misc.c (_gcry_burn_stack): Rename to __gcry_burn_stack. (__gcry_burn_stack_dummy): New. -- Tail call optimization can turn _gcry_burn_stack call in to tail jump. When this happens, stack pointer is restored to initial state of current function. This causes problem for _gcry_burn_stack because its callers do not count in current function stack depth. One solution is to prevent gcry_burn_stack being tail optimized by inserting dummy function call behind it. Another would be to add memory barrier 'asm volatile("":::"memory")' behind every _gcry_burn_stack call. This however requires GCC asm support from compiler. Patch adds detection for memory barrier support and when available uses memory barrier to prevent when tail call optimization. If not available dummy function call is used instead. Signed-off-by: Jussi Kivilinna diff --git a/configure.ac b/configure.ac index 2c92028..1460dfd 100644 --- a/configure.ac +++ b/configure.ac @@ -921,7 +921,7 @@ fi # # Check whether the compiler supports 'asm' or '__asm__' keyword for -# assembler blocks +# assembler blocks. # AC_CACHE_CHECK([whether 'asm' assembler keyword is supported], [gcry_cv_have_asm], @@ -945,6 +945,32 @@ fi # +# Check whether the compiler supports inline assembly memory barrier. +# +if test "$gcry_cv_have_asm" = "no" ; then + if test "$gcry_cv_have___asm__" = "yes" ; then + AC_CACHE_CHECK([whether inline assembly memory barrier is supported], + [gcry_cv_have_asm_volatile_memory], + [gcry_cv_have_asm_volatile_memory=no + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [[void a(void) { __asm__ volatile("":::"memory"); }]])], + [gcry_cv_have_asm_volatile_memory=yes])]) + fi +else + AC_CACHE_CHECK([whether inline assembly memory barrier is supported], + [gcry_cv_have_asm_volatile_memory], + [gcry_cv_have_asm_volatile_memory=no + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [[void a(void) { asm volatile("":::"memory"); }]])], + [gcry_cv_have_asm_volatile_memory=yes])]) +fi +if test "$gcry_cv_have_asm_volatile_memory" = "yes" ; then + AC_DEFINE(HAVE_GCC_ASM_VOLATILE_MEMORY,1, + [Define if inline asm memory barrier is supported]) +fi + + +# # Check whether GCC inline assembler supports SSSE3 instructions # This is required for the AES-NI instructions. # diff --git a/src/g10lib.h b/src/g10lib.h index 0ada30a..c1ba2f7 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -259,7 +259,16 @@ int strcasecmp (const char *a, const char *b) _GCRY_GCC_ATTR_PURE; /* Stack burning. */ -void _gcry_burn_stack (unsigned int bytes); +#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY +#define __gcry_burn_stack_dummy() asm volatile ("":::"memory") +#else +void __gcry_burn_stack_dummy (void); +#endif + +void __gcry_burn_stack (unsigned int bytes); +#define _gcry_burn_stack(bytes) \ + do { __gcry_burn_stack (bytes); \ + __gcry_burn_stack_dummy (); } while(0) /* To avoid that a compiler optimizes certain memset calls away, these diff --git a/src/misc.c b/src/misc.c index 912039a..9b30ac3 100644 --- a/src/misc.c +++ b/src/misc.c @@ -438,7 +438,7 @@ _gcry_log_printsxp (const char *text, gcry_sexp_t sexp) void -_gcry_burn_stack (unsigned int bytes) +__gcry_burn_stack (unsigned int bytes) { #ifdef HAVE_VLA /* (bytes == 0 ? 1 : bytes) == (!bytes + bytes) */ @@ -456,6 +456,13 @@ _gcry_burn_stack (unsigned int bytes) #endif } +#ifndef HAVE_GCC_ASM_VOLATILE_MEMORY +void +__gcry_burn_stack_dummy (void) +{ +} +#endif + void _gcry_divide_by_zero (void) { ----------------------------------------------------------------------- Summary of changes: configure.ac | 28 +++++++++++++++++++++++++++- src/g10lib.h | 11 ++++++++++- src/misc.c | 9 ++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From jussi.kivilinna at iki.fi Thu Oct 10 16:43:25 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Thu, 10 Oct 2013 17:43:25 +0300 Subject: [PATCH] arcfour: more optimized version for non-i386 architectures Message-ID: <20131010144325.30641.99663.stgit@localhost6.localdomain6> * cipher/arcfour.c (ARCFOUR_context): Reorder members. (do_encrypt_stream) [!__i386__]: Faster implementation for non-i386. (do_arcfour_setkey): Avoid modulo operations. -- Patch adds faster arcfour implementation for non-i386 architectures. New code is not activated on i386 as performance would regress. This is because i386 does not have enough registers hold new variables. Speed up on Intel i5-4570 (x86_64): 1.56x Speed up on ARM Cortex-A8: 1.18x Signed-off-by: Jussi Kivilinna --- cipher/arcfour.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/cipher/arcfour.c b/cipher/arcfour.c index dc32b07..e8a5484 100644 --- a/cipher/arcfour.c +++ b/cipher/arcfour.c @@ -34,14 +34,39 @@ static const char *selftest(void); typedef struct { - int idx_i, idx_j; byte sbox[256]; + int idx_i, idx_j; } ARCFOUR_context; static void do_encrypt_stream( ARCFOUR_context *ctx, byte *outbuf, const byte *inbuf, unsigned int length ) { +#ifndef __i386__ + register unsigned int i = ctx->idx_i; + register byte j = ctx->idx_j; + register byte *sbox = ctx->sbox; + register byte t, u; + + while ( length-- ) + { + i++; + t = sbox[(byte)i]; + j += t; + u = sbox[j]; + sbox[(byte)i] = u; + u += t; + sbox[j] = t; + *outbuf++ = sbox[u] ^ *inbuf++; + } + + ctx->idx_i = (byte)i; + ctx->idx_j = (byte)j; +#else /*__i386__*/ + /* Old implementation of arcfour is faster on i386 than the version above. + * This is because version above increases register pressure which on i386 + * would push some of the variables to memory/stack. Therefore keep this + * version for i386 to avoid regressing performance. */ register int i = ctx->idx_i; register int j = ctx->idx_j; register byte *sbox = ctx->sbox; @@ -59,6 +84,7 @@ do_encrypt_stream( ARCFOUR_context *ctx, ctx->idx_i = i; ctx->idx_j = j; +#endif } static void @@ -96,17 +122,21 @@ do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) ctx->idx_i = ctx->idx_j = 0; for (i=0; i < 256; i++ ) ctx->sbox[i] = i; - for (i=0; i < 256; i++ ) - karr[i] = key[i%keylen]; + for (i=j=0; i < 256; i++,j++ ) + { + if (j >= keylen) + j = 0; + karr[i] = key[j]; + } for (i=j=0; i < 256; i++ ) { int t; - j = (j + ctx->sbox[i] + karr[i]) % 256; + j = (j + ctx->sbox[i] + karr[i]) & 255; t = ctx->sbox[i]; ctx->sbox[i] = ctx->sbox[j]; ctx->sbox[j] = t; } - memset( karr, 0, 256 ); + wipememory( karr, sizeof(karr) ); return GPG_ERR_NO_ERROR; } From jussi.kivilinna at iki.fi Sun Oct 13 12:02:28 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sun, 13 Oct 2013 13:02:28 +0300 Subject: [RFC PATCH 1/3] Add API to support AEAD cipher modes Message-ID: <20131013100228.32014.526.stgit@localhost6.localdomain6> From: Dmitry Eremin-Solenikov * cipher/cipher.c (_gcry_cipher_authenticate, _gcry_cipher_tag): New. * src/visibility.c (gcry_cipher_authenticate, gcry_cipher_tag): New. * src/gcrypt.h.in, src/visibility.h: add declarations of these functions. * src/libgcrypt.defs, src/libgcrypt.vers: export functions. -- Authenticated Encryption with Associated Data (AEAD) cipher modes provide authentication tag that can be used to authenticate message. At the same time it allows one to specify additional (unencrypted data) that will be authenticated together with the message. This class of cipher modes requires additional API present in this commit. Signed-off-by: Dmitry Eremin-Solenikov --- cipher/cipher.c | 15 +++++++++++++++ src/gcrypt.h.in | 7 +++++++ src/libgcrypt.def | 2 ++ src/libgcrypt.vers | 1 + src/visibility.c | 18 ++++++++++++++++++ src/visibility.h | 6 ++++++ 6 files changed, 49 insertions(+) diff --git a/cipher/cipher.c b/cipher/cipher.c index 75d42d1..2d3a457 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -910,6 +910,21 @@ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return 0; } +gcry_error_t +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, + const void *aad, size_t aadsize) +{ + log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_tag (gcry_cipher_hd_t hd, void *out, size_t outsize) +{ + log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + gcry_error_t gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 8646f43..a33dc08 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -940,6 +940,13 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen); +/* Provide additional authentication data for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t h, + const void *aad, size_t aadlen); + +/* Get authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_tag (gcry_cipher_hd_t h, + void *out, size_t outsize); /* Reset the handle to the state after open. */ #define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0) diff --git a/src/libgcrypt.def b/src/libgcrypt.def index 7efb3b9..7d8e679 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -253,5 +253,7 @@ EXPORTS gcry_log_debugpnt @223 gcry_log_debugsxp @224 + gcry_cipher_authenticate @225 + gcry_cipher_tag @226 ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index b1669fd..be20f51 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -51,6 +51,7 @@ GCRYPT_1.6 { gcry_cipher_info; gcry_cipher_map_name; gcry_cipher_mode_from_oid; gcry_cipher_open; gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr; + gcry_cipher_authenticate; gcry_cipher_tag; gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl; gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey; diff --git a/src/visibility.c b/src/visibility.c index 6e3c755..669537f 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -689,6 +689,24 @@ gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) return _gcry_cipher_setiv (hd, iv, ivlen); } +gcry_error_t +gcry_cipher_tag (gcry_cipher_hd_t hd, void *out, size_t outsize) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_tag (hd, out, outsize); +} + +gcry_error_t +gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *aad, size_t aadsize) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_authenticate (hd, aad, aadsize); +} + gpg_error_t gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) { diff --git a/src/visibility.h b/src/visibility.h index cd2a60f..d4db258 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -81,6 +81,8 @@ #define gcry_cipher_setkey _gcry_cipher_setkey #define gcry_cipher_setiv _gcry_cipher_setiv #define gcry_cipher_setctr _gcry_cipher_setctr +#define gcry_cipher_authenticate _gcry_cipher_authenticate +#define gcry_cipher_tag _gcry_cipher_tag #define gcry_cipher_ctl _gcry_cipher_ctl #define gcry_cipher_decrypt _gcry_cipher_decrypt #define gcry_cipher_encrypt _gcry_cipher_encrypt @@ -297,6 +299,8 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, #undef gcry_cipher_setkey #undef gcry_cipher_setiv #undef gcry_cipher_setctr +#undef gcry_cipher_authenticate +#undef gcry_cipher_tag #undef gcry_cipher_ctl #undef gcry_cipher_decrypt #undef gcry_cipher_encrypt @@ -474,6 +478,8 @@ MARK_VISIBLE (gcry_cipher_close) MARK_VISIBLE (gcry_cipher_setkey) MARK_VISIBLE (gcry_cipher_setiv) MARK_VISIBLE (gcry_cipher_setctr) +MARK_VISIBLE (gcry_cipher_authenticate) +MARK_VISIBLE (gcry_cipher_tag) MARK_VISIBLE (gcry_cipher_ctl) MARK_VISIBLE (gcry_cipher_decrypt) MARK_VISIBLE (gcry_cipher_encrypt) From jussi.kivilinna at iki.fi Sun Oct 13 12:02:33 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sun, 13 Oct 2013 13:02:33 +0300 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <20131013100228.32014.526.stgit@localhost6.localdomain6> References: <20131013100228.32014.526.stgit@localhost6.localdomain6> Message-ID: <20131013100233.32014.24561.stgit@localhost6.localdomain6> -- AEAD modes may have different requirements for initialization. For example, CCM mode needs to know length of encrypted data in advance. So, would it make sense to add variadic API function for initilizing AEAD mode? The one that this patch adds is: gcry_error_t gcry_cipher_aead_init (gcry_cipher_hd_t hd, ...); With this API, CCM mode could be initialized by calling gcry_cipher_aead_init using arguments (CCM needs the length of encrypted data, and the length of authentication tag at begining): 'gcry_cipher_hd_t hd, void *nonce, int noncelen, int cryptlen, int taglen'. GCM mode, in the other hand, could omit the length of data and tag from initialization and just provide nonce and nonce_len. Signed-off-by: Jussi Kivilinna --- cipher/cipher.c | 21 +++++++++++++++++++++ src/g10lib.h | 4 ++++ src/gcrypt.h.in | 5 ++++- src/libgcrypt.def | 1 + src/libgcrypt.vers | 2 +- src/visibility.c | 16 ++++++++++++++++ src/visibility.h | 3 +++ 7 files changed, 50 insertions(+), 2 deletions(-) diff --git a/cipher/cipher.c b/cipher/cipher.c index 2d3a457..8ebab7c 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -910,18 +910,39 @@ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return 0; } + gcry_error_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *aad, size_t aadsize) { log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + + (void)aad; + (void)aadsize; + return gpg_error (GPG_ERR_INV_CIPHER_MODE); } + gcry_error_t _gcry_cipher_tag (gcry_cipher_hd_t hd, void *out, size_t outsize) { log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + + (void)out; + (void)outsize; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + + +gcry_error_t +_gcry_cipher_aead_vinit (gcry_cipher_hd_t hd, va_list arg_ptr) +{ + log_fatal ("gcry_cipher_aead_init: invalid mode %d\n", hd->mode ); + + (void)arg_ptr; + return gpg_error (GPG_ERR_INV_CIPHER_MODE); } diff --git a/src/g10lib.h b/src/g10lib.h index c1ba2f7..e4f9e7e 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -190,6 +190,10 @@ void _gcry_detect_hw_features (unsigned int); const char *_gcry_mpi_get_hw_config (void); +/*-- cipher/cipher.c --*/ +gcry_error_t _gcry_cipher_aead_vinit (gcry_cipher_hd_t hd, va_list arg_ptr); + + /*-- cipher/pubkey.c --*/ /* FIXME: shouldn't this go into mpi.h? */ diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index a33dc08..2fffd69 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -940,7 +940,7 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen); -/* Provide additional authentication data for AEAD modes/ciphers. */ +/* Provide additional authentication data for AEAD modes/ciphers. */ gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t h, const void *aad, size_t aadlen); @@ -948,6 +948,9 @@ gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t h, gcry_error_t gcry_cipher_tag (gcry_cipher_hd_t h, void *out, size_t outsize); +/* Initialization for different AEAD modes. */ +gcry_error_t gcry_cipher_aead_init (gcry_cipher_hd_t hd, ...); + /* Reset the handle to the state after open. */ #define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0) diff --git a/src/libgcrypt.def b/src/libgcrypt.def index 7d8e679..176958e 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -255,5 +255,6 @@ EXPORTS gcry_cipher_authenticate @225 gcry_cipher_tag @226 + gcry_cipher_aead_init @227 ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index be20f51..5b837d6 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -51,7 +51,7 @@ GCRYPT_1.6 { gcry_cipher_info; gcry_cipher_map_name; gcry_cipher_mode_from_oid; gcry_cipher_open; gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr; - gcry_cipher_authenticate; gcry_cipher_tag; + gcry_cipher_authenticate; gcry_cipher_tag; gcry_cipher_aead_init; gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl; gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey; diff --git a/src/visibility.c b/src/visibility.c index 669537f..ed53a14 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -707,6 +707,22 @@ gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *aad, size_t aadsize) return _gcry_cipher_authenticate (hd, aad, aadsize); } +gcry_error_t +gcry_cipher_aead_init (gcry_cipher_hd_t hd, ...) +{ + va_list arg_ptr; + gcry_error_t err; + + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + va_start (arg_ptr, hd); + err = _gcry_cipher_aead_vinit (hd, arg_ptr); + va_end (arg_ptr); + + return err; +} + gpg_error_t gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) { diff --git a/src/visibility.h b/src/visibility.h index d4db258..a992ef5 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -83,6 +83,7 @@ #define gcry_cipher_setctr _gcry_cipher_setctr #define gcry_cipher_authenticate _gcry_cipher_authenticate #define gcry_cipher_tag _gcry_cipher_tag +#define gcry_cipher_aead_init _gcry_cipher_aead_init #define gcry_cipher_ctl _gcry_cipher_ctl #define gcry_cipher_decrypt _gcry_cipher_decrypt #define gcry_cipher_encrypt _gcry_cipher_encrypt @@ -301,6 +302,7 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, #undef gcry_cipher_setctr #undef gcry_cipher_authenticate #undef gcry_cipher_tag +#undef gcry_cipher_aead_init #undef gcry_cipher_ctl #undef gcry_cipher_decrypt #undef gcry_cipher_encrypt @@ -480,6 +482,7 @@ MARK_VISIBLE (gcry_cipher_setiv) MARK_VISIBLE (gcry_cipher_setctr) MARK_VISIBLE (gcry_cipher_authenticate) MARK_VISIBLE (gcry_cipher_tag) +MARK_VISIBLE (gcry_cipher_aead_init) MARK_VISIBLE (gcry_cipher_ctl) MARK_VISIBLE (gcry_cipher_decrypt) MARK_VISIBLE (gcry_cipher_encrypt) From jussi.kivilinna at iki.fi Sun Oct 13 12:02:38 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sun, 13 Oct 2013 13:02:38 +0300 Subject: [RFC PATCH 3/3] Add Counter with CBC-MAC mode (CCM) In-Reply-To: <20131013100228.32014.526.stgit@localhost6.localdomain6> References: <20131013100228.32014.526.stgit@localhost6.localdomain6> Message-ID: <20131013100238.32014.88403.stgit@localhost6.localdomain6> -- Patch adds CCM (Counter with CBC-MAC) mode as defined in RFC 3610 and NIST Special Publication 800-38C. --- cipher/Makefile.am | 1 cipher/cipher-ccm.c | 349 ++++++++++++++++++++++++++++++ cipher/cipher-internal.h | 41 +++- cipher/cipher.c | 88 ++++++-- src/gcrypt.h.in | 5 tests/basic.c | 532 ++++++++++++++++++++++++++++++++++++++++++++++ tests/benchmark.c | 67 +++++- 7 files changed, 1063 insertions(+), 20 deletions(-) create mode 100644 cipher/cipher-ccm.c diff --git a/cipher/Makefile.am b/cipher/Makefile.am index a2b2c8a..b0efd89 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -40,6 +40,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES) libcipher_la_SOURCES = \ cipher.c cipher-internal.h \ cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \ +cipher-ccm.c \ cipher-selftest.c cipher-selftest.h \ pubkey.c pubkey-internal.h pubkey-util.c \ md.c \ diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c new file mode 100644 index 0000000..94ffbea --- /dev/null +++ b/cipher/cipher-ccm.c @@ -0,0 +1,349 @@ +/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static unsigned int +do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, unsigned int inlen, + int do_padding) +{ + unsigned int burn = 0; + unsigned int unused = c->u_mode.ccm.mac_unused; + unsigned int blocksize = 16; + + if (inlen == 0 && unused == 0) + return 0; + + do + { + if (inlen + unused < blocksize || unused > 0) + { + for (; inlen && unused < blocksize; inlen--) + c->u_mode.ccm.macbuf[unused++] = *inbuf++; + } + if (!inlen) + { + if (!do_padding) + break; + + while (unused < blocksize) + c->u_mode.ccm.macbuf[unused++] = 0; + } + + if (unused > 0) + { + /* Process one block from macbuf. */ + buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + unused = 0; + } + + while (inlen >= blocksize) + { + buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + inlen -= blocksize; + inbuf += blocksize; + } + } + while (inlen > 0); + + c->u_mode.ccm.mac_unused = unused; + + if (burn) + burn += 4 * sizeof(void *); + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_ccm_aead_init (gcry_cipher_hd_t c, const unsigned char *nonce, + unsigned int noncelen, unsigned int authlen, + size_t encryptlen) +{ + unsigned int L = 15 - noncelen; + unsigned int M = authlen; + unsigned int L_, M_; + int i; + + M_ = (M - 2) / 2; + L_ = L - 1; + + if (!nonce) + return GPG_ERR_INV_ARG; + /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */ + if ((M_ * 2 + 2) != M || M < 4 || M > 16) + return GPG_ERR_INV_LENGTH; + /* Length field must be 2, 3, ..., or 8. */ + if (L < 2 || L > 8) + return GPG_ERR_INV_LENGTH; + + /* Reset state */ + memset (&c->u_mode, 0, sizeof(c->u_mode)); + memset (&c->marks, 0, sizeof(c->marks)); + memset (&c->u_iv, 0, sizeof(c->u_iv)); + memset (&c->u_ctr, 0, sizeof(c->u_ctr)); + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + + c->u_mode.ccm.authlen = authlen; + c->u_mode.ccm.encryptlen = encryptlen; + + /* Setup IV & CTR */ + c->u_iv.iv[0] = M_ * 8 + L_; /* Do not yet know if addlen > 0. */ + memcpy (&c->u_iv.iv[1], nonce, noncelen); + for (i = 16 - 1; i >= 1 + noncelen; i--) + { + c->u_iv.iv[i] = encryptlen & 0xff; + encryptlen >>= 8; + } + c->u_ctr.ctr[0] = L_; + memcpy (&c->u_ctr.ctr[1], nonce, noncelen); + memset (&c->u_ctr.ctr[1 + noncelen], 0, L); + + c->u_mode.ccm.aead = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *aadbuf, + unsigned int aadbuflen) +{ + unsigned int burn = 0; + unsigned char b0[16]; + + if (aadbuflen > 0 && !aadbuf) + return GPG_ERR_INV_ARG; + if (!c->u_mode.ccm.aead || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.ccm.aad) + return GPG_ERR_INV_STATE; + + memcpy (b0, c->u_iv.iv, 16); + memset (c->u_iv.iv, 0, 16); + + b0[0] |= (aadbuflen > 0) * 64; + + set_burn (burn, do_cbc_mac (c, b0, 16, 0)); + + if (aadbuflen > 0 && aadbuflen <= (unsigned int)0xfeff) + { + b0[0] = (aadbuflen >> 8) & 0xff; + b0[1] = aadbuflen & 0xff; + set_burn (burn, do_cbc_mac (c, b0, 2, 0)); + } + else if (aadbuflen > 0xfeff && aadbuflen <= (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xfe; + buf_put_be32(&b0[2], aadbuflen); + set_burn (burn, do_cbc_mac (c, b0, 6, 0)); + } +#ifdef HAVE_U64_TYPEDEF + else if (aadbuflen > (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xff; + buf_put_be64(&b0[2], aadbuflen); + set_burn (burn, do_cbc_mac (c, b0, 10, 0)); + } +#endif + + if (aadbuflen > 0) + set_burn (burn, do_cbc_mac (c, aadbuf, aadbuflen, 1)); + + + /* Generate S_0 and increase counter. */ + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0, + c->u_ctr.ctr )); + c->u_ctr.ctr[15]++; + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->u_mode.ccm.aad = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, int check) +{ + gcry_err_code_t err; + unsigned int burn; + + if (!outbuf || outbuflen == 0) + return GPG_ERR_INV_ARG; + /* Tag length must be same as initial authlen. */ + if (c->u_mode.ccm.authlen != outbuflen) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.aead) + return GPG_ERR_INV_STATE; + /* Initial encrypt length must match with length of actual data processed. */ + if (c->u_mode.ccm.encryptlen > 0) + return GPG_ERR_UNFINISHED; + + if (!c->u_mode.ccm.aad) + { + err = _gcry_cipher_ccm_authenticate (c, NULL, 0); + if (err) + return err; + } + + if (!c->u_mode.ccm.tag) + { + burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ + + /* Add S_0 */ + buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + + wipememory (c->u_ctr.ctr, 16); + wipememory (c->u_mode.ccm.s0, 16); + wipememory (c->u_mode.ccm.macbuf, 16); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + int diff, i; + + /* Constant-time compare. */ + for (i = 0, diff = 0; i < outbuflen; i++) + diff -= !!(outbuf[i] - c->u_iv.iv[i]); + + return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + gcry_err_code_t err; + unsigned int burn; + + if (outbuflen < inbuflen + c->u_mode.ccm.authlen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.aead || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (inbuflen != c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + if (!c->u_mode.ccm.aad) + { + err = _gcry_cipher_ccm_authenticate (c, NULL, 0); + if (err) + return err; + } + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, inbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + if (err) + return err; + + /* Generate and append MAC. */ + return _gcry_cipher_ccm_tag (c, &outbuf[inbuflen], c->u_mode.ccm.authlen, 0); +} + + +gcry_err_code_t +_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + gcry_err_code_t err; + unsigned int burn; + unsigned int datalen; + + if (inbuflen < c->u_mode.ccm.authlen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (outbuflen < inbuflen - c->u_mode.ccm.authlen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.aead || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + datalen = inbuflen - c->u_mode.ccm.authlen; + if (datalen != c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + if (!c->u_mode.ccm.aad) + { + err = _gcry_cipher_ccm_authenticate (c, NULL, 0); + if (err) + return err; + } + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, datalen); + if (err) + return err; + + c->u_mode.ccm.encryptlen -= datalen; + burn = do_cbc_mac (c, outbuf, datalen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + err = _gcry_cipher_ccm_tag (c, (unsigned char *)&inbuf[datalen], + c->u_mode.ccm.authlen, 1); + if (err) + { + /* MAC check failed! */ + wipememory (outbuf, outbuflen); + wipememory (c->u_iv.iv, 16); + } + return err; +} + diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index b60ef38..abd70f4 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -100,7 +100,8 @@ struct gcry_cipher_handle /* The initialization vector. For best performance we make sure that it is properly aligned. In particular some implementations - of bulk operations expect an 16 byte aligned IV. */ + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */ union { cipher_context_alignment_t iv_align; unsigned char iv[MAX_BLOCKSIZE]; @@ -117,6 +118,24 @@ struct gcry_cipher_handle unsigned char lastiv[MAX_BLOCKSIZE]; int unused; /* Number of unused bytes in LASTIV. */ + union { + /* Mode specific storage for CCM mode. */ + struct { + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int authlen; + unsigned int encryptlen; + + unsigned int aead:1;/* Set to 1 if AEAD mode has been initialized. */ + unsigned int aad:1; /* Set to 1 if AAD has been processed. */ + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ + } ccm; + } u_mode; + /* What follows are two contexts of the cipher in use. The first one needs to be aligned well enough for the cipher operation whereas the second one is a copy created by cipher_setkey and @@ -175,5 +194,25 @@ gcry_err_code_t _gcry_cipher_aeswrap_decrypt const byte *inbuf, unsigned int inbuflen); +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_aead_init +/* */ (gcry_cipher_hd_t c, + const unsigned char *nonce, unsigned int noncelen, + unsigned int authlen, size_t encryptlen); +gcry_err_code_t _gcry_cipher_ccm_authenticate +/* */ (gcry_cipher_hd_t c, + const unsigned char *aadbuf, unsigned int aadbuflen); +gcry_err_code_t _gcry_cipher_ccm_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, int check); + #endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/cipher/cipher.c b/cipher/cipher.c index 8ebab7c..42fecce 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -375,6 +375,13 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, if (! err) switch (mode) { + case GCRY_CIPHER_MODE_CCM: + if (spec->blocksize != GCRY_CCM_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: @@ -718,6 +725,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stencrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -811,6 +822,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stdecrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -885,8 +900,20 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) gcry_error_t _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) { - cipher_setiv (hd, iv, ivlen); - return 0; + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + log_fatal ("cipher_setiv: invalid mode %d\n", hd->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + + default: + cipher_setiv (hd, iv, ivlen); + break; + } + return gpg_error (rc); } /* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of @@ -915,35 +942,70 @@ gcry_error_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *aad, size_t aadsize) { - log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_authenticate (hd, aad, aadsize); + break; - (void)aad; - (void)aadsize; + default: + log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_tag (gcry_cipher_hd_t hd, void *out, size_t outsize) { - log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + gcry_err_code_t rc = GPG_ERR_NO_ERROR; - (void)out; - (void)outsize; + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_tag (hd, out, outsize, 0); + break; + + default: + log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_aead_vinit (gcry_cipher_hd_t hd, va_list arg_ptr) { - log_fatal ("gcry_cipher_aead_init: invalid mode %d\n", hd->mode ); + gcry_err_code_t rc; - (void)arg_ptr; + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + { + const void *nonce = va_arg(arg_ptr, const void *); + unsigned int nonce_len = va_arg(arg_ptr, unsigned int); + unsigned int auth_len = va_arg(arg_ptr, unsigned int); + size_t encrypt_len = va_arg(arg_ptr, size_t); + + rc = _gcry_cipher_ccm_aead_init (hd, nonce, nonce_len, auth_len, + encrypt_len); + break; + } + default: + log_fatal ("gcry_cipher_aead_init: invalid mode %d\n", hd->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 2fffd69..88e9c36 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -871,7 +871,8 @@ enum gcry_cipher_modes GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ GCRY_CIPHER_MODE_CTR = 6, /* Counter. */ - GCRY_CIPHER_MODE_AESWRAP= 7 /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_AESWRAP= 7, /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_CCM = 8 /* Counter with CBC-MAC. */ }; /* Flags used with the open function. */ @@ -883,6 +884,8 @@ enum gcry_cipher_flags GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */ }; +/* CCM works only with blocks of 128 bits. */ +#define GCRY_CCM_BLOCK_LEN (128 / 8) /* Create a handle for algorithm ALGO to be used in MODE. FLAGS may be given as an bitwise OR of the gcry_cipher_flags values. */ diff --git a/tests/basic.c b/tests/basic.c index ee04900..78f6a48 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -1139,6 +1139,537 @@ check_ofb_cipher (void) static void +check_ccm_cipher (void) +{ + static const struct tv + { + int algo; + int keylen; + const char *key; + int noncelen; + const char *nonce; + int aadlen; + const char *aad; + int plainlen; + const char *plaintext; + int cipherlen; + const char *ciphertext; + } tv[] = + { + /* RFC 3610 */ + { GCRY_CIPHER_AES, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\x58\x8C\x97\x9A\x61\xC6\x63\xD2\xF0\x66\xD0\xC2\xC0\xF9\x89\x80\x6D\x5F\x6B\x61\xDA\xC3\x84\x17\xE8\xD1\x2C\xFD\xF9\x26\xE0"}, + { GCRY_CIPHER_AES, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x72\xC9\x1A\x36\xE1\x35\xF8\xCF\x29\x1C\xA8\x94\x08\x5C\x87\xE3\xCC\x15\xC4\x39\xC9\xE4\x3A\x3B\xA0\x91\xD5\x6E\x10\x40\x09\x16"}, + { GCRY_CIPHER_AES, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x51\xB1\xE5\xF4\x4A\x19\x7D\x1D\xA4\x6B\x0F\x8E\x2D\x28\x2A\xE8\x71\xE8\x38\xBB\x64\xDA\x85\x96\x57\x4A\xDA\xA7\x6F\xBD\x9F\xB0\xC5"}, + { GCRY_CIPHER_AES, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xA2\x8C\x68\x65\x93\x9A\x9A\x79\xFA\xAA\x5C\x4C\x2A\x9D\x4A\x91\xCD\xAC\x8C\x96\xC8\x61\xB9\xC9\xE6\x1E\xF1"}, + { GCRY_CIPHER_AES, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\xDC\xF1\xFB\x7B\x5D\x9E\x23\xFB\x9D\x4E\x13\x12\x53\x65\x8A\xD8\x6E\xBD\xCA\x3E\x51\xE8\x3F\x07\x7D\x9C\x2D\x93"}, + { GCRY_CIPHER_AES, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\x6F\xC1\xB0\x11\xF0\x06\x56\x8B\x51\x71\xA4\x2D\x95\x3D\x46\x9B\x25\x70\xA4\xBD\x87\x40\x5A\x04\x43\xAC\x91\xCB\x94"}, + { GCRY_CIPHER_AES, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x01\x35\xD1\xB2\xC9\x5F\x41\xD5\xD1\xD4\xFE\xC1\x85\xD1\x66\xB8\x09\x4E\x99\x9D\xFE\xD9\x6C\x04\x8C\x56\x60\x2C\x97\xAC\xBB\x74\x90"}, + { GCRY_CIPHER_AES, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x7B\x75\x39\x9A\xC0\x83\x1D\xD2\xF0\xBB\xD7\x58\x79\xA2\xFD\x8F\x6C\xAE\x6B\x6C\xD9\xB7\xDB\x24\xC1\x7B\x44\x33\xF4\x34\x96\x3F\x34\xB4"}, + { GCRY_CIPHER_AES, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x82\x53\x1A\x60\xCC\x24\x94\x5A\x4B\x82\x79\x18\x1A\xB5\xC8\x4D\xF2\x1C\xE7\xF9\xB7\x3F\x42\xE1\x97\xEA\x9C\x07\xE5\x6B\x5E\xB1\x7E\x5F\x4E"}, + { GCRY_CIPHER_AES, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\x07\x34\x25\x94\x15\x77\x85\x15\x2B\x07\x40\x98\x33\x0A\xBB\x14\x1B\x94\x7B\x56\x6A\xA9\x40\x6B\x4D\x99\x99\x88\xDD"}, + { GCRY_CIPHER_AES, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x67\x6B\xB2\x03\x80\xB0\xE3\x01\xE8\xAB\x79\x59\x0A\x39\x6D\xA7\x8B\x83\x49\x34\xF5\x3A\xA2\xE9\x10\x7A\x8B\x6C\x02\x2C"}, + { GCRY_CIPHER_AES, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\xC0\xFF\xA0\xD6\xF0\x5B\xDB\x67\xF2\x4D\x43\xA4\x33\x8D\x2A\xA4\xBE\xD7\xB2\x0E\x43\xCD\x1A\xA3\x16\x62\xE7\xAD\x65\xD6\xDB"}, + { GCRY_CIPHER_AES, /* Packet Vector #13 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x41\x2B\x4E\xA9\xCD\xBE\x3C\x96\x96\x76\x6C\xFA", + 8, "\x0B\xE1\xA8\x8B\xAC\xE0\x18\xB1", + 23, + "\x08\xE8\xCF\x97\xD8\x20\xEA\x25\x84\x60\xE9\x6A\xD9\xCF\x52\x89\x05\x4D\x89\x5C\xEA\xC4\x7C", + 31, + "\x4C\xB9\x7F\x86\xA2\xA4\x68\x9A\x87\x79\x47\xAB\x80\x91\xEF\x53\x86\xA6\xFF\xBD\xD0\x80\xF8\xE7\x8C\xF7\xCB\x0C\xDD\xD7\xB3"}, + { GCRY_CIPHER_AES, /* Packet Vector #14 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x33\x56\x8E\xF7\xB2\x63\x3C\x96\x96\x76\x6C\xFA", + 8, "\x63\x01\x8F\x76\xDC\x8A\x1B\xCB", + 24, + "\x90\x20\xEA\x6F\x91\xBD\xD8\x5A\xFA\x00\x39\xBA\x4B\xAF\xF9\xBF\xB7\x9C\x70\x28\x94\x9C\xD0\xEC", + 32, + "\x4C\xCB\x1E\x7C\xA9\x81\xBE\xFA\xA0\x72\x6C\x55\xD3\x78\x06\x12\x98\xC8\x5C\x92\x81\x4A\xBC\x33\xC5\x2E\xE8\x1D\x7D\x77\xC0\x8A"}, + { GCRY_CIPHER_AES, /* Packet Vector #15 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x10\x3F\xE4\x13\x36\x71\x3C\x96\x96\x76\x6C\xFA", + 8, "\xAA\x6C\xFA\x36\xCA\xE8\x6B\x40", + 25, + "\xB9\x16\xE0\xEA\xCC\x1C\x00\xD7\xDC\xEC\x68\xEC\x0B\x3B\xBB\x1A\x02\xDE\x8A\x2D\x1A\xA3\x46\x13\x2E", + 33, + "\xB1\xD2\x3A\x22\x20\xDD\xC0\xAC\x90\x0D\x9A\xA0\x3C\x61\xFC\xF4\xA5\x59\xA4\x41\x77\x67\x08\x97\x08\xA7\x76\x79\x6E\xDB\x72\x35\x06"}, + { GCRY_CIPHER_AES, /* Packet Vector #16 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x76\x4C\x63\xB8\x05\x8E\x3C\x96\x96\x76\x6C\xFA", + 12, "\xD0\xD0\x73\x5C\x53\x1E\x1B\xEC\xF0\x49\xC2\x44", + 19, + "\x12\xDA\xAC\x56\x30\xEF\xA5\x39\x6F\x77\x0C\xE1\xA6\x6B\x21\xF7\xB2\x10\x1C", + 27, + "\x14\xD2\x53\xC3\x96\x7B\x70\x60\x9B\x7C\xBB\x7C\x49\x91\x60\x28\x32\x45\x26\x9A\x6F\x49\x97\x5B\xCA\xDE\xAF"}, + { GCRY_CIPHER_AES, /* Packet Vector #17 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xF8\xB6\x78\x09\x4E\x3B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x77\xB6\x0F\x01\x1C\x03\xE1\x52\x58\x99\xBC\xAE", + 20, + "\xE8\x8B\x6A\x46\xC7\x8D\x63\xE5\x2E\xB8\xC5\x46\xEF\xB5\xDE\x6F\x75\xE9\xCC\x0D", + 28, + "\x55\x45\xFF\x1A\x08\x5E\xE2\xEF\xBF\x52\xB2\xE0\x4B\xEE\x1E\x23\x36\xC7\x3E\x3F\x76\x2C\x0C\x77\x44\xFE\x7E\x3C"}, + { GCRY_CIPHER_AES, /* Packet Vector #18 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xD5\x60\x91\x2D\x3F\x70\x3C\x96\x96\x76\x6C\xFA", + 12, "\xCD\x90\x44\xD2\xB7\x1F\xDB\x81\x20\xEA\x60\xC0", + 21, + "\x64\x35\xAC\xBA\xFB\x11\xA8\x2E\x2F\x07\x1D\x7C\xA4\xA5\xEB\xD9\x3A\x80\x3B\xA8\x7F", + 29, + "\x00\x97\x69\xEC\xAB\xDF\x48\x62\x55\x94\xC5\x92\x51\xE6\x03\x57\x22\x67\x5E\x04\xC8\x47\x09\x9E\x5A\xE0\x70\x45\x51"}, + { GCRY_CIPHER_AES, /* Packet Vector #19 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x42\xFF\xF8\xF1\x95\x1C\x3C\x96\x96\x76\x6C\xFA", + 8, "\xD8\x5B\xC7\xE6\x9F\x94\x4F\xB8", + 23, + "\x8A\x19\xB9\x50\xBC\xF7\x1A\x01\x8E\x5E\x67\x01\xC9\x17\x87\x65\x98\x09\xD6\x7D\xBE\xDD\x18", + 33, + "\xBC\x21\x8D\xAA\x94\x74\x27\xB6\xDB\x38\x6A\x99\xAC\x1A\xEF\x23\xAD\xE0\xB5\x29\x39\xCB\x6A\x63\x7C\xF9\xBE\xC2\x40\x88\x97\xC6\xBA"}, + { GCRY_CIPHER_AES, /* Packet Vector #20 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x92\x0F\x40\xE5\x6C\xDC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x74\xA0\xEB\xC9\x06\x9F\x5B\x37", + 24, + "\x17\x61\x43\x3C\x37\xC5\xA3\x5F\xC1\xF3\x9F\x40\x63\x02\xEB\x90\x7C\x61\x63\xBE\x38\xC9\x84\x37", + 34, + "\x58\x10\xE6\xFD\x25\x87\x40\x22\xE8\x03\x61\xA4\x78\xE3\xE9\xCF\x48\x4A\xB0\x4F\x44\x7E\xFF\xF6\xF0\xA4\x77\xCC\x2F\xC9\xBF\x54\x89\x44"}, + { GCRY_CIPHER_AES, /* Packet Vector #21 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x27\xCA\x0C\x71\x20\xBC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x44\xA3\xAA\x3A\xAE\x64\x75\xCA", + 25, + "\xA4\x34\xA8\xE5\x85\x00\xC6\xE4\x15\x30\x53\x88\x62\xD6\x86\xEA\x9E\x81\x30\x1B\x5A\xE4\x22\x6B\xFA", + 35, + "\xF2\xBE\xED\x7B\xC5\x09\x8E\x83\xFE\xB5\xB3\x16\x08\xF8\xE2\x9C\x38\x81\x9A\x89\xC8\xE7\x76\xF1\x54\x4D\x41\x51\xA4\xED\x3A\x8B\x87\xB9\xCE"}, + { GCRY_CIPHER_AES, /* Packet Vector #22 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x5B\x8C\xCB\xCD\x9A\xF8\x3C\x96\x96\x76\x6C\xFA", + 12, "\xEC\x46\xBB\x63\xB0\x25\x20\xC3\x3C\x49\xFD\x70", + 19, + "\xB9\x6B\x49\xE2\x1D\x62\x17\x41\x63\x28\x75\xDB\x7F\x6C\x92\x43\xD2\xD7\xC2", + 29, + "\x31\xD7\x50\xA0\x9D\xA3\xED\x7F\xDD\xD4\x9A\x20\x32\xAA\xBF\x17\xEC\x8E\xBF\x7D\x22\xC8\x08\x8C\x66\x6B\xE5\xC1\x97"}, + { GCRY_CIPHER_AES, /* Packet Vector #23 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x3E\xBE\x94\x04\x4B\x9A\x3C\x96\x96\x76\x6C\xFA", + 12, "\x47\xA6\x5A\xC7\x8B\x3D\x59\x42\x27\xE8\x5E\x71", + 20, + "\xE2\xFC\xFB\xB8\x80\x44\x2C\x73\x1B\xF9\x51\x67\xC8\xFF\xD7\x89\x5E\x33\x70\x76", + 30, + "\xE8\x82\xF1\xDB\xD3\x8C\xE3\xED\xA7\xC2\x3F\x04\xDD\x65\x07\x1E\xB4\x13\x42\xAC\xDF\x7E\x00\xDC\xCE\xC7\xAE\x52\x98\x7D"}, + { GCRY_CIPHER_AES, /* Packet Vector #24 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x8D\x49\x3B\x30\xAE\x8B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x6E\x37\xA6\xEF\x54\x6D\x95\x5D\x34\xAB\x60\x59", + 21, + "\xAB\xF2\x1C\x0B\x02\xFE\xB8\x8F\x85\x6D\xF4\xA3\x73\x81\xBC\xE3\xCC\x12\x85\x17\xD4", + 31, + "\xF3\x29\x05\xB8\x8A\x64\x1B\x04\xB9\xC9\xFF\xB5\x8C\xC3\x90\x90\x0F\x3D\xA1\x2A\xB1\x6D\xCE\x9E\x82\xEF\xA1\x6D\xA6\x20\x59"}, + /* RFC 5528 */ + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\xBA\x73\x71\x85\xE7\x19\x31\x04\x92\xF3\x8A\x5F\x12\x51\xDA\x55\xFA\xFB\xC9\x49\x84\x8A\x0D\xFC\xAE\xCE\x74\x6B\x3D\xB9\xAD"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x5D\x25\x64\xBF\x8E\xAF\xE1\xD9\x95\x26\xEC\x01\x6D\x1B\xF0\x42\x4C\xFB\xD2\xCD\x62\x84\x8F\x33\x60\xB2\x29\x5D\xF2\x42\x83\xE8"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x81\xF6\x63\xD6\xC7\x78\x78\x17\xF9\x20\x36\x08\xB9\x82\xAD\x15\xDC\x2B\xBD\x87\xD7\x56\xF7\x92\x04\xF5\x51\xD6\x68\x2F\x23\xAA\x46"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xCA\xEF\x1E\x82\x72\x11\xB0\x8F\x7B\xD9\x0F\x08\xC7\x72\x88\xC0\x70\xA4\xA0\x8B\x3A\x93\x3A\x63\xE4\x97\xA0"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\x2A\xD3\xBA\xD9\x4F\xC5\x2E\x92\xBE\x43\x8E\x82\x7C\x10\x23\xB9\x6A\x8A\x77\x25\x8F\xA1\x7B\xA7\xF3\x31\xDB\x09"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\xFE\xA5\x48\x0B\xA5\x3F\xA8\xD3\xC3\x44\x22\xAA\xCE\x4D\xE6\x7F\xFA\x3B\xB7\x3B\xAB\xAB\x36\xA1\xEE\x4F\xE0\xFE\x28"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x54\x53\x20\x26\xE5\x4C\x11\x9A\x8D\x36\xD9\xEC\x6E\x1E\xD9\x74\x16\xC8\x70\x8C\x4B\x5C\x2C\xAC\xAF\xA3\xBC\xCF\x7A\x4E\xBF\x95\x73"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x8A\xD1\x9B\x00\x1A\x87\xD1\x48\xF4\xD9\x2B\xEF\x34\x52\x5C\xCC\xE3\xA6\x3C\x65\x12\xA6\xF5\x75\x73\x88\xE4\x91\x3E\xF1\x47\x01\xF4\x41"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x5D\xB0\x8D\x62\x40\x7E\x6E\x31\xD6\x0F\x9C\xA2\xC6\x04\x74\x21\x9A\xC0\xBE\x50\xC0\xD4\xA5\x77\x87\x94\xD6\xE2\x30\xCD\x25\xC9\xFE\xBF\x87"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\xDB\x11\x8C\xCE\xC1\xB8\x76\x1C\x87\x7C\xD8\x96\x3A\x67\xD6\xF3\xBB\xBC\x5C\xD0\x92\x99\xEB\x11\xF3\x12\xF2\x32\x37"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x7C\xC8\x3D\x8D\xC4\x91\x03\x52\x5B\x48\x3D\xC5\xCA\x7E\xA9\xAB\x81\x2B\x70\x56\x07\x9D\xAF\xFA\xDA\x16\xCC\xCF\x2C\x4E"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\x2C\xD3\x5B\x88\x20\xD2\x3E\x7A\xA3\x51\xB0\xE9\x2F\xC7\x93\x67\x23\x8B\x2C\xC7\x48\xCB\xB9\x4C\x29\x47\x79\x3D\x64\xAF\x75"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #13 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xA9\x70\x11\x0E\x19\x27\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x6B\x7F\x46\x45\x07\xFA\xE4\x96", + 23, + "\xC6\xB5\xF3\xE6\xCA\x23\x11\xAE\xF7\x47\x2B\x20\x3E\x73\x5E\xA5\x61\xAD\xB1\x7D\x56\xC5\xA3", + 31, + "\xA4\x35\xD7\x27\x34\x8D\xDD\x22\x90\x7F\x7E\xB8\xF5\xFD\xBB\x4D\x93\x9D\xA6\x52\x4D\xB4\xF6\x45\x58\xC0\x2D\x25\xB1\x27\xEE"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #14 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x83\xCD\x8C\xE0\xCB\x42\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x98\x66\x05\xB4\x3D\xF1\x5D\xE7", + 24, + "\x01\xF6\xCE\x67\x64\xC5\x74\x48\x3B\xB0\x2E\x6B\xBF\x1E\x0A\xBD\x26\xA2\x25\x72\xB4\xD8\x0E\xE7", + 32, + "\x8A\xE0\x52\x50\x8F\xBE\xCA\x93\x2E\x34\x6F\x05\xE0\xDC\x0D\xFB\xCF\x93\x9E\xAF\xFA\x3E\x58\x7C\x86\x7D\x6E\x1C\x48\x70\x38\x06"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #15 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x5F\x54\x95\x0B\x18\xF2\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x48\xF2\xE7\xE1\xA7\x67\x1A\x51", + 25, + "\xCD\xF1\xD8\x40\x6F\xC2\xE9\x01\x49\x53\x89\x70\x05\xFB\xFB\x8B\xA5\x72\x76\xF9\x24\x04\x60\x8E\x08", + 33, + "\x08\xB6\x7E\xE2\x1C\x8B\xF2\x6E\x47\x3E\x40\x85\x99\xE9\xC0\x83\x6D\x6A\xF0\xBB\x18\xDF\x55\x46\x6C\xA8\x08\x78\xA7\x90\x47\x6D\xE5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #16 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xEC\x60\x08\x63\x31\x9A\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xDE\x97\xDF\x3B\x8C\xBD\x6D\x8E\x50\x30\xDA\x4C", + 19, + "\xB0\x05\xDC\xFA\x0B\x59\x18\x14\x26\xA9\x61\x68\x5A\x99\x3D\x8C\x43\x18\x5B", + 27, + "\x63\xB7\x8B\x49\x67\xB1\x9E\xDB\xB7\x33\xCD\x11\x14\xF6\x4E\xB2\x26\x08\x93\x68\xC3\x54\x82\x8D\x95\x0C\xC5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #17 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x60\xCF\xF1\xA3\x1E\xA1\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA5\xEE\x93\xE4\x57\xDF\x05\x46\x6E\x78\x2D\xCF", + 20, + "\x2E\x20\x21\x12\x98\x10\x5F\x12\x9D\x5E\xD9\x5B\x93\xF7\x2D\x30\xB2\xFA\xCC\xD7", + 28, + "\x0B\xC6\xBB\xE2\xA8\xB9\x09\xF4\x62\x9E\xE6\xDC\x14\x8D\xA4\x44\x10\xE1\x8A\xF4\x31\x47\x38\x32\x76\xF6\x6A\x9F"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #18 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x0F\x85\xCD\x99\x5C\x97\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x24\xAA\x1B\xF9\xA5\xCD\x87\x61\x82\xA2\x50\x74", + 21, + "\x26\x45\x94\x1E\x75\x63\x2D\x34\x91\xAF\x0F\xC0\xC9\x87\x6C\x3B\xE4\xAA\x74\x68\xC9", + 29, + "\x22\x2A\xD6\x32\xFA\x31\xD6\xAF\x97\x0C\x34\x5F\x7E\x77\xCA\x3B\xD0\xDC\x25\xB3\x40\xA1\xA3\xD3\x1F\x8D\x4B\x44\xB7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #19 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC2\x9B\x2C\xAA\xC4\xCD\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x69\x19\x46\xB9\xCA\x07\xBE\x87", + 23, + "\x07\x01\x35\xA6\x43\x7C\x9D\xB1\x20\xCD\x61\xD8\xF6\xC3\x9C\x3E\xA1\x25\xFD\x95\xA0\xD2\x3D", + 33, + "\x05\xB8\xE1\xB9\xC4\x9C\xFD\x56\xCF\x13\x0A\xA6\x25\x1D\xC2\xEC\xC0\x6C\xCC\x50\x8F\xE6\x97\xA0\x06\x6D\x57\xC8\x4B\xEC\x18\x27\x68"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #20 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x2C\x6B\x75\x95\xEE\x62\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xD0\xC5\x4E\xCB\x84\x62\x7D\xC4", + 24, + "\xC8\xC0\x88\x0E\x6C\x63\x6E\x20\x09\x3D\xD6\x59\x42\x17\xD2\xE1\x88\x77\xDB\x26\x4E\x71\xA5\xCC", + 34, + "\x54\xCE\xB9\x68\xDE\xE2\x36\x11\x57\x5E\xC0\x03\xDF\xAA\x1C\xD4\x88\x49\xBD\xF5\xAE\x2E\xDB\x6B\x7F\xA7\x75\xB1\x50\xED\x43\x83\xC5\xA9"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #21 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC5\x3C\xD4\xC2\xAA\x24\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xE2\x85\xE0\xE4\x80\x8C\xDA\x3D", + 25, + "\xF7\x5D\xAA\x07\x10\xC4\xE6\x42\x97\x79\x4D\xC2\xB7\xD2\xA2\x07\x57\xB1\xAA\x4E\x44\x80\x02\xFF\xAB", + 35, + "\xB1\x40\x45\x46\xBF\x66\x72\x10\xCA\x28\xE3\x09\xB3\x9B\xD6\xCA\x7E\x9F\xC8\x28\x5F\xE6\x98\xD4\x3C\xD2\x0A\x02\xE0\xBD\xCA\xED\x20\x10\xD3"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #22 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xBE\xE9\x26\x7F\xBA\xDC\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x6C\xAE\xF9\x94\x11\x41\x57\x0D\x7C\x81\x34\x05", + 19, + "\xC2\x38\x82\x2F\xAC\x5F\x98\xFF\x92\x94\x05\xB0\xAD\x12\x7A\x4E\x41\x85\x4E", + 29, + "\x94\xC8\x95\x9C\x11\x56\x9A\x29\x78\x31\xA7\x21\x00\x58\x57\xAB\x61\xB8\x7A\x2D\xEA\x09\x36\xB6\xEB\x5F\x62\x5F\x5D"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #23 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xDF\xA8\xB1\x24\x50\x07\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x36\xA5\x2C\xF1\x6B\x19\xA2\x03\x7A\xB7\x01\x1E", + 20, + "\x4D\xBF\x3E\x77\x4A\xD2\x45\xE5\xD5\x89\x1F\x9D\x1C\x32\xA0\xAE\x02\x2C\x85\xD7", + 30, + "\x58\x69\xE3\xAA\xD2\x44\x7C\x74\xE0\xFC\x05\xF9\xA4\xEA\x74\x57\x7F\x4D\xE8\xCA\x89\x24\x76\x42\x96\xAD\x04\x11\x9C\xE7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #24 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x3B\x8F\xD8\xD3\xA9\x37\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA4\xD4\x99\xF7\x84\x19\x72\x8C\x19\x17\x8B\x0C", + 21, + "\x9D\xC9\xED\xAE\x2F\xF5\xDF\x86\x36\xE8\xC6\xDE\x0E\xED\x55\xF7\x86\x7E\x33\x33\x7D", + 31, + "\x4B\x19\x81\x56\x39\x3B\x0F\x77\x96\x08\x6A\xAF\xB4\x54\xF8\xC3\xF0\x34\xCC\xA9\x66\x94\x5F\x1F\xCE\xA7\xE1\x1B\xEE\x6A\x2F"} + }; + gcry_cipher_hd_t hde, hdd; + unsigned char out[MAX_DATA_LEN]; + int i, keylen, blklen, authlen; + gcry_error_t err = 0; + + if (verbose) + fprintf (stderr, " Starting CCM checks.\n"); + + for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) + { + if (verbose) + fprintf (stderr, " checking CCM mode for %s [%i]\n", + gcry_cipher_algo_name (tv[i].algo), + tv[i].algo); + err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + keylen = gcry_cipher_get_algo_keylen(tv[i].algo); + if (!keylen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_keylen failed\n"); + return; + } + + err = gcry_cipher_setkey (hde, tv[i].key, keylen); + if (!err) + err = gcry_cipher_setkey (hdd, tv[i].key, keylen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + blklen = gcry_cipher_get_algo_blklen(tv[i].algo); + if (!blklen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_blklen failed\n"); + return; + } + + authlen = tv[i].cipherlen - tv[i].plainlen; + err = gcry_cipher_aead_init (hde, tv[i].nonce, tv[i].noncelen, + authlen, tv[i].plainlen); + if (!err) + err = gcry_cipher_aead_init (hdd, tv[i].nonce, tv[i].noncelen, + authlen, tv[i].plainlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_aead_init failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_authenticate (hde, tv[i].aad, tv[i].aadlen); + if (!err) + err = gcry_cipher_authenticate (hdd, tv[i].aad, tv[i].aadlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, tv[i].plaintext, + tv[i].plainlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_encrypt (%d) failed: %s\n", + i, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].ciphertext, out, tv[i].cipherlen)) + fail ("cipher-ccm, encrypt mismatch entry %d\n", i); + + err = gcry_cipher_decrypt (hdd, out, tv[i].cipherlen, NULL, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_decrypt (%d) failed: %s\n", + i, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].plaintext, out, tv[i].plainlen)) + fail ("cipher-ccm, decrypt mismatch entry %d:%d\n", i); + + memset (out, 0, sizeof(out)); + err = gcry_cipher_tag (hdd, out, authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_tag (%d) failed: %s\n", + i, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (&tv[i].ciphertext[tv[i].plainlen], out, authlen)) + fail ("cipher-ccm, decrypt auth-tag mismatch entry %d\n", i); + + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + } + if (verbose) + fprintf (stderr, " Completed CCM checks.\n"); +} + + +static void check_stream_cipher (void) { struct tv @@ -2455,6 +2986,7 @@ check_cipher_modes(void) check_ctr_cipher (); check_cfb_cipher (); check_ofb_cipher (); + check_ccm_cipher (); check_stream_cipher (); check_stream_cipher_large_block (); diff --git a/tests/benchmark.c b/tests/benchmark.c index 5d1434a..21ae176 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -435,6 +435,36 @@ md_bench ( const char *algoname ) fflush (stdout); } + +static void ccm_aead_init(gcry_cipher_hd_t hd, size_t buflen, int authlen) +{ + const int _L = 4; + const int noncelen = 15 - _L; + char nonce[noncelen]; + gcry_error_t err = GPG_ERR_NO_ERROR; + + memset (nonce, 0x33, noncelen); + + err = gcry_cipher_aead_init (hd, nonce, noncelen, authlen, buflen - authlen); + if (err) + { + fprintf (stderr, "gcry_cipher_aead_init failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } + + err = gcry_cipher_authenticate (hd, NULL, 0); + if (err) + { + fprintf (stderr, "gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } +} + + static void cipher_bench ( const char *algoname ) { @@ -446,14 +476,23 @@ cipher_bench ( const char *algoname ) char key[128]; char *outbuf, *buf; char *raw_outbuf, *raw_buf; - size_t allocated_buflen, buflen; + size_t allocated_buflen, buflen, plainlen; int repetitions; - static struct { int mode; const char *name; int blocked; } modes[] = { + static const struct { + int mode; + const char *name; + int blocked; + void (* const aead_init)(gcry_cipher_hd_t hd, size_t buflen, int authlen); + int req_blocksize; + int authlen; + } modes[] = { { GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1 }, { GCRY_CIPHER_MODE_CBC, " CBC", 1 }, { GCRY_CIPHER_MODE_CFB, " CFB", 0 }, { GCRY_CIPHER_MODE_OFB, " OFB", 0 }, { GCRY_CIPHER_MODE_CTR, " CTR", 0 }, + { GCRY_CIPHER_MODE_CCM, " CCM", 0, + ccm_aead_init, GCRY_CCM_BLOCK_LEN, 8 }, { GCRY_CIPHER_MODE_STREAM, "", 0 }, {0} }; @@ -542,9 +581,16 @@ cipher_bench ( const char *algoname ) for (modeidx=0; modes[modeidx].mode; modeidx++) { if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM) - | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) + || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) continue; + if (modes[modeidx].req_blocksize > 0 + && blklen != modes[modeidx].req_blocksize) + { + printf (" %7s %7s", "-", "-" ); + continue; + } + for (i=0; i < sizeof buf; i++) buf[i] = i; @@ -570,6 +616,7 @@ cipher_bench ( const char *algoname ) buflen = allocated_buflen; if (modes[modeidx].blocked) buflen = (buflen / blklen) * blklen; + plainlen = buflen - modes[modeidx].authlen; start_timer (); for (i=err=0; !err && i < repetitions; i++) @@ -585,7 +632,9 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, plainlen); } stop_timer (); @@ -632,7 +681,15 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_decrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_decrypt (hd, outbuf, plainlen, buf, buflen); + if (gpg_err_code (err) == GPG_ERR_CHECKSUM) + err = gpg_error (GPG_ERR_NO_ERROR); + } + else + err = gcry_cipher_decrypt (hd, outbuf, plainlen, buf, buflen); } stop_timer (); printf (" %s", elapsed_time ()); From wk at gnupg.org Sun Oct 13 12:45:07 2013 From: wk at gnupg.org (Werner Koch) Date: Sun, 13 Oct 2013 12:45:07 +0200 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <20131013100233.32014.24561.stgit@localhost6.localdomain6> (Jussi Kivilinna's message of "Sun, 13 Oct 2013 13:02:33 +0300") References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> Message-ID: <87iox1phzg.fsf@vigenere.g10code.de> On Sun, 13 Oct 2013 12:02, jussi.kivilinna at iki.fi said: > CCM mode needs to know length of encrypted data in advance. So, would it make > sense to add variadic API function for initilizing AEAD mode? The one that Let's talks about this api first. I need to look closer at it. Did you notice the new gcry_buffer_t ? Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Sun Oct 13 13:57:53 2013 From: wk at gnupg.org (Werner Koch) Date: Sun, 13 Oct 2013 13:57:53 +0200 Subject: [PATCH 3/3] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: (Dmitry Eremin-Solenikov's message of "Thu, 3 Oct 2013 23:56:22 +0400") References: <1380197263-750-1-git-send-email-dbaryshkov@gmail.com> <1380197263-750-3-git-send-email-dbaryshkov@gmail.com> <1380773653.32263.2.camel@cfw2.gniibe.org> <1380805874.3589.0.camel@latx1.gniibe.org> Message-ID: <87bo2tpem6.fsf@vigenere.g10code.de> On Thu, 3 Oct 2013 21:56, dbaryshkov at gmail.com said: > Werner, would you take first two patches in this serie? Can you please rework them to fit into the new module-does-parsing framework? Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From jussi.kivilinna at iki.fi Mon Oct 14 13:20:10 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 14 Oct 2013 14:20:10 +0300 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <87iox1phzg.fsf@vigenere.g10code.de> References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> Message-ID: <525BD36A.9010507@iki.fi> On 13.10.2013 13:45, Werner Koch wrote: > On Sun, 13 Oct 2013 12:02, jussi.kivilinna at iki.fi said: > >> CCM mode needs to know length of encrypted data in advance. So, would it make >> sense to add variadic API function for initilizing AEAD mode? The one that > > Let's talks about this api first. I need to look closer at it. Sure. I based CCM patchset on the AEAD API patch Dmitry sent earlier for GCM. Since CCM has more restrictions (need to know data lengths in advance) than GCM, I added gcry_cipher_aead_init. With this patchset to encrypt a buffer using CCM, you'd first need to initialize/reset CCM state with: gcry_cipher_aead_init (hd, nonce_buf, nonce_len, authtag_len, plaintext_len) CCM needs tag and plaintext lengths for MAC initialization. CCM also needs length of AAD (additional authenticated data) for MAC, so this call is followed by: gcry_cipher_authenticate (hd, aadbuf, aadbuflen) which does the actual MAC initialization. If aadbuflen == 0, then above call can be omitted and gcry_cipher_(en|de)crypt will call gcry_cipher_authenticate with zero length. Plaintext can then be encrypted with: gcry_cipher_encrypt (hd, ciphertext_buf, ciphertext_len, plaintext_buf, plaintext_len) where ciphertext_len >= plaintext_len + authtag_len. Ciphertext can be decrypted with: gcry_cipher_decrypt (hd, plaintext_buf, plaintext_len, ciphertext_buf, ciphertext_len) NIST paper and RFC 3610 define CCM ciphertext as [ctr-enc(plaintext) || authtag] and that decryption must not reveal any information (plaintext or authtag) if authtag is not correct. Therefore full buffers, matching with length of plaintext_len and authtag_len given in gcry_cipher_aead_init, have to be used. If authentication check fails, decrypt function clears output buffer and internal authtag buffer. > Did you notice the new gcry_buffer_t ? Yes, I did. Would it be better to add functions to do AEAD encrypt/decrypt in single go and use gcry_buffer_t? This would avoid having internal state machines in AEAD modes and having to call different functions in correct order. gcry_cipher_aead_encrypt (hd, gcry_buffer_t ct_buf, ct_len, gcry_buffer_t pt_buf, pt_len, gcry_buffer_t aad_buf, aad_len, nonce, nonce_len) For CCM, authentication tag length could be calculated from ct_len - pt_len. -Jussi > > > Salam-Shalom, > > Werner > From cvs at cvs.gnupg.org Tue Oct 15 09:10:34 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 15 Oct 2013 09:10:34 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-308-g537969f Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 537969fbbb1104b8305a7edb331b7666d54eff2c (commit) via d3a605d7827b8a73ef844e9e5183590bd6b1389a (commit) via 5be2345ddec4147e535d5b039ee74f84bcacf9e4 (commit) via 0cd551faa775ad5309a40629ae30bf86b75fca09 (commit) from a951c061523e1c13f1358c9760fc3a9d787ab2d4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 537969fbbb1104b8305a7edb331b7666d54eff2c Author: Werner Koch Date: Tue Oct 15 09:08:31 2013 +0200 ecc: Support use of Ed25519 with ECDSA. * src/cipher.h (PUBKEY_FLAG_ECDSA): New. * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Add flag "ecdsa". * cipher/ecc.c (verify_ecdsa, verify_eddsa): Remove some debug output. (ecc_generate, ecc_sign, ecc_verify): Support Ed25519 with ECDSA. * tests/keygen.c (check_ecc_keys): Create such a test key. * tests/pubkey.c (fail, info, data_from_hex, extract_cmp_data): New. Take from dsa-6979.c (check_ed25519ecdsa_sample_key): new. (main): Call new test. Signed-off-by: Werner Koch diff --git a/cipher/ecc.c b/cipher/ecc.c index da384e8..3b75fea 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -558,13 +558,10 @@ verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey, log_mpidump (" x", x); log_mpidump (" r", r); log_mpidump (" s", s); - log_debug ("ecc verify: Not verified\n"); } err = GPG_ERR_BAD_SIGNATURE; goto leave; } - if (DBG_CIPHER) - log_debug ("ecc verify: Accepted\n"); leave: _gcry_mpi_ec_free (ctx); @@ -1208,14 +1205,10 @@ verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey, goto leave; if (tlen != rlen || memcmp (tbuf, rbuf, tlen)) { - if (DBG_CIPHER) - log_debug ("eddsa verify: Not verified\n"); rc = GPG_ERR_BAD_SIGNATURE; goto leave; } - if (DBG_CIPHER) - log_debug ("eddsa verify: Accepted\n"); rc = 0; leave: @@ -1250,10 +1243,12 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) gcry_random_level_t random_level; mpi_ec_t ctx = NULL; gcry_sexp_t curve_info = NULL; + gcry_sexp_t curve_flags = NULL; gcry_mpi_t base = NULL; gcry_mpi_t public = NULL; gcry_mpi_t secret = NULL; int flags = 0; + int ed25519_with_ecdsa = 0; memset (&E, 0, sizeof E); memset (&sk, 0, sizeof sk); @@ -1328,7 +1323,13 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) rc = nist_generate_key (&sk, &E, ctx, random_level, nbits); break; case ECC_DIALECT_ED25519: - rc = eddsa_generate_key (&sk, &E, ctx, random_level); + if ((flags & PUBKEY_FLAG_ECDSA)) + { + ed25519_with_ecdsa = 1; + rc = nist_generate_key (&sk, &E, ctx, random_level, nbits); + } + else + rc = eddsa_generate_key (&sk, &E, ctx, random_level); break; default: rc = GPG_ERR_INTERNAL; @@ -1341,7 +1342,7 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) if (_gcry_mpi_ec_get_affine (x, y, &sk.E.G, ctx)) log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G"); base = _gcry_ecc_ec2os (x, y, sk.E.p); - if (sk.E.dialect == ECC_DIALECT_ED25519) + if (sk.E.dialect == ECC_DIALECT_ED25519 && !ed25519_with_ecdsa) { unsigned char *encpk; unsigned int encpklen; @@ -1367,16 +1368,23 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) goto leave; } + if (ed25519_with_ecdsa) + { + rc = gcry_sexp_build (&curve_info, NULL, "(flags ecdsa)"); + if (rc) + goto leave; + } + rc = gcry_sexp_build (r_skey, NULL, "(key-data" " (public-key" - " (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))" " (private-key" - " (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))" " )", - curve_info, + curve_info, curve_flags, sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, - curve_info, + curve_info, curve_flags, sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, secret); if (rc) goto leave; @@ -1390,6 +1398,8 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) log_printmpi ("ecgen result n", sk.E.n); log_printmpi ("ecgen result Q", public); log_printmpi ("ecgen result d", secret); + if (ed25519_with_ecdsa) + log_debug ("ecgen result using Ed25519/ECDSA\n"); } leave: @@ -1580,9 +1590,11 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) } if (DBG_CIPHER) { - log_debug ("ecc_sign info: %s/%s\n", + log_debug ("ecc_sign info: %s/%s%s\n", _gcry_ecc_model2str (sk.E.model), - _gcry_ecc_dialect2str (sk.E.dialect)); + _gcry_ecc_dialect2str (sk.E.dialect), + (sk.E.dialect == ECC_DIALECT_ED25519 + && (ctx.flags & PUBKEY_FLAG_ECDSA))? "ECDSA":""); if (sk.E.name) log_debug ("ecc_sign name: %s\n", sk.E.name); log_printmpi ("ecc_sign p", sk.E.p); @@ -1733,9 +1745,11 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) if (DBG_CIPHER) { - log_debug ("ecc_verify info: %s/%s\n", + log_debug ("ecc_verify info: %s/%s%s\n", _gcry_ecc_model2str (pk.E.model), - _gcry_ecc_dialect2str (pk.E.dialect)); + _gcry_ecc_dialect2str (pk.E.dialect), + (pk.E.dialect == ECC_DIALECT_ED25519 + && !(sigflags & PUBKEY_FLAG_EDDSA))? "/ECDSA":""); if (pk.E.name) log_debug ("ecc_verify name: %s\n", pk.E.name); log_printmpi ("ecc_verify p", pk.E.p); diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index 3dfc027..caf715e 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -75,6 +75,10 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list, encoding = PUBKEY_ENC_RAW; flags |= PUBKEY_FLAG_EDDSA; } + else if (n == 5 && !memcmp (s, "ecdsa", 5)) + { + flags |= PUBKEY_FLAG_ECDSA; + } else if (n == 3 && !memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN) { diff --git a/src/cipher.h b/src/cipher.h index b3469e5..077af98 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -28,14 +28,15 @@ #define PUBKEY_FLAG_NO_BLINDING (1 << 0) #define PUBKEY_FLAG_RFC6979 (1 << 1) -#define PUBKEY_FLAG_EDDSA (1 << 2) -#define PUBKEY_FLAG_FIXEDLEN (1 << 3) -#define PUBKEY_FLAG_LEGACYRESULT (1 << 4) -#define PUBKEY_FLAG_RAW_FLAG (1 << 5) -#define PUBKEY_FLAG_TRANSIENT_KEY (1 << 6) -#define PUBKEY_FLAG_USE_X931 (1 << 7) -#define PUBKEY_FLAG_USE_FIPS186 (1 << 8) -#define PUBKEY_FLAG_USE_FIPS186_2 (1 << 9) +#define PUBKEY_FLAG_FIXEDLEN (1 << 2) +#define PUBKEY_FLAG_LEGACYRESULT (1 << 3) +#define PUBKEY_FLAG_RAW_FLAG (1 << 4) +#define PUBKEY_FLAG_TRANSIENT_KEY (1 << 5) +#define PUBKEY_FLAG_USE_X931 (1 << 6) +#define PUBKEY_FLAG_USE_FIPS186 (1 << 7) +#define PUBKEY_FLAG_USE_FIPS186_2 (1 << 8) +#define PUBKEY_FLAG_ECDSA (1 << 9) +#define PUBKEY_FLAG_EDDSA (1 << 10) enum pk_operation diff --git a/tests/keygen.c b/tests/keygen.c index b955116..2b98c42 100644 --- a/tests/keygen.c +++ b/tests/keygen.c @@ -394,6 +394,23 @@ check_ecc_keys (void) gcry_sexp_release (key); } + + if (verbose) + show ("creating ECC key using curve Ed25519 for ECDSA\n"); + rc = gcry_sexp_build (&keyparm, NULL, + "(genkey(ecc(curve Ed25519)(flags ecdsa)))"); + if (rc) + die ("error creating S-expression: %s\n", gpg_strerror (rc)); + rc = gcry_pk_genkey (&key, keyparm); + gcry_sexp_release (keyparm); + if (rc) + die ("error generating ECC key using curve Ed25519 for ECDSA: %s\n", + gpg_strerror (rc)); + + if (verbose > 1) + show_sexp ("ECC key:\n", key); + + gcry_sexp_release (key); } diff --git a/tests/pubkey.c b/tests/pubkey.c index baf234c..4dadf88 100644 --- a/tests/pubkey.c +++ b/tests/pubkey.c @@ -28,6 +28,18 @@ #include "../src/gcrypt-int.h" +#define my_isascii(c) (!((c) & 0x80)) +#define digitp(p) (*(p) >= '0' && *(p) <= '9') +#define hexdigitp(a) (digitp (a) \ + || (*(a) >= 'A' && *(a) <= 'F') \ + || (*(a) >= 'a' && *(a) <= 'f')) +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + /* Sample RSA keys, taken from basic.c. */ static const char sample_private_key_1[] = @@ -101,6 +113,7 @@ static const char sample_public_key_1[] = static int verbose; +static int error_count; static void die (const char *format, ...) @@ -116,6 +129,27 @@ die (const char *format, ...) } static void +fail (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + error_count++; +} + +static void +info (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); +} + +static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; @@ -132,6 +166,59 @@ show_sexp (const char *prefix, gcry_sexp_t a) } +/* Convert STRING consisting of hex characters into its binary + representation and return it as an allocated buffer. The valid + length of the buffer is returned at R_LENGTH. The string is + delimited by end of string. The function returns NULL on + error. */ +static void * +data_from_hex (const char *string, size_t *r_length) +{ + const char *s; + unsigned char *buffer; + size_t length; + + buffer = gcry_xmalloc (strlen(string)/2+1); + length = 0; + for (s=string; *s; s +=2 ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + die ("error parsing hex string `%s'\n", string); + ((unsigned char*)buffer)[length++] = xtoi_2 (s); + } + *r_length = length; + return buffer; +} + + +static void +extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected) +{ + gcry_sexp_t l1; + const void *a; + size_t alen; + void *b; + size_t blen; + + l1 = gcry_sexp_find_token (sexp, name, 0); + a = gcry_sexp_nth_data (l1, 1, &alen); + b = data_from_hex (expected, &blen); + if (!a) + fail ("parameter \"%s\" missing in key\n", name); + else if ( alen != blen || memcmp (a, b, alen) ) + { + fail ("parameter \"%s\" does not match expected value\n", name); + if (verbose) + { + info ("expected: %s\n", expected); + show_sexp ("sexp: ", sexp); + } + } + gcry_free (b); + gcry_sexp_release (l1); +} + + static void check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey, gcry_sexp_t plain0, gpg_err_code_t decrypt_fail_code) @@ -939,6 +1026,85 @@ check_ecc_sample_key (void) } +static void +check_ed25519ecdsa_sample_key (void) +{ + static const char ecc_private_key[] = + "(private-key\n" + " (ecc\n" + " (curve \"Ed25519\")\n" + " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" + " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" + " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" + "))"; + static const char ecc_private_key_wo_q[] = + "(private-key\n" + " (ecc\n" + " (curve \"Ed25519\")\n" + " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" + "))"; + static const char ecc_public_key[] = + "(public-key\n" + " (ecc\n" + " (curve \"Ed25519\")\n" + " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" + " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" + "))"; + static const char hash_string[] = + "(data (flags ecdsa rfc6979)\n" + " (hash sha256 #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F#))"; + + gpg_error_t err; + gcry_sexp_t key, hash, sig; + + if (verbose) + fprintf (stderr, "Checking sample Ed25519/ECDSA key.\n"); + + if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_sign (&sig, hash, key))) + die ("gcry_pk_sign failed: %s", gpg_strerror (err)); + + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_verify (sig, hash, key))) + die ("gcry_pk_verify failed: %s", gpg_strerror (err)); + + /* Now try signing without the Q parameter. */ + + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + gcry_sexp_release (sig); + if ((err = gcry_pk_sign (&sig, hash, key))) + die ("gcry_pk_sign without Q failed: %s", gpg_strerror (err)); + + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_verify (sig, hash, key))) + die ("gcry_pk_verify signed without Q failed: %s", gpg_strerror (err)); + + extract_cmp_data (sig, "r", ("a63123a783ef29b8276e08987daca4" + "655d0179e22199bf63691fd88eb64e15")); + extract_cmp_data (sig, "s", ("0d9b45c696ab90b96b08812b485df185" + "623ddaf5d02fa65ca5056cb6bd0f16f1")); + + gcry_sexp_release (sig); + gcry_sexp_release (key); + gcry_sexp_release (hash); +} + + int main (int argc, char **argv) { @@ -969,6 +1135,7 @@ main (int argc, char **argv) check_x931_derived_key (i); check_ecc_sample_key (); + check_ed25519ecdsa_sample_key (); - return 0; + return !!error_count; } commit d3a605d7827b8a73ef844e9e5183590bd6b1389a Author: Werner Koch Date: Mon Oct 14 19:48:10 2013 +0200 pubkey: Support flags list in gcry_pk_genkey. * src/cipher.h (PUBKEY_FLAG_TRANSIENT_KEY): New. (PUBKEY_FLAG_USE_X931): New. (PUBKEY_FLAG_USE_FIPS186): New. (PUBKEY_FLAG_USE_FIPS186_2): New. * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Rename from parse_flags_list. Parse new flags. * cipher/dsa.c (dsa_generate): Support flag list. * cipher/ecc.c (ecc_generate): Ditto. * cipher/rsa.c (rsa_generate): Ditto. Signed-off-by: Werner Koch diff --git a/cipher/dsa.c b/cipher/dsa.c index f86ff15..e43bdf4 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -710,9 +710,7 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) gcry_sexp_t deriveparms = NULL; gcry_sexp_t seedinfo = NULL; gcry_sexp_t misc_info = NULL; - int transient_key = 0; - int use_fips186_2 = 0; - int use_fips186 = 0; + int flags = 0; dsa_domain_t domain; gcry_mpi_t *factors = NULL; @@ -723,6 +721,16 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) if (rc) return rc; + /* Parse the optional flags list. */ + l1 = gcry_sexp_find_token (genparms, "flags", 0); + if (l1) + { + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + gcry_sexp_release (l1); + if (rc) + return rc;\ + } + /* Parse the optional qbits element. */ l1 = gcry_sexp_find_token (genparms, "qbits", 0); if (l1) @@ -744,28 +752,37 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) } /* Parse the optional transient-key flag. */ - l1 = gcry_sexp_find_token (genparms, "transient-key", 0); - if (l1) + if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) { - transient_key = 1; - gcry_sexp_release (l1); + l1 = gcry_sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + gcry_sexp_release (l1); + } } /* Get the optional derive parameters. */ deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0); /* Parse the optional "use-fips186" flags. */ - l1 = gcry_sexp_find_token (genparms, "use-fips186", 0); - if (l1) + if (!(flags & PUBKEY_FLAG_USE_FIPS186)) { - use_fips186 = 1; - gcry_sexp_release (l1); + l1 = gcry_sexp_find_token (genparms, "use-fips186", 0); + if (l1) + { + flags |= PUBKEY_FLAG_USE_FIPS186; + gcry_sexp_release (l1); + } } - l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0); - if (l1) + if (!(flags & PUBKEY_FLAG_USE_FIPS186_2)) { - use_fips186_2 = 1; - gcry_sexp_release (l1); + l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0); + if (l1) + { + flags |= PUBKEY_FLAG_USE_FIPS186_2; + gcry_sexp_release (l1); + } } /* Check whether domain parameters are given. */ @@ -809,14 +826,18 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) qbits = mpi_get_nbits (domain.q); } - if (deriveparms || use_fips186 || use_fips186_2 || fips_mode ()) + if (deriveparms + || (flags & PUBKEY_FLAG_USE_FIPS186) + || (flags & PUBKEY_FLAG_USE_FIPS186_2) + || fips_mode ()) { int counter; void *seed; size_t seedlen; gcry_mpi_t h_value; - rc = generate_fips186 (&sk, nbits, qbits, deriveparms, use_fips186_2, + rc = generate_fips186 (&sk, nbits, qbits, deriveparms, + !!(flags & PUBKEY_FLAG_USE_FIPS186_2), &domain, &counter, &seed, &seedlen, &h_value); if (!rc && h_value) @@ -832,7 +853,9 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) } else { - rc = generate (&sk, nbits, qbits, transient_key, &domain, &factors); + rc = generate (&sk, nbits, qbits, + !!(flags & PUBKEY_FLAG_TRANSIENT_KEY), + &domain, &factors); } if (!rc) diff --git a/cipher/ecc.c b/cipher/ecc.c index bd4d253..da384e8 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1247,13 +1247,13 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) gcry_mpi_t y = NULL; char *curve_name = NULL; gcry_sexp_t l1; - int transient_key = 0; gcry_random_level_t random_level; mpi_ec_t ctx = NULL; gcry_sexp_t curve_info = NULL; gcry_mpi_t base = NULL; gcry_mpi_t public = NULL; gcry_mpi_t secret = NULL; + int flags = 0; memset (&E, 0, sizeof E); memset (&sk, 0, sizeof sk); @@ -1276,10 +1276,20 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) l1 = gcry_sexp_find_token (genparms, "transient-key", 0); if (l1) { - transient_key = 1; + flags |= PUBKEY_FLAG_TRANSIENT_KEY; gcry_sexp_release (l1); } + /* Parse the optional flags list. */ + l1 = gcry_sexp_find_token (genparms, "flags", 0); + if (l1) + { + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + gcry_sexp_release (l1); + if (rc) + goto leave; + } + /* NBITS is required if no curve name has been given. */ if (!nbits && !curve_name) return GPG_ERR_NO_OBJ; /* No NBITS parameter. */ @@ -1303,7 +1313,11 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) log_printpnt ("ecgen curve G", &E.G, NULL); } - random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; + if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) + random_level = GCRY_STRONG_RANDOM; + else + random_level = GCRY_VERY_STRONG_RANDOM; + ctx = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, E.p, E.a, E.b); x = mpi_new (0); y = mpi_new (0); diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h index 7e3667e..cb2721d 100644 --- a/cipher/pubkey-internal.h +++ b/cipher/pubkey-internal.h @@ -21,6 +21,9 @@ #define GCRY_PUBKEY_INTERNAL_H /*-- pubkey-util.c --*/ +gpg_err_code_t _gcry_pk_util_parse_flaglist (gcry_sexp_t list, + int *r_flags, + enum pk_encoding *r_encoding); gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits); gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index 52d69cf..3dfc027 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -50,9 +50,9 @@ pss_verify_cmp (void *opaque, gcry_mpi_t tmp) R_ENCODING and the flags are stored at R_FLAGS. if any of them is not needed, NULL may be passed. The function returns 0 on success or an error code. */ -static gpg_err_code_t -parse_flag_list (gcry_sexp_t list, - int *r_flags, enum pk_encoding *r_encoding) +gpg_err_code_t +_gcry_pk_util_parse_flaglist (gcry_sexp_t list, + int *r_flags, enum pk_encoding *r_encoding) { gpg_err_code_t rc = 0; const char *s; @@ -101,6 +101,14 @@ parse_flag_list (gcry_sexp_t list, } else if (n == 11 && ! memcmp (s, "no-blinding", 11)) flags |= PUBKEY_FLAG_NO_BLINDING; + else if (n == 13 && ! memcmp (s, "transient-key", 13)) + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + else if (n == 8 && ! memcmp (s, "use-x931", 8)) + flags |= PUBKEY_FLAG_USE_X931; + else if (n == 11 && ! memcmp (s, "use-fips186", 11)) + flags |= PUBKEY_FLAG_USE_FIPS186; + else if (n == 13 && ! memcmp (s, "use-fips186-2", 13)) + flags |= PUBKEY_FLAG_USE_FIPS186_2; else rc = GPG_ERR_INV_FLAG; } @@ -524,7 +532,7 @@ _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names, const char *s; /* There is a flags element - process it. */ - rc = parse_flag_list (l2, &parsed_flags, &ctx->encoding); + rc = _gcry_pk_util_parse_flaglist (l2, &parsed_flags, &ctx->encoding); if (rc) goto leave; if (ctx->encoding == PUBKEY_ENC_PSS) @@ -701,12 +709,13 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ; } - /* see whether there is a flags object */ + /* See whether there is a flags list. */ { gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0); if (lflags) { - if (parse_flag_list (lflags, &parsed_flags, &ctx->encoding)) + if (_gcry_pk_util_parse_flaglist (lflags, + &parsed_flags, &ctx->encoding)) unknown_flag = 1; gcry_sexp_release (lflags); } diff --git a/cipher/rsa.c b/cipher/rsa.c index fc6bbe5..d4d2a0a 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -760,8 +760,7 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) unsigned long evalue; RSA_secret_key sk; gcry_sexp_t deriveparms; - int transient_key = 0; - int use_x931 = 0; + int flags = 0; gcry_sexp_t l1; gcry_sexp_t swap_info = NULL; @@ -775,6 +774,16 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) if (ec) return ec; + /* Parse the optional flags list. */ + l1 = gcry_sexp_find_token (genparms, "flags", 0); + if (l1) + { + ec = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + gcry_sexp_release (l1); + if (ec) + return ec; + } + deriveparms = (genparms? gcry_sexp_find_token (genparms, "derive-parms", 0) : NULL); if (!deriveparms) @@ -783,12 +792,12 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) l1 = gcry_sexp_find_token (genparms, "use-x931", 0); if (l1) { - use_x931 = 1; + flags |= PUBKEY_FLAG_USE_X931; gcry_sexp_release (l1); } } - if (deriveparms || use_x931 || fips_mode ()) + if (deriveparms || (flags & PUBKEY_FLAG_USE_X931) || fips_mode ()) { int swapped; ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped); @@ -799,14 +808,18 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) else { /* Parse the optional "transient-key" flag. */ - l1 = gcry_sexp_find_token (genparms, "transient-key", 0); - if (l1) + if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) { - transient_key = 1; - gcry_sexp_release (l1); + l1 = gcry_sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + gcry_sexp_release (l1); + } } /* Generate. */ - ec = generate_std (&sk, nbits, evalue, transient_key); + ec = generate_std (&sk, nbits, evalue, + !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); } if (!ec) diff --git a/src/cipher.h b/src/cipher.h index 28f5070..b3469e5 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -32,6 +32,11 @@ #define PUBKEY_FLAG_FIXEDLEN (1 << 3) #define PUBKEY_FLAG_LEGACYRESULT (1 << 4) #define PUBKEY_FLAG_RAW_FLAG (1 << 5) +#define PUBKEY_FLAG_TRANSIENT_KEY (1 << 6) +#define PUBKEY_FLAG_USE_X931 (1 << 7) +#define PUBKEY_FLAG_USE_FIPS186 (1 << 8) +#define PUBKEY_FLAG_USE_FIPS186_2 (1 << 9) + enum pk_operation { commit 5be2345ddec4147e535d5b039ee74f84bcacf9e4 Author: Werner Koch Date: Mon Oct 14 10:21:53 2013 +0200 pubkey: Remove duplicated flag parsing code. * cipher/pubkey-util.c (_gcry_pk_util_preparse_encval) (_gcry_pk_util_data_to_mpi): Factor flag parsing code out to .. (parse_flag_list): New. * src/cipher.h (PUBKEY_FLAG_RAW_FLAG): New. -- A minor disadvantage of that code is that invalid flags are not anymore detected depending on the use. According to the documentation this is anyway the expected behavior. Signed-off-by: Werner Koch diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index 2838802..52d69cf 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -46,6 +46,74 @@ pss_verify_cmp (void *opaque, gcry_mpi_t tmp) } +/* Parser for a flag list. On return the encoding is stored at + R_ENCODING and the flags are stored at R_FLAGS. if any of them is + not needed, NULL may be passed. The function returns 0 on success + or an error code. */ +static gpg_err_code_t +parse_flag_list (gcry_sexp_t list, + int *r_flags, enum pk_encoding *r_encoding) +{ + gpg_err_code_t rc = 0; + const char *s; + size_t n; + int i; + int encoding = PUBKEY_ENC_UNKNOWN; + int flags = 0; + + for (i=list?gcry_sexp_length (list)-1:0; i > 0; i--) + { + s = gcry_sexp_nth_data (list, i, &n); + if (!s) + ; /* not a data element*/ + else if (n == 7 && !memcmp (s, "rfc6979", 7)) + { + flags |= PUBKEY_FLAG_RFC6979; + } + else if (n == 5 && !memcmp (s, "eddsa", 5)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_EDDSA; + } + else if (n == 3 && !memcmp (s, "raw", 3) + && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_RAW_FLAG; /* Explicitly given. */ + } + else if (n == 5 && !memcmp (s, "pkcs1", 5) + && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PKCS1; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (n == 4 && !memcmp (s, "oaep", 4) + && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_OAEP; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (n == 3 && !memcmp (s, "pss", 3) + && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PSS; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (n == 11 && ! memcmp (s, "no-blinding", 11)) + flags |= PUBKEY_FLAG_NO_BLINDING; + else + rc = GPG_ERR_INV_FLAG; + } + + if (r_flags) + *r_flags = flags; + if (r_encoding) + *r_encoding = encoding; + + return rc; +} + + static int get_hash_algo (const char *s, size_t n) { @@ -453,36 +521,16 @@ _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names, if (!strcmp (name, "flags")) { - /* There is a flags element - process it. */ const char *s; - for (i = gcry_sexp_length (l2) - 1; i > 0; i--) + /* There is a flags element - process it. */ + rc = parse_flag_list (l2, &parsed_flags, &ctx->encoding); + if (rc) + goto leave; + if (ctx->encoding == PUBKEY_ENC_PSS) { - s = gcry_sexp_nth_data (l2, i, &n); - if (! s) - ; /* Not a data element - ignore. */ - else if (n == 3 && !memcmp (s, "raw", 3) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_RAW; - else if (n == 5 && !memcmp (s, "pkcs1", 5) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_PKCS1; - else if (n == 4 && !memcmp (s, "oaep", 4) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_OAEP; - else if (n == 3 && !memcmp (s, "pss", 3) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - { - rc = GPG_ERR_CONFLICT; - goto leave; - } - else if (n == 11 && !memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - { - rc = GPG_ERR_INV_FLAG; - goto leave; - } + rc = GPG_ERR_CONFLICT; + goto leave; } /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */ @@ -640,12 +688,10 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, { gcry_err_code_t rc = 0; gcry_sexp_t ldata, lhash, lvalue; - int i; size_t n; const char *s; int unknown_flag = 0; int parsed_flags = 0; - int explicit_raw = 0; *ret_mpi = NULL; ldata = gcry_sexp_find_token (input, "data", 0); @@ -659,48 +705,9 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, { gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0); if (lflags) - { /* parse the flags list. */ - for (i=gcry_sexp_length (lflags)-1; i > 0; i--) - { - s = gcry_sexp_nth_data (lflags, i, &n); - if (!s) - ; /* not a data element*/ - else if (n == 7 && !memcmp (s, "rfc6979", 7)) - parsed_flags |= PUBKEY_FLAG_RFC6979; - else if (n == 5 && !memcmp (s, "eddsa", 5)) - { - ctx->encoding = PUBKEY_ENC_RAW; - parsed_flags |= PUBKEY_FLAG_EDDSA; - } - else if ( n == 3 && !memcmp (s, "raw", 3) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - { - ctx->encoding = PUBKEY_ENC_RAW; - explicit_raw = 1; - } - else if ( n == 5 && !memcmp (s, "pkcs1", 5) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - { - ctx->encoding = PUBKEY_ENC_PKCS1; - parsed_flags |= PUBKEY_FLAG_FIXEDLEN; - } - else if ( n == 4 && !memcmp (s, "oaep", 4) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - { - ctx->encoding = PUBKEY_ENC_OAEP; - parsed_flags |= PUBKEY_FLAG_FIXEDLEN; - } - else if ( n == 3 && !memcmp (s, "pss", 3) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - { - ctx->encoding = PUBKEY_ENC_PSS; - parsed_flags |= PUBKEY_FLAG_FIXEDLEN; - } - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - unknown_flag = 1; - } + { + if (parse_flag_list (lflags, &parsed_flags, &ctx->encoding)) + unknown_flag = 1; gcry_sexp_release (lflags); } } @@ -773,7 +780,8 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, *ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8); } else if (ctx->encoding == PUBKEY_ENC_RAW && lhash - && (explicit_raw || (parsed_flags & PUBKEY_FLAG_RFC6979))) + && ((parsed_flags & PUBKEY_FLAG_RAW_FLAG) + || (parsed_flags & PUBKEY_FLAG_RFC6979))) { /* Raw encoding along with a hash element. This is commonly used for DSA. For better backward error compatibility we diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 4585a32..79d4d74 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -2181,33 +2181,78 @@ or @code{oid.}. @section Cryptographic Functions @noindent -Note that we will in future allow to use keys without p,q and u -specified and may also support other parameters for performance -reasons. - - at noindent - -Some functions operating on S-expressions support `flags', that -influence the operation. These flags have to be listed in a -sub-S-expression named `flags'; the following flags are known: +Some functions operating on S-expressions support `flags' to influence +the operation. These flags have to be listed in a sub-S-expression +named `flags'. Flag names are case-sensitive. The following flags +are known: @table @code @item pkcs1 + at cindex PKCS1 Use PKCS#1 block type 2 padding for encryption, block type 1 padding for signing. + @item oaep + at cindex OAEP Use RSA-OAEP padding for encryption. + @item pss + at cindex PSS Use RSA-PSS padding for signing. + + at item ecdsa + at cindex ECDSA +Create an ECDSA public key instead of using the default key generation +of the specified curve. + @item eddsa -Use the EdDSA scheme instead of ECDSA. + at cindex EdDSA +Use the EdDSA scheme instead of the default signature algorithm of the +used curve. + @item rfc6979 + at cindex RFC6979 For DSA and ECDSA use a deterministic scheme for the k parameter. + @item no-blinding + at cindex no-blinding Do not use a technique called `blinding', which is used by default in order to prevent leaking of secret information. Blinding is only implemented by RSA, but it might be implemented by other algorithms in the future as well, when necessary. + + at item transient-key + at cindex transient-key +This flag is only meaningful for RSA, DSA, and ECC key generation. If +given the key is created using a faster and a somewhat less secure +random number generator. This flag may be used for keys which are +only used for a short time or per-message and do not require full +cryptographic strength. + + at item use-x931 + at cindex X9.31 +Force the use of the ANSI X9.31 key generation algorithm instead of +the default algorithm. This flag is only meaningful for RSA key +generation and usually not required. Note that this algorithm is +implicitly used if either @code{derive-parms} is given or Libgcrypt is +in FIPS mode. + + at item use-fips186 + at cindex FIPS 186 +Force the use of the FIPS 186 key generation algorithm instead of the +default algorithm. This flag is only meaningful for DSA and usually +not required. Note that this algorithm is implicitly used if either + at code{derive-parms} is given or Libgcrypt is in FIPS mode. As of now +FIPS 186-2 is implemented; after the approval of FIPS 186-3 the code +will be changed to implement 186-3. + + at item use-fips186-2 + at cindex FIPS 186-2 +Force the use of the FIPS 186-2 key generation algorithm instead of +the default algorithm. This algorithm is slighlty different from +FIPS 186-3 and allows only 1024 bit keys. This flag is only meaningful +for DSA and only required for FIPS testing backward compatibility. + @end table @noindent @@ -2641,10 +2686,10 @@ default selection Libgcrypt would have taken if @code{nbits} has been given. The available names are listed with the description of the ECC public key parameters. - at item rsa-use-e + at item rsa-use-e @var{value} This is only used with RSA to give a hint for the public exponent. The -value will be used as a base to test for a usable exponent. Some values -are special: + at var{value} will be used as a base to test for a usable exponent. Some +values are special: @table @samp @item 0 @@ -2662,10 +2707,10 @@ Use the given value. If this parameter is not used, Libgcrypt uses for historic reasons 65537. - at item qbits + at item qbits @var{n} This is only meanigful for DSA keys. If it is given the DSA key is -generated with a Q parameyer of this size. If it is not given or zero -Q is deduced from NBITS in this way: +generated with a Q parameyer of size @var{n} bits. If it is not given +or zero Q is deduced from NBITS in this way: @table @samp @item 512 <= N <= 1024 Q = 160 @@ -2682,14 +2727,7 @@ Note that in this case only the values for N, as given in the table, are allowed. When specifying Q all values of N in the range 512 to 15680 are valid as long as they are multiples of 8. - at item transient-key -This is only meaningful for RSA, DSA, and ECC keys. This is a flag -with no value. If given the key is created using a faster and a -somewhat less secure random number generator. This flag may be used -for keys which are only used for a short time or per-message and do -not require full cryptographic strength. - - at item domain + at item domain @var{list} This is only meaningful for DLP algorithms. If specified keys are generated with domain parameters taken from this list. The exact format of this parameter depends on the actual algorithm. It is @@ -2707,7 +2745,7 @@ currently only implemented for DSA using this format: @code{nbits} and @code{qbits} may not be specified because they are derived from the domain parameters. - at item derive-parms + at item derive-parms @var{list} This is currently only implemented for RSA and DSA keys. It is not allowed to use this together with a @code{domain} specification. If given, it is used to derive the keys using the given parameters. @@ -2745,28 +2783,25 @@ FIPS 186 algorithm is used even if libgcrypt is not in FIPS mode. @end example - at item use-x931 - at cindex X9.31 -Force the use of the ANSI X9.31 key generation algorithm instead of -the default algorithm. This flag is only meaningful for RSA and -usually not required. Note that this algorithm is implicitly used if -either @code{derive-parms} is given or Libgcrypt is in FIPS mode. - - at item use-fips186 - at cindex FIPS 186 -Force the use of the FIPS 186 key generation algorithm instead of the -default algorithm. This flag is only meaningful for DSA and usually -not required. Note that this algorithm is implicitly used if either - at code{derive-parms} is given or Libgcrypt is in FIPS mode. As of now -FIPS 186-2 is implemented; after the approval of FIPS 186-3 the code -will be changed to implement 186-3. + at item flags @var{flaglist} +This is preferred way to define flags. @var{flaglist} may contain any +number of flags. See above for a specification of these flags. +Here is an example on how to create a key using curve Ed25519 with the +ECDSA signature algorithm. Note that the use of ECDSA with that curve +is in general not recommended. + at example +(genkey + (ecc + (flags transient-key ecdsa))) + at end example - at item use-fips186-2 -Force the use of the FIPS 186-2 key generation algorithm instead of -the default algorithm. This algorithm is slighlty different from -FIPS 186-3 and allows only 1024 bit keys. This flag is only meaningful -for DSA and only required for FIPS testing backward compatibility. + at item transient-key + at itemx use-x931 + at itemx use-fips186 + at itemx use-fips186-2 +These are deprecated ways to set a flag with that name; see above for +a description of each flag. @end table diff --git a/src/cipher.h b/src/cipher.h index 3b7744a..28f5070 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -31,6 +31,7 @@ #define PUBKEY_FLAG_EDDSA (1 << 2) #define PUBKEY_FLAG_FIXEDLEN (1 << 3) #define PUBKEY_FLAG_LEGACYRESULT (1 << 4) +#define PUBKEY_FLAG_RAW_FLAG (1 << 5) enum pk_operation { commit 0cd551faa775ad5309a40629ae30bf86b75fca09 Author: Werner Koch Date: Mon Oct 14 08:09:31 2013 +0200 mpicalc: Accept lowercase hex digits. * src/mpicalc.c (main): Test for lowercase hex digits. -- This change is useful so to make use of Libgcrypt debug code easier. diff --git a/src/mpicalc.c b/src/mpicalc.c index dd85227..335b7c3 100644 --- a/src/mpicalc.c +++ b/src/mpicalc.c @@ -399,7 +399,9 @@ main (int argc, char **argv) case '-': if ((c = my_getc ()) == '-') do_dec (); - else if (isdigit (c) || (c >= 'A' && c <= 'F')) + else if (isdigit (c) + || (c >= 'A' && c <= 'F') + || (c >= 'a' && c <= 'f')) { state = 1; ungetc (c, stdin); ----------------------------------------------------------------------- Summary of changes: cipher/dsa.c | 59 +++++++++++----- cipher/ecc.c | 68 +++++++++++++------ cipher/pubkey-internal.h | 3 + cipher/pubkey-util.c | 167 +++++++++++++++++++++++++-------------------- cipher/rsa.c | 31 ++++++--- doc/gcrypt.texi | 125 ++++++++++++++++++++++------------ src/cipher.h | 13 +++- src/mpicalc.c | 4 +- tests/keygen.c | 17 +++++ tests/pubkey.c | 169 +++++++++++++++++++++++++++++++++++++++++++++- 10 files changed, 486 insertions(+), 170 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From wk at gnupg.org Tue Oct 15 15:49:44 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 15 Oct 2013 15:49:44 +0200 Subject: possible mpi-pow improvement In-Reply-To: <1380674512.3342.2.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Wed, 02 Oct 2013 09:41:52 +0900") References: <1378456897.3188.14.camel@cfw2.gniibe.org> <87a9itb52z.fsf@vigenere.g10code.de> <1380674512.3342.2.camel@cfw2.gniibe.org> Message-ID: <87d2n6myo7.fsf@vigenere.g10code.de> On Wed, 2 Oct 2013 02:41, gniibe at fsij.org said: > Yes, at least on machine. And on mine ;-)/ Before: Algorithm generate 100*sign 100*verify ------------------------------------------------ RSA 1024 bit 20ms 120ms 10ms RSA 2048 bit 120ms 630ms 10ms RSA 3072 bit 450ms 1780ms 10ms RSA 4096 bit 4110ms 3700ms 30ms DSA 1024/160 - 60ms 60ms DSA 2048/224 - 210ms 200ms DSA 3072/256 - 470ms 440ms After: Algorithm generate 100*sign 100*verify ------------------------------------------------ RSA 1024 bit 10ms 80ms 0ms RSA 2048 bit 60ms 370ms 10ms RSA 3072 bit 1710ms 1060ms 10ms RSA 4096 bit 1310ms 2220ms 20ms DSA 1024/160 - 40ms 60ms DSA 2048/224 - 140ms 200ms DSA 3072/256 - 300ms 430ms > With compilation option -DUSE_ALGORITHM_SIMPLE_EXPONENTIATION, we can > use old implementation. > > Please test it out. Please push your patch to master. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Tue Oct 15 15:46:28 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 15 Oct 2013 15:46:28 +0200 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <525BD36A.9010507@iki.fi> (Jussi Kivilinna's message of "Mon, 14 Oct 2013 14:20:10 +0300") References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> Message-ID: <87hacimytn.fsf@vigenere.g10code.de> On Mon, 14 Oct 2013 13:20, jussi.kivilinna at iki.fi said: > I based CCM patchset on the AEAD API patch Dmitry sent earlier for > GCM. Since CCM has more restrictions (need to know data lengths in > advance) than GCM, I added gcry_cipher_aead_init. I forgot about this because I delayed that far too long. Sorry. > With this patchset to encrypt a buffer using CCM, you'd first need to > initialize/reset CCM state with: > > gcry_cipher_aead_init (hd, nonce_buf, nonce_len, authtag_len, plaintext_len) > > CCM needs tag and plaintext lengths for MAC initialization. CCM also Up until now we use separate functions to set key, IV, and counter. This function changes this pattern. Why not reusing setiv for the nonce and adding a function for the authentication tag? Is the plaintext length really required in advance? That is embarrassing in particular because the authenticated data is appended to the ciphertext. > gcry_cipher_authenticate (hd, aadbuf, aadbuflen) > > which does the actual MAC initialization. If aadbuflen == 0, then > above call can be omitted and gcry_cipher_(en|de)crypt will call > gcry_cipher_authenticate with zero length. What about extending this fucntion to also take the authentication tag and, if the plaintext length is required for the MAC setup, also that length? That would group the information together. > NIST paper and RFC 3610 define CCM ciphertext as [ctr-enc(plaintext) > || authtag] and that decryption must not reveal any information > (plaintext or authtag) if authtag is not correct. Therefore full > buffers, matching with length of plaintext_len and authtag_len given > in gcry_cipher_aead_init, have to be used. If authentication check I don't see that. That is an implementaion detail and the requirement could also be achieved by putting it into the security policy. > Would it be better to add functions to do AEAD encrypt/decrypt in > single go and use gcry_buffer_t? This would avoid having internal > state machines in AEAD modes and having to call different functions in > correct order. And it also means that you can't use that mode with large amounts of data. Not a good idea; there are still lots of platforms with a quite limited amount of memory but in need to encrypt large data take from somewhere. Yes, the need for the plaintext length makes it hard to use but I can image systems which know that length on advance even if the data does not fit into memory. I mentioned gcry_buffer_t having the AAD in mind; a scatter/gather style operation may be useful here. We should also keep in mind that adding support for OCB is desirable. I had in mind to require the use of a new GCRYCTL_ENABLE_GPL_CODE to state that Libgcrypt is used under the terms of the GPL. However, meanwhile Phil Rogaway relaxed the requirement for royalty free patent licensing to all free software licenses and thus we could simply got forth and implement OCB. Any new API should make it easy to do just that. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dbaryshkov at gmail.com Tue Oct 15 21:56:42 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Tue, 15 Oct 2013 23:56:42 +0400 Subject: [PATCH v2 0/2] Suppot for GOST R 34.10-2001/-2012 signatures Message-ID: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> Hello, I have forward-ported my patchset to current ECC/Pubkey interfaces. As agreed with NIIBE Yutaka, I did not add a 'subgroup' domain (at least for now), because for "test" curves subgroup is equal to the whole group. -- With best wishes Dmitry From dbaryshkov at gmail.com Tue Oct 15 21:56:44 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Tue, 15 Oct 2013 23:56:44 +0400 Subject: [PATCH v2 2/2] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> Message-ID: <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> * src/cipher.h: define PUBKEY_FLAG_GOST * cipher/ecc-curves.c: add GOST2001-test and GOST2012-test curves defined in standards. Typical applications would use either those curves, or curves defined in RFC 4357 (will be added later). * cipher/ecc.c (sign_gost, verify_gost): New. (ecc_sign, ecc_verify): use sign_gost/verify_gost if PUBKEY_FLAG_GOST is set. (ecc_names): add "gost" for gost signatures. * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist, _gcry_pk_util_preparse_sigval): set PUBKEY_FLAG_GOST if gost flag is present in s-exp. * tests/benchmark.c (ecc_bench): also benchmark GOST signatures. * tests/basic.c (check_pubkey): add two public keys from GOST R 34.10-2012 standard. (check_pubkey_sign_ecdsa): add two data sets to check gost signatures. * tests/curves.c: correct N_CURVES as we now have 2 more curves. Signed-off-by: Dmitry Eremin-Solenikov --- cipher/ecc-curves.c | 28 +++++++ cipher/ecc.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++ cipher/pubkey-util.c | 7 ++ src/cipher.h | 1 + tests/basic.c | 75 ++++++++++++++++++ tests/benchmark.c | 17 +++- tests/curves.c | 2 +- 7 files changed, 342 insertions(+), 2 deletions(-) diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c index 53433a2..9fbd721 100644 --- a/cipher/ecc-curves.c +++ b/cipher/ecc-curves.c @@ -267,6 +267,34 @@ static const ecc_domain_parms_t domain_parms[] = "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111" "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892" }, + { + "GOST2001-test", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000431", /* p */ + "0x0000000000000000000000000000000000000000000000000000000000000007", /* a */ + "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e", /* b */ + "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3", /* q */ + + "0x0000000000000000000000000000000000000000000000000000000000000002", /* x */ + "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8", /* y */ + }, + + { + "GOST2012-test", 511, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373", /* p */ + "0x0000000000000000000000000000000000000000000000000000000000000007", /* a */ + "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4" + "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc", /* b */ + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df", /* q */ + + "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762" + "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a", /* x */ + "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2" + "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e", /* y */ + }, { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL } }; diff --git a/cipher/ecc.c b/cipher/ecc.c index 3b75fea..d241770 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -71,6 +71,7 @@ static const char *ecc_names[] = "ecdsa", "ecdh", "eddsa", + "gost", NULL, }; @@ -575,6 +576,203 @@ verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey, return err; } +/* Compute an GOST R 34.10-01/-12 signature. + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R and S. + */ +static gpg_err_code_t +sign_gost (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t k, dr, sum, ke, x, e; + mpi_point_struct I; + gcry_mpi_t hash; + const void *abuf; + unsigned int abits, qbits; + mpi_ec_t ctx; + + if (DBG_CIPHER) + log_mpidump ("gost sign hash ", input ); + + qbits = mpi_get_nbits (skey->E.n); + + /* Convert the INPUT into an MPI if needed. */ + if (mpi_is_opaque (input)) + { + abuf = gcry_mpi_get_opaque (input, &abits); + err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, + abuf, (abits+7)/8, NULL)); + if (err) + return err; + if (abits > qbits) + gcry_mpi_rshift (hash, hash, abits - qbits); + } + else + hash = input; + + + k = NULL; + dr = mpi_alloc (0); + sum = mpi_alloc (0); + ke = mpi_alloc (0); + e = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&I); + + ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, + skey->E.p, skey->E.a, skey->E.b); + + mpi_mod (e, input, skey->E.n); /* e = hash mod n */ + + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + + /* Two loops to avoid R or S are zero. This is more of a joke than + a real demand because the probability of them being zero is less + than any hardware failure. Some specs however require it. */ + do + { + do + { + mpi_free (k); + k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); + + _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); + if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc sign: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (r, x, skey->E.n); /* r = x mod n */ + } + while (!mpi_cmp_ui (r, 0)); + mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ + mpi_mulm (ke, k, e, skey->E.n); /* ke = k*e mod n */ + mpi_addm (s, ke, dr, skey->E.n); /* sum = (k*e+ d*r) mod n */ + } + while (!mpi_cmp_ui (s, 0)); + + if (DBG_CIPHER) + { + log_mpidump ("gost sign result r ", r); + log_mpidump ("gost sign result s ", s); + } + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&I); + mpi_free (x); + mpi_free (e); + mpi_free (ke); + mpi_free (sum); + mpi_free (dr); + mpi_free (k); + + if (hash != input) + mpi_free (hash); + + return err; +} + +/* Verify a GOST R 34.10-01/-12 signature. + * Check if R and S verifies INPUT. + */ +static gpg_err_code_t +verify_gost (gcry_mpi_t input, ECC_public_key *pkey, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t e, x, z1, z2, v, rv, zero; + mpi_point_struct Q, Q1, Q2; + mpi_ec_t ctx; + + if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ + if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + x = mpi_alloc (0); + e = mpi_alloc (0); + z1 = mpi_alloc (0); + z2 = mpi_alloc (0); + v = mpi_alloc (0); + rv = mpi_alloc (0); + zero = mpi_alloc (0); + + point_init (&Q); + point_init (&Q1); + point_init (&Q2); + + ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, + pkey->E.p, pkey->E.a, pkey->E.b); + + mpi_mod (e, input, pkey->E.n); /* e = hash mod n */ + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + mpi_invm (v, e, pkey->E.n); /* v = e^(-1) (mod n) */ + mpi_mulm (z1, s, v, pkey->E.n); /* z1 = s*v (mod n) */ + mpi_mulm (rv, r, v, pkey->E.n); /* rv = s*v (mod n) */ + mpi_subm (z2, zero, rv, pkey->E.n); /* z2 = -r*v (mod n) */ + + _gcry_mpi_ec_mul_point (&Q1, z1, &pkey->E.G, ctx); +/* log_mpidump ("Q1.x", Q1.x); */ +/* log_mpidump ("Q1.y", Q1.y); */ +/* log_mpidump ("Q1.z", Q1.z); */ + _gcry_mpi_ec_mul_point (&Q2, z2, &pkey->Q, ctx); +/* log_mpidump ("Q2.x", Q2.x); */ +/* log_mpidump ("Q2.y", Q2.y); */ +/* log_mpidump ("Q2.z", Q2.z); */ + _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); +/* log_mpidump (" Q.x", Q.x); */ +/* log_mpidump (" Q.y", Q.y); */ +/* log_mpidump (" Q.z", Q.z); */ + + if (!mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Rejected\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ + if (mpi_cmp (x, r)) /* x != r */ + { + if (DBG_CIPHER) + { + log_mpidump (" x", x); + log_mpidump (" r", r); + log_mpidump (" s", s); + log_debug ("ecc verify: Not verified\n"); + } + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (DBG_CIPHER) + log_debug ("ecc verify: Accepted\n"); + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&Q2); + point_free (&Q1); + point_free (&Q); + mpi_free (zero); + mpi_free (rv); + mpi_free (v); + mpi_free (z2); + mpi_free (z1); + mpi_free (x); + mpi_free (e); + return err; +} static void @@ -1623,6 +1821,13 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = gcry_sexp_build (r_sig, NULL, "(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s); } + else if ((ctx.flags & PUBKEY_FLAG_GOST)) + { + rc = sign_gost (data, &sk, sig_r, sig_s); + if (!rc) + rc = gcry_sexp_build (r_sig, NULL, + "(sig-val(gost(r%M)(s%M)))", sig_r, sig_s); + } else { rc = sign_ecdsa (data, &sk, sig_r, sig_s, ctx.flags, ctx.hash_algo); @@ -1773,6 +1978,15 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { rc = verify_eddsa (data, &pk, sig_r, sig_s, ctx.hash_algo, mpi_q); } + else if ((sigflags & PUBKEY_FLAG_GOST)) + { + point_init (&pk.Q); + rc = _gcry_ecc_os2ec (&pk.Q, mpi_q); + if (rc) + goto leave; + + rc = verify_gost (data, &pk, sig_r, sig_s); + } else { point_init (&pk.Q); diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index 54832ec..c4058bd 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -79,6 +79,11 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list, { flags |= PUBKEY_FLAG_ECDSA; } + else if (n == 4 && !memcmp (s, "gost", 4)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_GOST; + } else if (n == 3 && !memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN) { @@ -460,6 +465,8 @@ _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, { if (!strcmp (name, "eddsa")) *r_eccflags = PUBKEY_FLAG_EDDSA; + if (!strcmp (name, "gost")) + *r_eccflags = PUBKEY_FLAG_GOST; } *r_parms = l2; diff --git a/src/cipher.h b/src/cipher.h index 077af98..20818ba 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -37,6 +37,7 @@ #define PUBKEY_FLAG_USE_FIPS186_2 (1 << 8) #define PUBKEY_FLAG_ECDSA (1 << 9) #define PUBKEY_FLAG_EDDSA (1 << 10) +#define PUBKEY_FLAG_GOST (1 << 11) enum pk_operation diff --git a/tests/basic.c b/tests/basic.c index 899dae5..1267831 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -3677,6 +3677,30 @@ check_pubkey_sign_ecdsa (int n, gcry_sexp_t skey, gcry_sexp_t pkey) /* */ "000102030405060708090A0B0C0D0E0F#))", 0 }, + { 256, + "(data (flags gost)\n" + " (value #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0, + "(data (flags gost)\n" + " (value #80112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0 + }, + { 512, + "(data (flags gost)\n" + " (value #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0, + "(data (flags gost)\n" + " (value #80112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0 + }, { 0, NULL } }; @@ -4264,6 +4288,57 @@ check_pubkey (void) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } + }, + { /* GOST R 34.10-2001/2012 test 256 bit. */ + GCRY_PK_ECDSA, FLAG_SIGN, + { + "(private-key\n" + " (ecc\n" + " (curve GOST2001-test)\n" + " (q #047F2B49E270DB6D90D8595BEC458B50C58585BA1D4E9B78" + " 8F6689DBD8E56FD80B26F1B489D6701DD185C8413A977B3C" + " BBAF64D1C593D26627DFFB101A87FF77DA#)\n" + " (d #7A929ADE789BB9BE10ED359DD39A72C11B60961F49397EEE" + " 1D19CE9891EC3B28#)))\n", + + "(public-key\n" + " (ecc\n" + " (curve GOST2001-test)\n" + " (q #047F2B49E270DB6D90D8595BEC458B50C58585BA1D4E9B78" + " 8F6689DBD8E56FD80B26F1B489D6701DD185C8413A977B3C" + " BBAF64D1C593D26627DFFB101A87FF77DA#)))\n", + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } + }, + { /* GOST R 34.10-2012 test 512 bit. */ + GCRY_PK_ECDSA, FLAG_SIGN, + { + "(private-key\n" + " (ecc\n" + " (curve GOST2012-test)\n" + " (q #04115DC5BC96760C7B48598D8AB9E740D4C4A85A65BE33C1" + " 815B5C320C854621DD5A515856D13314AF69BC5B924C8B" + " 4DDFF75C45415C1D9DD9DD33612CD530EFE137C7C90CD4" + " 0B0F5621DC3AC1B751CFA0E2634FA0503B3D52639F5D7F" + " B72AFD61EA199441D943FFE7F0C70A2759A3CDB84C114E" + " 1F9339FDF27F35ECA93677BEEC#)\n" + " (d #0BA6048AADAE241BA40936D47756D7C93091A0E851466970" + " 0EE7508E508B102072E8123B2200A0563322DAD2827E2714" + " A2636B7BFD18AADFC62967821FA18DD4#)))\n", + + "(public-key\n" + " (ecc\n" + " (curve GOST2001-test)\n" + " (q #04115DC5BC96760C7B48598D8AB9E740D4C4A85A65BE33C1" + " 815B5C320C854621DD5A515856D13314AF69BC5B924C8B" + " 4DDFF75C45415C1D9DD9DD33612CD530EFE137C7C90CD4" + " 0B0F5621DC3AC1B751CFA0E2634FA0503B3D52639F5D7F" + " B72AFD61EA199441D943FFE7F0C70A2759A3CDB84C114E" + " 1F9339FDF27F35ECA93677BEEC#)))\n" + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } } }; int i; diff --git a/tests/benchmark.c b/tests/benchmark.c index 5d1434a..ecda0d3 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -883,7 +883,8 @@ ecc_bench (int iterations, int print_header) { #if USE_ECC gpg_error_t err; - const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519" }; + const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519", + "gost256", "gost512" }; int testno; if (print_header) @@ -899,14 +900,22 @@ ecc_bench (int iterations, int print_header) int count; int p_size; int is_ed25519; + int is_gost; is_ed25519 = !strcmp (p_sizes[testno], "Ed25519"); + is_gost = !strncmp (p_sizes[testno], "gost", 4); if (is_ed25519) { p_size = 256; printf ("EdDSA Ed25519 "); fflush (stdout); } + else if (is_gost) + { + p_size = atoi (p_sizes[testno] + 4); + printf ("GOST %3d bit ", p_size); + fflush (stdout); + } else { p_size = atoi (p_sizes[testno]); @@ -917,6 +926,10 @@ ecc_bench (int iterations, int print_header) if (is_ed25519) err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecdsa (curve \"Ed25519\")))"); + else if (is_gost) + err = gcry_sexp_build (&key_spec, NULL, + "(genkey (ecdsa (curve %s)))", + p_size == 256 ? "GOST2001-test" : "GOST2012-test"); else err = gcry_sexp_build (&key_spec, NULL, "(genkey (ECDSA (nbits %d)))", p_size); @@ -950,6 +963,8 @@ ecc_bench (int iterations, int print_header) err = gcry_sexp_build (&data, NULL, "(data (flags eddsa)(hash-algo sha512)" " (value %m))", x); + else if (is_gost) + err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); else err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x); gcry_mpi_release (x); diff --git a/tests/curves.c b/tests/curves.c index 2c3ae53..198693e 100644 --- a/tests/curves.c +++ b/tests/curves.c @@ -29,7 +29,7 @@ #include "../src/gcrypt-int.h" /* Number of curves defined in ../cipger/ecc.c */ -#define N_CURVES 13 +#define N_CURVES 15 /* A real world sample public key. */ static char const sample_key_1[] = -- 1.8.4.rc3 From dbaryshkov at gmail.com Tue Oct 15 21:56:43 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Tue, 15 Oct 2013 23:56:43 +0400 Subject: [PATCH v2 1/2] Fix 256-bit ecdsa test key definition In-Reply-To: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> Message-ID: <1381867004-21231-2-git-send-email-dbaryshkov@gmail.com> * tests/basic.c (check_pubkey): fix nistp256 testing key declaration - add missing comma. Signed-off-by: Dmitry Eremin-Solenikov --- tests/basic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/basic.c b/tests/basic.c index 3ffcefe..899dae5 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -4260,7 +4260,7 @@ check_pubkey (void) " (curve nistp256)\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2B" " EB6644D3609FC781B71F9A8072F58CB66AE2F89BB1245187" - " 3ABF7D91F9E1FBF96BF2F70E73AAC9A283#)))\n" + " 3ABF7D91F9E1FBF96BF2F70E73AAC9A283#)))\n", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } -- 1.8.4.rc3 From cvs at cvs.gnupg.org Wed Oct 16 02:12:54 2013 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Wed, 16 Oct 2013 02:12:54 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-309-g45aa613 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 45aa6131e93fac89d46733b3436d960f35fb99b2 (commit) from 537969fbbb1104b8305a7edb331b7666d54eff2c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 45aa6131e93fac89d46733b3436d960f35fb99b2 Author: NIIBE Yutaka Date: Wed Oct 2 09:27:09 2013 +0900 mpi: mpi-pow improvement. * mpi/mpi-pow.c (gcry_mpi_powm): New implementation of left-to-right k-ary exponentiation. -- Signed-off-by: NIIBE Yutaka For the Yarom/Falkner flush+reload cache side-channel attack, we changed the code so that it always calls the multiplication routine (even if we can skip it to get result). This results some performance regression. This change is for recovering performance with efficient algorithm. diff --git a/mpi/mpi-pow.c b/mpi/mpi-pow.c index 85d6fd8..469c382 100644 --- a/mpi/mpi-pow.c +++ b/mpi/mpi-pow.c @@ -34,6 +34,14 @@ #include "longlong.h" +/* + * When you need old implementation, please add compilation option + * -DUSE_ALGORITHM_SIMPLE_EXPONENTIATION + * or expose this line: +#define USE_ALGORITHM_SIMPLE_EXPONENTIATION 1 + */ + +#if defined(USE_ALGORITHM_SIMPLE_EXPONENTIATION) /**************** * RES = BASE ^ EXPO mod MOD */ @@ -336,3 +344,449 @@ gcry_mpi_powm (gcry_mpi_t res, if (tspace) _gcry_mpi_free_limb_space( tspace, 0 ); } +#else +/** + * Internal function to compute + * + * X = R * S mod M + * + * and set the size of X at the pointer XSIZE_P. + * Use karatsuba structure at KARACTX_P. + * + * Condition: + * RSIZE >= SSIZE + * Enough space for X is allocated beforehand. + * + * For generic cases, we can/should use gcry_mpi_mulm. + * This function is use for specific internal case. + */ +static void +mul_mod (mpi_ptr_t xp, mpi_size_t *xsize_p, + mpi_ptr_t rp, mpi_size_t rsize, + mpi_ptr_t sp, mpi_size_t ssize, + mpi_ptr_t mp, mpi_size_t msize, + struct karatsuba_ctx *karactx_p) +{ + if( ssize < KARATSUBA_THRESHOLD ) + _gcry_mpih_mul ( xp, rp, rsize, sp, ssize ); + else + _gcry_mpih_mul_karatsuba_case (xp, rp, rsize, sp, ssize, karactx_p); + + if (rsize + ssize > msize) + { + _gcry_mpih_divrem (xp + msize, 0, xp, rsize + ssize, mp, msize); + *xsize_p = msize; + } + else + *xsize_p = rsize + ssize; +} + +#define SIZE_B_2I3 ((1 << (5 - 1)) - 1) + +/**************** + * RES = BASE ^ EXPO mod MOD + * + * To mitigate the Yarom/Falkner flush+reload cache side-channel + * attack on the RSA secret exponent, we don't use the square + * routine but multiplication. + * + * Reference: + * Handbook of Applied Cryptography + * Algorithm 14.83: Modified left-to-right k-ary exponentiation + */ +void +gcry_mpi_powm (gcry_mpi_t res, + gcry_mpi_t base, gcry_mpi_t expo, gcry_mpi_t mod) +{ + /* Pointer to the limbs of the arguments, their size and signs. */ + mpi_ptr_t rp, ep, mp, bp; + mpi_size_t esize, msize, bsize, rsize; + int msign, bsign, rsign; + /* Flags telling the secure allocation status of the arguments. */ + int esec, msec, bsec; + /* Size of the result including space for temporary values. */ + mpi_size_t size; + /* Helper. */ + int mod_shift_cnt; + int negative_result; + mpi_ptr_t mp_marker = NULL; + mpi_ptr_t bp_marker = NULL; + mpi_ptr_t ep_marker = NULL; + mpi_ptr_t xp_marker = NULL; + unsigned int mp_nlimbs = 0; + unsigned int bp_nlimbs = 0; + unsigned int ep_nlimbs = 0; + unsigned int xp_nlimbs = 0; + mpi_ptr_t b_2i3[SIZE_B_2I3]; /* Pre-computed array: BASE^3, ^5, ^7, ... */ + mpi_size_t b_2i3size[SIZE_B_2I3]; + mpi_size_t W; + mpi_ptr_t base_u; + mpi_size_t base_u_size; + + esize = expo->nlimbs; + msize = mod->nlimbs; + size = 2 * msize; + msign = mod->sign; + + if (esize * BITS_PER_MPI_LIMB > 512) + W = 5; + else if (esize * BITS_PER_MPI_LIMB > 256) + W = 4; + else if (esize * BITS_PER_MPI_LIMB > 128) + W = 3; + else if (esize * BITS_PER_MPI_LIMB > 64) + W = 2; + else + W = 1; + + esec = mpi_is_secure(expo); + msec = mpi_is_secure(mod); + bsec = mpi_is_secure(base); + + rp = res->d; + ep = expo->d; + + if (!msize) + _gcry_divide_by_zero(); + + if (!esize) + { + /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 depending + on if MOD equals 1. */ + res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; + if (res->nlimbs) + { + RESIZE_IF_NEEDED (res, 1); + rp = res->d; + rp[0] = 1; + } + res->sign = 0; + goto leave; + } + + /* Normalize MOD (i.e. make its most significant bit set) as + required by mpn_divrem. This will make the intermediate values + in the calculation slightly larger, but the correct result is + obtained after a final reduction using the original MOD value. */ + mp_nlimbs = msec? msize:0; + mp = mp_marker = mpi_alloc_limb_space(msize, msec); + count_leading_zeros (mod_shift_cnt, mod->d[msize-1]); + if (mod_shift_cnt) + _gcry_mpih_lshift (mp, mod->d, msize, mod_shift_cnt); + else + MPN_COPY( mp, mod->d, msize ); + + bsize = base->nlimbs; + bsign = base->sign; + if (bsize > msize) + { + /* The base is larger than the module. Reduce it. + + Allocate (BSIZE + 1) with space for remainder and quotient. + (The quotient is (bsize - msize + 1) limbs.) */ + bp_nlimbs = bsec ? (bsize + 1):0; + bp = bp_marker = mpi_alloc_limb_space( bsize + 1, bsec ); + MPN_COPY ( bp, base->d, bsize ); + /* We don't care about the quotient, store it above the + * remainder, at BP + MSIZE. */ + _gcry_mpih_divrem( bp + msize, 0, bp, bsize, mp, msize ); + bsize = msize; + /* Canonicalize the base, since we are going to multiply with it + quite a few times. */ + MPN_NORMALIZE( bp, bsize ); + } + else + bp = base->d; + + if (!bsize) + { + res->nlimbs = 0; + res->sign = 0; + goto leave; + } + + + /* Make BASE, EXPO and MOD not overlap with RES. */ + if ( rp == bp ) + { + /* RES and BASE are identical. Allocate temp. space for BASE. */ + gcry_assert (!bp_marker); + bp_nlimbs = bsec? bsize:0; + bp = bp_marker = mpi_alloc_limb_space( bsize, bsec ); + MPN_COPY(bp, rp, bsize); + } + if ( rp == ep ) + { + /* RES and EXPO are identical. Allocate temp. space for EXPO. */ + ep_nlimbs = esec? esize:0; + ep = ep_marker = mpi_alloc_limb_space( esize, esec ); + MPN_COPY(ep, rp, esize); + } + if ( rp == mp ) + { + /* RES and MOD are identical. Allocate temporary space for MOD.*/ + gcry_assert (!mp_marker); + mp_nlimbs = msec?msize:0; + mp = mp_marker = mpi_alloc_limb_space( msize, msec ); + MPN_COPY(mp, rp, msize); + } + + /* Copy base to the result. */ + if (res->alloced < size) + { + mpi_resize (res, size); + rp = res->d; + } + + /* Main processing. */ + { + mpi_size_t i, j; + mpi_ptr_t xp; + mpi_size_t xsize; + int c; + mpi_limb_t e; + mpi_limb_t carry_limb; + struct karatsuba_ctx karactx; + mpi_ptr_t tp; + + xp_nlimbs = msec? (2 * (msize + 1)):0; + xp = xp_marker = mpi_alloc_limb_space( 2 * (msize + 1), msec ); + + memset( &karactx, 0, sizeof karactx ); + negative_result = (ep[0] & 1) && bsign; + + /* Precompute B_2I3[], BASE^(2 * i + 3), BASE^3, ^5, ^7, ... */ + if (W > 1) /* X := BASE^2 */ + mul_mod (xp, &xsize, bp, bsize, bp, bsize, mp, msize, &karactx); + for (i = 0; i < (1 << (W - 1)) - 1; i++) + { /* B_2I3[i] = BASE^(2 * i + 3) */ + if (i == 0) + { + base_u = bp; + base_u_size = bsize; + } + else + { + base_u = b_2i3[i-1]; + base_u_size = b_2i3size[i-1]; + } + + if (xsize >= base_u_size) + mul_mod (rp, &rsize, xp, xsize, base_u, base_u_size, + mp, msize, &karactx); + else + mul_mod (rp, &rsize, base_u, base_u_size, xp, xsize, + mp, msize, &karactx); + b_2i3[i] = mpi_alloc_limb_space (rsize, esec); + b_2i3size[i] = rsize; + MPN_COPY (b_2i3[i], rp, rsize); + } + + i = esize - 1; + + /* Main loop. + + Make the result be pointed to alternately by XP and RP. This + helps us avoid block copying, which would otherwise be + necessary with the overlap restrictions of + _gcry_mpih_divmod. With 50% probability the result after this + loop will be in the area originally pointed by RP (==RES->d), + and with 50% probability in the area originally pointed to by XP. */ + rsign = 0; + if (W == 1) + { + rsize = bsize; + } + else + { + rsize = msize; + MPN_ZERO (rp, rsize); + } + MPN_COPY ( rp, bp, bsize ); + + e = ep[i]; + count_leading_zeros (c, e); + e = (e << c) << 1; + c = BITS_PER_MPI_LIMB - 1 - c; + + j = 0; + + for (;;) + if (e == 0) + { + j += c; + i--; + if ( i < 0 ) + { + c = 0; + break; + } + + e = ep[i]; + c = BITS_PER_MPI_LIMB; + } + else + { + int c0; + mpi_limb_t e0; + + count_leading_zeros (c0, e); + e = (e << c0); + c -= c0; + j += c0; + + if (c >= W) + { + e0 = (e >> (BITS_PER_MPI_LIMB - W)); + e = (e << W); + c -= W; + } + else + { + i--; + if ( i < 0 ) + { + e = (e >> (BITS_PER_MPI_LIMB - c)); + break; + } + + c0 = c; + e0 = (e >> (BITS_PER_MPI_LIMB - W)) + | (ep[i] >> (BITS_PER_MPI_LIMB - W + c0)); + e = (ep[i] << (W - c0)); + c = BITS_PER_MPI_LIMB - W + c0; + } + + count_trailing_zeros (c0, e0); + e0 = (e0 >> c0) >> 1; + + for (j += W - c0; j; j--) + { + mul_mod (xp, &xsize, rp, rsize, rp, rsize, mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + } + + if (e0 == 0) + { + base_u = bp; + base_u_size = bsize; + } + else + { + base_u = b_2i3[e0 - 1]; + base_u_size = b_2i3size[e0 -1]; + } + + mul_mod (xp, &xsize, rp, rsize, base_u, base_u_size, + mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + + j = c0; + } + + if (c != 0) + { + j += c; + count_trailing_zeros (c, e); + e = (e >> c); + j -= c; + } + + while (j--) + { + mul_mod (xp, &xsize, rp, rsize, rp, rsize, mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + } + + if (e != 0) + { + if ((e>>1) == 0) + { + base_u = bp; + base_u_size = bsize; + } + else + { + base_u = b_2i3[(e>>1) - 1]; + base_u_size = b_2i3size[(e>>1) -1]; + } + + mul_mod (xp, &xsize, rp, rsize, base_u, base_u_size, + mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + + for (; c; c--) + { + mul_mod (xp, &xsize, rp, rsize, rp, rsize, mp, msize, &karactx); + tp = rp; rp = xp; xp = tp; + rsize = xsize; + } + } + + /* We shifted MOD, the modulo reduction argument, left + MOD_SHIFT_CNT steps. Adjust the result by reducing it with the + original MOD. + + Also make sure the result is put in RES->d (where it already + might be, see above). */ + if ( mod_shift_cnt ) + { + carry_limb = _gcry_mpih_lshift( res->d, rp, rsize, mod_shift_cnt); + rp = res->d; + if ( carry_limb ) + { + rp[rsize] = carry_limb; + rsize++; + } + } + else if (res->d != rp) + { + MPN_COPY (res->d, rp, rsize); + rp = res->d; + } + + if ( rsize >= msize ) + { + _gcry_mpih_divrem(rp + msize, 0, rp, rsize, mp, msize); + rsize = msize; + } + + /* Remove any leading zero words from the result. */ + if ( mod_shift_cnt ) + _gcry_mpih_rshift( rp, rp, rsize, mod_shift_cnt); + MPN_NORMALIZE (rp, rsize); + + _gcry_mpih_release_karatsuba_ctx (&karactx ); + for (i = 0; i < (1 << (W - 1)) - 1; i++) + _gcry_mpi_free_limb_space( b_2i3[i], esec ? b_2i3size[i] : 0 ); + } + + /* Fixup for negative results. */ + if ( negative_result && rsize ) + { + if ( mod_shift_cnt ) + _gcry_mpih_rshift( mp, mp, msize, mod_shift_cnt); + _gcry_mpih_sub( rp, mp, msize, rp, rsize); + rsize = msize; + rsign = msign; + MPN_NORMALIZE(rp, rsize); + } + gcry_assert (res->d == rp); + res->nlimbs = rsize; + res->sign = rsign; + + leave: + if (mp_marker) + _gcry_mpi_free_limb_space( mp_marker, mp_nlimbs ); + if (bp_marker) + _gcry_mpi_free_limb_space( bp_marker, bp_nlimbs ); + if (ep_marker) + _gcry_mpi_free_limb_space( ep_marker, ep_nlimbs ); + if (xp_marker) + _gcry_mpi_free_limb_space( xp_marker, xp_nlimbs ); +} +#endif ----------------------------------------------------------------------- Summary of changes: mpi/mpi-pow.c | 454 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 454 insertions(+) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From gniibe at fsij.org Wed Oct 16 02:26:43 2013 From: gniibe at fsij.org (NIIBE Yutaka) Date: Wed, 16 Oct 2013 09:26:43 +0900 Subject: possible mpi-pow improvement In-Reply-To: <87d2n6myo7.fsf@vigenere.g10code.de> References: <1378456897.3188.14.camel@cfw2.gniibe.org> <87a9itb52z.fsf@vigenere.g10code.de> <1380674512.3342.2.camel@cfw2.gniibe.org> <87d2n6myo7.fsf@vigenere.g10code.de> Message-ID: <1381883203.3175.0.camel@cfw2.gniibe.org> Thank you for your testing. On 2013-10-15 at 15:49 +0200, Werner Koch wrote: > Please push your patch to master. Done. -- From jussi.kivilinna at iki.fi Wed Oct 16 11:05:06 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Wed, 16 Oct 2013 12:05:06 +0300 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <87hacimytn.fsf@vigenere.g10code.de> References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> <87hacimytn.fsf@vigenere.g10code.de> Message-ID: <525E56C2.6060704@iki.fi> On 15.10.2013 16:46, Werner Koch wrote: > On Mon, 14 Oct 2013 13:20, jussi.kivilinna at iki.fi said: > >> I based CCM patchset on the AEAD API patch Dmitry sent earlier for >> GCM. Since CCM has more restrictions (need to know data lengths in >> advance) than GCM, I added gcry_cipher_aead_init. > > I forgot about this because I delayed that far too long. Sorry. > >> With this patchset to encrypt a buffer using CCM, you'd first need to >> initialize/reset CCM state with: >> >> gcry_cipher_aead_init (hd, nonce_buf, nonce_len, authtag_len, plaintext_len) >> >> CCM needs tag and plaintext lengths for MAC initialization. CCM also > > Up until now we use separate functions to set key, IV, and counter. > This function changes this pattern. Why not reusing setiv for the > nonce and adding a function for the authentication tag? Sure, setiv can be reused. > > Is the plaintext length really required in advance? That is > embarrassing in particular because the authenticated data is appended to > the ciphertext. Yes, this is really the case with CCM. The first block to CBC-MAC contains length of encrypted message.. from RFC: The first block B_0 is formatted as follows, where l(m) is encoded in most-significant-byte first order: Octet Number Contents ------------ --------- 0 Flags 1 ... 15-L Nonce N 16-L ... 15 l(m) Flags encodes the length of length field (L), tag length and an AAD flag. > >> gcry_cipher_authenticate (hd, aadbuf, aadbuflen) >> >> which does the actual MAC initialization. If aadbuflen == 0, then >> above call can be omitted and gcry_cipher_(en|de)crypt will call >> gcry_cipher_authenticate with zero length. > > What about extending this fucntion to also take the authentication tag > and, if the plaintext length is required for the MAC setup, also that > length? That would group the information together. Ok, so we'd have gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, count void *tag, size_t taglen, size_t crypt_len) For encryption, tag is NULL pointer and taglen is zero and after encryption authentication tag can be read with 'gcry_cipher_tag'. For decryption, tag is given for authentication check with above function. Also (at least) for CCM, encrypt_len needs to be given. > >> NIST paper and RFC 3610 define CCM ciphertext as [ctr-enc(plaintext) >> || authtag] and that decryption must not reveal any information >> (plaintext or authtag) if authtag is not correct. Therefore full >> buffers, matching with length of plaintext_len and authtag_len given >> in gcry_cipher_aead_init, have to be used. If authentication check > > I don't see that. That is an implementaion detail and the requirement > could also be achieved by putting it into the security policy. Ok. > >> Would it be better to add functions to do AEAD encrypt/decrypt in >> single go and use gcry_buffer_t? This would avoid having internal >> state machines in AEAD modes and having to call different functions in >> correct order. > > And it also means that you can't use that mode with large amounts of > data. Not a good idea; there are still lots of platforms with a quite > limited amount of memory but in need to encrypt large data take from > somewhere. Yes, the need for the plaintext length makes it hard to use > but I can image systems which know that length on advance even if the > data does not fit into memory. Agreed and not all AEAD modes require plaintext length in advance. > > I mentioned gcry_buffer_t having the AAD in mind; a scatter/gather style > operation may be useful here. > > We should also keep in mind that adding support for OCB is desirable. I > had in mind to require the use of a new GCRYCTL_ENABLE_GPL_CODE to state > that Libgcrypt is used under the terms of the GPL. However, meanwhile > Phil Rogaway relaxed the requirement for royalty free patent licensing > to all free software licenses and thus we could simply got forth and > implement OCB. Any new API should make it easy to do just that. > > > > Shalom-Salam, > > Werner > From wk at gnupg.org Wed Oct 16 11:25:36 2013 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Oct 2013 11:25:36 +0200 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <525E56C2.6060704@iki.fi> (Jussi Kivilinna's message of "Wed, 16 Oct 2013 12:05:06 +0300") References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> <87hacimytn.fsf@vigenere.g10code.de> <525E56C2.6060704@iki.fi> Message-ID: <87eh7llg8f.fsf@vigenere.g10code.de> On Wed, 16 Oct 2013 11:05, jussi.kivilinna at iki.fi said: > Ok, so we'd have > gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, > count void *tag, size_t taglen, size_t crypt_len) > > For encryption, tag is NULL pointer and taglen is zero and after encryption > authentication tag can be read with 'gcry_cipher_tag'. For decryption, tag > is given for authentication check with above function. A last idea: What about two functions gcry_cipher_settag () -- To be used before decryption gcry_cipher_gettag () -- to be used after encryption. gcry_cipher_set_tag would actually look prettier but we already use setkey and setiv. Wit these fucntions gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, size_t crypt_len) would be pretty easy to describe. And a very last idea: What about renaming gcry_cipher_authenticate to gcry_cipher_setaad ? Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dbaryshkov at gmail.com Wed Oct 16 13:20:15 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Wed, 16 Oct 2013 15:20:15 +0400 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <525E56C2.6060704@iki.fi> References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> <87hacimytn.fsf@vigenere.g10code.de> <525E56C2.6060704@iki.fi> Message-ID: Hello, On Wed, Oct 16, 2013 at 1:05 PM, Jussi Kivilinna wrote: > On 15.10.2013 16:46, Werner Koch wrote: >> On Mon, 14 Oct 2013 13:20, jussi.kivilinna at iki.fi said: >> >>> gcry_cipher_authenticate (hd, aadbuf, aadbuflen) >>> >>> which does the actual MAC initialization. If aadbuflen == 0, then >>> above call can be omitted and gcry_cipher_(en|de)crypt will call >>> gcry_cipher_authenticate with zero length. >> >> What about extending this fucntion to also take the authentication tag >> and, if the plaintext length is required for the MAC setup, also that >> length? That would group the information together. > > Ok, so we'd have > gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, > count void *tag, size_t taglen, size_t crypt_len) > > For encryption, tag is NULL pointer and taglen is zero and after encryption > authentication tag can be read with 'gcry_cipher_tag'. For decryption, tag > is given for authentication check with above function. Hmm. That would require for the tag to be stored in the context to be validated after we process all enciphered data. I would suggest to move tag validation to upper layer: * setiv/setkey/etc. * authenticate(AAD, crypt_len) * while (has_data) enc_data = encrypt(data) * tag = tag() -> returns tag for AAD and passed data Upper layer passes AAD, enc_data and tag to other side. Upper layer received AAD, enc_data, and tag * setiv/setkey/etc * authenticate(AAD, crypt_len) * while (has_enc_data) data = decrypt(enc_data) * new_tag = tag() -> returns tag for AAD and unencrypted data Then upper layer can compare tag with new_tag and thus verify that data is authenticated. What do you think? BTW: Looking at GCM/GMAC I have the feeling that single authenticate() might be enough for now (and should be enough for e.g. TLS), but in future to support GMAC (GCM working in auth-only mode, no crypto data) we might want to support several sequential authenticate() calls (if all of them come before first encrypt()/decrypt() call). -- With best wishes Dmitry From jussi.kivilinna at iki.fi Wed Oct 16 13:26:19 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Wed, 16 Oct 2013 14:26:19 +0300 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <87eh7llg8f.fsf@vigenere.g10code.de> References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> <87hacimytn.fsf@vigenere.g10code.de> <525E56C2.6060704@iki.fi> <87eh7llg8f.fsf@vigenere.g10code.de> Message-ID: <525E77DB.8030402@iki.fi> On 16.10.2013 12:25, Werner Koch wrote: > On Wed, 16 Oct 2013 11:05, jussi.kivilinna at iki.fi said: > >> Ok, so we'd have >> gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, >> count void *tag, size_t taglen, size_t crypt_len) >> >> For encryption, tag is NULL pointer and taglen is zero and after encryption >> authentication tag can be read with 'gcry_cipher_tag'. For decryption, tag >> is given for authentication check with above function. > > A last idea: What about two functions > > gcry_cipher_settag () -- To be used before decryption > gcry_cipher_gettag () -- to be used after encryption. > > gcry_cipher_set_tag would actually look prettier but we already use > setkey and setiv. Wit these fucntions > > gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, > size_t crypt_len) > > would be pretty easy to describe. And a very last idea: What about > renaming > > gcry_cipher_authenticate to gcry_cipher_setaad > > ? I started writing following example to check is for CCM would work with these. Problem here is that CCM needs authentication tag length for first CBC-MAC block. Maybe taglen could be given to CCM mode encryption with gcry_cipher_settag(hd, NULL, taglen)? CCM encryption, without AAD: gcry_cipher_setkey (hd, key, key_len); /* Set nonce. */ gcry_cipher_setiv (hd, nonce, nonce_len); /* No AAD, but for CCM need to set crypt_len. */ gcry_cipher_setaad (hd, NULL, 0, inbuf_len_1 + inbuf_len_2); <-- cannot initialize CBC-MAC, needs tag_len. /* Do encryption. */ gcry_cipher_encrypt (hd, outbuf_1, outbuf_len_1, inbuf_1, inbuf_len_1); /* More data... */ gcry_cipher_encrypt (hd, outbuf_2, outbuf_len_2, inbuf_2, inbuf_len_2); /* Finalize and read tag. */ gcry_cipher_gettag (hd, tag, tag_len); With OCB, if AAD stays the same between messages, one can reuse the preprocessed HASH(Key, AAD). Following example would process three messages, where first two have same AAD and last one has zero length AAD. Does this look ok? OCB encryption: gcry_cipher_setkey (hd, key, key_len); /* Process packet/message #1. */ /* Set nonce. */ gcry_cipher_setiv (hd, nonce_1, nonce_len); /* Set AAD. */ gcry_cipher_setaad (hd, aad, aadlen, 0); /* Do encryption. */ gcry_cipher_encrypt (hd, outbuf_1, inbuf_len_1, inbuf_1, inbuf_len_1); /* Finalize and read tag. */ gcry_cipher_gettag (hd, tag_1, tag_len); /*** Process next packet/message, #2. */ /* Same key and AAD (preprocessed). */ /* Set next nonce. */ gcry_cipher_setiv (hd, nonce_2, nonce_len); /* Do encryption. */ gcry_cipher_encrypt (hd, outbuf_2, inbuf_len_2, inbuf_2, inbuf_len_2); /* Finalize and read tag. */ gcry_cipher_gettag (hd, tag_2, tag_len); /*** Process next packet/message, #3. */ /* Same key and new AAD (empty). */ /* Set next nonce. */ gcry_cipher_setiv (hd, nonce_3, nonce_len); /* Set/clear AAD. */ gcry_cipher_setaad (hd, NULL, 0, 0); /* Do encryption. */ gcry_cipher_encrypt (hd, outbuf_3, inbuf_len_3, inbuf_3, inbuf_len_3); /* Finalize and read tag. */ gcry_cipher_gettag (hd, tag_3, tag_len); -Jussi > > > > Shalom-Salam, > > Werner > > From jussi.kivilinna at iki.fi Wed Oct 16 13:49:13 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Wed, 16 Oct 2013 14:49:13 +0300 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> <87hacimytn.fsf@vigenere.g10code.de> <525E56C2.6060704@iki.fi> Message-ID: <525E7D39.4080407@iki.fi> On 16.10.2013 14:20, Dmitry Eremin-Solenikov wrote: > Hello, > > On Wed, Oct 16, 2013 at 1:05 PM, Jussi Kivilinna wrote: >> On 15.10.2013 16:46, Werner Koch wrote: >>> On Mon, 14 Oct 2013 13:20, jussi.kivilinna at iki.fi said: >>> >>>> gcry_cipher_authenticate (hd, aadbuf, aadbuflen) >>>> >>>> which does the actual MAC initialization. If aadbuflen == 0, then >>>> above call can be omitted and gcry_cipher_(en|de)crypt will call >>>> gcry_cipher_authenticate with zero length. >>> >>> What about extending this fucntion to also take the authentication tag >>> and, if the plaintext length is required for the MAC setup, also that >>> length? That would group the information together. >> >> Ok, so we'd have >> gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, >> count void *tag, size_t taglen, size_t crypt_len) >> >> For encryption, tag is NULL pointer and taglen is zero and after encryption >> authentication tag can be read with 'gcry_cipher_tag'. For decryption, tag >> is given for authentication check with above function. > > Hmm. That would require for the tag to be stored in the context to be validated > after we process all enciphered data. I would suggest to move tag validation > to upper layer: > > * setiv/setkey/etc. > * authenticate(AAD, crypt_len) > * while (has_data) enc_data = encrypt(data) > * tag = tag() -> returns tag for AAD and passed data > Upper layer passes AAD, enc_data and tag to other side. > > Upper layer received AAD, enc_data, and tag > * setiv/setkey/etc > * authenticate(AAD, crypt_len) > * while (has_enc_data) data = decrypt(enc_data) > * new_tag = tag() -> returns tag for AAD and unencrypted data > Then upper layer can compare tag with new_tag and thus verify that data > is authenticated. What do you think? > > BTW: Looking at GCM/GMAC I have the feeling that single > authenticate() might be enough for now (and should be enough for > e.g. TLS), but in future to support GMAC (GCM working in auth-only mode, > no crypto data) we might want to support several sequential authenticate() > calls (if all of them come before first encrypt()/decrypt() call). > I've been looking at adding CMAC to libgcrypt, maybe gcry_cipher_authenticate() could be used for this too. -Jussi From wk at gnupg.org Wed Oct 16 15:18:32 2013 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Oct 2013 15:18:32 +0200 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <525E77DB.8030402@iki.fi> (Jussi Kivilinna's message of "Wed, 16 Oct 2013 14:26:19 +0300") References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> <87hacimytn.fsf@vigenere.g10code.de> <525E56C2.6060704@iki.fi> <87eh7llg8f.fsf@vigenere.g10code.de> <525E77DB.8030402@iki.fi> Message-ID: <87txghjqvr.fsf@vigenere.g10code.de> On Wed, 16 Oct 2013 13:26, jussi.kivilinna at iki.fi said: > I started writing following example to check is for CCM would work with > these. Problem here is that CCM needs authentication tag length for > first CBC-MAC block. Maybe taglen could be given to CCM mode encryption > with gcry_cipher_settag(hd, NULL, taglen)? Yes, I think this is okay. > With OCB, if AAD stays the same between messages, one can reuse the > preprocessed HASH(Key, AAD). Following example would process three messages, > where first two have same AAD and last one has zero length AAD. Does this > look ok? Yes. We may eventually put such examples into the manual. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From cvs at cvs.gnupg.org Wed Oct 16 16:36:37 2013 From: cvs at cvs.gnupg.org (by Dmitry Eremin-Solenikov) Date: Wed, 16 Oct 2013 16:36:37 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-312-g83902f1 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 83902f1f1dbc8263a0c3f61be59cd2eb95293c97 (commit) via 187b2bb541b985255aee262d181434a7cb4ae2e7 (commit) from a329b6abf00c990faf1986f9fbad7b4d71c13bcb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 83902f1f1dbc8263a0c3f61be59cd2eb95293c97 Author: Dmitry Eremin-Solenikov Date: Tue Oct 15 23:56:44 2013 +0400 ecc: Add support for GOST R 34.10-2001/-2012 signatures * src/cipher.h: define PUBKEY_FLAG_GOST * cipher/ecc-curves.c: Add GOST2001-test and GOST2012-test curves defined in standards. Typical applications would use either those curves, or curves defined in RFC 4357 (will be added later). * cipher/ecc.c (sign_gost, verify_gost): New. (ecc_sign, ecc_verify): use sign_gost/verify_gost if PUBKEY_FLAG_GOST is set. (ecc_names): add "gost" for gost signatures. * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist, _gcry_pk_util_preparse_sigval): set PUBKEY_FLAG_GOST if gost flag is present in s-exp. * tests/benchmark.c (ecc_bench): also benchmark GOST signatures. * tests/basic.c (check_pubkey): add two public keys from GOST R 34.10-2012 standard. (check_pubkey_sign_ecdsa): add two data sets to check gost signatures. * tests/curves.c: correct N_CURVES as we now have 2 more curves. Signed-off-by: Dmitry Eremin-Solenikov Removed some comments from the new curve definitions in ecc-curves.c to avoid line wrapping. Eventually we will develop a precompiler to avoid parsing those hex strings. -wk diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c index 2cdb9b4..fb0db3b 100644 --- a/cipher/ecc-curves.c +++ b/cipher/ecc-curves.c @@ -267,6 +267,34 @@ static const ecc_domain_parms_t domain_parms[] = "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111" "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892" }, + { + "GOST2001-test", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000431", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e", + "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3", + + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8", + }, + + { + "GOST2012-test", 511, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4" + "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc", + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df", + + "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762" + "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a", + "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2" + "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e", + }, { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL } }; diff --git a/cipher/ecc.c b/cipher/ecc.c index 1323d00..8b61ae4 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -71,6 +71,7 @@ static const char *ecc_names[] = "ecdsa", "ecdh", "eddsa", + "gost", NULL, }; @@ -575,6 +576,203 @@ verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey, return err; } +/* Compute an GOST R 34.10-01/-12 signature. + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R and S. + */ +static gpg_err_code_t +sign_gost (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t k, dr, sum, ke, x, e; + mpi_point_struct I; + gcry_mpi_t hash; + const void *abuf; + unsigned int abits, qbits; + mpi_ec_t ctx; + + if (DBG_CIPHER) + log_mpidump ("gost sign hash ", input ); + + qbits = mpi_get_nbits (skey->E.n); + + /* Convert the INPUT into an MPI if needed. */ + if (mpi_is_opaque (input)) + { + abuf = gcry_mpi_get_opaque (input, &abits); + err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, + abuf, (abits+7)/8, NULL)); + if (err) + return err; + if (abits > qbits) + gcry_mpi_rshift (hash, hash, abits - qbits); + } + else + hash = input; + + + k = NULL; + dr = mpi_alloc (0); + sum = mpi_alloc (0); + ke = mpi_alloc (0); + e = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&I); + + ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, + skey->E.p, skey->E.a, skey->E.b); + + mpi_mod (e, input, skey->E.n); /* e = hash mod n */ + + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + + /* Two loops to avoid R or S are zero. This is more of a joke than + a real demand because the probability of them being zero is less + than any hardware failure. Some specs however require it. */ + do + { + do + { + mpi_free (k); + k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); + + _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); + if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc sign: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (r, x, skey->E.n); /* r = x mod n */ + } + while (!mpi_cmp_ui (r, 0)); + mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ + mpi_mulm (ke, k, e, skey->E.n); /* ke = k*e mod n */ + mpi_addm (s, ke, dr, skey->E.n); /* sum = (k*e+ d*r) mod n */ + } + while (!mpi_cmp_ui (s, 0)); + + if (DBG_CIPHER) + { + log_mpidump ("gost sign result r ", r); + log_mpidump ("gost sign result s ", s); + } + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&I); + mpi_free (x); + mpi_free (e); + mpi_free (ke); + mpi_free (sum); + mpi_free (dr); + mpi_free (k); + + if (hash != input) + mpi_free (hash); + + return err; +} + +/* Verify a GOST R 34.10-01/-12 signature. + * Check if R and S verifies INPUT. + */ +static gpg_err_code_t +verify_gost (gcry_mpi_t input, ECC_public_key *pkey, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t e, x, z1, z2, v, rv, zero; + mpi_point_struct Q, Q1, Q2; + mpi_ec_t ctx; + + if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ + if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + x = mpi_alloc (0); + e = mpi_alloc (0); + z1 = mpi_alloc (0); + z2 = mpi_alloc (0); + v = mpi_alloc (0); + rv = mpi_alloc (0); + zero = mpi_alloc (0); + + point_init (&Q); + point_init (&Q1); + point_init (&Q2); + + ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, + pkey->E.p, pkey->E.a, pkey->E.b); + + mpi_mod (e, input, pkey->E.n); /* e = hash mod n */ + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + mpi_invm (v, e, pkey->E.n); /* v = e^(-1) (mod n) */ + mpi_mulm (z1, s, v, pkey->E.n); /* z1 = s*v (mod n) */ + mpi_mulm (rv, r, v, pkey->E.n); /* rv = s*v (mod n) */ + mpi_subm (z2, zero, rv, pkey->E.n); /* z2 = -r*v (mod n) */ + + _gcry_mpi_ec_mul_point (&Q1, z1, &pkey->E.G, ctx); +/* log_mpidump ("Q1.x", Q1.x); */ +/* log_mpidump ("Q1.y", Q1.y); */ +/* log_mpidump ("Q1.z", Q1.z); */ + _gcry_mpi_ec_mul_point (&Q2, z2, &pkey->Q, ctx); +/* log_mpidump ("Q2.x", Q2.x); */ +/* log_mpidump ("Q2.y", Q2.y); */ +/* log_mpidump ("Q2.z", Q2.z); */ + _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); +/* log_mpidump (" Q.x", Q.x); */ +/* log_mpidump (" Q.y", Q.y); */ +/* log_mpidump (" Q.z", Q.z); */ + + if (!mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Rejected\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ + if (mpi_cmp (x, r)) /* x != r */ + { + if (DBG_CIPHER) + { + log_mpidump (" x", x); + log_mpidump (" r", r); + log_mpidump (" s", s); + log_debug ("ecc verify: Not verified\n"); + } + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (DBG_CIPHER) + log_debug ("ecc verify: Accepted\n"); + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&Q2); + point_free (&Q1); + point_free (&Q); + mpi_free (zero); + mpi_free (rv); + mpi_free (v); + mpi_free (z2); + mpi_free (z1); + mpi_free (x); + mpi_free (e); + return err; +} static void @@ -1623,6 +1821,13 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = gcry_sexp_build (r_sig, NULL, "(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s); } + else if ((ctx.flags & PUBKEY_FLAG_GOST)) + { + rc = sign_gost (data, &sk, sig_r, sig_s); + if (!rc) + rc = gcry_sexp_build (r_sig, NULL, + "(sig-val(gost(r%M)(s%M)))", sig_r, sig_s); + } else { rc = sign_ecdsa (data, &sk, sig_r, sig_s, ctx.flags, ctx.hash_algo); @@ -1773,6 +1978,15 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { rc = verify_eddsa (data, &pk, sig_r, sig_s, ctx.hash_algo, mpi_q); } + else if ((sigflags & PUBKEY_FLAG_GOST)) + { + point_init (&pk.Q); + rc = _gcry_ecc_os2ec (&pk.Q, mpi_q); + if (rc) + goto leave; + + rc = verify_gost (data, &pk, sig_r, sig_s); + } else { point_init (&pk.Q); diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index 0b90054..0db5840 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -79,6 +79,11 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list, { flags |= PUBKEY_FLAG_ECDSA; } + else if (n == 4 && !memcmp (s, "gost", 4)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_GOST; + } else if (n == 3 && !memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN) { @@ -347,6 +352,8 @@ _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, { if (!strcmp (name, "eddsa")) *r_eccflags = PUBKEY_FLAG_EDDSA; + if (!strcmp (name, "gost")) + *r_eccflags = PUBKEY_FLAG_GOST; } *r_parms = l2; diff --git a/src/cipher.h b/src/cipher.h index 077af98..20818ba 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -37,6 +37,7 @@ #define PUBKEY_FLAG_USE_FIPS186_2 (1 << 8) #define PUBKEY_FLAG_ECDSA (1 << 9) #define PUBKEY_FLAG_EDDSA (1 << 10) +#define PUBKEY_FLAG_GOST (1 << 11) enum pk_operation diff --git a/tests/basic.c b/tests/basic.c index 991309a..1d6e637 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -3439,6 +3439,30 @@ check_pubkey_sign_ecdsa (int n, gcry_sexp_t skey, gcry_sexp_t pkey) /* */ "000102030405060708090A0B0C0D0E0F#))", 0 }, + { 256, + "(data (flags gost)\n" + " (value #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0, + "(data (flags gost)\n" + " (value #80112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0 + }, + { 512, + "(data (flags gost)\n" + " (value #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0, + "(data (flags gost)\n" + " (value #80112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F#))", + 0 + }, { 0, NULL } }; @@ -4021,6 +4045,57 @@ check_pubkey (void) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } + }, + { /* GOST R 34.10-2001/2012 test 256 bit. */ + GCRY_PK_ECDSA, FLAG_SIGN, + { + "(private-key\n" + " (ecc\n" + " (curve GOST2001-test)\n" + " (q #047F2B49E270DB6D90D8595BEC458B50C58585BA1D4E9B78" + " 8F6689DBD8E56FD80B26F1B489D6701DD185C8413A977B3C" + " BBAF64D1C593D26627DFFB101A87FF77DA#)\n" + " (d #7A929ADE789BB9BE10ED359DD39A72C11B60961F49397EEE" + " 1D19CE9891EC3B28#)))\n", + + "(public-key\n" + " (ecc\n" + " (curve GOST2001-test)\n" + " (q #047F2B49E270DB6D90D8595BEC458B50C58585BA1D4E9B78" + " 8F6689DBD8E56FD80B26F1B489D6701DD185C8413A977B3C" + " BBAF64D1C593D26627DFFB101A87FF77DA#)))\n", + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } + }, + { /* GOST R 34.10-2012 test 512 bit. */ + GCRY_PK_ECDSA, FLAG_SIGN, + { + "(private-key\n" + " (ecc\n" + " (curve GOST2012-test)\n" + " (q #04115DC5BC96760C7B48598D8AB9E740D4C4A85A65BE33C1" + " 815B5C320C854621DD5A515856D13314AF69BC5B924C8B" + " 4DDFF75C45415C1D9DD9DD33612CD530EFE137C7C90CD4" + " 0B0F5621DC3AC1B751CFA0E2634FA0503B3D52639F5D7F" + " B72AFD61EA199441D943FFE7F0C70A2759A3CDB84C114E" + " 1F9339FDF27F35ECA93677BEEC#)\n" + " (d #0BA6048AADAE241BA40936D47756D7C93091A0E851466970" + " 0EE7508E508B102072E8123B2200A0563322DAD2827E2714" + " A2636B7BFD18AADFC62967821FA18DD4#)))\n", + + "(public-key\n" + " (ecc\n" + " (curve GOST2001-test)\n" + " (q #04115DC5BC96760C7B48598D8AB9E740D4C4A85A65BE33C1" + " 815B5C320C854621DD5A515856D13314AF69BC5B924C8B" + " 4DDFF75C45415C1D9DD9DD33612CD530EFE137C7C90CD4" + " 0B0F5621DC3AC1B751CFA0E2634FA0503B3D52639F5D7F" + " B72AFD61EA199441D943FFE7F0C70A2759A3CDB84C114E" + " 1F9339FDF27F35ECA93677BEEC#)))\n" + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } } }; int i; diff --git a/tests/benchmark.c b/tests/benchmark.c index 5d1434a..ecda0d3 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -883,7 +883,8 @@ ecc_bench (int iterations, int print_header) { #if USE_ECC gpg_error_t err; - const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519" }; + const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519", + "gost256", "gost512" }; int testno; if (print_header) @@ -899,14 +900,22 @@ ecc_bench (int iterations, int print_header) int count; int p_size; int is_ed25519; + int is_gost; is_ed25519 = !strcmp (p_sizes[testno], "Ed25519"); + is_gost = !strncmp (p_sizes[testno], "gost", 4); if (is_ed25519) { p_size = 256; printf ("EdDSA Ed25519 "); fflush (stdout); } + else if (is_gost) + { + p_size = atoi (p_sizes[testno] + 4); + printf ("GOST %3d bit ", p_size); + fflush (stdout); + } else { p_size = atoi (p_sizes[testno]); @@ -917,6 +926,10 @@ ecc_bench (int iterations, int print_header) if (is_ed25519) err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecdsa (curve \"Ed25519\")))"); + else if (is_gost) + err = gcry_sexp_build (&key_spec, NULL, + "(genkey (ecdsa (curve %s)))", + p_size == 256 ? "GOST2001-test" : "GOST2012-test"); else err = gcry_sexp_build (&key_spec, NULL, "(genkey (ECDSA (nbits %d)))", p_size); @@ -950,6 +963,8 @@ ecc_bench (int iterations, int print_header) err = gcry_sexp_build (&data, NULL, "(data (flags eddsa)(hash-algo sha512)" " (value %m))", x); + else if (is_gost) + err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); else err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x); gcry_mpi_release (x); diff --git a/tests/curves.c b/tests/curves.c index 2c3ae53..198693e 100644 --- a/tests/curves.c +++ b/tests/curves.c @@ -29,7 +29,7 @@ #include "../src/gcrypt-int.h" /* Number of curves defined in ../cipger/ecc.c */ -#define N_CURVES 13 +#define N_CURVES 15 /* A real world sample public key. */ static char const sample_key_1[] = commit 187b2bb541b985255aee262d181434a7cb4ae2e7 Author: Dmitry Eremin-Solenikov Date: Tue Oct 15 23:56:43 2013 +0400 Fix 256-bit ecdsa test key definition * tests/basic.c (check_pubkey): fix nistp256 testing key declaration - add missing comma. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/tests/basic.c b/tests/basic.c index ee04900..991309a 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -4017,7 +4017,7 @@ check_pubkey (void) " (curve nistp256)\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2B" " EB6644D3609FC781B71F9A8072F58CB66AE2F89BB1245187" - " 3ABF7D91F9E1FBF96BF2F70E73AAC9A283#)))\n" + " 3ABF7D91F9E1FBF96BF2F70E73AAC9A283#)))\n", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } ----------------------------------------------------------------------- Summary of changes: cipher/ecc-curves.c | 28 +++++++ cipher/ecc.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++ cipher/pubkey-util.c | 7 ++ src/cipher.h | 1 + tests/basic.c | 77 +++++++++++++++++- tests/benchmark.c | 17 +++- tests/curves.c | 2 +- 7 files changed, 343 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From wk at gnupg.org Wed Oct 16 16:35:25 2013 From: wk at gnupg.org (Werner Koch) Date: Wed, 16 Oct 2013 16:35:25 +0200 Subject: [PATCH v2 2/2] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> (Dmitry Eremin-Solenikov's message of "Tue, 15 Oct 2013 23:56:44 +0400") References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> Message-ID: <87ppr5jnbm.fsf@vigenere.g10code.de> Hi, Thanks for the patches. I just pushed them. > + "GOST2001-test", 256, 0, What is the reason that you used the "-test" suffix? Is tehre a standard name for this curve? I am fine with GOSTxxxx, though. Shalom-Salam, Werner p.s. "make check" currently often fails in keygen. This is due to a problem with Ed25519 with ECDSA - I will look into that. -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From dbaryshkov at gmail.com Wed Oct 16 18:13:12 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Wed, 16 Oct 2013 20:13:12 +0400 Subject: [PATCH v2 2/2] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: <87ppr5jnbm.fsf@vigenere.g10code.de> References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> <87ppr5jnbm.fsf@vigenere.g10code.de> Message-ID: Hello, On Wed, Oct 16, 2013 at 6:35 PM, Werner Koch wrote: > Hi, > > Thanks for the patches. I just pushed them. > >> + "GOST2001-test", 256, 0, > > What is the reason that you used the "-test" suffix? Is tehre a standard > name for this curve? I am fine with GOSTxxxx, though. Because they are "test" curves defined by the GOST standards. RFC 4357 e.g. names the first curve as 'id-GostR3410-2001-TestParamSet' and tells that And adds that 'Use of the test parameter sets [...] is NOT RECOMMENDED.' Unfortunately these parameter sets are the only parameters defined by standard and thus they are used to verify implementation. > p.s. > "make check" currently often fails in keygen. This is due to a > problem with Ed25519 with ECDSA - I will look into that. And strangely enough it aborts in 50% of runs. Sometimes it does, sometimes it just outputs a note regarding testkey and and exits normally. I failed to capture a problem either via gdb or via valgrind. -- With best wishes Dmitry From cvs at cvs.gnupg.org Wed Oct 16 20:22:16 2013 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Wed, 16 Oct 2013 20:22:16 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-313-gc89ab92 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via c89ab921ccfaefe6c4f6a724d01e0df41a1a381f (commit) from 83902f1f1dbc8263a0c3f61be59cd2eb95293c97 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c89ab921ccfaefe6c4f6a724d01e0df41a1a381f Author: Jussi Kivilinna Date: Wed Oct 16 21:16:15 2013 +0300 Avoid void* pointer arithmetic * tests/tsexp.c (check_extract_param): Cast void* pointers to char* before doing arithmetics. -- GCC was complaining: tsexp.c: In function ?check_extract_param?: tsexp.c:938:44: warning: pointer of type ?void *? used in arithmetic [-Wpointer-arith] tsexp.c:944:46: warning: pointer of type ?void *? used in arithmetic [-Wpointer-arith] tsexp.c:955:44: warning: pointer of type ?void *? used in arithmetic [-Wpointer-arith] tsexp.c:961:46: warning: pointer of type ?void *? used in arithmetic [-Wpointer-arith] Signed-off-by: Jussi Kivilinna diff --git a/tests/tsexp.c b/tests/tsexp.c index 8a6b912..afa79ff 100644 --- a/tests/tsexp.c +++ b/tests/tsexp.c @@ -935,13 +935,14 @@ check_extract_param (void) fail ("gcry_sexp_extract_param/desc failed: A off changed"); else if (ioarray[1].len != 1) fail ("gcry_sexp_extract_param/desc failed: A has wrong length"); - else if (cmp_bufhex (ioarray[1].data + ioarray[1].off, ioarray[1].len, - sample1_a)) + else if (cmp_bufhex ((char *)ioarray[1].data + ioarray[1].off, + ioarray[1].len, sample1_a)) { fail ("gcry_sexp_extract_param/desc failed: A mismatch"); gcry_log_debug ("expected: %s\n", sample1_a); gcry_log_debughex (" got", - ioarray[1].data + ioarray[1].off, ioarray[1].len); + (char *)ioarray[1].data + ioarray[1].off, + ioarray[1].len); } if (!ioarray[2].data) @@ -952,13 +953,14 @@ check_extract_param (void) fail ("gcry_sexp_extract_param/desc failed: B off changed"); else if (ioarray[2].len != 32) fail ("gcry_sexp_extract_param/desc failed: B has wrong length"); - else if (cmp_bufhex (ioarray[2].data + ioarray[2].off, ioarray[2].len, - sample1_b)) + else if (cmp_bufhex ((char *)ioarray[2].data + ioarray[2].off, + ioarray[2].len, sample1_b)) { fail ("gcry_sexp_extract_param/desc failed: B mismatch"); gcry_log_debug ("expected: %s\n", sample1_b); gcry_log_debughex (" got", - ioarray[2].data + ioarray[2].off, ioarray[2].len); + (char *)ioarray[2].data + ioarray[2].off, + ioarray[2].len); } xfree (ioarray[0].data); ----------------------------------------------------------------------- Summary of changes: tests/tsexp.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From cvs at cvs.gnupg.org Wed Oct 16 21:40:36 2013 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Wed, 16 Oct 2013 21:40:36 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-314-gf9371c0 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via f9371c026aad09ff48746d22c8333746c886e773 (commit) from c89ab921ccfaefe6c4f6a724d01e0df41a1a381f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f9371c026aad09ff48746d22c8333746c886e773 Author: Jussi Kivilinna Date: Wed Oct 16 21:23:15 2013 +0300 arcfour: more optimized version for non-i386 architectures * cipher/arcfour.c (ARCFOUR_context): Reorder members. (do_encrypt_stream) [!__i386__]: Faster implementation for non-i386. (do_arcfour_setkey): Avoid modulo operations. -- Patch adds faster arcfour implementation for non-i386 architectures. New code is not activated on i386 as performance would regress. This is because i386 does not have enough registers hold new variables. Speed up on Intel i5-4570 (x86_64): 1.56x Speed up on ARM Cortex-A8: 1.18x Signed-off-by: Jussi Kivilinna diff --git a/cipher/arcfour.c b/cipher/arcfour.c index dc32b07..e8a5484 100644 --- a/cipher/arcfour.c +++ b/cipher/arcfour.c @@ -34,14 +34,39 @@ static const char *selftest(void); typedef struct { - int idx_i, idx_j; byte sbox[256]; + int idx_i, idx_j; } ARCFOUR_context; static void do_encrypt_stream( ARCFOUR_context *ctx, byte *outbuf, const byte *inbuf, unsigned int length ) { +#ifndef __i386__ + register unsigned int i = ctx->idx_i; + register byte j = ctx->idx_j; + register byte *sbox = ctx->sbox; + register byte t, u; + + while ( length-- ) + { + i++; + t = sbox[(byte)i]; + j += t; + u = sbox[j]; + sbox[(byte)i] = u; + u += t; + sbox[j] = t; + *outbuf++ = sbox[u] ^ *inbuf++; + } + + ctx->idx_i = (byte)i; + ctx->idx_j = (byte)j; +#else /*__i386__*/ + /* Old implementation of arcfour is faster on i386 than the version above. + * This is because version above increases register pressure which on i386 + * would push some of the variables to memory/stack. Therefore keep this + * version for i386 to avoid regressing performance. */ register int i = ctx->idx_i; register int j = ctx->idx_j; register byte *sbox = ctx->sbox; @@ -59,6 +84,7 @@ do_encrypt_stream( ARCFOUR_context *ctx, ctx->idx_i = i; ctx->idx_j = j; +#endif } static void @@ -96,17 +122,21 @@ do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) ctx->idx_i = ctx->idx_j = 0; for (i=0; i < 256; i++ ) ctx->sbox[i] = i; - for (i=0; i < 256; i++ ) - karr[i] = key[i%keylen]; + for (i=j=0; i < 256; i++,j++ ) + { + if (j >= keylen) + j = 0; + karr[i] = key[j]; + } for (i=j=0; i < 256; i++ ) { int t; - j = (j + ctx->sbox[i] + karr[i]) % 256; + j = (j + ctx->sbox[i] + karr[i]) & 255; t = ctx->sbox[i]; ctx->sbox[i] = ctx->sbox[j]; ctx->sbox[j] = t; } - memset( karr, 0, 256 ); + wipememory( karr, sizeof(karr) ); return GPG_ERR_NO_ERROR; } ----------------------------------------------------------------------- Summary of changes: cipher/arcfour.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From cvs at cvs.gnupg.org Wed Oct 16 16:23:13 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 16 Oct 2013 16:23:13 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-310-ga329b6a Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via a329b6abf00c990faf1986f9fbad7b4d71c13bcb (commit) from 45aa6131e93fac89d46733b3436d960f35fb99b2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a329b6abf00c990faf1986f9fbad7b4d71c13bcb Author: Werner Koch Date: Wed Oct 16 16:20:56 2013 +0200 sexp: Add function gcry_sexp_extract_param. * src/gcrypt.h.in (_GCRY_GCC_ATTR_SENTINEL): New. (gcry_sexp_extract_param): New. * src/visibility.c (gcry_sexp_extract_param): New. * src/visibility.h (gcry_sexp_extract_param): Add hack to detect internal use. * cipher/pubkey-util.c (_gcry_pk_util_extract_mpis): Move and split into ... * src/sexp.c (_gcry_sexp_vextract_param) (_gcry_sexp_extract_param): this. Change all callers. Add support for buffer descriptors and a path option/ * tests/tsexp.c (die, hex2buffer, hex2mpi, hex2mpiopa): New. (cmp_mpihex, cmp_bufhex): New. (check_extract_param): New. Signed-off-by: Werner Koch diff --git a/NEWS b/NEWS index ab326eb..d60e067 100644 --- a/NEWS +++ b/NEWS @@ -35,13 +35,13 @@ Noteworthy changes in version 1.6.0 (unreleased) * Added a scatter gather hash convenience function. - * Added several MPI helper functions. + * Added several MPI amd SEXP helper functions. * Added support for negative numbers to gcry_mpi_print, gcry_mpi_aprint and gcry_mpi_scan. * The algorithm ids GCRY_PK_ECDSA and GCRY_PK_ECDH are now - deprecated. Use GCRY_PK_ECC instead. + deprecated. Use GCRY_PK_ECC if you need an algorithm id. * Interface changes relative to the 1.5.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -108,6 +108,7 @@ Noteworthy changes in version 1.6.0 (unreleased) GCRYCTL_DISABLE_PRIV_DROP NEW. GCRY_CIPHER_SALSA20 NEW. gcry_sexp_nth_buffer NEW. + gcry_sexp_extract_param NEW. GCRY_CIPHER_SALSA20R12 NEW. GCRY_CIPHER_GOST28147 NEW. GCRY_MD_GOSTR3411_94 NEW. diff --git a/cipher/dsa.c b/cipher/dsa.c index e43bdf4..45ad97a 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -956,9 +956,9 @@ dsa_check_secret_key (gcry_sexp_t keyparms) gcry_err_code_t rc; DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; - rc = _gcry_pk_util_extract_mpis (keyparms, "pqgyx", - &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, + NULL); if (rc) goto leave; @@ -998,8 +998,8 @@ dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) log_mpidump ("dsa_sign data", data); /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pqgyx", - &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1065,7 +1065,7 @@ dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1075,8 +1075,8 @@ dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (s_keyparms, "pqgy", - &pk.p, &pk.q, &pk.g, &pk.y, NULL); + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy", + &pk.p, &pk.q, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c index 53433a2..2cdb9b4 100644 --- a/cipher/ecc-curves.c +++ b/cipher/ecc-curves.c @@ -436,9 +436,9 @@ _gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits) /* * Extract the curve parameters.. */ - if (_gcry_pk_util_extract_mpis (keyparms, "-pabgn", - &E.p, &E.a, &E.b, &mpi_g, &E.n, - NULL)) + if (_gcry_sexp_extract_param (keyparms, NULL, "-pabgn", + &E.p, &E.a, &E.b, &mpi_g, &E.n, + NULL)) goto leave; if (mpi_g) { diff --git a/cipher/ecc-misc.c b/cipher/ecc-misc.c index d89971f..fa0bded 100644 --- a/cipher/ecc-misc.c +++ b/cipher/ecc-misc.c @@ -55,6 +55,7 @@ _gcry_ecc_curve_copy (elliptic_curve_t E) R.model = E.model; R.dialect = E.dialect; + R.name = E.name; R.p = mpi_copy (E.p); R.a = mpi_copy (E.a); R.b = mpi_copy (E.b); diff --git a/cipher/ecc.c b/cipher/ecc.c index 3b75fea..1323d00 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1435,9 +1435,9 @@ ecc_check_secret_key (gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d", - &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, - &mpi_q, &sk.d, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &mpi_q, &sk.d, NULL); if (rc) goto leave; if (mpi_g) @@ -1552,9 +1552,9 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d", - &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, - &mpi_q, &sk.d, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &mpi_q, &sk.d, NULL); if (rc) goto leave; if (mpi_g) @@ -1686,9 +1686,9 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, - (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs", - &sig_r, &sig_s, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, + (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs", + &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1706,9 +1706,9 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (s_keyparms, "-p?a?b?g?n?/q?", - &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, - &mpi_q, NULL); + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "-p?a?b?g?n?/q?", + &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, + &mpi_q, NULL); if (rc) goto leave; if (mpi_g) @@ -1890,9 +1890,9 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+q", - &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, - &mpi_q, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+q", + &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, + &mpi_q, NULL); if (rc) goto leave; if (mpi_g) @@ -2044,7 +2044,7 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "e", &data_e, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "e", &data_e, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -2058,9 +2058,9 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) /* * Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+d", - &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, - &sk.d, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &sk.d, NULL); if (rc) goto leave; if (mpi_g) diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 691e122..432ba6f 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -735,9 +735,9 @@ elg_check_secret_key (gcry_sexp_t keyparms) gcry_err_code_t rc; ELG_secret_key sk = {NULL, NULL, NULL, NULL}; - rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx", - &sk.p, &sk.g, &sk.y, &sk.x, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); if (rc) goto leave; @@ -781,7 +781,8 @@ elg_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pgy", &pk.p, &pk.g, &pk.y, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -831,7 +832,7 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_encval (s_data, elg_names, &l1, &ctx); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "ab", &data_a, &data_b, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "ab", &data_a, &data_b, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -846,9 +847,9 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx", - &sk.p, &sk.g, &sk.y, &sk.x, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -940,8 +941,8 @@ elg_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx", - &sk.p, &sk.g, &sk.y, &sk.x, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1008,7 +1009,7 @@ elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, elg_names, &l1, NULL); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1018,8 +1019,8 @@ elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (s_keyparms, "pgy", - &pk.p, &pk.g, &pk.y, NULL); + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h index cb2721d..db1399d 100644 --- a/cipher/pubkey-internal.h +++ b/cipher/pubkey-internal.h @@ -28,9 +28,6 @@ gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits); gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e); -gpg_err_code_t _gcry_pk_util_extract_mpis (gcry_sexp_t sexp, - const char *list, ...) - GCC_ATTR_SENTINEL(0); gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, gcry_sexp_t *r_parms, diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index caf715e..0b90054 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -273,119 +273,6 @@ _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e) } -/* Extract MPIs from an s-expression using a list of one letter - * parameters. The names of these parameters are given by the string - * LIST. Some special characters may be given to control the - * conversion: - * - * + :: Switch to unsigned integer format (default). - * - :: Switch to standard signed format. - * / :: Switch to opaque format. - * ? :: The previous parameter is optional. - * - * For each parameter name a pointer to an MPI variable is expected - * and finally a NULL is expected. Example: - * - * _gcry_pk_util_extract_mpis (key, "n/x+ed", &mpi_n, &mpi_x, &mpi_e, NULL) - * - * This stores the parameter "N" from KEY as an unsigned MPI into - * MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the - * parameter "E" again as an unsigned MPI into MPI_E. - * - * The function returns NULL on success. On error an error code is - * returned and the passed MPIs are either unchanged or set to NULL. - */ -gpg_err_code_t -_gcry_pk_util_extract_mpis (gcry_sexp_t sexp, const char *list, ...) -{ - va_list arg_ptr; - const char *s; - gcry_mpi_t *array[10]; - int idx; - gcry_sexp_t l1; - enum gcry_mpi_format mpifmt = GCRYMPI_FMT_USG; - - /* First copy all the args into an array. This is required so that - we are able to release already allocated MPIs if later an error - was found. */ - va_start (arg_ptr, list) ; - for (s=list, idx=0; *s && idx < DIM (array); s++) - { - if (*s == '+' || *s == '-' || *s == '/' || *s == '?') - ; - else - { - array[idx] = va_arg (arg_ptr, gcry_mpi_t *); - if (!array[idx]) - { - va_end (arg_ptr); - return GPG_ERR_INTERNAL; /* NULL pointer given. */ - } - idx++; - } - } - if (*s) - { - va_end (arg_ptr); - return GPG_ERR_INTERNAL; /* Too many list elements. */ - } - if (va_arg (arg_ptr, gcry_mpi_t *)) - { - va_end (arg_ptr); - return GPG_ERR_INTERNAL; /* Not enough list elemends. */ - } - va_end (arg_ptr); - - /* Now extract all parameters. */ - for (s=list, idx=0; *s; s++) - { - if (*s == '+') - mpifmt = GCRYMPI_FMT_USG; - else if (*s == '-') - mpifmt = GCRYMPI_FMT_STD; - else if (*s == '/') - mpifmt = GCRYMPI_FMT_HEX; /* Used to indicate opaque. */ - else if (*s == '?') - ; /* Only used via lookahead. */ - else - { - l1 = gcry_sexp_find_token (sexp, s, 1); - if (!l1 && s[1] == '?') - *array[idx] = NULL; /* Optional element not found. */ - else if (!l1) - { - while (idx--) - { - gcry_mpi_release (*array[idx]); - *array[idx] = NULL; - } - return GPG_ERR_NO_OBJ; /* List element not found. */ - } - else - { - if (mpifmt == GCRYMPI_FMT_HEX) - *array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1); - else - *array[idx] = gcry_sexp_nth_mpi (l1, 1, mpifmt); - gcry_sexp_release (l1); - if (!*array[idx]) - { - while (idx--) - { - gcry_mpi_release (*array[idx]); - *array[idx] = NULL; - } - return GPG_ERR_INV_OBJ; /* Conversion failed. */ - } - } - idx++; - } - } - - return 0; -} - - /* Parse a "sig-val" s-expression and store the inner parameter list at R_PARMS. ALGO_NAMES is used to verify that the algorithm in "sig-val" is valid. Returns 0 on success and stores a new list at diff --git a/cipher/rsa.c b/cipher/rsa.c index d4d2a0a..fed52a1 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -855,9 +855,9 @@ rsa_check_secret_key (gcry_sexp_t keyparms) RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; /* To check the key we need the optional parameters. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "nedpqu", - &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "nedpqu", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); if (rc) goto leave; @@ -902,7 +902,7 @@ rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -969,7 +969,7 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "a", &data, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "a", &data, NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -981,9 +981,9 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?", - &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "nedp?q?u?", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1125,9 +1125,9 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) } /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?", - &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, - NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "nedp?q?u?", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); if (rc) goto leave; if (DBG_CIPHER) @@ -1213,14 +1213,14 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) rc = _gcry_pk_util_preparse_sigval (s_sig, rsa_names, &l1, NULL); if (rc) goto leave; - rc = _gcry_pk_util_extract_mpis (l1, "s", &sig, NULL); + rc = _gcry_sexp_extract_param (l1, NULL, "s", &sig, NULL); if (rc) goto leave; if (DBG_CIPHER) log_printmpi ("rsa_verify sig", sig); /* Extract the key. */ - rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL); + rc = _gcry_sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL); if (rc) goto leave; if (DBG_CIPHER) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 79d4d74..473c484 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -3748,6 +3748,66 @@ this function to parse results of a public key function, you most likely want to use @code{GCRYMPI_FMT_USG}. @end deftypefun + at deftypefun gpg_error_t gcry_sexp_extract_param ( @ + @w{gcry_sexp_t @var{sexp}}, @ + @w{const char *@var{path}}, @ + @w{const char *@var{list}}, ...) + +Extract parameters from an S-expression using a list of single letter +parameter names. The names of these parameters are specified in +LIST. Some special characters may be given to control the +conversion: + + at table @samp + at item + +Switch to unsigned integer format (GCRYMPI_FMT_USG). This is the +default mode. + at item - +Switch to standard signed format (GCRYMPI_FMT_STD). + at item / +Switch to opaque MPI format. The resulting MPIs may not be used for +computations; see @code{gcry_mpi_get_opaque} for details. + at item & +Switch to buffer descriptor mode. See below for details. + at item ? +If immediately following a parameter letter, that parameter is +considered optional. + at end table + +Unless in buffer descriptor mode for each parameter name a pointer to +an @code{gcry_mpi_t} variable is expected finally followed by a @code{NULL}. +For example + at example + _gcry_sexp_extract_param (key, NULL, "n/x+ed", + &mpi_n, &mpi_x, &mpi_e, NULL) + at end example + +stores the parameter 'n' from @var{key} as an unsigned MPI into + at var{mpi_n}, the parameter 'x' as an opaque MPI into @var{mpi_x}, and +the parameter 'e' again as an unsigned MPI into @var{mpi_e}. + + at var{path} is an optional string used to locate a token. The +exclamation mark separated tokens are used via + at code{gcry_sexp_find_token} to find a start point inside the +S-expression. + +In buffer descriptor mode a pointer to a @code{gcry_buffer_t} +descriptor is expected instead of a pointer to an MPI. The caller may +use two different operation modes here: If the @var{data} field of the +provided descriptor is @code{NULL}, the function allocates a new +buffer and stores it at @var{data}; the other fields are set +accordingly with @var{off} set to 0. If @var{data} is not + at code{NULL}, the function assumes that the @var{data}, @var{size}, and + at var{off} fields specify a buffer where to but the value of the +respective parameter; on return the @var{len} field receives the +number of bytes copied to that buffer; in case the buffer is too +small, the function immediately returns with an error code (and + at var{len} is set to 0). + +The function returns NULL on success. On error an error code is +returned and the passed MPIs are either unchanged or set to NULL. + at end deftypefun + @c ********************************************************** @c ******************* MPIs ******** *********************** diff --git a/src/g10lib.h b/src/g10lib.h index c1ba2f7..3b09448 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -75,13 +75,6 @@ #define GCC_ATTR_UNUSED #endif -#if __GNUC__ >= 4 -# define GCC_ATTR_SENTINEL(a) __attribute__ ((sentinel(a))) -#else -# define GCC_ATTR_SENTINEL(a) -#endif - - /* Gettext macros. */ #define _(a) _gcry_gettext(a) @@ -382,6 +375,12 @@ gcry_err_code_t _gcry_sexp_vbuild (gcry_sexp_t *retsexp, size_t *erroff, const char *format, va_list arg_ptr); gcry_mpi_t _gcry_sexp_nth_opaque_mpi (gcry_sexp_t list, int number); char *_gcry_sexp_nth_string (const gcry_sexp_t list, int number); +gpg_err_code_t _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path, + const char *list, va_list arg_ptr); +gpg_err_code_t _gcry_sexp_extract_param (gcry_sexp_t sexp, + const char *path, + const char *list, + ...) _GCRY_GCC_ATTR_SENTINEL(0); /*-- fips.c --*/ diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 8646f43..64cc0e4 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -102,6 +102,10 @@ extern "C" { #define _GCRY_GCC_ATTR_PRINTF(f,a) __attribute__ ((format (printf,f,a))) +#if _GCRT_GCC_VERSION >= 40000 +#define _GCRY_GCC_ATTR_SENTINEL(a) __attribute__ ((sentinel(a))) +#endif + #endif /*__GNUC__*/ #ifndef _GCRY_GCC_ATTR_DEPRECATED @@ -114,7 +118,10 @@ extern "C" { #define _GCRY_GCC_ATTR_MALLOC #endif #ifndef _GCRY_GCC_ATTR_PRINTF -#define _GCRY_GCC_ATTR_PRINTF +#define _GCRY_GCC_ATTR_PRINTF(f,a) +#endif +#ifndef _GCRY_GCC_ATTR_SENTINEL +#define _GCRY_GCC_ATTR_SENTINEL(a) #endif /* Make up an attribute to mark functions and types as deprecated but @@ -459,6 +466,12 @@ char *gcry_sexp_nth_string (gcry_sexp_t list, int number); value can't be converted to an MPI, `NULL' is returned. */ gcry_mpi_t gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt); +/* Convenience fucntion to extract parameters from an S-expression + * using a list of single letter parameters. */ +gpg_error_t gcry_sexp_extract_param (gcry_sexp_t sexp, + const char *path, + const char *list, + ...) _GCRY_GCC_ATTR_SENTINEL(0); /******************************************* diff --git a/src/libgcrypt.def b/src/libgcrypt.def index 7efb3b9..ec0c1e3 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -253,5 +253,8 @@ EXPORTS gcry_log_debugpnt @223 gcry_log_debugsxp @224 + gcry_sexp_extract_param @225 + + ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index b1669fd..be72aad 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -76,7 +76,7 @@ GCRYPT_1.6 { gcry_sexp_new; gcry_sexp_nth; gcry_sexp_nth_buffer; gcry_sexp_nth_data; gcry_sexp_nth_mpi; gcry_sexp_prepend; gcry_sexp_release; gcry_sexp_sprint; gcry_sexp_sscan; gcry_sexp_vlist; - gcry_sexp_nth_string; + gcry_sexp_nth_string; gcry_sexp_extract_param; gcry_mpi_is_neg; gcry_mpi_neg; gcry_mpi_abs; gcry_mpi_add; gcry_mpi_add_ui; gcry_mpi_addm; gcry_mpi_aprint; diff --git a/src/sexp.c b/src/sexp.c index 6a2a9be..6e4ff27 100644 --- a/src/sexp.c +++ b/src/sexp.c @@ -2117,3 +2117,238 @@ gcry_sexp_canon_len (const unsigned char *buffer, size_t length, } } } + + +/* Extract MPIs from an s-expression using a list of one letter + * parameters. The names of these parameters are given by the string + * LIST. Some special characters may be given to control the + * conversion: + * + * + :: Switch to unsigned integer format (default). + * - :: Switch to standard signed format. + * / :: Switch to opaque format. + * & :: Switch to buffer descriptor mode - see below. + * ? :: The previous parameter is optional. + * + * Unless in gcry_buffer_t mode for each parameter name a pointer to + * an MPI variable is expected and finally a NULL is expected. + * Example: + * + * _gcry_sexp_extract_param (key, NULL, "n/x+ed", + * &mpi_n, &mpi_x, &mpi_e, NULL) + * + * This stores the parameter "N" from KEY as an unsigned MPI into + * MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the + * parameter "E" again as an unsigned MPI into MPI_E. + * + * If in buffer descriptor mode a pointer to gcry_buffer_t descriptor + * is expected instead of a pointer to an MPI. The caller may use two + * different operation modes: If the DATA field of the provided buffer + * descriptor is NULL, the function allocates a new buffer and stores + * it at DATA; the other fields are set accordingly with OFF being 0. + * If DATA is not NULL, the function assumes that DATA, SIZE, and OFF + * describe a buffer where to but the data; on return the LEN field + * receives the number of bytes copied to that buffer; if the buffer + * is too small, the function immediately returns with an error code + * (and LEN set to 0). + * + * PATH is an optional string used to locate a token. The exclamation + * mark separated tokens are used to via gcry_sexp_find_token to find + * a start point inside SEXP. + * + * The function returns NULL on success. On error an error code is + * returned and the passed MPIs are either unchanged or set to NULL. + */ +gpg_err_code_t +_gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path, + const char *list, va_list arg_ptr) +{ + gpg_err_code_t rc; + const char *s; + gcry_mpi_t *array[20]; + char arrayisdesc[20]; + int idx; + gcry_sexp_t l1; + int mode = '+'; /* Default to GCRYMPI_FMT_USG. */ + gcry_sexp_t freethis = NULL; + + memset (arrayisdesc, 0, sizeof arrayisdesc); + + /* First copy all the args into an array. This is required so that + we are able to release already allocated MPIs if later an error + was found. */ + for (s=list, idx=0; *s && idx < DIM (array); s++) + { + if (*s == '&' || *s == '+' || *s == '-' || *s == '/' || *s == '?' ) + ; + else + { + array[idx] = va_arg (arg_ptr, gcry_mpi_t *); + if (!array[idx]) + return GPG_ERR_MISSING_VALUE; /* NULL pointer given. */ + idx++; + } + } + if (*s) + return GPG_ERR_LIMIT_REACHED; /* Too many list elements. */ + if (va_arg (arg_ptr, gcry_mpi_t *)) + return GPG_ERR_INV_ARG; /* Not enough list elemends. */ + + /* Drill down. */ + while (path && *path) + { + size_t n; + + s = strchr (path, '!'); + if (s == path) + { + rc = GPG_ERR_NOT_FOUND; + goto cleanup; + } + n = s? s - path : 0; + l1 = gcry_sexp_find_token (sexp, path, n); + if (!l1) + { + rc = GPG_ERR_NOT_FOUND; + goto cleanup; + } + sexp = l1; l1 = NULL; + gcry_sexp_release (freethis); + freethis = sexp; + if (n) + path += n + 1; + else + path = NULL; + } + + + /* Now extract all parameters. */ + for (s=list, idx=0; *s; s++) + { + if (*s == '&' || *s == '+' || *s == '-' || *s == '/') + mode = *s; + else if (*s == '?') + ; /* Only used via lookahead. */ + else + { + l1 = gcry_sexp_find_token (sexp, s, 1); + if (!l1 && s[1] == '?') + { + /* Optional element not found. */ + if (mode == '&') + { + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + if (!spec->data) + { + spec->size = 0; + spec->off = 0; + } + spec->len = 0; + } + else + *array[idx] = NULL; + } + else if (!l1) + { + rc = GPG_ERR_NO_OBJ; /* List element not found. */ + goto cleanup; + } + else + { + if (mode == '&') + { + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + + if (spec->data) + { + const char *pbuf; + size_t nbuf; + + pbuf = gcry_sexp_nth_data (l1, 1, &nbuf); + if (!pbuf || !nbuf) + { + rc = GPG_ERR_INV_OBJ; + goto cleanup; + } + if (spec->off + nbuf > spec->size) + { + rc = GPG_ERR_BUFFER_TOO_SHORT; + goto cleanup; + } + memcpy ((char*)spec->data + spec->off, pbuf, nbuf); + spec->len = nbuf; + arrayisdesc[idx] = 1; + } + else + { + spec->data = gcry_sexp_nth_buffer (l1, 1, &spec->size); + if (!spec->data) + { + rc = GPG_ERR_INV_OBJ; /* Or out of core. */ + goto cleanup; + } + spec->len = spec->size; + spec->off = 0; + arrayisdesc[idx] = 2; + } + } + else if (mode == '/') + *array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1); + else if (mode == '-') + *array[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_STD); + else + *array[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l1); l1 = NULL; + if (!*array[idx]) + { + rc = GPG_ERR_INV_OBJ; /* Conversion failed. */ + goto cleanup; + } + } + idx++; + } + } + + gcry_sexp_release (freethis); + return 0; + + cleanup: + gcry_sexp_release (freethis); + gcry_sexp_release (l1); + while (idx--) + { + if (!arrayisdesc[idx]) + { + gcry_mpi_release (*array[idx]); + *array[idx] = NULL; + } + else if (!arrayisdesc[idx] == 1) + { + /* Caller provided buffer. */ + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + spec->len = 0; + } + else + { + /* We might have allocated a buffer. */ + gcry_buffer_t *spec = (gcry_buffer_t*)array[idx]; + gcry_free (spec->data); + spec->data = NULL; + spec->size = spec->off = spec->len = 0; + } + } + return rc; +} + +gpg_error_t +_gcry_sexp_extract_param (gcry_sexp_t sexp, const char *path, + const char *list, ...) +{ + gcry_err_code_t rc; + va_list arg_ptr; + + va_start (arg_ptr, list); + rc = _gcry_sexp_vextract_param (sexp, path, list, arg_ptr); + va_end (arg_ptr); + return gpg_error (rc); +} diff --git a/src/visibility.c b/src/visibility.c index 6e3c755..848925e 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -250,6 +250,21 @@ gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt) return _gcry_sexp_nth_mpi (list, number, mpifmt); } +gpg_error_t +gcry_sexp_extract_param (gcry_sexp_t sexp, const char *path, + const char *list, ...) +{ + gcry_err_code_t rc; + va_list arg_ptr; + + va_start (arg_ptr, list); + rc = _gcry_sexp_vextract_param (sexp, path, list, arg_ptr); + va_end (arg_ptr); + return gpg_error (rc); +} + + + gcry_mpi_t gcry_mpi_new (unsigned int nbits) { diff --git a/src/visibility.h b/src/visibility.h index cd2a60f..1c8f047 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -537,6 +537,7 @@ MARK_VISIBLE (gcry_sexp_release) MARK_VISIBLE (gcry_sexp_sprint) MARK_VISIBLE (gcry_sexp_sscan) MARK_VISIBLE (gcry_sexp_vlist) +MARK_VISIBLEX(gcry_sexp_extract_param) MARK_VISIBLEX(gcry_mpi_abs) MARK_VISIBLE (gcry_mpi_add) @@ -615,6 +616,16 @@ MARK_VISIBLEX(_gcry_mpi_get_const) #undef MARK_VISIBLE -#endif /*_GCRY_INCLUDED_BY_VISIBILITY_C*/ +#else /*!_GCRY_INCLUDED_BY_VISIBILITY_C*/ + +/* To avoid accidental use of the public functions inside Libgcrypt, + we redefine them to catch such errors. The usual difference + between a public and an internal version is that the internal + version use gpg_err_code_t and the public version gpg_error_t. */ + +#define gcry_sexp_extract_param _gcry_USE_THE_UNDERSCORED_FUNCTION + + +#endif /*!_GCRY_INCLUDED_BY_VISIBILITY_C*/ #endif /*GCRY_VISIBILITY_H*/ diff --git a/tests/tsexp.c b/tests/tsexp.c index 7c4f7c8..8a6b912 100644 --- a/tests/tsexp.c +++ b/tests/tsexp.c @@ -25,14 +25,48 @@ #include #include #include +#include #include "../src/gcrypt-int.h" #define PGMNAME "tsexp" +#ifndef DIM +# define DIM(v) (sizeof(v)/sizeof((v)[0])) +#endif +#define my_isascii(c) (!((c) & 0x80)) +#define digitp(p) (*(p) >= '0' && *(p) <= '9') +#define hexdigitp(a) (digitp (a) \ + || (*(a) >= 'A' && *(a) <= 'F') \ + || (*(a) >= 'a' && *(a) <= 'f')) +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define xmalloc(a) gcry_xmalloc ((a)) +#define xcalloc(a,b) gcry_xcalloc ((a),(b)) +#define xstrdup(a) gcry_xstrdup ((a)) +#define xfree(a) gcry_free ((a)) +#define pass() do { ; } while (0) + + static int verbose; static int error_count; static void +die (const char *format, ...) +{ + va_list arg_ptr ; + + fflush (stdout); + fprintf (stderr, "%s: ", PGMNAME); + va_start( arg_ptr, format ) ; + vfprintf (stderr, format, arg_ptr ); + va_end(arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); + exit (1); +} + +static void info (const char *format, ...) { va_list arg_ptr; @@ -42,6 +76,8 @@ info (const char *format, ...) va_start( arg_ptr, format ) ; vfprintf (stderr, format, arg_ptr ); va_end(arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); } } @@ -54,10 +90,110 @@ fail ( const char *format, ... ) va_start( arg_ptr, format ) ; vfprintf (stderr, format, arg_ptr ); va_end(arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); error_count++; } + +/* Convert STRING consisting of hex characters into its binary + representation and return it as an allocated buffer. The valid + length of the buffer is returned at R_LENGTH. The string is + delimited by end of string. The function returns NULL on + error. */ +static void * +hex2buffer (const char *string, size_t *r_length) +{ + const char *s; + unsigned char *buffer; + size_t length; + + buffer = xmalloc (strlen(string)/2+1); + length = 0; + for (s=string; *s; s +=2 ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + return NULL; /* Invalid hex digits. */ + ((unsigned char*)buffer)[length++] = xtoi_2 (s); + } + *r_length = length; + return buffer; +} + + +static gcry_mpi_t +hex2mpi (const char *string) +{ + gpg_error_t err; + gcry_mpi_t val; + + err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (err) + die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err)); + return val; +} + +static gcry_mpi_t +hex2mpiopa (const char *string) +{ + char *buffer; + size_t buflen; + gcry_mpi_t val; + + buffer = hex2buffer (string, &buflen); + if (!buffer) + die ("hex2mpiopa '%s' failed: parser error\n", string); + val = gcry_mpi_set_opaque (NULL, buffer, buflen*8); + if (!buffer) + die ("hex2mpiopa '%s' failed: set_opaque error%s\n", string); + return val; +} + + +/* Compare A to B, where B is given as a hex string. */ +static int +cmp_mpihex (gcry_mpi_t a, const char *b) +{ + gcry_mpi_t bval; + int res; + + if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + bval = hex2mpiopa (b); + else + bval = hex2mpi (b); + res = gcry_mpi_cmp (a, bval); + gcry_mpi_release (bval); + return res; +} + +/* Compare A to B, where A is a buffer and B a hex string. */ +static int +cmp_bufhex (const void *a, size_t alen, const char *b) +{ + void *bbuf; + size_t blen; + int res; + + if (!a && !b) + return 0; + if (a && !b) + return 1; + if (!a && b) + return -1; + + bbuf = hex2buffer (b, &blen); + if (!bbuf) + die ("cmp_bufhex: error converting hex string\n"); + if (alen != blen) + return alen < blen? -1 : 1; + res = memcmp (a, bbuf, alen); + xfree (bbuf); + return res; +} + + + /* fixme: we need better tests */ static void basic (void) @@ -195,7 +331,7 @@ basic (void) fail ("no car for `%s'\n", token); continue; } - info ("car=`%.*s'\n", (int)n, p); + /* info ("car=`%.*s'\n", (int)n, p); */ s2 = gcry_sexp_cdr (s1); if (!s2) @@ -230,7 +366,7 @@ basic (void) fail("no car for `%s'\n", parm ); continue; } - info ("car=`%.*s'\n", (int)n, p); + /* info ("car=`%.*s'\n", (int)n, p); */ p = gcry_sexp_nth_data (s2, 1, &n); if (!p) { @@ -238,7 +374,7 @@ basic (void) fail("no cdr for `%s'\n", parm ); continue; } - info ("cdr=`%.*s'\n", (int)n, p); + /* info ("cdr=`%.*s'\n", (int)n, p); */ a = gcry_sexp_nth_mpi (s2, 0, GCRYMPI_FMT_USG); gcry_sexp_release (s2); @@ -457,6 +593,379 @@ check_sscan (void) } +static void +check_extract_param (void) +{ + /* This sample data is a real key but with some parameters of the + public key modified. */ + static char sample1[] = + "(key-data" + " (public-key" + " (ecc" + " (curve Ed25519)" + " (p #6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" + " (a #EF#)" + " (b #C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" + " (g #14" + " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + " 6666666666666666666666666666666666666666666666666666666666666658#)" + " (n #0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" + " (q #20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" + "))" + " (private-key" + " (ecc" + " (curve Ed25519)" + " (p #7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" + " (a #FF#)" + " (b #D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" + " (g #04" + " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + " 6666666666666666666666666666666666666666666666666666666666666658#)" + " (n #1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" + " (q #30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" + " (d #56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276#)" + ")))"; + + static char sample1_p[] = + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; + static char sample1_px[] = + "6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; + static char sample1_a[] = "FF"; + static char sample1_ax[] = "EF"; + static char sample1_b[] = + "D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; + static char sample1_bx[] = + "C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; + static char sample1_g[] = + "04" + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + "6666666666666666666666666666666666666666666666666666666666666658"; + static char sample1_gx[] = + "14" + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + "6666666666666666666666666666666666666666666666666666666666666658"; + static char sample1_n[] = + "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; + static char sample1_nx[] = + "0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; + static char sample1_q[] = + "30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; + static char sample1_qx[] = + "20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; + static char sample1_d[] = + "56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276"; + + static struct { + const char *sexp_str; + const char *path; + const char *list; + int nparam; + gpg_err_code_t expected_err; + const char *exp_p; + const char *exp_a; + const char *exp_b; + const char *exp_g; + const char *exp_n; + const char *exp_q; + const char *exp_d; + } tests[] = { + { + sample1, + NULL, + "pabgnqd", 6, + GPG_ERR_MISSING_VALUE, + }, + { + sample1, + NULL, + "pabgnq", 7, + GPG_ERR_INV_ARG + }, + { + sample1, + NULL, + "pabgnqd", 7, + 0, + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + NULL, + "abg", 3, + 0, + sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "x?abg", 4, + 0, + NULL, sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "p?abg", 4, + GPG_ERR_USER_1, + NULL, sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "pax?gnqd", 7, + 0, + sample1_px, sample1_ax, NULL, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + "public-key", + "pabgnqd", 7, + GPG_ERR_NO_OBJ, /* d is not in public key. */ + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + "private-key", + "pabgnqd", 7, + 0, + sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + { + sample1, + "public-key!ecc", + "pabgnq", 6, + 0, + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx + }, + { + sample1, + "public-key!ecc!foo", + "pabgnq", 6, + GPG_ERR_NOT_FOUND + }, + { + sample1, + "public-key!!ecc", + "pabgnq", 6, + GPG_ERR_NOT_FOUND + }, + { + sample1, + "private-key", + "pa/bgnqd", 7, + 0, + sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + { + sample1, + "private-key", + "p-a+bgnqd", 7, + 0, + sample1_p, "-01", sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + {NULL} + }; + int idx, i; + const char *paramstr; + int paramidx; + gpg_error_t err; + gcry_sexp_t sxp; + gcry_mpi_t mpis[7]; + gcry_buffer_t ioarray[7]; + char iobuffer[200]; + + info ("checking gcry_sexp_extract_param\n"); + for (idx=0; tests[idx].sexp_str; idx++) + { + err = gcry_sexp_new (&sxp, tests[idx].sexp_str, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + memset (mpis, 0, sizeof mpis); + switch (tests[idx].nparam) + { + case 0: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + NULL); + break; + case 1: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, NULL); + break; + case 2: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, NULL); + break; + case 3: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, NULL); + break; + case 4: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, NULL); + break; + case 5: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + NULL); + break; + case 6: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + mpis+5, NULL); + break; + case 7: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + mpis+5, mpis+6, NULL); + break; + default: + die ("test %d: internal error", idx); + } + + if (tests[idx].expected_err + && tests[idx].expected_err != GPG_ERR_USER_1) + { + if (tests[idx].expected_err != gpg_err_code (err)) + fail ("gcry_sexp_extract_param test %d failed: " + "expected error '%s' - got '%s'", idx, + gpg_strerror (tests[idx].expected_err),gpg_strerror (err)); + + } + else if (err) + { + fail ("gcry_sexp_extract_param test %d failed: %s", + idx, gpg_strerror (err)); + } + else /* No error - check the extracted values. */ + { + for (paramidx=0; paramidx < DIM (mpis); paramidx++) + { + switch (paramidx) + { + case 0: paramstr = tests[idx].exp_p; break; + case 1: paramstr = tests[idx].exp_a; break; + case 2: paramstr = tests[idx].exp_b; break; + case 3: paramstr = tests[idx].exp_g; break; + case 4: paramstr = tests[idx].exp_n; break; + case 5: paramstr = tests[idx].exp_q; break; + case 6: paramstr = tests[idx].exp_d; break; + default: + die ("test %d: internal error: bad param %d", + idx, paramidx); + } + + if (tests[idx].expected_err == GPG_ERR_USER_1 + && mpis[paramidx] && !paramstr && paramidx == 0) + ; /* Okay Special case error for param 0. */ + else if (!mpis[paramidx] && !paramstr) + ; /* Okay. */ + else if (!mpis[paramidx] && paramstr) + fail ("test %d: value for param %d expected but not returned", + idx, paramidx); + else if (mpis[paramidx] && !paramstr) + fail ("test %d: value for param %d not expected", + idx, paramidx); + else if (cmp_mpihex (mpis[paramidx], paramstr)) + { + fail ("test %d: param %d mismatch", idx, paramidx); + gcry_log_debug ("expected: %s\n", paramstr); + gcry_log_debugmpi (" got", mpis[paramidx]); + } + else if (tests[idx].expected_err && paramidx == 0) + fail ("test %d: param %d: expected error '%s' - got 'Success'", + idx, paramidx, gpg_strerror (tests[idx].expected_err)); + } + + } + + for (i=0; i < DIM (mpis); i++) + gcry_mpi_release (mpis[i]); + gcry_sexp_release (sxp); + } + + info ("checking gcry_sexp_extract_param/desc\n"); + + memset (ioarray, 0, sizeof ioarray); + + err = gcry_sexp_new (&sxp, sample1, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + ioarray[1].size = sizeof iobuffer; + ioarray[1].data = iobuffer; + ioarray[1].off = 0; + ioarray[2].size = sizeof iobuffer; + ioarray[2].data = iobuffer; + ioarray[2].off = 50; + assert (ioarray[2].off < sizeof iobuffer); + err = gcry_sexp_extract_param (sxp, "key-data!private-key", "&pab", + ioarray+0, ioarray+1, ioarray+2, NULL); + if (err) + fail ("gcry_sexp_extract_param with desc failed: %s", gpg_strerror (err)); + else + { + if (!ioarray[0].data) + fail ("gcry_sexp_extract_param/desc failed: no P"); + else if (ioarray[0].size != 32) + fail ("gcry_sexp_extract_param/desc failed: P has wrong size"); + else if (ioarray[0].len != 32) + fail ("gcry_sexp_extract_param/desc failed: P has wrong length"); + else if (ioarray[0].off) + fail ("gcry_sexp_extract_param/desc failed: P has OFF set"); + else if (cmp_bufhex (ioarray[0].data, ioarray[0].len, sample1_p)) + { + fail ("gcry_sexp_extract_param/desc failed: P mismatch"); + gcry_log_debug ("expected: %s\n", sample1_p); + gcry_log_debughex (" got", ioarray[0].data, ioarray[0].len); + } + + if (!ioarray[1].data) + fail ("gcry_sexp_extract_param/desc failed: A buffer lost"); + else if (ioarray[1].size != sizeof iobuffer) + fail ("gcry_sexp_extract_param/desc failed: A size changed"); + else if (ioarray[1].off != 0) + fail ("gcry_sexp_extract_param/desc failed: A off changed"); + else if (ioarray[1].len != 1) + fail ("gcry_sexp_extract_param/desc failed: A has wrong length"); + else if (cmp_bufhex (ioarray[1].data + ioarray[1].off, ioarray[1].len, + sample1_a)) + { + fail ("gcry_sexp_extract_param/desc failed: A mismatch"); + gcry_log_debug ("expected: %s\n", sample1_a); + gcry_log_debughex (" got", + ioarray[1].data + ioarray[1].off, ioarray[1].len); + } + + if (!ioarray[2].data) + fail ("gcry_sexp_extract_param/desc failed: B buffer lost"); + else if (ioarray[2].size != sizeof iobuffer) + fail ("gcry_sexp_extract_param/desc failed: B size changed"); + else if (ioarray[2].off != 50) + fail ("gcry_sexp_extract_param/desc failed: B off changed"); + else if (ioarray[2].len != 32) + fail ("gcry_sexp_extract_param/desc failed: B has wrong length"); + else if (cmp_bufhex (ioarray[2].data + ioarray[2].off, ioarray[2].len, + sample1_b)) + { + fail ("gcry_sexp_extract_param/desc failed: B mismatch"); + gcry_log_debug ("expected: %s\n", sample1_b); + gcry_log_debughex (" got", + ioarray[2].data + ioarray[2].off, ioarray[2].len); + } + + xfree (ioarray[0].data); + } + + gcry_sexp_release (sxp); +} int @@ -472,6 +981,7 @@ main (int argc, char **argv) canon_len (); back_and_forth (); check_sscan (); + check_extract_param (); return error_count? 1:0; } ----------------------------------------------------------------------- Summary of changes: NEWS | 5 +- cipher/dsa.c | 16 +- cipher/ecc-curves.c | 6 +- cipher/ecc-misc.c | 1 + cipher/ecc.c | 38 ++-- cipher/elgamal.c | 27 +-- cipher/pubkey-internal.h | 3 - cipher/pubkey-util.c | 113 ---------- cipher/rsa.c | 26 +-- doc/gcrypt.texi | 60 ++++++ src/g10lib.h | 13 +- src/gcrypt.h.in | 15 +- src/libgcrypt.def | 3 + src/libgcrypt.vers | 2 +- src/sexp.c | 235 +++++++++++++++++++++ src/visibility.c | 15 ++ src/visibility.h | 13 +- tests/tsexp.c | 516 +++++++++++++++++++++++++++++++++++++++++++++- 18 files changed, 920 insertions(+), 187 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From dbaryshkov at gmail.com Wed Oct 16 23:05:36 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Thu, 17 Oct 2013 01:05:36 +0400 Subject: Question regarding GCM/block alignment Message-ID: Hello, While implementing/imroving GCM code, I have stumbled upon the following question/problem. My current code only supports encryption/decryption of data if data is submitted in full-blocksize quantities (except last data block of course). Manual vaguely mentions that 'Depending on the selected algorithms and encryption mode, the length of the buffers must be a multiple of the block size.' Should I add buffering of non-full blocks (by the cost of additional -- With best wishes Dmitry From dbaryshkov at gmail.com Wed Oct 16 23:38:54 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Thu, 17 Oct 2013 01:38:54 +0400 Subject: [PATCH] Drop _gcry_cipher_ofb_decrypt as it duplicates _gcry_cipher_ofb_encrypt Message-ID: <1381959534-14943-1-git-send-email-dbaryshkov@gmail.com> * cipher/cipher.c (cipher_decrypt): Use _gcry_cipher_ofb_encrypt for OFB decryption. * cipher/cipher-internal.h: Remove _gcry_cipher_ofb_decrypt declaration. * cipher/cipher-ofb.c (_gcry_cipher_ofb_decrypt): Remove. (_gcry_cipher_ofb_encrypt): remove copying of IV to lastiv, it's unused there. Signed-off-by: Dmitry Eremin-Solenikov --- cipher/cipher-internal.h | 4 --- cipher/cipher-ofb.c | 70 +----------------------------------------------- cipher/cipher.c | 2 +- 3 files changed, 2 insertions(+), 74 deletions(-) diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index b60ef38..95f9759 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -152,10 +152,6 @@ gcry_err_code_t _gcry_cipher_ofb_encrypt /* */ (gcry_cipher_hd_t c, unsigned char *outbuf, unsigned int outbuflen, const unsigned char *inbuf, unsigned int inbuflen); -gcry_err_code_t _gcry_cipher_ofb_decrypt -/* */ (gcry_cipher_hd_t c, - unsigned char *outbuf, unsigned int outbuflen, - const unsigned char *inbuf, unsigned int inbuflen); /*-- cipher-ctr.c --*/ gcry_err_code_t _gcry_cipher_ctr_encrypt diff --git a/cipher/cipher-ofb.c b/cipher/cipher-ofb.c index 3d9d54c..ab426bd 100644 --- a/cipher/cipher-ofb.c +++ b/cipher/cipher-ofb.c @@ -47,7 +47,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, { /* Short enough to be encoded by the remaining XOR mask. */ /* XOR the input with the IV */ - ivp = c->u_iv.iv + c->spec->blocksize - c->unused; + ivp = c->u_iv.iv + blocksize - c->unused; buf_xor(outbuf, ivp, inbuf, inbuflen); c->unused -= inbuflen; return 0; @@ -69,7 +69,6 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, while ( inbuflen >= blocksize ) { /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize); @@ -79,73 +78,6 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, } if ( inbuflen ) { /* process the remaining bytes */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - burn = nburn > burn ? nburn : burn; - c->unused = blocksize; - c->unused -= inbuflen; - buf_xor(outbuf, c->u_iv.iv, inbuf, inbuflen); - outbuf += inbuflen; - inbuf += inbuflen; - inbuflen = 0; - } - - if (burn > 0) - _gcry_burn_stack (burn + 4 * sizeof(void *)); - - return 0; -} - - -gcry_err_code_t -_gcry_cipher_ofb_decrypt (gcry_cipher_hd_t c, - unsigned char *outbuf, unsigned int outbuflen, - const unsigned char *inbuf, unsigned int inbuflen) -{ - unsigned char *ivp; - size_t blocksize = c->spec->blocksize; - unsigned int burn, nburn; - - if (outbuflen < inbuflen) - return GPG_ERR_BUFFER_TOO_SHORT; - - if( inbuflen <= c->unused ) - { - /* Short enough to be encoded by the remaining XOR mask. */ - ivp = c->u_iv.iv + blocksize - c->unused; - buf_xor(outbuf, ivp, inbuf, inbuflen); - c->unused -= inbuflen; - return 0; - } - - burn = 0; - - if ( c->unused ) - { - inbuflen -= c->unused; - ivp = c->u_iv.iv + blocksize - c->unused; - buf_xor(outbuf, ivp, inbuf, c->unused); - outbuf += c->unused; - inbuf += c->unused; - c->unused = 0; - } - - /* Now we can process complete blocks. */ - while ( inbuflen >= blocksize ) - { - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - burn = nburn > burn ? nburn : burn; - buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize); - outbuf += blocksize; - inbuf += blocksize; - inbuflen -= blocksize; - } - if ( inbuflen ) - { /* Process the remaining bytes. */ - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; c->unused = blocksize; diff --git a/cipher/cipher.c b/cipher/cipher.c index 75d42d1..a02affb 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -799,7 +799,7 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, break; case GCRY_CIPHER_MODE_OFB: - rc = _gcry_cipher_ofb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); break; case GCRY_CIPHER_MODE_CTR: -- 1.8.4.rc3 From wk at gnupg.org Thu Oct 17 08:43:03 2013 From: wk at gnupg.org (Werner Koch) Date: Thu, 17 Oct 2013 08:43:03 +0200 Subject: Question regarding GCM/block alignment In-Reply-To: (Dmitry Eremin-Solenikov's message of "Thu, 17 Oct 2013 01:05:36 +0400") References: Message-ID: <87mwm8ieiw.fsf@vigenere.g10code.de> On Wed, 16 Oct 2013 23:05, dbaryshkov at gmail.com said: > Should I add buffering of non-full blocks (by the cost of additional This is a long standing open question. Until known there has been no real requirement for this. Buffering should be put on top of the existing functions (probably by using a new flag for gcry_cipher_open). However, I think it is more important to stabilize the current API with all the changes we did for 1.6 and work towards a release of 1.6. Adding a few feature can be done later. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Thu Oct 17 08:44:51 2013 From: wk at gnupg.org (Werner Koch) Date: Thu, 17 Oct 2013 08:44:51 +0200 Subject: [PATCH v2 2/2] Add support for GOST R 34.10-2001/-2012 signatures In-Reply-To: (Dmitry Eremin-Solenikov's message of "Wed, 16 Oct 2013 20:13:12 +0400") References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> <87ppr5jnbm.fsf@vigenere.g10code.de> Message-ID: <87iowwiefw.fsf@vigenere.g10code.de> On Wed, 16 Oct 2013 18:13, dbaryshkov at gmail.com said: > Because they are "test" curves defined by the GOST standards. RFC 4357 > e.g. names the first curve as 'id-GostR3410-2001-TestParamSet' and tells that > And adds that 'Use of the test parameter sets [...] is NOT RECOMMENDED.' Funny standard. > And strangely enough it aborts in 50% of runs. Sometimes it does, sometimes > it just outputs a note regarding testkey and and exits normally. > I failed to capture a problem either via gdb or via valgrind. It is an algorithmic problem. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From cvs at cvs.gnupg.org Thu Oct 17 10:50:24 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 17 Oct 2013 10:50:24 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-315-gb224171 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via b22417158c50ec3a0b2ff55b4ade063b42a87e8f (commit) from f9371c026aad09ff48746d22c8333746c886e773 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b22417158c50ec3a0b2ff55b4ade063b42a87e8f Author: Werner Koch Date: Thu Oct 17 10:45:14 2013 +0200 ecc: Support Weierstrass curves in gcry_mpi_ec_curve_point. * mpi/ec.c (_gcry_mpi_ec_curve_point): Support MPI_EC_WEIERSTRASS. diff --git a/mpi/ec.c b/mpi/ec.c index 889df8e..39ab5eb 100644 --- a/mpi/ec.c +++ b/mpi/ec.c @@ -1216,8 +1216,23 @@ _gcry_mpi_ec_curve_point (gcry_mpi_point_t point, mpi_ec_t ctx) switch (ctx->model) { case MPI_EC_WEIERSTRASS: - log_fatal ("%s: %s not yet supported\n", - "_gcry_mpi_ec_curve_point", "Weierstrass"); + { + gcry_mpi_t xx = mpi_new (0); + + /* y^2 == x^3 + a?x^2 + b */ + ec_pow2 (y, y, ctx); + + ec_pow2 (xx, x, ctx); + ec_mulm (w, ctx->a, xx, ctx); + ec_addm (w, w, ctx->b, ctx); + ec_mulm (xx, xx, x, ctx); + ec_addm (w, w, xx, ctx); + + if (!mpi_cmp (y, w)) + res = 1; + + gcry_mpi_release (xx); + } break; case MPI_EC_MONTGOMERY: log_fatal ("%s: %s not yet supported\n", ----------------------------------------------------------------------- Summary of changes: mpi/ec.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From dbaryshkov at gmail.com Thu Oct 17 11:02:21 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Thu, 17 Oct 2013 13:02:21 +0400 Subject: Question regarding GCM/block alignment In-Reply-To: <87mwm8ieiw.fsf@vigenere.g10code.de> References: <87mwm8ieiw.fsf@vigenere.g10code.de> Message-ID: Hello, On Thu, Oct 17, 2013 at 10:43 AM, Werner Koch wrote: > On Wed, 16 Oct 2013 23:05, dbaryshkov at gmail.com said: > >> Should I add buffering of non-full blocks (by the cost of additional > > This is a long standing open question. Until known there has been no > real requirement for this. Buffering should be put on top of the > existing functions (probably by using a new flag for gcry_cipher_open). Ack. > > However, I think it is more important to stabilize the current API with > all the changes we did for 1.6 and work towards a release of 1.6. > Adding a few feature can be done later. Do you plan to merge AEAD support (GCM/CCM/whatever) before 1.6? Or we better postpone those modes till next release? -- With best wishes Dmitry From wk at gnupg.org Thu Oct 17 12:06:04 2013 From: wk at gnupg.org (Werner Koch) Date: Thu, 17 Oct 2013 12:06:04 +0200 Subject: Question regarding GCM/block alignment In-Reply-To: (Dmitry Eremin-Solenikov's message of "Thu, 17 Oct 2013 13:02:21 +0400") References: <87mwm8ieiw.fsf@vigenere.g10code.de> Message-ID: <87a9i8i54j.fsf@vigenere.g10code.de> On Thu, 17 Oct 2013 11:02, dbaryshkov at gmail.com said: > Do you plan to merge AEAD support (GCM/CCM/whatever) before 1.6? Yes. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From cvs at cvs.gnupg.org Fri Oct 18 13:09:01 2013 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Fri, 18 Oct 2013 13:09:01 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-318-gf7711e6 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via f7711e6eb5f02d03c74911f6f037ab28075e7c0d (commit) via 91e007606f1f6f8e1416c403fe809d47fddf9b1f (commit) via 4776dcd394ce59fa50d959921857b3427c5a63c8 (commit) from b22417158c50ec3a0b2ff55b4ade063b42a87e8f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f7711e6eb5f02d03c74911f6f037ab28075e7c0d Author: Werner Koch Date: Thu Oct 17 18:08:59 2013 +0200 tests: Add test options to keygen. * tests/keygen.c (usage): New. (main): Print usage info. Allow running just one algo. Signed-off-by: Werner Koch diff --git a/tests/keygen.c b/tests/keygen.c index 2b98c42..5ab8e9d 100644 --- a/tests/keygen.c +++ b/tests/keygen.c @@ -470,6 +470,19 @@ progress_cb (void *cb_data, const char *what, int printchar, } +static void +usage (int mode) +{ + fputs ("usage: " PGM " [options] [{rsa|elg|dsa|ecc|nonce}]\n" + "Options:\n" + " --verbose be verbose\n" + " --debug flyswatter\n" + " --progress print progress indicators\n", + mode? stderr : stdout); + if (mode) + exit (1); +} + int main (int argc, char **argv) { @@ -489,12 +502,7 @@ main (int argc, char **argv) } else if (!strcmp (*argv, "--help")) { - fputs ("usage: " PGM " [options]\n" - "Options:\n" - " --verbose be verbose\n" - " --debug flyswatter\n" - " --progress print progress indicators\n", - stdout); + usage (0); exit (0); } else if (!strcmp (*argv, "--verbose")) @@ -515,6 +523,8 @@ main (int argc, char **argv) } else if (!strncmp (*argv, "--", 2)) die ("unknown option '%s'", *argv); + else + break; } if (!gcry_check_version (GCRYPT_VERSION)) @@ -528,11 +538,30 @@ main (int argc, char **argv) if (with_progress) gcry_set_progress_handler (progress_cb, NULL); - check_rsa_keys (); - check_elg_keys (); - check_dsa_keys (); - check_ecc_keys (); - check_nonce (); + if (!argc) + { + check_rsa_keys (); + check_elg_keys (); + check_dsa_keys (); + check_ecc_keys (); + check_nonce (); + } + else + { + for (; argc; argc--, argv++) + if (!strcmp (*argv, "rsa")) + check_rsa_keys (); + else if (!strcmp (*argv, "elg")) + check_elg_keys (); + else if (!strcmp (*argv, "dsa")) + check_dsa_keys (); + else if (!strcmp (*argv, "ecc")) + check_ecc_keys (); + else if (!strcmp (*argv, "nonce")) + check_nonce (); + else + usage (1); + } return error_count? 1:0; } commit 91e007606f1f6f8e1416c403fe809d47fddf9b1f Author: Werner Koch Date: Thu Oct 17 18:07:28 2013 +0200 mpi: Do not clear the sign of the mpi_mod result. * mpi/mpi-mod.c (_gcry_mpi_mod): Remove sign setting. Signed-off-by: Werner Koch diff --git a/mpi/mpi-mod.c b/mpi/mpi-mod.c index 3d6248b..d48d7f4 100644 --- a/mpi/mpi-mod.c +++ b/mpi/mpi-mod.c @@ -47,7 +47,6 @@ void _gcry_mpi_mod (gcry_mpi_t rem, gcry_mpi_t dividend, gcry_mpi_t divisor) { _gcry_mpi_fdiv_r (rem, dividend, divisor); - rem->sign = 0; } commit 4776dcd394ce59fa50d959921857b3427c5a63c8 Author: Werner Koch Date: Thu Oct 17 18:01:48 2013 +0200 ecc: Put the curve name again into the output of gcry_pk_genkey. * cipher/ecc.c (ecc_generate): Use the correct var. Release CURVE_FLAGS. Signed-off-by: Werner Koch diff --git a/cipher/ecc.c b/cipher/ecc.c index 8b61ae4..6f3cbbd 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1568,7 +1568,7 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) if (ed25519_with_ecdsa) { - rc = gcry_sexp_build (&curve_info, NULL, "(flags ecdsa)"); + rc = gcry_sexp_build (&curve_flags, NULL, "(flags ecdsa)"); if (rc) goto leave; } @@ -1613,6 +1613,7 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) mpi_free (x); mpi_free (y); _gcry_mpi_ec_free (ctx); + gcry_sexp_release (curve_flags); gcry_sexp_release (curve_info); return rc; } ----------------------------------------------------------------------- Summary of changes: cipher/ecc.c | 3 ++- mpi/mpi-mod.c | 1 - tests/keygen.c | 51 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 42 insertions(+), 13 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From jussi.kivilinna at iki.fi Sat Oct 19 16:36:48 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sat, 19 Oct 2013 17:36:48 +0300 Subject: [RFC PATCH 2/3] Add API for initializing AEAD modes In-Reply-To: <87eh7llg8f.fsf@vigenere.g10code.de> References: <20131013100228.32014.526.stgit@localhost6.localdomain6> <20131013100233.32014.24561.stgit@localhost6.localdomain6> <87iox1phzg.fsf@vigenere.g10code.de> <525BD36A.9010507@iki.fi> <87hacimytn.fsf@vigenere.g10code.de> <525E56C2.6060704@iki.fi> <87eh7llg8f.fsf@vigenere.g10code.de> Message-ID: <52629900.7070501@iki.fi> On 16.10.2013 12:25, Werner Koch wrote: > On Wed, 16 Oct 2013 11:05, jussi.kivilinna at iki.fi said: > >> Ok, so we'd have >> gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, >> count void *tag, size_t taglen, size_t crypt_len) >> >> For encryption, tag is NULL pointer and taglen is zero and after encryption >> authentication tag can be read with 'gcry_cipher_tag'. For decryption, tag >> is given for authentication check with above function. > > A last idea: What about two functions > > gcry_cipher_settag () -- To be used before decryption > gcry_cipher_gettag () -- to be used after encryption. For some modes, gettag would need to be used to decryption too. For example, GCM does not need the encrypted data length before hand, so for decryption (and for encryption) one needs to mark end of encrypted data with gcry_cipher_gettag call. So we'd have GCM encryption as: gcry_cipher_setiv(h, nonce, noncelen); gcry_cipher_setaad(h, aad, addlen, 0); gcry_cipher_encrypt(h, buf1, len1, NULL, 0); gcry_cipher_encrypt(h, buf2, len2, NULL, 0); ... gcry_cipher_encrypt(h, bufX, lenX, NULL, 0); gcry_cipher_gettag(h, tag, 8); /* Mark end of data stream, output tag. */ and decryption: gcry_cipher_setiv(h, nonce, noncelen); gcry_cipher_setaad(h, aad, addlen, 0); gcry_cipher_settag(h, tag, 8); gcry_cipher_decrypt(h, buf1, len1, NULL, 0); gcry_cipher_decrypt(h, buf2, len2, NULL, 0); ... gcry_cipher_decrypt(h, bufX, lenX, NULL, 0); gcry_cipher_gettag(h, NULL, 0); /* Mark end of data stream, return 'checksum failed' if tags mismatch. */ So, renaming settag to checktag might be better: gcry_cipher_setiv(h, nonce, noncelen); gcry_cipher_setaad(h, aad, addlen, 0); gcry_cipher_decrypt(h, buf1, len1, NULL, 0); gcry_cipher_decrypt(h, buf2, len2, NULL, 0); ... gcry_cipher_decrypt(h, bufX, lenX, NULL, 0); gcry_cipher_checktag(h, tag, 8); /* Mark end of data stream, return 'checksum failed' if tags mismatch. */ But CCM would still need the tag length passed in before setaad. So do I add 'taglen' argument to setaad? Or just add gcry_cipher_ctl command to pass CCM specific values (encryptlen, taglen)? -Jussi > > gcry_cipher_set_tag would actually look prettier but we already use > setkey and setiv. Wit these fucntions > > gcry_cipher_authenticate (hd, const void *aadbuf, size_t aadbuflen, > size_t crypt_len) > > would be pretty easy to describe. And a very last idea: What about > renaming > > gcry_cipher_authenticate to gcry_cipher_setaad > > ? > > > > Shalom-Salam, > > Werner > > From jussi.kivilinna at iki.fi Sun Oct 20 14:03:13 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sun, 20 Oct 2013 15:03:13 +0300 Subject: [PATCH 1/2] [v2] Add API to support AEAD cipher modes Message-ID: <20131020120313.21970.15918.stgit@localhost6.localdomain6> * cipher/cipher.c (_gcry_cipher_setaad, _gcry_cipher_checktag) (_gcry_cipher_gettag): New. * doc/gcrypt.texi: Add documentation for new API functions. * src/visibility.c (gcry_cipher_setaad, gcry_cipher_checktag) (gcry_cipher_gettag): New. * src/gcrypt.h.in, src/visibility.h: add declarations of these functions. * src/libgcrypt.defs, src/libgcrypt.vers: export functions. -- Authenticated Encryption with Associated Data (AEAD) cipher modes provide authentication tag that can be used to authenticate message. At the same time it allows one to specify additional (unencrypted data) that will be authenticated together with the message. This class of cipher modes requires additional API present in this commit. This patch is based on original patch by Dmitry Eremin-Solenikov. Changes in v2: - Change gcry_cipher_tag to gcry_cipher_checktag and gcry_cipher_gettag for giving tag (checktag) for decryption and reading tag (gettag) after encryption. - Change gcry_cipher_authenticate to gcry_cipher_setaad, since additional parameters needed for some AEAD modes (in this case CCM, which needs the length of encrypted data and tag for MAC initialization). - Add some documentation. Signed-off-by: Jussi Kivilinna --- cipher/cipher.c | 36 ++++++++++++++++++++++++++++++++++++ doc/gcrypt.texi | 42 ++++++++++++++++++++++++++++++++++++++++++ src/gcrypt.h.in | 14 ++++++++++++++ src/libgcrypt.def | 3 +++ src/libgcrypt.vers | 1 + src/visibility.c | 28 ++++++++++++++++++++++++++++ src/visibility.h | 9 +++++++++ 7 files changed, 133 insertions(+) diff --git a/cipher/cipher.c b/cipher/cipher.c index 75d42d1..60f1f0e 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -910,6 +910,42 @@ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return 0; } +gcry_error_t +_gcry_cipher_setaad (gcry_cipher_hd_t hd, const void *aad, size_t aadlen, + size_t encryptedlen, size_t taglen) +{ + log_fatal ("gcry_cipher_setaad: invalid mode %d\n", hd->mode ); + + (void)aad; + (void)aadlen; + (void)encryptedlen; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode ); + + (void)outtag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode ); + + (void)intag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + gcry_error_t gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 473c484..1e5f414 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1731,6 +1731,10 @@ matches the requirement of the selected algorithm and mode. This function is also used with the Salsa20 stream cipher to set or update the required nonce. In this case it needs to be called after setting the key. + +This function is also used with the AEAD cipher modes to set or +update the required nonce. + @end deftypefun @deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, const void *@var{c}, size_t @var{l}) @@ -1750,6 +1754,44 @@ call to gcry_cipher_setkey and clear the initialization vector. Note that gcry_cipher_reset is implemented as a macro. @end deftypefun +Authenticated Encryption with Associated Data (AEAD) block cipher +modes require the handling of the authentication tag and the additional +authenticated data, which can be done by using the following +functions: + + at deftypefun gcry_error_t gcry_cipher_setaad (gcry_cipher_hd_t @var{h}, const void *@var{aad}, size_t @var{aadlen}, size_t @var{enclen}, size_t @var{taglen}) + +Process the buffer @var{aad} of length @var{aadlen} as the additional +authenticated data (AAD) for AEAD cipher modes. + +Some modes require more information at the beginning of operation; such +as the length of the data to be encrypted/decrypted or the length of +authentication tag. The length of encrypted data can be passed through + at var{enclen} and the length of authentication tag through @var{taglen}. +If currently used cipher mode does not require such information at the +early stages of the operation, these fields may be set to zero. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t @var{h}, void *@var{tag}, size_t @var{taglen}) + +This function is used to read the authentication tag after encryption. +The function finalizes and outputs theauthentication tag to the buffer + at var{tag} of length @var{taglen} bytes. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t @var{h}, const void *@var{tag}, size_t @var{taglen}) + +Check the authentication tag after decryption. The authentication +tag is passed as the buffer @var{tag} of length @var{taglen} bytes +and compared to internal authentication tag computed during +decryption. Error code @code{GPG_ERR_CHECKSUM} is returned if +the authentication tag in the buffer @var{tag} does not match +the authentication tag calculated during decryption. + + at end deftypefun + The actual encryption and decryption is done by using one of the following functions. They may be used as often as required to process all the data. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 64cc0e4..6132868 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -953,6 +953,20 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen); +/* Provide additional authentication data for AEAD modes/ciphers. Also + provides the length of encrypted data and authentication tag for modes that + require this information at early stage. */ +gcry_error_t gcry_cipher_setaad (gcry_cipher_hd_t hd, const void *aad, + size_t aadlen, size_t encryptedlen, + size_t taglen); + +/* Get authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, + size_t taglen); + +/* Check authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, + size_t taglen); /* Reset the handle to the state after open. */ #define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0) diff --git a/src/libgcrypt.def b/src/libgcrypt.def index ec0c1e3..ac2dfb8 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -255,6 +255,9 @@ EXPORTS gcry_sexp_extract_param @225 + gcry_cipher_setaad @226 + gcry_cipher_gettag @227 + gcry_cipher_checktag @228 ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index be72aad..0990ff2 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -51,6 +51,7 @@ GCRYPT_1.6 { gcry_cipher_info; gcry_cipher_map_name; gcry_cipher_mode_from_oid; gcry_cipher_open; gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr; + gcry_cipher_setaad; gcry_cipher_gettag; gcry_cipher_checktag; gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl; gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey; diff --git a/src/visibility.c b/src/visibility.c index 848925e..5daf2ea 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -713,6 +713,34 @@ gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return _gcry_cipher_setctr (hd, ctr, ctrlen); } +gcry_error_t +gcry_cipher_setaad (gcry_cipher_hd_t hd, const void *aad, size_t aadlen, + size_t encryptedlen, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_setaad (hd, aad, aadlen, encryptedlen, taglen); +} + +gcry_error_t +gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_gettag (hd, outtag, taglen); +} + +gcry_error_t +gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_checktag (hd, intag, taglen); +} + gcry_error_t gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/src/visibility.h b/src/visibility.h index 1c8f047..e406d7d 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -81,6 +81,9 @@ #define gcry_cipher_setkey _gcry_cipher_setkey #define gcry_cipher_setiv _gcry_cipher_setiv #define gcry_cipher_setctr _gcry_cipher_setctr +#define gcry_cipher_setaad _gcry_cipher_setaad +#define gcry_cipher_checktag _gcry_cipher_checktag +#define gcry_cipher_gettag _gcry_cipher_gettag #define gcry_cipher_ctl _gcry_cipher_ctl #define gcry_cipher_decrypt _gcry_cipher_decrypt #define gcry_cipher_encrypt _gcry_cipher_encrypt @@ -297,6 +300,9 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, #undef gcry_cipher_setkey #undef gcry_cipher_setiv #undef gcry_cipher_setctr +#undef gcry_cipher_setaad +#undef gcry_cipher_checktag +#undef gcry_cipher_gettag #undef gcry_cipher_ctl #undef gcry_cipher_decrypt #undef gcry_cipher_encrypt @@ -474,6 +480,9 @@ MARK_VISIBLE (gcry_cipher_close) MARK_VISIBLE (gcry_cipher_setkey) MARK_VISIBLE (gcry_cipher_setiv) MARK_VISIBLE (gcry_cipher_setctr) +MARK_VISIBLE (gcry_cipher_setaad) +MARK_VISIBLE (gcry_cipher_checktag) +MARK_VISIBLE (gcry_cipher_gettag) MARK_VISIBLE (gcry_cipher_ctl) MARK_VISIBLE (gcry_cipher_decrypt) MARK_VISIBLE (gcry_cipher_encrypt) From jussi.kivilinna at iki.fi Sun Oct 20 14:03:18 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sun, 20 Oct 2013 15:03:18 +0300 Subject: [PATCH 2/2] Add Counter with CBC-MAC mode (CCM) In-Reply-To: <20131020120313.21970.15918.stgit@localhost6.localdomain6> References: <20131020120313.21970.15918.stgit@localhost6.localdomain6> Message-ID: <20131020120318.21970.31300.stgit@localhost6.localdomain6> * cipher/Makefile.am: Add 'cipher-ccm.c'. * cipher/cipher-ccm.c: New. * cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode'. (_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt) (_gcry_cipher_ccm_set_nonce, _gcry_cipher_ccm_set_aad) (_gcry_cipher_ccm_get_tag, _gcry_cipher_ccm_check_tag): New prototypes. * cipher/cipher.c (gcry_cipher_open, cipher_encrypt, cipher_decrypt) (_gcry_cipher_setiv, _gcry_cipher_setaad, _gcry_cipher_gettag) (_gcry_cipher_checktag): Add handling for CCM mode. * doc/gcrypt.texi: Add documentation for GCRY_CIPHER_MODE_CCM. * src/gcrypt.h.in (gcry_cipher_modes): Add 'GCRY_CIPHER_MODE_CCM'. (GCRY_CCM_BLOCK_LEN): New. * tests/basic.c (check_ccm_cipher): New. (check_cipher_modes): Call 'check_ccm_cipher'. * tests/benchmark.c (ccm_aead_init): New. (cipher_bench): Add handling for AEAD modes and add CCM benchmarking. -- Patch adds CCM (Counter with CBC-MAC) mode as defined in RFC 3610 and NIST Special Publication 800-38C. Example for encrypting message (split in two buffers; buf1, buf2) and authenticating additional non-encrypted data (aadbuf) with authentication tag length of eigth bytes: taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); gcry_cipher_setaad(h, aadbuf, len(aadbuf), len(buf1) + len(buf2), taglen); gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_encrypt(h, buf2, len(buf2), buf2, len(buf2)); gcry_cipher_gettag(h, tag, taglen); Example for decrypting above message and checking authentication tag: taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); gcry_cipher_setaad(h, aadbuf, len(aadbuf), len(buf1) + len(buf2), taglen); gcry_cipher_decrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_decrypt(h, buf2, len(buf2), buf2, len(buf2)); err = gcry_cipher_checktag(h, tag, taglen); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) { /* Authentication failed. */ } else if (err == 0) { /* Authentication ok. */ } Example for encrypting message without additional authenticated data: taglen = 10; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); gcry_cipher_setaad(h, NULL, 0, len(buf1), taglen); gcry_cipher_decrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_gettag(h, tag, taglen); To reset CCM state for cipher handle, one can either set new nonce or use 'gcry_cipher_reset'. This implementation reuses existing CTR mode code for encryption/decryption and is there for able to process multiple buffers that are not multiple of blocksize. Signed-off-by: Jussi Kivilinna --- cipher/Makefile.am | 1 cipher/cipher-ccm.c | 346 +++++++++++++++++++++++++++++ cipher/cipher-internal.h | 44 ++++ cipher/cipher.c | 85 ++++++- doc/gcrypt.texi | 16 + src/gcrypt.h.in | 5 tests/basic.c | 556 ++++++++++++++++++++++++++++++++++++++++++++++ tests/benchmark.c | 76 ++++++ 8 files changed, 1103 insertions(+), 26 deletions(-) create mode 100644 cipher/cipher-ccm.c diff --git a/cipher/Makefile.am b/cipher/Makefile.am index a2b2c8a..b0efd89 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -40,6 +40,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES) libcipher_la_SOURCES = \ cipher.c cipher-internal.h \ cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \ +cipher-ccm.c \ cipher-selftest.c cipher-selftest.h \ pubkey.c pubkey-internal.h pubkey-util.c \ md.c \ diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c new file mode 100644 index 0000000..64cce5f --- /dev/null +++ b/cipher/cipher-ccm.c @@ -0,0 +1,346 @@ +/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static unsigned int +do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, + int do_padding) +{ + const unsigned int blocksize = 16; + unsigned char tmp[blocksize]; + unsigned int burn = 0; + unsigned int unused = c->u_mode.ccm.mac_unused; + size_t nblocks; + + if (inlen == 0 && (unused == 0 || !do_padding)) + return 0; + + do + { + if (inlen + unused < blocksize || unused > 0) + { + for (; inlen && unused < blocksize; inlen--) + c->u_mode.ccm.macbuf[unused++] = *inbuf++; + } + if (!inlen) + { + if (!do_padding) + break; + + while (unused < blocksize) + c->u_mode.ccm.macbuf[unused++] = 0; + } + + if (unused > 0) + { + /* Process one block from macbuf. */ + buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + unused = 0; + } + + if (c->bulk.cbc_enc) + { + nblocks = inlen / blocksize; + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1); + inbuf += nblocks * blocksize; + inlen -= nblocks * blocksize; + + wipememory (tmp, sizeof(tmp)); + } + else + { + while (inlen >= blocksize) + { + buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + inlen -= blocksize; + inbuf += blocksize; + } + } + } + while (inlen > 0); + + c->u_mode.ccm.mac_unused = unused; + + if (burn) + burn += 4 * sizeof(void *); + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + size_t L = 15 - noncelen; + size_t L_; + + L_ = L - 1; + + if (!nonce) + return GPG_ERR_INV_ARG; + /* Length field must be 2, 3, ..., or 8. */ + if (L < 2 || L > 8) + return GPG_ERR_INV_LENGTH; + + /* Reset state */ + memset (&c->u_mode, 0, sizeof(c->u_mode)); + memset (&c->marks, 0, sizeof(c->marks)); + memset (&c->u_iv, 0, sizeof(c->u_iv)); + memset (&c->u_ctr, 0, sizeof(c->u_ctr)); + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + + /* Setup CTR */ + c->u_ctr.ctr[0] = L_; + memcpy (&c->u_ctr.ctr[1], nonce, noncelen); + memset (&c->u_ctr.ctr[1 + noncelen], 0, L); + + /* Setup IV */ + c->u_iv.iv[0] = L_; + memcpy (&c->u_iv.iv[1], nonce, noncelen); + /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later + in set_aad. */ + memset (&c->u_iv.iv[1 + noncelen], 0, L); + + c->u_mode.ccm.nonce = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_aad (gcry_cipher_hd_t c, const unsigned char *aadbuf, + size_t aadbuflen, size_t encryptlen, size_t taglen) +{ + unsigned int burn = 0; + unsigned char b0[16]; + size_t noncelen = 15 - (c->u_iv.iv[0] + 1); + size_t M = taglen; + size_t M_; + int i; + + M_ = (M - 2) / 2; + + if (aadbuflen > 0 && !aadbuf) + return GPG_ERR_INV_ARG; + /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */ + if ((M_ * 2 + 2) != M || M < 4 || M > 16) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.ccm.aad) + return GPG_ERR_INV_STATE; + + c->u_mode.ccm.authlen = taglen; + c->u_mode.ccm.encryptlen = encryptlen; + + /* Complete IV setup. */ + c->u_iv.iv[0] += (aadbuflen > 0) * 64 + M_ * 8; + for (i = 16 - 1; i >= 1 + noncelen; i--) + { + c->u_iv.iv[i] = encryptlen & 0xff; + encryptlen >>= 8; + } + + memcpy (b0, c->u_iv.iv, 16); + memset (c->u_iv.iv, 0, 16); + + set_burn (burn, do_cbc_mac (c, b0, 16, 0)); + + if (aadbuflen > 0 && aadbuflen <= (unsigned int)0xfeff) + { + b0[0] = (aadbuflen >> 8) & 0xff; + b0[1] = aadbuflen & 0xff; + set_burn (burn, do_cbc_mac (c, b0, 2, 0)); + set_burn (burn, do_cbc_mac (c, aadbuf, aadbuflen, 1)); + } + else if (aadbuflen > 0xfeff && aadbuflen <= (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xfe; + buf_put_be32(&b0[2], aadbuflen); + set_burn (burn, do_cbc_mac (c, b0, 6, 0)); + set_burn (burn, do_cbc_mac (c, aadbuf, aadbuflen, 1)); + } +#ifdef HAVE_U64_TYPEDEF + else if (aadbuflen > (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xff; + buf_put_be64(&b0[2], aadbuflen); + set_burn (burn, do_cbc_mac (c, b0, 10, 0)); + set_burn (burn, do_cbc_mac (c, aadbuf, aadbuflen, 1)); + } +#endif + + /* Generate S_0 and increase counter. */ + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0, + c->u_ctr.ctr )); + c->u_ctr.ctr[15]++; + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->u_mode.ccm.aad = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, int check) +{ + unsigned int burn; + + if (!outbuf || outbuflen == 0) + return GPG_ERR_INV_ARG; + /* Tag length must be same as initial authlen. */ + if (c->u_mode.ccm.authlen != outbuflen) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.aad) + return GPG_ERR_INV_STATE; + /* Initial encrypt length must match with length of actual data processed. */ + if (c->u_mode.ccm.encryptlen > 0) + return GPG_ERR_UNFINISHED; + + if (!c->u_mode.ccm.tag) + { + burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ + + /* Add S_0 */ + buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + + wipememory (c->u_ctr.ctr, 16); + wipememory (c->u_mode.ccm.s0, 16); + wipememory (c->u_mode.ccm.macbuf, 16); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + int diff, i; + + /* Constant-time compare. */ + for (i = 0, diff = 0; i < outbuflen; i++) + diff -= !!(outbuf[i] - c->u_iv.iv[i]); + + return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); +} + + +gcry_err_code_t +_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.aad) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, inbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +} + + +gcry_err_code_t +_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + gcry_err_code_t err; + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.aad) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + if (err) + return err; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, outbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return err; +} + diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index b60ef38..6dc8385 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -100,7 +100,8 @@ struct gcry_cipher_handle /* The initialization vector. For best performance we make sure that it is properly aligned. In particular some implementations - of bulk operations expect an 16 byte aligned IV. */ + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */ union { cipher_context_alignment_t iv_align; unsigned char iv[MAX_BLOCKSIZE]; @@ -117,6 +118,24 @@ struct gcry_cipher_handle unsigned char lastiv[MAX_BLOCKSIZE]; int unused; /* Number of unused bytes in LASTIV. */ + union { + /* Mode specific storage for CCM mode. */ + struct { + size_t encryptlen; + unsigned int authlen; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int nonce:1;/* Set to 1 if nonce has been set. */ + unsigned int aad:1; /* Set to 1 if AAD has been processed. */ + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ + } ccm; + } u_mode; + /* What follows are two contexts of the cipher in use. The first one needs to be aligned well enough for the cipher operation whereas the second one is a copy created by cipher_setkey and @@ -175,5 +194,28 @@ gcry_err_code_t _gcry_cipher_aeswrap_decrypt const byte *inbuf, unsigned int inbuflen); +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ccm_set_aad +/* */ (gcry_cipher_hd_t c, const unsigned char *aadbuf, + size_t aadbuflen, size_t encryptedlen, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); + + #endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/cipher/cipher.c b/cipher/cipher.c index 60f1f0e..29796bd 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -375,6 +375,13 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, if (! err) switch (mode) { + case GCRY_CIPHER_MODE_CCM: + if (spec->blocksize != GCRY_CCM_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: @@ -613,6 +620,8 @@ cipher_reset (gcry_cipher_hd_t c) memset (c->u_iv.iv, 0, c->spec->blocksize); memset (c->lastiv, 0, c->spec->blocksize); memset (c->u_ctr.ctr, 0, c->spec->blocksize); + memset (&c->u_mode, 0, sizeof c->u_mode); + c->unused = 0; } @@ -718,6 +727,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stencrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -811,6 +824,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stdecrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -885,8 +902,19 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) gcry_error_t _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) { - cipher_setiv (hd, iv, ivlen); - return 0; + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen); + break; + + default: + cipher_setiv (hd, iv, ivlen); + break; + } + return gpg_error (rc); } /* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of @@ -914,36 +942,61 @@ gcry_error_t _gcry_cipher_setaad (gcry_cipher_hd_t hd, const void *aad, size_t aadlen, size_t encryptedlen, size_t taglen) { - log_fatal ("gcry_cipher_setaad: invalid mode %d\n", hd->mode ); + gcry_err_code_t rc; - (void)aad; - (void)aadlen; - (void)encryptedlen; - (void)taglen; + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_set_aad (hd, aad, aadlen, encryptedlen, taglen); + break; - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + default: + log_fatal ("gcry_cipher_setaad: invalid mode %d\n", hd->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return gpg_error (rc); } gcry_error_t _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) { - log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode ); + gcry_err_code_t rc; - (void)outtag; - (void)taglen; + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen); + break; + + default: + log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) { - log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode ); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen); + break; - (void)intag; - (void)taglen; + default: + log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 1e5f414..8b8867a 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1635,6 +1635,12 @@ may be specified 64 bit (8 byte) shorter than then input buffer. As per specs the input length must be at least 128 bits and the length must be a multiple of 64 bits. + at item GCRY_CIPHER_MODE_CCM + at cindex CCM, Counter with CBC-MAC mode +Counter with CBC-MAC mode is an Authenticated Encryption with +Associated Data (AEAD) block cipher mode, which is specified in +'NIST Special Publication 800-38C' and RFC 3610. + @end table @node Working with cipher handles @@ -1661,11 +1667,13 @@ The cipher mode to use must be specified via @var{mode}. See @xref{Available cipher modes}, for a list of supported cipher modes and the according constants. Note that some modes are incompatible with some algorithms - in particular, stream mode -(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. Any -block cipher mode (@code{GCRY_CIPHER_MODE_ECB}, +(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. The +block cipher modes (@code{GCRY_CIPHER_MODE_ECB}, @code{GCRY_CIPHER_MODE_CBC}, @code{GCRY_CIPHER_MODE_CFB}, - at code{GCRY_CIPHER_MODE_OFB} or @code{GCRY_CIPHER_MODE_CTR}) will work -with any block cipher algorithm. + at code{GCRY_CIPHER_MODE_OFB} and @code{GCRY_CIPHER_MODE_CTR}) will work +with any block cipher algorithm. The @code{GCRY_CIPHER_MODE_CCM} will +only work with block cipher algorithms which have the block size of +16 bytes. The third argument @var{flags} can either be passed as @code{0} or as the bit-wise OR of the following constants. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 6132868..ac42276 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -884,7 +884,8 @@ enum gcry_cipher_modes GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ GCRY_CIPHER_MODE_CTR = 6, /* Counter. */ - GCRY_CIPHER_MODE_AESWRAP= 7 /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_AESWRAP= 7, /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_CCM = 8 /* Counter with CBC-MAC. */ }; /* Flags used with the open function. */ @@ -896,6 +897,8 @@ enum gcry_cipher_flags GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */ }; +/* CCM works only with blocks of 128 bits. */ +#define GCRY_CCM_BLOCK_LEN (128 / 8) /* Create a handle for algorithm ALGO to be used in MODE. FLAGS may be given as an bitwise OR of the gcry_cipher_flags values. */ diff --git a/tests/basic.c b/tests/basic.c index 1d6e637..6228c0e 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -1139,6 +1139,561 @@ check_ofb_cipher (void) static void +check_ccm_cipher (void) +{ + static const struct tv + { + int algo; + int keylen; + const char *key; + int noncelen; + const char *nonce; + int aadlen; + const char *aad; + int plainlen; + const char *plaintext; + int cipherlen; + const char *ciphertext; + } tv[] = + { + /* RFC 3610 */ + { GCRY_CIPHER_AES, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\x58\x8C\x97\x9A\x61\xC6\x63\xD2\xF0\x66\xD0\xC2\xC0\xF9\x89\x80\x6D\x5F\x6B\x61\xDA\xC3\x84\x17\xE8\xD1\x2C\xFD\xF9\x26\xE0"}, + { GCRY_CIPHER_AES, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x72\xC9\x1A\x36\xE1\x35\xF8\xCF\x29\x1C\xA8\x94\x08\x5C\x87\xE3\xCC\x15\xC4\x39\xC9\xE4\x3A\x3B\xA0\x91\xD5\x6E\x10\x40\x09\x16"}, + { GCRY_CIPHER_AES, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x51\xB1\xE5\xF4\x4A\x19\x7D\x1D\xA4\x6B\x0F\x8E\x2D\x28\x2A\xE8\x71\xE8\x38\xBB\x64\xDA\x85\x96\x57\x4A\xDA\xA7\x6F\xBD\x9F\xB0\xC5"}, + { GCRY_CIPHER_AES, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xA2\x8C\x68\x65\x93\x9A\x9A\x79\xFA\xAA\x5C\x4C\x2A\x9D\x4A\x91\xCD\xAC\x8C\x96\xC8\x61\xB9\xC9\xE6\x1E\xF1"}, + { GCRY_CIPHER_AES, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\xDC\xF1\xFB\x7B\x5D\x9E\x23\xFB\x9D\x4E\x13\x12\x53\x65\x8A\xD8\x6E\xBD\xCA\x3E\x51\xE8\x3F\x07\x7D\x9C\x2D\x93"}, + { GCRY_CIPHER_AES, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\x6F\xC1\xB0\x11\xF0\x06\x56\x8B\x51\x71\xA4\x2D\x95\x3D\x46\x9B\x25\x70\xA4\xBD\x87\x40\x5A\x04\x43\xAC\x91\xCB\x94"}, + { GCRY_CIPHER_AES, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x01\x35\xD1\xB2\xC9\x5F\x41\xD5\xD1\xD4\xFE\xC1\x85\xD1\x66\xB8\x09\x4E\x99\x9D\xFE\xD9\x6C\x04\x8C\x56\x60\x2C\x97\xAC\xBB\x74\x90"}, + { GCRY_CIPHER_AES, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x7B\x75\x39\x9A\xC0\x83\x1D\xD2\xF0\xBB\xD7\x58\x79\xA2\xFD\x8F\x6C\xAE\x6B\x6C\xD9\xB7\xDB\x24\xC1\x7B\x44\x33\xF4\x34\x96\x3F\x34\xB4"}, + { GCRY_CIPHER_AES, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x82\x53\x1A\x60\xCC\x24\x94\x5A\x4B\x82\x79\x18\x1A\xB5\xC8\x4D\xF2\x1C\xE7\xF9\xB7\x3F\x42\xE1\x97\xEA\x9C\x07\xE5\x6B\x5E\xB1\x7E\x5F\x4E"}, + { GCRY_CIPHER_AES, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\x07\x34\x25\x94\x15\x77\x85\x15\x2B\x07\x40\x98\x33\x0A\xBB\x14\x1B\x94\x7B\x56\x6A\xA9\x40\x6B\x4D\x99\x99\x88\xDD"}, + { GCRY_CIPHER_AES, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x67\x6B\xB2\x03\x80\xB0\xE3\x01\xE8\xAB\x79\x59\x0A\x39\x6D\xA7\x8B\x83\x49\x34\xF5\x3A\xA2\xE9\x10\x7A\x8B\x6C\x02\x2C"}, + { GCRY_CIPHER_AES, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\xC0\xFF\xA0\xD6\xF0\x5B\xDB\x67\xF2\x4D\x43\xA4\x33\x8D\x2A\xA4\xBE\xD7\xB2\x0E\x43\xCD\x1A\xA3\x16\x62\xE7\xAD\x65\xD6\xDB"}, + { GCRY_CIPHER_AES, /* Packet Vector #13 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x41\x2B\x4E\xA9\xCD\xBE\x3C\x96\x96\x76\x6C\xFA", + 8, "\x0B\xE1\xA8\x8B\xAC\xE0\x18\xB1", + 23, + "\x08\xE8\xCF\x97\xD8\x20\xEA\x25\x84\x60\xE9\x6A\xD9\xCF\x52\x89\x05\x4D\x89\x5C\xEA\xC4\x7C", + 31, + "\x4C\xB9\x7F\x86\xA2\xA4\x68\x9A\x87\x79\x47\xAB\x80\x91\xEF\x53\x86\xA6\xFF\xBD\xD0\x80\xF8\xE7\x8C\xF7\xCB\x0C\xDD\xD7\xB3"}, + { GCRY_CIPHER_AES, /* Packet Vector #14 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x33\x56\x8E\xF7\xB2\x63\x3C\x96\x96\x76\x6C\xFA", + 8, "\x63\x01\x8F\x76\xDC\x8A\x1B\xCB", + 24, + "\x90\x20\xEA\x6F\x91\xBD\xD8\x5A\xFA\x00\x39\xBA\x4B\xAF\xF9\xBF\xB7\x9C\x70\x28\x94\x9C\xD0\xEC", + 32, + "\x4C\xCB\x1E\x7C\xA9\x81\xBE\xFA\xA0\x72\x6C\x55\xD3\x78\x06\x12\x98\xC8\x5C\x92\x81\x4A\xBC\x33\xC5\x2E\xE8\x1D\x7D\x77\xC0\x8A"}, + { GCRY_CIPHER_AES, /* Packet Vector #15 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x10\x3F\xE4\x13\x36\x71\x3C\x96\x96\x76\x6C\xFA", + 8, "\xAA\x6C\xFA\x36\xCA\xE8\x6B\x40", + 25, + "\xB9\x16\xE0\xEA\xCC\x1C\x00\xD7\xDC\xEC\x68\xEC\x0B\x3B\xBB\x1A\x02\xDE\x8A\x2D\x1A\xA3\x46\x13\x2E", + 33, + "\xB1\xD2\x3A\x22\x20\xDD\xC0\xAC\x90\x0D\x9A\xA0\x3C\x61\xFC\xF4\xA5\x59\xA4\x41\x77\x67\x08\x97\x08\xA7\x76\x79\x6E\xDB\x72\x35\x06"}, + { GCRY_CIPHER_AES, /* Packet Vector #16 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x76\x4C\x63\xB8\x05\x8E\x3C\x96\x96\x76\x6C\xFA", + 12, "\xD0\xD0\x73\x5C\x53\x1E\x1B\xEC\xF0\x49\xC2\x44", + 19, + "\x12\xDA\xAC\x56\x30\xEF\xA5\x39\x6F\x77\x0C\xE1\xA6\x6B\x21\xF7\xB2\x10\x1C", + 27, + "\x14\xD2\x53\xC3\x96\x7B\x70\x60\x9B\x7C\xBB\x7C\x49\x91\x60\x28\x32\x45\x26\x9A\x6F\x49\x97\x5B\xCA\xDE\xAF"}, + { GCRY_CIPHER_AES, /* Packet Vector #17 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xF8\xB6\x78\x09\x4E\x3B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x77\xB6\x0F\x01\x1C\x03\xE1\x52\x58\x99\xBC\xAE", + 20, + "\xE8\x8B\x6A\x46\xC7\x8D\x63\xE5\x2E\xB8\xC5\x46\xEF\xB5\xDE\x6F\x75\xE9\xCC\x0D", + 28, + "\x55\x45\xFF\x1A\x08\x5E\xE2\xEF\xBF\x52\xB2\xE0\x4B\xEE\x1E\x23\x36\xC7\x3E\x3F\x76\x2C\x0C\x77\x44\xFE\x7E\x3C"}, + { GCRY_CIPHER_AES, /* Packet Vector #18 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xD5\x60\x91\x2D\x3F\x70\x3C\x96\x96\x76\x6C\xFA", + 12, "\xCD\x90\x44\xD2\xB7\x1F\xDB\x81\x20\xEA\x60\xC0", + 21, + "\x64\x35\xAC\xBA\xFB\x11\xA8\x2E\x2F\x07\x1D\x7C\xA4\xA5\xEB\xD9\x3A\x80\x3B\xA8\x7F", + 29, + "\x00\x97\x69\xEC\xAB\xDF\x48\x62\x55\x94\xC5\x92\x51\xE6\x03\x57\x22\x67\x5E\x04\xC8\x47\x09\x9E\x5A\xE0\x70\x45\x51"}, + { GCRY_CIPHER_AES, /* Packet Vector #19 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x42\xFF\xF8\xF1\x95\x1C\x3C\x96\x96\x76\x6C\xFA", + 8, "\xD8\x5B\xC7\xE6\x9F\x94\x4F\xB8", + 23, + "\x8A\x19\xB9\x50\xBC\xF7\x1A\x01\x8E\x5E\x67\x01\xC9\x17\x87\x65\x98\x09\xD6\x7D\xBE\xDD\x18", + 33, + "\xBC\x21\x8D\xAA\x94\x74\x27\xB6\xDB\x38\x6A\x99\xAC\x1A\xEF\x23\xAD\xE0\xB5\x29\x39\xCB\x6A\x63\x7C\xF9\xBE\xC2\x40\x88\x97\xC6\xBA"}, + { GCRY_CIPHER_AES, /* Packet Vector #20 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x92\x0F\x40\xE5\x6C\xDC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x74\xA0\xEB\xC9\x06\x9F\x5B\x37", + 24, + "\x17\x61\x43\x3C\x37\xC5\xA3\x5F\xC1\xF3\x9F\x40\x63\x02\xEB\x90\x7C\x61\x63\xBE\x38\xC9\x84\x37", + 34, + "\x58\x10\xE6\xFD\x25\x87\x40\x22\xE8\x03\x61\xA4\x78\xE3\xE9\xCF\x48\x4A\xB0\x4F\x44\x7E\xFF\xF6\xF0\xA4\x77\xCC\x2F\xC9\xBF\x54\x89\x44"}, + { GCRY_CIPHER_AES, /* Packet Vector #21 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x27\xCA\x0C\x71\x20\xBC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x44\xA3\xAA\x3A\xAE\x64\x75\xCA", + 25, + "\xA4\x34\xA8\xE5\x85\x00\xC6\xE4\x15\x30\x53\x88\x62\xD6\x86\xEA\x9E\x81\x30\x1B\x5A\xE4\x22\x6B\xFA", + 35, + "\xF2\xBE\xED\x7B\xC5\x09\x8E\x83\xFE\xB5\xB3\x16\x08\xF8\xE2\x9C\x38\x81\x9A\x89\xC8\xE7\x76\xF1\x54\x4D\x41\x51\xA4\xED\x3A\x8B\x87\xB9\xCE"}, + { GCRY_CIPHER_AES, /* Packet Vector #22 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x5B\x8C\xCB\xCD\x9A\xF8\x3C\x96\x96\x76\x6C\xFA", + 12, "\xEC\x46\xBB\x63\xB0\x25\x20\xC3\x3C\x49\xFD\x70", + 19, + "\xB9\x6B\x49\xE2\x1D\x62\x17\x41\x63\x28\x75\xDB\x7F\x6C\x92\x43\xD2\xD7\xC2", + 29, + "\x31\xD7\x50\xA0\x9D\xA3\xED\x7F\xDD\xD4\x9A\x20\x32\xAA\xBF\x17\xEC\x8E\xBF\x7D\x22\xC8\x08\x8C\x66\x6B\xE5\xC1\x97"}, + { GCRY_CIPHER_AES, /* Packet Vector #23 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x3E\xBE\x94\x04\x4B\x9A\x3C\x96\x96\x76\x6C\xFA", + 12, "\x47\xA6\x5A\xC7\x8B\x3D\x59\x42\x27\xE8\x5E\x71", + 20, + "\xE2\xFC\xFB\xB8\x80\x44\x2C\x73\x1B\xF9\x51\x67\xC8\xFF\xD7\x89\x5E\x33\x70\x76", + 30, + "\xE8\x82\xF1\xDB\xD3\x8C\xE3\xED\xA7\xC2\x3F\x04\xDD\x65\x07\x1E\xB4\x13\x42\xAC\xDF\x7E\x00\xDC\xCE\xC7\xAE\x52\x98\x7D"}, + { GCRY_CIPHER_AES, /* Packet Vector #24 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x8D\x49\x3B\x30\xAE\x8B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x6E\x37\xA6\xEF\x54\x6D\x95\x5D\x34\xAB\x60\x59", + 21, + "\xAB\xF2\x1C\x0B\x02\xFE\xB8\x8F\x85\x6D\xF4\xA3\x73\x81\xBC\xE3\xCC\x12\x85\x17\xD4", + 31, + "\xF3\x29\x05\xB8\x8A\x64\x1B\x04\xB9\xC9\xFF\xB5\x8C\xC3\x90\x90\x0F\x3D\xA1\x2A\xB1\x6D\xCE\x9E\x82\xEF\xA1\x6D\xA6\x20\x59"}, + /* RFC 5528 */ + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\xBA\x73\x71\x85\xE7\x19\x31\x04\x92\xF3\x8A\x5F\x12\x51\xDA\x55\xFA\xFB\xC9\x49\x84\x8A\x0D\xFC\xAE\xCE\x74\x6B\x3D\xB9\xAD"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x5D\x25\x64\xBF\x8E\xAF\xE1\xD9\x95\x26\xEC\x01\x6D\x1B\xF0\x42\x4C\xFB\xD2\xCD\x62\x84\x8F\x33\x60\xB2\x29\x5D\xF2\x42\x83\xE8"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x81\xF6\x63\xD6\xC7\x78\x78\x17\xF9\x20\x36\x08\xB9\x82\xAD\x15\xDC\x2B\xBD\x87\xD7\x56\xF7\x92\x04\xF5\x51\xD6\x68\x2F\x23\xAA\x46"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xCA\xEF\x1E\x82\x72\x11\xB0\x8F\x7B\xD9\x0F\x08\xC7\x72\x88\xC0\x70\xA4\xA0\x8B\x3A\x93\x3A\x63\xE4\x97\xA0"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\x2A\xD3\xBA\xD9\x4F\xC5\x2E\x92\xBE\x43\x8E\x82\x7C\x10\x23\xB9\x6A\x8A\x77\x25\x8F\xA1\x7B\xA7\xF3\x31\xDB\x09"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\xFE\xA5\x48\x0B\xA5\x3F\xA8\xD3\xC3\x44\x22\xAA\xCE\x4D\xE6\x7F\xFA\x3B\xB7\x3B\xAB\xAB\x36\xA1\xEE\x4F\xE0\xFE\x28"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x54\x53\x20\x26\xE5\x4C\x11\x9A\x8D\x36\xD9\xEC\x6E\x1E\xD9\x74\x16\xC8\x70\x8C\x4B\x5C\x2C\xAC\xAF\xA3\xBC\xCF\x7A\x4E\xBF\x95\x73"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x8A\xD1\x9B\x00\x1A\x87\xD1\x48\xF4\xD9\x2B\xEF\x34\x52\x5C\xCC\xE3\xA6\x3C\x65\x12\xA6\xF5\x75\x73\x88\xE4\x91\x3E\xF1\x47\x01\xF4\x41"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x5D\xB0\x8D\x62\x40\x7E\x6E\x31\xD6\x0F\x9C\xA2\xC6\x04\x74\x21\x9A\xC0\xBE\x50\xC0\xD4\xA5\x77\x87\x94\xD6\xE2\x30\xCD\x25\xC9\xFE\xBF\x87"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\xDB\x11\x8C\xCE\xC1\xB8\x76\x1C\x87\x7C\xD8\x96\x3A\x67\xD6\xF3\xBB\xBC\x5C\xD0\x92\x99\xEB\x11\xF3\x12\xF2\x32\x37"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x7C\xC8\x3D\x8D\xC4\x91\x03\x52\x5B\x48\x3D\xC5\xCA\x7E\xA9\xAB\x81\x2B\x70\x56\x07\x9D\xAF\xFA\xDA\x16\xCC\xCF\x2C\x4E"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\x2C\xD3\x5B\x88\x20\xD2\x3E\x7A\xA3\x51\xB0\xE9\x2F\xC7\x93\x67\x23\x8B\x2C\xC7\x48\xCB\xB9\x4C\x29\x47\x79\x3D\x64\xAF\x75"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #13 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xA9\x70\x11\x0E\x19\x27\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x6B\x7F\x46\x45\x07\xFA\xE4\x96", + 23, + "\xC6\xB5\xF3\xE6\xCA\x23\x11\xAE\xF7\x47\x2B\x20\x3E\x73\x5E\xA5\x61\xAD\xB1\x7D\x56\xC5\xA3", + 31, + "\xA4\x35\xD7\x27\x34\x8D\xDD\x22\x90\x7F\x7E\xB8\xF5\xFD\xBB\x4D\x93\x9D\xA6\x52\x4D\xB4\xF6\x45\x58\xC0\x2D\x25\xB1\x27\xEE"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #14 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x83\xCD\x8C\xE0\xCB\x42\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x98\x66\x05\xB4\x3D\xF1\x5D\xE7", + 24, + "\x01\xF6\xCE\x67\x64\xC5\x74\x48\x3B\xB0\x2E\x6B\xBF\x1E\x0A\xBD\x26\xA2\x25\x72\xB4\xD8\x0E\xE7", + 32, + "\x8A\xE0\x52\x50\x8F\xBE\xCA\x93\x2E\x34\x6F\x05\xE0\xDC\x0D\xFB\xCF\x93\x9E\xAF\xFA\x3E\x58\x7C\x86\x7D\x6E\x1C\x48\x70\x38\x06"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #15 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x5F\x54\x95\x0B\x18\xF2\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x48\xF2\xE7\xE1\xA7\x67\x1A\x51", + 25, + "\xCD\xF1\xD8\x40\x6F\xC2\xE9\x01\x49\x53\x89\x70\x05\xFB\xFB\x8B\xA5\x72\x76\xF9\x24\x04\x60\x8E\x08", + 33, + "\x08\xB6\x7E\xE2\x1C\x8B\xF2\x6E\x47\x3E\x40\x85\x99\xE9\xC0\x83\x6D\x6A\xF0\xBB\x18\xDF\x55\x46\x6C\xA8\x08\x78\xA7\x90\x47\x6D\xE5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #16 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xEC\x60\x08\x63\x31\x9A\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xDE\x97\xDF\x3B\x8C\xBD\x6D\x8E\x50\x30\xDA\x4C", + 19, + "\xB0\x05\xDC\xFA\x0B\x59\x18\x14\x26\xA9\x61\x68\x5A\x99\x3D\x8C\x43\x18\x5B", + 27, + "\x63\xB7\x8B\x49\x67\xB1\x9E\xDB\xB7\x33\xCD\x11\x14\xF6\x4E\xB2\x26\x08\x93\x68\xC3\x54\x82\x8D\x95\x0C\xC5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #17 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x60\xCF\xF1\xA3\x1E\xA1\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA5\xEE\x93\xE4\x57\xDF\x05\x46\x6E\x78\x2D\xCF", + 20, + "\x2E\x20\x21\x12\x98\x10\x5F\x12\x9D\x5E\xD9\x5B\x93\xF7\x2D\x30\xB2\xFA\xCC\xD7", + 28, + "\x0B\xC6\xBB\xE2\xA8\xB9\x09\xF4\x62\x9E\xE6\xDC\x14\x8D\xA4\x44\x10\xE1\x8A\xF4\x31\x47\x38\x32\x76\xF6\x6A\x9F"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #18 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x0F\x85\xCD\x99\x5C\x97\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x24\xAA\x1B\xF9\xA5\xCD\x87\x61\x82\xA2\x50\x74", + 21, + "\x26\x45\x94\x1E\x75\x63\x2D\x34\x91\xAF\x0F\xC0\xC9\x87\x6C\x3B\xE4\xAA\x74\x68\xC9", + 29, + "\x22\x2A\xD6\x32\xFA\x31\xD6\xAF\x97\x0C\x34\x5F\x7E\x77\xCA\x3B\xD0\xDC\x25\xB3\x40\xA1\xA3\xD3\x1F\x8D\x4B\x44\xB7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #19 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC2\x9B\x2C\xAA\xC4\xCD\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x69\x19\x46\xB9\xCA\x07\xBE\x87", + 23, + "\x07\x01\x35\xA6\x43\x7C\x9D\xB1\x20\xCD\x61\xD8\xF6\xC3\x9C\x3E\xA1\x25\xFD\x95\xA0\xD2\x3D", + 33, + "\x05\xB8\xE1\xB9\xC4\x9C\xFD\x56\xCF\x13\x0A\xA6\x25\x1D\xC2\xEC\xC0\x6C\xCC\x50\x8F\xE6\x97\xA0\x06\x6D\x57\xC8\x4B\xEC\x18\x27\x68"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #20 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x2C\x6B\x75\x95\xEE\x62\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xD0\xC5\x4E\xCB\x84\x62\x7D\xC4", + 24, + "\xC8\xC0\x88\x0E\x6C\x63\x6E\x20\x09\x3D\xD6\x59\x42\x17\xD2\xE1\x88\x77\xDB\x26\x4E\x71\xA5\xCC", + 34, + "\x54\xCE\xB9\x68\xDE\xE2\x36\x11\x57\x5E\xC0\x03\xDF\xAA\x1C\xD4\x88\x49\xBD\xF5\xAE\x2E\xDB\x6B\x7F\xA7\x75\xB1\x50\xED\x43\x83\xC5\xA9"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #21 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC5\x3C\xD4\xC2\xAA\x24\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xE2\x85\xE0\xE4\x80\x8C\xDA\x3D", + 25, + "\xF7\x5D\xAA\x07\x10\xC4\xE6\x42\x97\x79\x4D\xC2\xB7\xD2\xA2\x07\x57\xB1\xAA\x4E\x44\x80\x02\xFF\xAB", + 35, + "\xB1\x40\x45\x46\xBF\x66\x72\x10\xCA\x28\xE3\x09\xB3\x9B\xD6\xCA\x7E\x9F\xC8\x28\x5F\xE6\x98\xD4\x3C\xD2\x0A\x02\xE0\xBD\xCA\xED\x20\x10\xD3"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #22 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xBE\xE9\x26\x7F\xBA\xDC\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x6C\xAE\xF9\x94\x11\x41\x57\x0D\x7C\x81\x34\x05", + 19, + "\xC2\x38\x82\x2F\xAC\x5F\x98\xFF\x92\x94\x05\xB0\xAD\x12\x7A\x4E\x41\x85\x4E", + 29, + "\x94\xC8\x95\x9C\x11\x56\x9A\x29\x78\x31\xA7\x21\x00\x58\x57\xAB\x61\xB8\x7A\x2D\xEA\x09\x36\xB6\xEB\x5F\x62\x5F\x5D"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #23 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xDF\xA8\xB1\x24\x50\x07\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x36\xA5\x2C\xF1\x6B\x19\xA2\x03\x7A\xB7\x01\x1E", + 20, + "\x4D\xBF\x3E\x77\x4A\xD2\x45\xE5\xD5\x89\x1F\x9D\x1C\x32\xA0\xAE\x02\x2C\x85\xD7", + 30, + "\x58\x69\xE3\xAA\xD2\x44\x7C\x74\xE0\xFC\x05\xF9\xA4\xEA\x74\x57\x7F\x4D\xE8\xCA\x89\x24\x76\x42\x96\xAD\x04\x11\x9C\xE7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #24 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x3B\x8F\xD8\xD3\xA9\x37\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA4\xD4\x99\xF7\x84\x19\x72\x8C\x19\x17\x8B\x0C", + 21, + "\x9D\xC9\xED\xAE\x2F\xF5\xDF\x86\x36\xE8\xC6\xDE\x0E\xED\x55\xF7\x86\x7E\x33\x33\x7D", + 31, + "\x4B\x19\x81\x56\x39\x3B\x0F\x77\x96\x08\x6A\xAF\xB4\x54\xF8\xC3\xF0\x34\xCC\xA9\x66\x94\x5F\x1F\xCE\xA7\xE1\x1B\xEE\x6A\x2F"} + }; + static const int cut[] = { 0, 1, 8, 10, 16, 19, -1 }; + gcry_cipher_hd_t hde, hdd; + unsigned char out[MAX_DATA_LEN]; + int split, j, i, keylen, blklen, authlen; + gcry_error_t err = 0; + + if (verbose) + fprintf (stderr, " Starting CCM checks.\n"); + + for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) + { + if (verbose) + fprintf (stderr, " checking CCM mode for %s [%i]\n", + gcry_cipher_algo_name (tv[i].algo), + tv[i].algo); + + for (j = 0; j < sizeof (cut) / sizeof (cut[0]); j++) + { + split = cut[j] < 0 ? tv[i].plainlen : cut[j]; + if (tv[i].plainlen < split) + continue; + + err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + keylen = gcry_cipher_get_algo_keylen(tv[i].algo); + if (!keylen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_keylen failed\n"); + return; + } + + err = gcry_cipher_setkey (hde, tv[i].key, keylen); + if (!err) + err = gcry_cipher_setkey (hdd, tv[i].key, keylen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + blklen = gcry_cipher_get_algo_blklen(tv[i].algo); + if (!blklen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_blklen failed\n"); + return; + } + + err = gcry_cipher_setiv (hde, tv[i].nonce, tv[i].noncelen); + if (!err) + err = gcry_cipher_setiv (hdd, tv[i].nonce, tv[i].noncelen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + authlen = tv[i].cipherlen - tv[i].plainlen; + err = gcry_cipher_setaad (hde, tv[i].aad, tv[i].aadlen, + tv[i].plainlen, authlen); + if (!err) + err = gcry_cipher_setaad (hdd, tv[i].aad, tv[i].aadlen, + tv[i].plainlen, authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setaad failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, tv[i].plaintext, + tv[i].plainlen - split); + if (!err) + err = gcry_cipher_encrypt (hde, &out[tv[i].plainlen - split], + MAX_DATA_LEN - (tv[i].plainlen - split), + &tv[i].plaintext[tv[i].plainlen - split], + split); + if (err) + { + fail ("cipher-ccm, gcry_cipher_encrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_gettag (hde, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_gettag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].ciphertext, out, tv[i].cipherlen)) + fail ("cipher-ccm, encrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_decrypt (hdd, out, tv[i].plainlen - split, NULL, 0); + if (!err) + err = gcry_cipher_decrypt (hdd, &out[tv[i].plainlen - split], split, + NULL, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_decrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].plaintext, out, tv[i].plainlen)) + fail ("cipher-ccm, decrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_checktag (hdd, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_checktag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + } + } + + if (verbose) + fprintf (stderr, " Completed CCM checks.\n"); +} + + +static void check_stream_cipher (void) { struct tv @@ -2455,6 +3010,7 @@ check_cipher_modes(void) check_ctr_cipher (); check_cfb_cipher (); check_ofb_cipher (); + check_ccm_cipher (); check_stream_cipher (); check_stream_cipher_large_block (); diff --git a/tests/benchmark.c b/tests/benchmark.c index ecda0d3..5d7e7fd 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -435,6 +435,36 @@ md_bench ( const char *algoname ) fflush (stdout); } + +static void ccm_aead_init(gcry_cipher_hd_t hd, size_t buflen, int authlen) +{ + const int _L = 4; + const int noncelen = 15 - _L; + char nonce[noncelen]; + gcry_error_t err = GPG_ERR_NO_ERROR; + + memset (nonce, 0x33, noncelen); + + err = gcry_cipher_setiv (hd, nonce, noncelen); + if (err) + { + fprintf (stderr, "gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } + + err = gcry_cipher_setaad (hd, NULL, 0, buflen, authlen); + if (err) + { + fprintf (stderr, "gcry_cipher_setaad failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } +} + + static void cipher_bench ( const char *algoname ) { @@ -448,12 +478,21 @@ cipher_bench ( const char *algoname ) char *raw_outbuf, *raw_buf; size_t allocated_buflen, buflen; int repetitions; - static struct { int mode; const char *name; int blocked; } modes[] = { + static const struct { + int mode; + const char *name; + int blocked; + void (* const aead_init)(gcry_cipher_hd_t hd, size_t buflen, int authlen); + int req_blocksize; + int authlen; + } modes[] = { { GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1 }, { GCRY_CIPHER_MODE_CBC, " CBC", 1 }, { GCRY_CIPHER_MODE_CFB, " CFB", 0 }, { GCRY_CIPHER_MODE_OFB, " OFB", 0 }, { GCRY_CIPHER_MODE_CTR, " CTR", 0 }, + { GCRY_CIPHER_MODE_CCM, " CCM", 0, + ccm_aead_init, GCRY_CCM_BLOCK_LEN, 8 }, { GCRY_CIPHER_MODE_STREAM, "", 0 }, {0} }; @@ -542,9 +581,16 @@ cipher_bench ( const char *algoname ) for (modeidx=0; modes[modeidx].mode; modeidx++) { if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM) - | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) + || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) continue; + if (modes[modeidx].req_blocksize > 0 + && blklen != modes[modeidx].req_blocksize) + { + printf (" %7s %7s", "-", "-" ); + continue; + } + for (i=0; i < sizeof buf; i++) buf[i] = i; @@ -585,7 +631,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_gettag (hd, outbuf, modes[modeidx].authlen); + } + else + { + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + } } stop_timer (); @@ -632,7 +689,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_decrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_checktag (hd, outbuf, modes[modeidx].authlen); + if (gpg_err_code (err) == GPG_ERR_CHECKSUM) + err = gpg_error (GPG_ERR_NO_ERROR); + } + else + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); } stop_timer (); printf (" %s", elapsed_time ()); From jussi.kivilinna at iki.fi Sun Oct 20 20:01:42 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sun, 20 Oct 2013 21:01:42 +0300 Subject: [PATCH] serpent-amd64: do not use GAS macros Message-ID: <20131020180142.19195.21145.stgit@localhost6.localdomain6> * cipher/serpent-avx2-amd64.S: Remove use of GAS macros. * cipher/serpent-sse2-amd64.S: Ditto. * configure.ac [HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS]: Do not check for GAS macros. -- This way we have better portability; for example, when compiling with clang on x86-64, the assembly implementations are now enabled and working. Signed-off-by: Jussi Kivilinna --- cipher/serpent-avx2-amd64.S | 519 ++++++++++++++++++------------------------- cipher/serpent-sse2-amd64.S | 507 ++++++++++++++++++------------------------ configure.ac | 6 3 files changed, 439 insertions(+), 593 deletions(-) diff --git a/cipher/serpent-avx2-amd64.S b/cipher/serpent-avx2-amd64.S index c726e7b..8a76ab1 100644 --- a/cipher/serpent-avx2-amd64.S +++ b/cipher/serpent-avx2-amd64.S @@ -36,51 +36,36 @@ #define CTX %rdi /* vector registers */ -.set RA0, %ymm0 -.set RA1, %ymm1 -.set RA2, %ymm2 -.set RA3, %ymm3 -.set RA4, %ymm4 - -.set RB0, %ymm5 -.set RB1, %ymm6 -.set RB2, %ymm7 -.set RB3, %ymm8 -.set RB4, %ymm9 - -.set RNOT, %ymm10 -.set RTMP0, %ymm11 -.set RTMP1, %ymm12 -.set RTMP2, %ymm13 -.set RTMP3, %ymm14 -.set RTMP4, %ymm15 - -.set RNOTx, %xmm10 -.set RTMP0x, %xmm11 -.set RTMP1x, %xmm12 -.set RTMP2x, %xmm13 -.set RTMP3x, %xmm14 -.set RTMP4x, %xmm15 +#define RA0 %ymm0 +#define RA1 %ymm1 +#define RA2 %ymm2 +#define RA3 %ymm3 +#define RA4 %ymm4 + +#define RB0 %ymm5 +#define RB1 %ymm6 +#define RB2 %ymm7 +#define RB3 %ymm8 +#define RB4 %ymm9 + +#define RNOT %ymm10 +#define RTMP0 %ymm11 +#define RTMP1 %ymm12 +#define RTMP2 %ymm13 +#define RTMP3 %ymm14 +#define RTMP4 %ymm15 + +#define RNOTx %xmm10 +#define RTMP0x %xmm11 +#define RTMP1x %xmm12 +#define RTMP2x %xmm13 +#define RTMP3x %xmm14 +#define RTMP4x %xmm15 /********************************************************************** helper macros **********************************************************************/ -/* preprocessor macro for renaming vector registers using GAS macros */ -#define sbox_reg_rename(r0, r1, r2, r3, r4, \ - new_r0, new_r1, new_r2, new_r3, new_r4) \ - .set rename_reg0, new_r0; \ - .set rename_reg1, new_r1; \ - .set rename_reg2, new_r2; \ - .set rename_reg3, new_r3; \ - .set rename_reg4, new_r4; \ - \ - .set r0, rename_reg0; \ - .set r1, rename_reg1; \ - .set r2, rename_reg2; \ - .set r3, rename_reg3; \ - .set r4, rename_reg4; - /* vector 32-bit rotation to left */ #define vec_rol(reg, nleft, tmp) \ vpslld $(nleft), reg, tmp; \ @@ -128,9 +113,7 @@ vpxor r4, r2, r2; vpxor RNOT, r4, r4; \ vpor r1, r4, r4; vpxor r3, r1, r1; \ vpxor r4, r1, r1; vpor r0, r3, r3; \ - vpxor r3, r1, r1; vpxor r3, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r0,r3); + vpxor r3, r1, r1; vpxor r3, r4, r4; #define SBOX0_INVERSE(r0, r1, r2, r3, r4) \ vpxor RNOT, r2, r2; vmovdqa r1, r4; \ @@ -143,9 +126,7 @@ vpxor r1, r2, r2; vpxor r0, r3, r3; \ vpxor r1, r3, r3; \ vpand r3, r2, r2; \ - vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r4,r1,r3,r2); + vpxor r2, r4, r4; #define SBOX1(r0, r1, r2, r3, r4) \ vpxor RNOT, r0, r0; vpxor RNOT, r2, r2; \ @@ -157,9 +138,7 @@ vpand r4, r2, r2; vpxor r1, r0, r0; \ vpand r2, r1, r1; \ vpxor r0, r1, r1; vpand r2, r0, r0; \ - vpxor r4, r0, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r0,r3,r1,r4); + vpxor r4, r0, r0; #define SBOX1_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r1, r4; vpxor r3, r1, r1; \ @@ -172,9 +151,7 @@ vpxor r1, r4, r4; vpor r0, r1, r1; \ vpxor r0, r1, r1; \ vpor r4, r1, r1; \ - vpxor r1, r3, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r0,r3,r2,r1); + vpxor r1, r3, r3; #define SBOX2(r0, r1, r2, r3, r4) \ vmovdqa r0, r4; vpand r2, r0, r0; \ @@ -184,9 +161,7 @@ vmovdqa r3, r1; vpor r4, r3, r3; \ vpxor r0, r3, r3; vpand r1, r0, r0; \ vpxor r0, r4, r4; vpxor r3, r1, r1; \ - vpxor r4, r1, r1; vpxor RNOT, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r3,r1,r4,r0); + vpxor r4, r1, r1; vpxor RNOT, r4, r4; #define SBOX2_INVERSE(r0, r1, r2, r3, r4) \ vpxor r3, r2, r2; vpxor r0, r3, r3; \ @@ -198,9 +173,7 @@ vpor r0, r2, r2; vpxor RNOT, r3, r3; \ vpxor r3, r2, r2; vpxor r3, r0, r0; \ vpand r1, r0, r0; vpxor r4, r3, r3; \ - vpxor r0, r3, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r3,r0); + vpxor r0, r3, r3; #define SBOX3(r0, r1, r2, r3, r4) \ vmovdqa r0, r4; vpor r3, r0, r0; \ @@ -212,9 +185,7 @@ vpxor r2, r4, r4; vpor r0, r1, r1; \ vpxor r2, r1, r1; vpxor r3, r0, r0; \ vmovdqa r1, r2; vpor r3, r1, r1; \ - vpxor r0, r1, r1; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r3,r4,r0); + vpxor r0, r1, r1; #define SBOX3_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r2, r4; vpxor r1, r2, r2; \ @@ -226,9 +197,7 @@ vpxor r1, r3, r3; vpxor r0, r1, r1; \ vpor r2, r1, r1; vpxor r3, r0, r0; \ vpxor r4, r1, r1; \ - vpxor r1, r0, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r1,r3,r0,r4); + vpxor r1, r0, r0; #define SBOX4(r0, r1, r2, r3, r4) \ vpxor r3, r1, r1; vpxor RNOT, r3, r3; \ @@ -240,9 +209,7 @@ vpxor r0, r3, r3; vpor r1, r4, r4; \ vpxor r0, r4, r4; vpor r3, r0, r0; \ vpxor r2, r0, r0; vpand r3, r2, r2; \ - vpxor RNOT, r0, r0; vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r0,r3,r2); + vpxor RNOT, r0, r0; vpxor r2, r4, r4; #define SBOX4_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r2, r4; vpand r3, r2, r2; \ @@ -255,9 +222,7 @@ vpand r0, r2, r2; vpxor r0, r3, r3; \ vpxor r4, r2, r2; \ vpor r3, r2, r2; vpxor r0, r3, r3; \ - vpxor r1, r2, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r3,r2,r4,r1); + vpxor r1, r2, r2; #define SBOX5(r0, r1, r2, r3, r4) \ vpxor r1, r0, r0; vpxor r3, r1, r1; \ @@ -269,9 +234,7 @@ vpxor r2, r4, r4; vpxor r0, r2, r2; \ vpand r3, r0, r0; vpxor RNOT, r2, r2; \ vpxor r4, r0, r0; vpor r3, r4, r4; \ - vpxor r4, r2, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r3,r0,r2,r4); + vpxor r4, r2, r2; #define SBOX5_INVERSE(r0, r1, r2, r3, r4) \ vpxor RNOT, r1, r1; vmovdqa r3, r4; \ @@ -283,9 +246,7 @@ vpxor r3, r1, r1; vpxor r2, r4, r4; \ vpand r4, r3, r3; vpxor r1, r4, r4; \ vpxor r4, r3, r3; vpxor RNOT, r4, r4; \ - vpxor r0, r3, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r3,r2,r0); + vpxor r0, r3, r3; #define SBOX6(r0, r1, r2, r3, r4) \ vpxor RNOT, r2, r2; vmovdqa r3, r4; \ @@ -297,9 +258,7 @@ vpxor r2, r0, r0; vpxor r3, r4, r4; \ vpxor r0, r4, r4; vpxor RNOT, r3, r3; \ vpand r4, r2, r2; \ - vpxor r3, r2, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r1,r4,r2,r3); + vpxor r3, r2, r2; #define SBOX6_INVERSE(r0, r1, r2, r3, r4) \ vpxor r2, r0, r0; vmovdqa r2, r4; \ @@ -310,9 +269,7 @@ vpxor r1, r4, r4; vpand r3, r1, r1; \ vpxor r0, r1, r1; vpxor r3, r0, r0; \ vpor r2, r0, r0; vpxor r1, r3, r3; \ - vpxor r0, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r4,r3,r0); + vpxor r0, r4, r4; #define SBOX7(r0, r1, r2, r3, r4) \ vmovdqa r1, r4; vpor r2, r1, r1; \ @@ -325,9 +282,7 @@ vpxor r1, r2, r2; vpand r0, r1, r1; \ vpxor r4, r1, r1; vpxor RNOT, r2, r2; \ vpor r0, r2, r2; \ - vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r3,r1,r0,r2); + vpxor r2, r4, r4; #define SBOX7_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r2, r4; vpxor r0, r2, r2; \ @@ -339,9 +294,7 @@ vpor r2, r0, r0; vpxor r1, r4, r4; \ vpxor r3, r0, r0; vpxor r4, r3, r3; \ vpor r0, r4, r4; vpxor r2, r3, r3; \ - vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r3,r0,r1,r4,r2); + vpxor r2, r4, r4; /* Apply SBOX number WHICH to to the block. */ #define SBOX(which, r0, r1, r2, r3, r4) \ @@ -402,49 +355,51 @@ /* Apply a Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - LINEAR_TRANSFORMATION (a0, a1, a2, a3, a4); \ - LINEAR_TRANSFORMATION (b0, b1, b2, b3, b4); \ - .set round, (round + 1); +#define ROUND(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + LINEAR_TRANSFORMATION (na0, na1, na2, na3, na4); \ + LINEAR_TRANSFORMATION (nb0, nb1, nb2, nb3, nb4); /* Apply the last Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND_LAST(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - .set round, (round + 1); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round + 1); +#define ROUND_LAST(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, ((round) + 1)); \ + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, ((round) + 1)); /* Apply an inverse Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ +#define ROUND_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ LINEAR_TRANSFORMATION_INVERSE (a0, a1, a2, a3, a4); \ LINEAR_TRANSFORMATION_INVERSE (b0, b1, b2, b3, b4); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); /* Apply the first inverse Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND_FIRST_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); \ +#define ROUND_FIRST_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, ((round) + 1)); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, ((round) + 1)); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); .text @@ -456,72 +411,82 @@ __serpent_enc_blk16: * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: sixteen parallel * plaintext blocks * output: - * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: sixteen parallel + * RA4, RA1, RA2, RA0, RB4, RB1, RB2, RB0: sixteen parallel * ciphertext blocks */ - /* record input vector names for __serpent_enc_blk16 */ - .set enc_in_a0, RA0 - .set enc_in_a1, RA1 - .set enc_in_a2, RA2 - .set enc_in_a3, RA3 - .set enc_in_b0, RB0 - .set enc_in_b1, RB1 - .set enc_in_b2, RB2 - .set enc_in_b3, RB3 - vpcmpeqd RNOT, RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 0 - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_LAST (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); - transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - - /* record output vector names for __serpent_enc_blk16 */ - .set enc_out_a0, RA0 - .set enc_out_a1, RA1 - .set enc_out_a2, RA2 - .set enc_out_a3, RA3 - .set enc_out_b0, RB0 - .set enc_out_b1, RB1 - .set enc_out_b2, RB2 - .set enc_out_b3, RB3 + ROUND (0, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (1, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (2, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (3, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (4, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (5, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (6, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND (7, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + ROUND (8, 0, RA4, RA1, RA2, RA0, RA3, RA1, RA3, RA2, RA4, RA0, + RB4, RB1, RB2, RB0, RB3, RB1, RB3, RB2, RB4, RB0); + ROUND (9, 1, RA1, RA3, RA2, RA4, RA0, RA2, RA1, RA4, RA3, RA0, + RB1, RB3, RB2, RB4, RB0, RB2, RB1, RB4, RB3, RB0); + ROUND (10, 2, RA2, RA1, RA4, RA3, RA0, RA4, RA3, RA1, RA0, RA2, + RB2, RB1, RB4, RB3, RB0, RB4, RB3, RB1, RB0, RB2); + ROUND (11, 3, RA4, RA3, RA1, RA0, RA2, RA3, RA1, RA0, RA2, RA4, + RB4, RB3, RB1, RB0, RB2, RB3, RB1, RB0, RB2, RB4); + ROUND (12, 4, RA3, RA1, RA0, RA2, RA4, RA1, RA4, RA3, RA2, RA0, + RB3, RB1, RB0, RB2, RB4, RB1, RB4, RB3, RB2, RB0); + ROUND (13, 5, RA1, RA4, RA3, RA2, RA0, RA4, RA2, RA1, RA3, RA0, + RB1, RB4, RB3, RB2, RB0, RB4, RB2, RB1, RB3, RB0); + ROUND (14, 6, RA4, RA2, RA1, RA3, RA0, RA4, RA2, RA0, RA1, RA3, + RB4, RB2, RB1, RB3, RB0, RB4, RB2, RB0, RB1, RB3); + ROUND (15, 7, RA4, RA2, RA0, RA1, RA3, RA3, RA1, RA2, RA4, RA0, + RB4, RB2, RB0, RB1, RB3, RB3, RB1, RB2, RB4, RB0); + ROUND (16, 0, RA3, RA1, RA2, RA4, RA0, RA1, RA0, RA2, RA3, RA4, + RB3, RB1, RB2, RB4, RB0, RB1, RB0, RB2, RB3, RB4); + ROUND (17, 1, RA1, RA0, RA2, RA3, RA4, RA2, RA1, RA3, RA0, RA4, + RB1, RB0, RB2, RB3, RB4, RB2, RB1, RB3, RB0, RB4); + ROUND (18, 2, RA2, RA1, RA3, RA0, RA4, RA3, RA0, RA1, RA4, RA2, + RB2, RB1, RB3, RB0, RB4, RB3, RB0, RB1, RB4, RB2); + ROUND (19, 3, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA4, RA2, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB4, RB2, RB3); + ROUND (20, 4, RA0, RA1, RA4, RA2, RA3, RA1, RA3, RA0, RA2, RA4, + RB0, RB1, RB4, RB2, RB3, RB1, RB3, RB0, RB2, RB4); + ROUND (21, 5, RA1, RA3, RA0, RA2, RA4, RA3, RA2, RA1, RA0, RA4, + RB1, RB3, RB0, RB2, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND (22, 6, RA3, RA2, RA1, RA0, RA4, RA3, RA2, RA4, RA1, RA0, + RB3, RB2, RB1, RB0, RB4, RB3, RB2, RB4, RB1, RB0); + ROUND (23, 7, RA3, RA2, RA4, RA1, RA0, RA0, RA1, RA2, RA3, RA4, + RB3, RB2, RB4, RB1, RB0, RB0, RB1, RB2, RB3, RB4); + ROUND (24, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (25, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (26, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (27, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (28, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (29, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (30, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND_LAST (31, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + + transpose_4x4(RA4, RA1, RA2, RA0, RA3, RTMP0, RTMP1); + transpose_4x4(RB4, RB1, RB2, RB0, RB3, RTMP0, RTMP1); ret; .size __serpent_enc_blk16,.-__serpent_enc_blk16; @@ -538,69 +503,81 @@ __serpent_dec_blk16: * plaintext blocks */ - /* record input vector names for __serpent_dec_blk16 */ - .set dec_in_a0, RA0 - .set dec_in_a1, RA1 - .set dec_in_a2, RA2 - .set dec_in_a3, RA3 - .set dec_in_b0, RB0 - .set dec_in_b1, RB1 - .set dec_in_b2, RB2 - .set dec_in_b3, RB3 - vpcmpeqd RNOT, RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 32 - ROUND_FIRST_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); + ROUND_FIRST_INVERSE (31, 7, RA0, RA1, RA2, RA3, RA4, + RA3, RA0, RA1, RA4, RA2, + RB0, RB1, RB2, RB3, RB4, + RB3, RB0, RB1, RB4, RB2); + ROUND_INVERSE (30, 6, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA2, RA4, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB2, RB4, RB3); + ROUND_INVERSE (29, 5, RA0, RA1, RA2, RA4, RA3, RA1, RA3, RA4, RA2, RA0, + RB0, RB1, RB2, RB4, RB3, RB1, RB3, RB4, RB2, RB0); + ROUND_INVERSE (28, 4, RA1, RA3, RA4, RA2, RA0, RA1, RA2, RA4, RA0, RA3, + RB1, RB3, RB4, RB2, RB0, RB1, RB2, RB4, RB0, RB3); + ROUND_INVERSE (27, 3, RA1, RA2, RA4, RA0, RA3, RA4, RA2, RA0, RA1, RA3, + RB1, RB2, RB4, RB0, RB3, RB4, RB2, RB0, RB1, RB3); + ROUND_INVERSE (26, 2, RA4, RA2, RA0, RA1, RA3, RA2, RA3, RA0, RA1, RA4, + RB4, RB2, RB0, RB1, RB3, RB2, RB3, RB0, RB1, RB4); + ROUND_INVERSE (25, 1, RA2, RA3, RA0, RA1, RA4, RA4, RA2, RA1, RA0, RA3, + RB2, RB3, RB0, RB1, RB4, RB4, RB2, RB1, RB0, RB3); + ROUND_INVERSE (24, 0, RA4, RA2, RA1, RA0, RA3, RA4, RA3, RA2, RA0, RA1, + RB4, RB2, RB1, RB0, RB3, RB4, RB3, RB2, RB0, RB1); + ROUND_INVERSE (23, 7, RA4, RA3, RA2, RA0, RA1, RA0, RA4, RA3, RA1, RA2, + RB4, RB3, RB2, RB0, RB1, RB0, RB4, RB3, RB1, RB2); + ROUND_INVERSE (22, 6, RA0, RA4, RA3, RA1, RA2, RA4, RA3, RA2, RA1, RA0, + RB0, RB4, RB3, RB1, RB2, RB4, RB3, RB2, RB1, RB0); + ROUND_INVERSE (21, 5, RA4, RA3, RA2, RA1, RA0, RA3, RA0, RA1, RA2, RA4, + RB4, RB3, RB2, RB1, RB0, RB3, RB0, RB1, RB2, RB4); + ROUND_INVERSE (20, 4, RA3, RA0, RA1, RA2, RA4, RA3, RA2, RA1, RA4, RA0, + RB3, RB0, RB1, RB2, RB4, RB3, RB2, RB1, RB4, RB0); + ROUND_INVERSE (19, 3, RA3, RA2, RA1, RA4, RA0, RA1, RA2, RA4, RA3, RA0, + RB3, RB2, RB1, RB4, RB0, RB1, RB2, RB4, RB3, RB0); + ROUND_INVERSE (18, 2, RA1, RA2, RA4, RA3, RA0, RA2, RA0, RA4, RA3, RA1, + RB1, RB2, RB4, RB3, RB0, RB2, RB0, RB4, RB3, RB1); + ROUND_INVERSE (17, 1, RA2, RA0, RA4, RA3, RA1, RA1, RA2, RA3, RA4, RA0, + RB2, RB0, RB4, RB3, RB1, RB1, RB2, RB3, RB4, RB0); + ROUND_INVERSE (16, 0, RA1, RA2, RA3, RA4, RA0, RA1, RA0, RA2, RA4, RA3, + RB1, RB2, RB3, RB4, RB0, RB1, RB0, RB2, RB4, RB3); + ROUND_INVERSE (15, 7, RA1, RA0, RA2, RA4, RA3, RA4, RA1, RA0, RA3, RA2, + RB1, RB0, RB2, RB4, RB3, RB4, RB1, RB0, RB3, RB2); + ROUND_INVERSE (14, 6, RA4, RA1, RA0, RA3, RA2, RA1, RA0, RA2, RA3, RA4, + RB4, RB1, RB0, RB3, RB2, RB1, RB0, RB2, RB3, RB4); + ROUND_INVERSE (13, 5, RA1, RA0, RA2, RA3, RA4, RA0, RA4, RA3, RA2, RA1, + RB1, RB0, RB2, RB3, RB4, RB0, RB4, RB3, RB2, RB1); + ROUND_INVERSE (12, 4, RA0, RA4, RA3, RA2, RA1, RA0, RA2, RA3, RA1, RA4, + RB0, RB4, RB3, RB2, RB1, RB0, RB2, RB3, RB1, RB4); + ROUND_INVERSE (11, 3, RA0, RA2, RA3, RA1, RA4, RA3, RA2, RA1, RA0, RA4, + RB0, RB2, RB3, RB1, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND_INVERSE (10, 2, RA3, RA2, RA1, RA0, RA4, RA2, RA4, RA1, RA0, RA3, + RB3, RB2, RB1, RB0, RB4, RB2, RB4, RB1, RB0, RB3); + ROUND_INVERSE (9, 1, RA2, RA4, RA1, RA0, RA3, RA3, RA2, RA0, RA1, RA4, + RB2, RB4, RB1, RB0, RB3, RB3, RB2, RB0, RB1, RB4); + ROUND_INVERSE (8, 0, RA3, RA2, RA0, RA1, RA4, RA3, RA4, RA2, RA1, RA0, + RB3, RB2, RB0, RB1, RB4, RB3, RB4, RB2, RB1, RB0); + ROUND_INVERSE (7, 7, RA3, RA4, RA2, RA1, RA0, RA1, RA3, RA4, RA0, RA2, + RB3, RB4, RB2, RB1, RB0, RB1, RB3, RB4, RB0, RB2); + ROUND_INVERSE (6, 6, RA1, RA3, RA4, RA0, RA2, RA3, RA4, RA2, RA0, RA1, + RB1, RB3, RB4, RB0, RB2, RB3, RB4, RB2, RB0, RB1); + ROUND_INVERSE (5, 5, RA3, RA4, RA2, RA0, RA1, RA4, RA1, RA0, RA2, RA3, + RB3, RB4, RB2, RB0, RB1, RB4, RB1, RB0, RB2, RB3); + ROUND_INVERSE (4, 4, RA4, RA1, RA0, RA2, RA3, RA4, RA2, RA0, RA3, RA1, + RB4, RB1, RB0, RB2, RB3, RB4, RB2, RB0, RB3, RB1); + ROUND_INVERSE (3, 3, RA4, RA2, RA0, RA3, RA1, RA0, RA2, RA3, RA4, RA1, + RB4, RB2, RB0, RB3, RB1, RB0, RB2, RB3, RB4, RB1); + ROUND_INVERSE (2, 2, RA0, RA2, RA3, RA4, RA1, RA2, RA1, RA3, RA4, RA0, + RB0, RB2, RB3, RB4, RB1, RB2, RB1, RB3, RB4, RB0); + ROUND_INVERSE (1, 1, RA2, RA1, RA3, RA4, RA0, RA0, RA2, RA4, RA3, RA1, + RB2, RB1, RB3, RB4, RB0, RB0, RB2, RB4, RB3, RB1); + ROUND_INVERSE (0, 0, RA0, RA2, RA4, RA3, RA1, RA0, RA1, RA2, RA3, RA4, + RB0, RB2, RB4, RB3, RB1, RB0, RB1, RB2, RB3, RB4); transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - /* record output vector names for __serpent_dec_blk16 */ - .set dec_out_a0, RA0 - .set dec_out_a1, RA1 - .set dec_out_a2, RA2 - .set dec_out_a3, RA3 - .set dec_out_b0, RB0 - .set dec_out_b1, RB1 - .set dec_out_b2, RB2 - .set dec_out_b3, RB3 - ret; .size __serpent_dec_blk16,.-__serpent_dec_blk16; @@ -623,15 +600,6 @@ _gcry_serpent_avx2_ctr_enc: vzeroupper; - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - vbroadcasti128 .Lbswap128_mask RIP, RTMP3; vpcmpeqd RNOT, RNOT, RNOT; vpsrldq $8, RNOT, RNOT; /* ab: -1:0 ; cd: -1:0 */ @@ -703,32 +671,23 @@ _gcry_serpent_avx2_ctr_enc: call __serpent_enc_blk16; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - vpxor (0 * 32)(%rdx), RA0, RA0; + vpxor (0 * 32)(%rdx), RA4, RA4; vpxor (1 * 32)(%rdx), RA1, RA1; vpxor (2 * 32)(%rdx), RA2, RA2; - vpxor (3 * 32)(%rdx), RA3, RA3; - vpxor (4 * 32)(%rdx), RB0, RB0; + vpxor (3 * 32)(%rdx), RA0, RA0; + vpxor (4 * 32)(%rdx), RB4, RB4; vpxor (5 * 32)(%rdx), RB1, RB1; vpxor (6 * 32)(%rdx), RB2, RB2; - vpxor (7 * 32)(%rdx), RB3, RB3; + vpxor (7 * 32)(%rdx), RB0, RB0; - vmovdqu RA0, (0 * 32)(%rsi); + vmovdqu RA4, (0 * 32)(%rsi); vmovdqu RA1, (1 * 32)(%rsi); vmovdqu RA2, (2 * 32)(%rsi); - vmovdqu RA3, (3 * 32)(%rsi); - vmovdqu RB0, (4 * 32)(%rsi); + vmovdqu RA0, (3 * 32)(%rsi); + vmovdqu RB4, (4 * 32)(%rsi); vmovdqu RB1, (5 * 32)(%rsi); vmovdqu RB2, (6 * 32)(%rsi); - vmovdqu RB3, (7 * 32)(%rsi); + vmovdqu RB0, (7 * 32)(%rsi); vzeroall; @@ -748,15 +707,6 @@ _gcry_serpent_avx2_cbc_dec: vzeroupper; - .set RA0, dec_in_a0 - .set RA1, dec_in_a1 - .set RA2, dec_in_a2 - .set RA3, dec_in_a3 - .set RB0, dec_in_b0 - .set RB1, dec_in_b1 - .set RB2, dec_in_b2 - .set RB3, dec_in_b3 - vmovdqu (0 * 32)(%rdx), RA0; vmovdqu (1 * 32)(%rdx), RA1; vmovdqu (2 * 32)(%rdx), RA2; @@ -768,15 +718,6 @@ _gcry_serpent_avx2_cbc_dec: call __serpent_dec_blk16; - .set RA0, dec_out_a0 - .set RA1, dec_out_a1 - .set RA2, dec_out_a2 - .set RA3, dec_out_a3 - .set RB0, dec_out_b0 - .set RB1, dec_out_b1 - .set RB2, dec_out_b2 - .set RB3, dec_out_b3 - vmovdqu (%rcx), RNOTx; vinserti128 $1, (%rdx), RNOT, RNOT; vpxor RNOT, RA0, RA0; @@ -817,15 +758,6 @@ _gcry_serpent_avx2_cfb_dec: vzeroupper; - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - /* Load input */ vmovdqu (%rcx), RNOTx; vinserti128 $1, (%rdx), RNOT, RA0; @@ -843,32 +775,23 @@ _gcry_serpent_avx2_cfb_dec: call __serpent_enc_blk16; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - vpxor (0 * 32)(%rdx), RA0, RA0; + vpxor (0 * 32)(%rdx), RA4, RA4; vpxor (1 * 32)(%rdx), RA1, RA1; vpxor (2 * 32)(%rdx), RA2, RA2; - vpxor (3 * 32)(%rdx), RA3, RA3; - vpxor (4 * 32)(%rdx), RB0, RB0; + vpxor (3 * 32)(%rdx), RA0, RA0; + vpxor (4 * 32)(%rdx), RB4, RB4; vpxor (5 * 32)(%rdx), RB1, RB1; vpxor (6 * 32)(%rdx), RB2, RB2; - vpxor (7 * 32)(%rdx), RB3, RB3; + vpxor (7 * 32)(%rdx), RB0, RB0; - vmovdqu RA0, (0 * 32)(%rsi); + vmovdqu RA4, (0 * 32)(%rsi); vmovdqu RA1, (1 * 32)(%rsi); vmovdqu RA2, (2 * 32)(%rsi); - vmovdqu RA3, (3 * 32)(%rsi); - vmovdqu RB0, (4 * 32)(%rsi); + vmovdqu RA0, (3 * 32)(%rsi); + vmovdqu RB4, (4 * 32)(%rsi); vmovdqu RB1, (5 * 32)(%rsi); vmovdqu RB2, (6 * 32)(%rsi); - vmovdqu RB3, (7 * 32)(%rsi); + vmovdqu RB0, (7 * 32)(%rsi); vzeroall; diff --git a/cipher/serpent-sse2-amd64.S b/cipher/serpent-sse2-amd64.S index a5cf353..516126b 100644 --- a/cipher/serpent-sse2-amd64.S +++ b/cipher/serpent-sse2-amd64.S @@ -35,42 +35,27 @@ #define CTX %rdi /* vector registers */ -.set RA0, %xmm0 -.set RA1, %xmm1 -.set RA2, %xmm2 -.set RA3, %xmm3 -.set RA4, %xmm4 - -.set RB0, %xmm5 -.set RB1, %xmm6 -.set RB2, %xmm7 -.set RB3, %xmm8 -.set RB4, %xmm9 - -.set RNOT, %xmm10 -.set RTMP0, %xmm11 -.set RTMP1, %xmm12 -.set RTMP2, %xmm13 +#define RA0 %xmm0 +#define RA1 %xmm1 +#define RA2 %xmm2 +#define RA3 %xmm3 +#define RA4 %xmm4 + +#define RB0 %xmm5 +#define RB1 %xmm6 +#define RB2 %xmm7 +#define RB3 %xmm8 +#define RB4 %xmm9 + +#define RNOT %xmm10 +#define RTMP0 %xmm11 +#define RTMP1 %xmm12 +#define RTMP2 %xmm13 /********************************************************************** helper macros **********************************************************************/ -/* preprocessor macro for renaming vector registers using GAS macros */ -#define sbox_reg_rename(r0, r1, r2, r3, r4, \ - new_r0, new_r1, new_r2, new_r3, new_r4) \ - .set rename_reg0, new_r0; \ - .set rename_reg1, new_r1; \ - .set rename_reg2, new_r2; \ - .set rename_reg3, new_r3; \ - .set rename_reg4, new_r4; \ - \ - .set r0, rename_reg0; \ - .set r1, rename_reg1; \ - .set r2, rename_reg2; \ - .set r3, rename_reg3; \ - .set r4, rename_reg4; - /* vector 32-bit rotation to left */ #define vec_rol(reg, nleft, tmp) \ movdqa reg, tmp; \ @@ -147,9 +132,7 @@ pxor r4, r2; pxor RNOT, r4; \ por r1, r4; pxor r3, r1; \ pxor r4, r1; por r0, r3; \ - pxor r3, r1; pxor r3, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r0,r3); + pxor r3, r1; pxor r3, r4; #define SBOX0_INVERSE(r0, r1, r2, r3, r4) \ pxor RNOT, r2; movdqa r1, r4; \ @@ -162,9 +145,7 @@ pxor r1, r2; pxor r0, r3; \ pxor r1, r3; \ pand r3, r2; \ - pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r4,r1,r3,r2); + pxor r2, r4; #define SBOX1(r0, r1, r2, r3, r4) \ pxor RNOT, r0; pxor RNOT, r2; \ @@ -176,9 +157,7 @@ pand r4, r2; pxor r1, r0; \ pand r2, r1; \ pxor r0, r1; pand r2, r0; \ - pxor r4, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r0,r3,r1,r4); + pxor r4, r0; #define SBOX1_INVERSE(r0, r1, r2, r3, r4) \ movdqa r1, r4; pxor r3, r1; \ @@ -191,9 +170,7 @@ pxor r1, r4; por r0, r1; \ pxor r0, r1; \ por r4, r1; \ - pxor r1, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r0,r3,r2,r1); + pxor r1, r3; #define SBOX2(r0, r1, r2, r3, r4) \ movdqa r0, r4; pand r2, r0; \ @@ -203,9 +180,7 @@ movdqa r3, r1; por r4, r3; \ pxor r0, r3; pand r1, r0; \ pxor r0, r4; pxor r3, r1; \ - pxor r4, r1; pxor RNOT, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r3,r1,r4,r0); + pxor r4, r1; pxor RNOT, r4; #define SBOX2_INVERSE(r0, r1, r2, r3, r4) \ pxor r3, r2; pxor r0, r3; \ @@ -217,9 +192,7 @@ por r0, r2; pxor RNOT, r3; \ pxor r3, r2; pxor r3, r0; \ pand r1, r0; pxor r4, r3; \ - pxor r0, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r3,r0); + pxor r0, r3; #define SBOX3(r0, r1, r2, r3, r4) \ movdqa r0, r4; por r3, r0; \ @@ -231,9 +204,7 @@ pxor r2, r4; por r0, r1; \ pxor r2, r1; pxor r3, r0; \ movdqa r1, r2; por r3, r1; \ - pxor r0, r1; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r3,r4,r0); + pxor r0, r1; #define SBOX3_INVERSE(r0, r1, r2, r3, r4) \ movdqa r2, r4; pxor r1, r2; \ @@ -245,9 +216,7 @@ pxor r1, r3; pxor r0, r1; \ por r2, r1; pxor r3, r0; \ pxor r4, r1; \ - pxor r1, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r1,r3,r0,r4); + pxor r1, r0; #define SBOX4(r0, r1, r2, r3, r4) \ pxor r3, r1; pxor RNOT, r3; \ @@ -259,9 +228,7 @@ pxor r0, r3; por r1, r4; \ pxor r0, r4; por r3, r0; \ pxor r2, r0; pand r3, r2; \ - pxor RNOT, r0; pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r0,r3,r2); + pxor RNOT, r0; pxor r2, r4; #define SBOX4_INVERSE(r0, r1, r2, r3, r4) \ movdqa r2, r4; pand r3, r2; \ @@ -274,9 +241,7 @@ pand r0, r2; pxor r0, r3; \ pxor r4, r2; \ por r3, r2; pxor r0, r3; \ - pxor r1, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r3,r2,r4,r1); + pxor r1, r2; #define SBOX5(r0, r1, r2, r3, r4) \ pxor r1, r0; pxor r3, r1; \ @@ -288,9 +253,7 @@ pxor r2, r4; pxor r0, r2; \ pand r3, r0; pxor RNOT, r2; \ pxor r4, r0; por r3, r4; \ - pxor r4, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r3,r0,r2,r4); + pxor r4, r2; #define SBOX5_INVERSE(r0, r1, r2, r3, r4) \ pxor RNOT, r1; movdqa r3, r4; \ @@ -302,9 +265,7 @@ pxor r3, r1; pxor r2, r4; \ pand r4, r3; pxor r1, r4; \ pxor r4, r3; pxor RNOT, r4; \ - pxor r0, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r3,r2,r0); + pxor r0, r3; #define SBOX6(r0, r1, r2, r3, r4) \ pxor RNOT, r2; movdqa r3, r4; \ @@ -316,9 +277,7 @@ pxor r2, r0; pxor r3, r4; \ pxor r0, r4; pxor RNOT, r3; \ pand r4, r2; \ - pxor r3, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r1,r4,r2,r3); + pxor r3, r2; #define SBOX6_INVERSE(r0, r1, r2, r3, r4) \ pxor r2, r0; movdqa r2, r4; \ @@ -329,9 +288,7 @@ pxor r1, r4; pand r3, r1; \ pxor r0, r1; pxor r3, r0; \ por r2, r0; pxor r1, r3; \ - pxor r0, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r4,r3,r0); + pxor r0, r4; #define SBOX7(r0, r1, r2, r3, r4) \ movdqa r1, r4; por r2, r1; \ @@ -344,9 +301,7 @@ pxor r1, r2; pand r0, r1; \ pxor r4, r1; pxor RNOT, r2; \ por r0, r2; \ - pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r3,r1,r0,r2); + pxor r2, r4; #define SBOX7_INVERSE(r0, r1, r2, r3, r4) \ movdqa r2, r4; pxor r0, r2; \ @@ -358,9 +313,7 @@ por r2, r0; pxor r1, r4; \ pxor r3, r0; pxor r4, r3; \ por r0, r4; pxor r2, r3; \ - pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r3,r0,r1,r4,r2); + pxor r2, r4; /* Apply SBOX number WHICH to to the block. */ #define SBOX(which, r0, r1, r2, r3, r4) \ @@ -425,49 +378,51 @@ /* Apply a Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - LINEAR_TRANSFORMATION (a0, a1, a2, a3, a4); \ - LINEAR_TRANSFORMATION (b0, b1, b2, b3, b4); \ - .set round, (round + 1); +#define ROUND(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + LINEAR_TRANSFORMATION (na0, na1, na2, na3, na4); \ + LINEAR_TRANSFORMATION (nb0, nb1, nb2, nb3, nb4); /* Apply the last Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND_LAST(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - .set round, (round + 1); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round + 1); +#define ROUND_LAST(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, ((round) + 1)); \ + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, ((round) + 1)); /* Apply an inverse Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ +#define ROUND_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ LINEAR_TRANSFORMATION_INVERSE (a0, a1, a2, a3, a4); \ LINEAR_TRANSFORMATION_INVERSE (b0, b1, b2, b3, b4); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); /* Apply the first inverse Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND_FIRST_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); \ +#define ROUND_FIRST_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, ((round) + 1)); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, ((round) + 1)); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); .text @@ -479,72 +434,82 @@ __serpent_enc_blk8: * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel plaintext * blocks * output: - * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel + * RA4, RA1, RA2, RA0, RB4, RB1, RB2, RB0: eight parallel * ciphertext blocks */ - /* record input vector names for __serpent_enc_blk8 */ - .set enc_in_a0, RA0 - .set enc_in_a1, RA1 - .set enc_in_a2, RA2 - .set enc_in_a3, RA3 - .set enc_in_b0, RB0 - .set enc_in_b1, RB1 - .set enc_in_b2, RB2 - .set enc_in_b3, RB3 - pcmpeqd RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 0 - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_LAST (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); - transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - - /* record output vector names for __serpent_enc_blk8 */ - .set enc_out_a0, RA0 - .set enc_out_a1, RA1 - .set enc_out_a2, RA2 - .set enc_out_a3, RA3 - .set enc_out_b0, RB0 - .set enc_out_b1, RB1 - .set enc_out_b2, RB2 - .set enc_out_b3, RB3 + ROUND (0, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (1, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (2, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (3, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (4, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (5, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (6, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND (7, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + ROUND (8, 0, RA4, RA1, RA2, RA0, RA3, RA1, RA3, RA2, RA4, RA0, + RB4, RB1, RB2, RB0, RB3, RB1, RB3, RB2, RB4, RB0); + ROUND (9, 1, RA1, RA3, RA2, RA4, RA0, RA2, RA1, RA4, RA3, RA0, + RB1, RB3, RB2, RB4, RB0, RB2, RB1, RB4, RB3, RB0); + ROUND (10, 2, RA2, RA1, RA4, RA3, RA0, RA4, RA3, RA1, RA0, RA2, + RB2, RB1, RB4, RB3, RB0, RB4, RB3, RB1, RB0, RB2); + ROUND (11, 3, RA4, RA3, RA1, RA0, RA2, RA3, RA1, RA0, RA2, RA4, + RB4, RB3, RB1, RB0, RB2, RB3, RB1, RB0, RB2, RB4); + ROUND (12, 4, RA3, RA1, RA0, RA2, RA4, RA1, RA4, RA3, RA2, RA0, + RB3, RB1, RB0, RB2, RB4, RB1, RB4, RB3, RB2, RB0); + ROUND (13, 5, RA1, RA4, RA3, RA2, RA0, RA4, RA2, RA1, RA3, RA0, + RB1, RB4, RB3, RB2, RB0, RB4, RB2, RB1, RB3, RB0); + ROUND (14, 6, RA4, RA2, RA1, RA3, RA0, RA4, RA2, RA0, RA1, RA3, + RB4, RB2, RB1, RB3, RB0, RB4, RB2, RB0, RB1, RB3); + ROUND (15, 7, RA4, RA2, RA0, RA1, RA3, RA3, RA1, RA2, RA4, RA0, + RB4, RB2, RB0, RB1, RB3, RB3, RB1, RB2, RB4, RB0); + ROUND (16, 0, RA3, RA1, RA2, RA4, RA0, RA1, RA0, RA2, RA3, RA4, + RB3, RB1, RB2, RB4, RB0, RB1, RB0, RB2, RB3, RB4); + ROUND (17, 1, RA1, RA0, RA2, RA3, RA4, RA2, RA1, RA3, RA0, RA4, + RB1, RB0, RB2, RB3, RB4, RB2, RB1, RB3, RB0, RB4); + ROUND (18, 2, RA2, RA1, RA3, RA0, RA4, RA3, RA0, RA1, RA4, RA2, + RB2, RB1, RB3, RB0, RB4, RB3, RB0, RB1, RB4, RB2); + ROUND (19, 3, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA4, RA2, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB4, RB2, RB3); + ROUND (20, 4, RA0, RA1, RA4, RA2, RA3, RA1, RA3, RA0, RA2, RA4, + RB0, RB1, RB4, RB2, RB3, RB1, RB3, RB0, RB2, RB4); + ROUND (21, 5, RA1, RA3, RA0, RA2, RA4, RA3, RA2, RA1, RA0, RA4, + RB1, RB3, RB0, RB2, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND (22, 6, RA3, RA2, RA1, RA0, RA4, RA3, RA2, RA4, RA1, RA0, + RB3, RB2, RB1, RB0, RB4, RB3, RB2, RB4, RB1, RB0); + ROUND (23, 7, RA3, RA2, RA4, RA1, RA0, RA0, RA1, RA2, RA3, RA4, + RB3, RB2, RB4, RB1, RB0, RB0, RB1, RB2, RB3, RB4); + ROUND (24, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (25, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (26, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (27, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (28, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (29, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (30, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND_LAST (31, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + + transpose_4x4(RA4, RA1, RA2, RA0, RA3, RTMP0, RTMP1); + transpose_4x4(RB4, RB1, RB2, RB0, RB3, RTMP0, RTMP1); ret; .size __serpent_enc_blk8,.-__serpent_enc_blk8; @@ -561,69 +526,81 @@ __serpent_dec_blk8: * blocks */ - /* record input vector names for __serpent_dec_blk8 */ - .set dec_in_a0, RA0 - .set dec_in_a1, RA1 - .set dec_in_a2, RA2 - .set dec_in_a3, RA3 - .set dec_in_b0, RB0 - .set dec_in_b1, RB1 - .set dec_in_b2, RB2 - .set dec_in_b3, RB3 - pcmpeqd RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 32 - ROUND_FIRST_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); + ROUND_FIRST_INVERSE (31, 7, RA0, RA1, RA2, RA3, RA4, + RA3, RA0, RA1, RA4, RA2, + RB0, RB1, RB2, RB3, RB4, + RB3, RB0, RB1, RB4, RB2); + ROUND_INVERSE (30, 6, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA2, RA4, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB2, RB4, RB3); + ROUND_INVERSE (29, 5, RA0, RA1, RA2, RA4, RA3, RA1, RA3, RA4, RA2, RA0, + RB0, RB1, RB2, RB4, RB3, RB1, RB3, RB4, RB2, RB0); + ROUND_INVERSE (28, 4, RA1, RA3, RA4, RA2, RA0, RA1, RA2, RA4, RA0, RA3, + RB1, RB3, RB4, RB2, RB0, RB1, RB2, RB4, RB0, RB3); + ROUND_INVERSE (27, 3, RA1, RA2, RA4, RA0, RA3, RA4, RA2, RA0, RA1, RA3, + RB1, RB2, RB4, RB0, RB3, RB4, RB2, RB0, RB1, RB3); + ROUND_INVERSE (26, 2, RA4, RA2, RA0, RA1, RA3, RA2, RA3, RA0, RA1, RA4, + RB4, RB2, RB0, RB1, RB3, RB2, RB3, RB0, RB1, RB4); + ROUND_INVERSE (25, 1, RA2, RA3, RA0, RA1, RA4, RA4, RA2, RA1, RA0, RA3, + RB2, RB3, RB0, RB1, RB4, RB4, RB2, RB1, RB0, RB3); + ROUND_INVERSE (24, 0, RA4, RA2, RA1, RA0, RA3, RA4, RA3, RA2, RA0, RA1, + RB4, RB2, RB1, RB0, RB3, RB4, RB3, RB2, RB0, RB1); + ROUND_INVERSE (23, 7, RA4, RA3, RA2, RA0, RA1, RA0, RA4, RA3, RA1, RA2, + RB4, RB3, RB2, RB0, RB1, RB0, RB4, RB3, RB1, RB2); + ROUND_INVERSE (22, 6, RA0, RA4, RA3, RA1, RA2, RA4, RA3, RA2, RA1, RA0, + RB0, RB4, RB3, RB1, RB2, RB4, RB3, RB2, RB1, RB0); + ROUND_INVERSE (21, 5, RA4, RA3, RA2, RA1, RA0, RA3, RA0, RA1, RA2, RA4, + RB4, RB3, RB2, RB1, RB0, RB3, RB0, RB1, RB2, RB4); + ROUND_INVERSE (20, 4, RA3, RA0, RA1, RA2, RA4, RA3, RA2, RA1, RA4, RA0, + RB3, RB0, RB1, RB2, RB4, RB3, RB2, RB1, RB4, RB0); + ROUND_INVERSE (19, 3, RA3, RA2, RA1, RA4, RA0, RA1, RA2, RA4, RA3, RA0, + RB3, RB2, RB1, RB4, RB0, RB1, RB2, RB4, RB3, RB0); + ROUND_INVERSE (18, 2, RA1, RA2, RA4, RA3, RA0, RA2, RA0, RA4, RA3, RA1, + RB1, RB2, RB4, RB3, RB0, RB2, RB0, RB4, RB3, RB1); + ROUND_INVERSE (17, 1, RA2, RA0, RA4, RA3, RA1, RA1, RA2, RA3, RA4, RA0, + RB2, RB0, RB4, RB3, RB1, RB1, RB2, RB3, RB4, RB0); + ROUND_INVERSE (16, 0, RA1, RA2, RA3, RA4, RA0, RA1, RA0, RA2, RA4, RA3, + RB1, RB2, RB3, RB4, RB0, RB1, RB0, RB2, RB4, RB3); + ROUND_INVERSE (15, 7, RA1, RA0, RA2, RA4, RA3, RA4, RA1, RA0, RA3, RA2, + RB1, RB0, RB2, RB4, RB3, RB4, RB1, RB0, RB3, RB2); + ROUND_INVERSE (14, 6, RA4, RA1, RA0, RA3, RA2, RA1, RA0, RA2, RA3, RA4, + RB4, RB1, RB0, RB3, RB2, RB1, RB0, RB2, RB3, RB4); + ROUND_INVERSE (13, 5, RA1, RA0, RA2, RA3, RA4, RA0, RA4, RA3, RA2, RA1, + RB1, RB0, RB2, RB3, RB4, RB0, RB4, RB3, RB2, RB1); + ROUND_INVERSE (12, 4, RA0, RA4, RA3, RA2, RA1, RA0, RA2, RA3, RA1, RA4, + RB0, RB4, RB3, RB2, RB1, RB0, RB2, RB3, RB1, RB4); + ROUND_INVERSE (11, 3, RA0, RA2, RA3, RA1, RA4, RA3, RA2, RA1, RA0, RA4, + RB0, RB2, RB3, RB1, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND_INVERSE (10, 2, RA3, RA2, RA1, RA0, RA4, RA2, RA4, RA1, RA0, RA3, + RB3, RB2, RB1, RB0, RB4, RB2, RB4, RB1, RB0, RB3); + ROUND_INVERSE (9, 1, RA2, RA4, RA1, RA0, RA3, RA3, RA2, RA0, RA1, RA4, + RB2, RB4, RB1, RB0, RB3, RB3, RB2, RB0, RB1, RB4); + ROUND_INVERSE (8, 0, RA3, RA2, RA0, RA1, RA4, RA3, RA4, RA2, RA1, RA0, + RB3, RB2, RB0, RB1, RB4, RB3, RB4, RB2, RB1, RB0); + ROUND_INVERSE (7, 7, RA3, RA4, RA2, RA1, RA0, RA1, RA3, RA4, RA0, RA2, + RB3, RB4, RB2, RB1, RB0, RB1, RB3, RB4, RB0, RB2); + ROUND_INVERSE (6, 6, RA1, RA3, RA4, RA0, RA2, RA3, RA4, RA2, RA0, RA1, + RB1, RB3, RB4, RB0, RB2, RB3, RB4, RB2, RB0, RB1); + ROUND_INVERSE (5, 5, RA3, RA4, RA2, RA0, RA1, RA4, RA1, RA0, RA2, RA3, + RB3, RB4, RB2, RB0, RB1, RB4, RB1, RB0, RB2, RB3); + ROUND_INVERSE (4, 4, RA4, RA1, RA0, RA2, RA3, RA4, RA2, RA0, RA3, RA1, + RB4, RB1, RB0, RB2, RB3, RB4, RB2, RB0, RB3, RB1); + ROUND_INVERSE (3, 3, RA4, RA2, RA0, RA3, RA1, RA0, RA2, RA3, RA4, RA1, + RB4, RB2, RB0, RB3, RB1, RB0, RB2, RB3, RB4, RB1); + ROUND_INVERSE (2, 2, RA0, RA2, RA3, RA4, RA1, RA2, RA1, RA3, RA4, RA0, + RB0, RB2, RB3, RB4, RB1, RB2, RB1, RB3, RB4, RB0); + ROUND_INVERSE (1, 1, RA2, RA1, RA3, RA4, RA0, RA0, RA2, RA4, RA3, RA1, + RB2, RB1, RB3, RB4, RB0, RB0, RB2, RB4, RB3, RB1); + ROUND_INVERSE (0, 0, RA0, RA2, RA4, RA3, RA1, RA0, RA1, RA2, RA3, RA4, + RB0, RB2, RB4, RB3, RB1, RB0, RB1, RB2, RB3, RB4); transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - /* record output vector names for __serpent_dec_blk8 */ - .set dec_out_a0, RA0 - .set dec_out_a1, RA1 - .set dec_out_a2, RA2 - .set dec_out_a3, RA3 - .set dec_out_b0, RB0 - .set dec_out_b1, RB1 - .set dec_out_b2, RB2 - .set dec_out_b3, RB3 - ret; .size __serpent_dec_blk8,.-__serpent_dec_blk8; @@ -638,15 +615,6 @@ _gcry_serpent_sse2_ctr_enc: * %rcx: iv (big endian, 128bit) */ - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - /* load IV and byteswap */ movdqu (%rcx), RA0; movdqa RA0, RTMP0; @@ -729,42 +697,35 @@ _gcry_serpent_sse2_ctr_enc: call __serpent_enc_blk8; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - pxor_u((0 * 16)(%rdx), RA0, RTMP0); + pxor_u((0 * 16)(%rdx), RA4, RTMP0); pxor_u((1 * 16)(%rdx), RA1, RTMP0); pxor_u((2 * 16)(%rdx), RA2, RTMP0); - pxor_u((3 * 16)(%rdx), RA3, RTMP0); - pxor_u((4 * 16)(%rdx), RB0, RTMP0); + pxor_u((3 * 16)(%rdx), RA0, RTMP0); + pxor_u((4 * 16)(%rdx), RB4, RTMP0); pxor_u((5 * 16)(%rdx), RB1, RTMP0); pxor_u((6 * 16)(%rdx), RB2, RTMP0); - pxor_u((7 * 16)(%rdx), RB3, RTMP0); + pxor_u((7 * 16)(%rdx), RB0, RTMP0); - movdqu RA0, (0 * 16)(%rsi); + movdqu RA4, (0 * 16)(%rsi); movdqu RA1, (1 * 16)(%rsi); movdqu RA2, (2 * 16)(%rsi); - movdqu RA3, (3 * 16)(%rsi); - movdqu RB0, (4 * 16)(%rsi); + movdqu RA0, (3 * 16)(%rsi); + movdqu RB4, (4 * 16)(%rsi); movdqu RB1, (5 * 16)(%rsi); movdqu RB2, (6 * 16)(%rsi); - movdqu RB3, (7 * 16)(%rsi); + movdqu RB0, (7 * 16)(%rsi); /* clear the used registers */ pxor RA0, RA0; pxor RA1, RA1; pxor RA2, RA2; pxor RA3, RA3; + pxor RA4, RA4; pxor RB0, RB0; pxor RB1, RB1; pxor RB2, RB2; pxor RB3, RB3; + pxor RB4, RB4; pxor RTMP0, RTMP0; pxor RTMP1, RTMP1; pxor RTMP2, RTMP2; @@ -784,15 +745,6 @@ _gcry_serpent_sse2_cbc_dec: * %rcx: iv */ - .set RA0, dec_in_a0 - .set RA1, dec_in_a1 - .set RA2, dec_in_a2 - .set RA3, dec_in_a3 - .set RB0, dec_in_b0 - .set RB1, dec_in_b1 - .set RB2, dec_in_b2 - .set RB3, dec_in_b3 - movdqu (0 * 16)(%rdx), RA0; movdqu (1 * 16)(%rdx), RA1; movdqu (2 * 16)(%rdx), RA2; @@ -804,15 +756,6 @@ _gcry_serpent_sse2_cbc_dec: call __serpent_dec_blk8; - .set RA0, dec_out_a0 - .set RA1, dec_out_a1 - .set RA2, dec_out_a2 - .set RA3, dec_out_a3 - .set RB0, dec_out_b0 - .set RB1, dec_out_b1 - .set RB2, dec_out_b2 - .set RB3, dec_out_b3 - movdqu (7 * 16)(%rdx), RNOT; pxor_u((%rcx), RA0, RTMP0); pxor_u((0 * 16)(%rdx), RA1, RTMP0); @@ -838,10 +781,12 @@ _gcry_serpent_sse2_cbc_dec: pxor RA1, RA1; pxor RA2, RA2; pxor RA3, RA3; + pxor RA4, RA4; pxor RB0, RB0; pxor RB1, RB1; pxor RB2, RB2; pxor RB3, RB3; + pxor RB4, RB4; pxor RTMP0, RTMP0; pxor RTMP1, RTMP1; pxor RTMP2, RTMP2; @@ -861,15 +806,6 @@ _gcry_serpent_sse2_cfb_dec: * %rcx: iv */ - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - /* Load input */ movdqu (%rcx), RA0; movdqu 0 * 16(%rdx), RA1; @@ -886,42 +822,35 @@ _gcry_serpent_sse2_cfb_dec: call __serpent_enc_blk8; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - pxor_u((0 * 16)(%rdx), RA0, RTMP0); + pxor_u((0 * 16)(%rdx), RA4, RTMP0); pxor_u((1 * 16)(%rdx), RA1, RTMP0); pxor_u((2 * 16)(%rdx), RA2, RTMP0); - pxor_u((3 * 16)(%rdx), RA3, RTMP0); - pxor_u((4 * 16)(%rdx), RB0, RTMP0); + pxor_u((3 * 16)(%rdx), RA0, RTMP0); + pxor_u((4 * 16)(%rdx), RB4, RTMP0); pxor_u((5 * 16)(%rdx), RB1, RTMP0); pxor_u((6 * 16)(%rdx), RB2, RTMP0); - pxor_u((7 * 16)(%rdx), RB3, RTMP0); + pxor_u((7 * 16)(%rdx), RB0, RTMP0); - movdqu RA0, (0 * 16)(%rsi); + movdqu RA4, (0 * 16)(%rsi); movdqu RA1, (1 * 16)(%rsi); movdqu RA2, (2 * 16)(%rsi); - movdqu RA3, (3 * 16)(%rsi); - movdqu RB0, (4 * 16)(%rsi); + movdqu RA0, (3 * 16)(%rsi); + movdqu RB4, (4 * 16)(%rsi); movdqu RB1, (5 * 16)(%rsi); movdqu RB2, (6 * 16)(%rsi); - movdqu RB3, (7 * 16)(%rsi); + movdqu RB0, (7 * 16)(%rsi); /* clear the used registers */ pxor RA0, RA0; pxor RA1, RA1; pxor RA2, RA2; pxor RA3, RA3; + pxor RA4, RA4; pxor RB0, RB0; pxor RB1, RB1; pxor RB2, RB2; pxor RB3, RB3; + pxor RB4, RB4; pxor RTMP0, RTMP0; pxor RTMP1, RTMP1; pxor RTMP2, RTMP2; diff --git a/configure.ac b/configure.ac index 1460dfd..a803b5f 100644 --- a/configure.ac +++ b/configure.ac @@ -1034,12 +1034,6 @@ if test $amd64_as_feature_detection = yes; then [gcry_cv_gcc_amd64_platform_as_ok=no AC_COMPILE_IFELSE([AC_LANG_SOURCE( [[__asm__( - /* Test if '.set' is supported by underlying assembler. */ - ".set a0, %rax\n\t" - ".set b0, %rdx\n\t" - "asmfunc:\n\t" - "movq a0, b0;\n\t" /* Fails here if .set ignored by as. */ - /* Test if '.type' and '.size' are supported. */ /* These work only on ELF targets. */ /* TODO: add COFF (mingw64, cygwin64) support to assembly From dbaryshkov at gmail.com Sun Oct 20 21:49:20 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Sun, 20 Oct 2013 23:49:20 +0400 Subject: [PATCH 1/2] [v2] Add API to support AEAD cipher modes In-Reply-To: <20131020120313.21970.15918.stgit@localhost6.localdomain6> References: <20131020120313.21970.15918.stgit@localhost6.localdomain6> Message-ID: Hello, On Sun, Oct 20, 2013 at 4:03 PM, Jussi Kivilinna wrote: > - Change gcry_cipher_tag to gcry_cipher_checktag and gcry_cipher_gettag > for giving tag (checktag) for decryption and reading tag (gettag) after > encryption. > - Change gcry_cipher_authenticate to gcry_cipher_setaad, since > additional parameters needed for some AEAD modes (in this case CCM, > which needs the length of encrypted data and tag for MAC > initialization). I'm quite unsure that we should make this API call _that_ specific. I would propose to separate _authenticate()/_aad() method for passing cleartext data and a set of ioctl's (GCRY_CTL_*) that pass additional information depending on selected AEAD mode. For example, for GCM you don't need to know aadlen/enclen/taglen in advance. -- With best wishes Dmitry From gniibe at fsij.org Mon Oct 21 09:46:13 2013 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 21 Oct 2013 16:46:13 +0900 Subject: ECDSA for Edwards curve (was: [PATCH v2 2/2] Add support for GOST R 34.10-2001/-2012 signatures) In-Reply-To: <87iowwiefw.fsf@vigenere.g10code.de> References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> <87ppr5jnbm.fsf@vigenere.g10code.de> <87iowwiefw.fsf@vigenere.g10code.de> Message-ID: <1382341573.3497.1.camel@cfw2.gniibe.org> On 2013-10-17 at 08:44 +0200, Werner Koch wrote: > On Wed, 16 Oct 2013 18:13, dbaryshkov at gmail.com said: > > And strangely enough it aborts in 50% of runs. Sometimes it does, sometimes > > it just outputs a note regarding testkey and and exits normally. > > I failed to capture a problem either via gdb or via valgrind. > > It is an algorithmic problem. I think that I figure out the issue of failure. In the function nist_generate_key, when we change the private key "d" into -d, it assumes Weierstrass curve, where negative point of (x, y) is (x, -y). However, for Twisted Edwards curve, negative point of (u, v) is (-u, v). Perhaps, compact form would be v only for Twisted Edwards curve. Or, we could change the code so that we can have interfaces of getting/setting affine point in the representation of corresponding Weierstrass curve (x, y) for Twisted Edwards curve. And public key is specified by Weierstrass curve representation. -- From jussi.kivilinna at iki.fi Mon Oct 21 12:30:10 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 21 Oct 2013 13:30:10 +0300 Subject: [PATCH 1/2] [v2] Add API to support AEAD cipher modes In-Reply-To: References: <20131020120313.21970.15918.stgit@localhost6.localdomain6> Message-ID: <52650232.7080009@iki.fi> On 20.10.2013 22:49, Dmitry Eremin-Solenikov wrote: > Hello, > > On Sun, Oct 20, 2013 at 4:03 PM, Jussi Kivilinna wrote: >> - Change gcry_cipher_tag to gcry_cipher_checktag and gcry_cipher_gettag >> for giving tag (checktag) for decryption and reading tag (gettag) after >> encryption. >> - Change gcry_cipher_authenticate to gcry_cipher_setaad, since >> additional parameters needed for some AEAD modes (in this case CCM, >> which needs the length of encrypted data and tag for MAC >> initialization). > > I'm quite unsure that we should make this API call _that_ specific. > I would propose to separate _authenticate()/_aad() method for passing > cleartext data and a set of ioctl's (GCRY_CTL_*) that pass additional > information > depending on selected AEAD mode. Ok, I changed API back to _authenticate() and added GCRYCTL_SET_CCM_PARAMS CCM patch. Looks better now and another benefit is that now AAD can be passed in multiple as calls to _authenticate. -Jussi > > For example, for GCM you don't need to know aadlen/enclen/taglen in advance. > From jussi.kivilinna at iki.fi Mon Oct 21 12:34:06 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 21 Oct 2013 13:34:06 +0300 Subject: [PATCH 1/2] [v3] Add API to support AEAD cipher modes Message-ID: <20131021103406.22420.58657.stgit@localhost6.localdomain6> * cipher/cipher.c (_gcry_cipher_authenticate, _gcry_cipher_checktag) (_gcry_cipher_gettag): New. * doc/gcrypt.texi: Add documentation for new API functions. * src/visibility.c (gcry_cipher_authenticate, gcry_cipher_checktag) (gcry_cipher_gettag): New. * src/gcrypt.h.in, src/visibility.h: add declarations of these functions. * src/libgcrypt.defs, src/libgcrypt.vers: export functions. -- Authenticated Encryption with Associated Data (AEAD) cipher modes provide authentication tag that can be used to authenticate message. At the same time it allows one to specify additional (unencrypted data) that will be authenticated together with the message. This class of cipher modes requires additional API present in this commit. This patch is based on original patch by Dmitry Eremin-Solenikov. Changes in v2: - Change gcry_cipher_tag to gcry_cipher_checktag and gcry_cipher_gettag for giving tag (checktag) for decryption and reading tag (gettag) after encryption. - Change gcry_cipher_authenticate to gcry_cipher_setaad, since additional parameters needed for some AEAD modes (in this case CCM, which needs the length of encrypted data and tag for MAC initialization). - Add some documentation. Changes in v3: - Change gcry_cipher_setaad back to gcry_cipher_authenticate. Additional parameters (encrypt_len, tag_len, aad_len) for CCM will be given through GCRY_CTL_SET_CCM_PARAMS. Signed-off-by: Jussi Kivilinna --- cipher/cipher.c | 34 ++++++++++++++++++++++++++++++++++ doc/gcrypt.texi | 35 +++++++++++++++++++++++++++++++++++ src/gcrypt.h.in | 11 +++++++++++ src/libgcrypt.def | 3 +++ src/libgcrypt.vers | 1 + src/visibility.c | 27 +++++++++++++++++++++++++++ src/visibility.h | 9 +++++++++ 7 files changed, 120 insertions(+) diff --git a/cipher/cipher.c b/cipher/cipher.c index 75d42d1..36c79db 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -910,6 +910,40 @@ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return 0; } +gcry_error_t +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen) +{ + log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + + (void)abuf; + (void)abuflen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + + (void)outtag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + + (void)intag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + gcry_error_t gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 473c484..0049fa0 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1731,6 +1731,10 @@ matches the requirement of the selected algorithm and mode. This function is also used with the Salsa20 stream cipher to set or update the required nonce. In this case it needs to be called after setting the key. + +This function is also used with the AEAD cipher modes to set or +update the required nonce. + @end deftypefun @deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, const void *@var{c}, size_t @var{l}) @@ -1750,6 +1754,37 @@ call to gcry_cipher_setkey and clear the initialization vector. Note that gcry_cipher_reset is implemented as a macro. @end deftypefun +Authenticated Encryption with Associated Data (AEAD) block cipher +modes require the handling of the authentication tag and the additional +authenticated data, which can be done by using the following +functions: + + at deftypefun gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t @var{h}, const void *@var{abuf}, size_t @var{abuflen}) + +Process the buffer @var{abuf} of length @var{abuflen} as the additional +authenticated data (AAD) for AEAD cipher modes. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t @var{h}, void *@var{tag}, size_t @var{taglen}) + +This function is used to read the authentication tag after encryption. +The function finalizes and outputs the authentication tag to the buffer + at var{tag} of length @var{taglen} bytes. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t @var{h}, const void *@var{tag}, size_t @var{taglen}) + +Check the authentication tag after decryption. The authentication +tag is passed as the buffer @var{tag} of length @var{taglen} bytes +and compared to internal authentication tag computed during +decryption. Error code @code{GPG_ERR_CHECKSUM} is returned if +the authentication tag in the buffer @var{tag} does not match +the authentication tag calculated during decryption. + + at end deftypefun + The actual encryption and decryption is done by using one of the following functions. They may be used as often as required to process all the data. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 64cc0e4..f0ae927 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -953,6 +953,17 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen); +/* Provide additional authentication data for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen); + +/* Get authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, + size_t taglen); + +/* Check authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, + size_t taglen); /* Reset the handle to the state after open. */ #define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0) diff --git a/src/libgcrypt.def b/src/libgcrypt.def index ec0c1e3..64ba370 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -255,6 +255,9 @@ EXPORTS gcry_sexp_extract_param @225 + gcry_cipher_authenticate @226 + gcry_cipher_gettag @227 + gcry_cipher_checktag @228 ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index be72aad..93eaa93 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -51,6 +51,7 @@ GCRYPT_1.6 { gcry_cipher_info; gcry_cipher_map_name; gcry_cipher_mode_from_oid; gcry_cipher_open; gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr; + gcry_cipher_authenticate; gcry_cipher_gettag; gcry_cipher_checktag; gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl; gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey; diff --git a/src/visibility.c b/src/visibility.c index 848925e..1f7bb3a 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -713,6 +713,33 @@ gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return _gcry_cipher_setctr (hd, ctr, ctrlen); } +gcry_error_t +gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_authenticate (hd, abuf, abuflen); +} + +gcry_error_t +gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_gettag (hd, outtag, taglen); +} + +gcry_error_t +gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_checktag (hd, intag, taglen); +} + gcry_error_t gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/src/visibility.h b/src/visibility.h index 1c8f047..b2fa4c0 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -81,6 +81,9 @@ #define gcry_cipher_setkey _gcry_cipher_setkey #define gcry_cipher_setiv _gcry_cipher_setiv #define gcry_cipher_setctr _gcry_cipher_setctr +#define gcry_cipher_authenticate _gcry_cipher_authenticate +#define gcry_cipher_checktag _gcry_cipher_checktag +#define gcry_cipher_gettag _gcry_cipher_gettag #define gcry_cipher_ctl _gcry_cipher_ctl #define gcry_cipher_decrypt _gcry_cipher_decrypt #define gcry_cipher_encrypt _gcry_cipher_encrypt @@ -297,6 +300,9 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, #undef gcry_cipher_setkey #undef gcry_cipher_setiv #undef gcry_cipher_setctr +#undef gcry_cipher_authenticate +#undef gcry_cipher_checktag +#undef gcry_cipher_gettag #undef gcry_cipher_ctl #undef gcry_cipher_decrypt #undef gcry_cipher_encrypt @@ -474,6 +480,9 @@ MARK_VISIBLE (gcry_cipher_close) MARK_VISIBLE (gcry_cipher_setkey) MARK_VISIBLE (gcry_cipher_setiv) MARK_VISIBLE (gcry_cipher_setctr) +MARK_VISIBLE (gcry_cipher_authenticate) +MARK_VISIBLE (gcry_cipher_checktag) +MARK_VISIBLE (gcry_cipher_gettag) MARK_VISIBLE (gcry_cipher_ctl) MARK_VISIBLE (gcry_cipher_decrypt) MARK_VISIBLE (gcry_cipher_encrypt) From jussi.kivilinna at iki.fi Mon Oct 21 12:34:11 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 21 Oct 2013 13:34:11 +0300 Subject: [PATCH 2/2] [v3] Add Counter with CBC-MAC mode (CCM) In-Reply-To: <20131021103406.22420.58657.stgit@localhost6.localdomain6> References: <20131021103406.22420.58657.stgit@localhost6.localdomain6> Message-ID: <20131021103411.22420.21185.stgit@localhost6.localdomain6> * cipher/Makefile.am: Add 'cipher-ccm.c'. * cipher/cipher-ccm.c: New. * cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode'. (_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt) (_gcry_cipher_ccm_set_nonce, _gcry_cipher_ccm_authenticate) (_gcry_cipher_ccm_get_tag, _gcry_cipher_ccm_check_tag) (_gcry_cipher_ccm_set_params): New prototypes. * cipher/cipher.c (gcry_cipher_open, cipher_encrypt, cipher_decrypt) (_gcry_cipher_setiv, _gcry_cipher_authenticate, _gcry_cipher_gettag) (_gcry_cipher_checktag, gry_cipher_ctl): Add handling for CCM mode. * doc/gcrypt.texi: Add documentation for GCRY_CIPHER_MODE_CCM. * src/gcrypt.h.in (gcry_cipher_modes): Add 'GCRY_CIPHER_MODE_CCM' and 'GCRYCTL_SET_CCM_PARAMS'. (GCRY_CCM_BLOCK_LEN): New. * tests/basic.c (check_ccm_cipher): New. (check_cipher_modes): Call 'check_ccm_cipher'. * tests/benchmark.c (ccm_aead_init): New. (cipher_bench): Add handling for AEAD modes and add CCM benchmarking. -- Patch adds CCM (Counter with CBC-MAC) mode as defined in RFC 3610 and NIST Special Publication 800-38C. Example for encrypting message (split in two buffers; buf1, buf2) and authenticating additional non-encrypted data (split in two buffers; aadbuf1, aadbuf2) with authentication tag length of eigth bytes: size_t params[3]; taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1) + len(buf2); /* 0: enclen */ params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_PARAMS, params, sizeof(size_t) * 3); gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1)); gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2)); gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_encrypt(h, buf2, len(buf2), buf2, len(buf2)); gcry_cipher_gettag(h, tag, taglen); Example for decrypting above message and checking authentication tag: size_t params[3]; taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1) + len(buf2); /* 0: enclen */ params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_PARAMS, params, sizeof(size_t) * 3); gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1)); gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2)); gcry_cipher_decrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_decrypt(h, buf2, len(buf2), buf2, len(buf2)); err = gcry_cipher_checktag(h, tag, taglen); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) { /* Authentication failed. */ } else if (err == 0) { /* Authentication ok. */ } Example for encrypting message without additional authenticated data: size_t params[3]; taglen = 10; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1); /* 0: enclen */ params[1] = 0; /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_PARAMS, params, sizeof(size_t) * 3); gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_gettag(h, tag, taglen); To reset CCM state for cipher handle, one can either set new nonce or use 'gcry_cipher_reset'. This implementation reuses existing CTR mode code for encryption/decryption and is there for able to process multiple buffers that are not multiple of blocksize. AAD data maybe also be passed into gcry_cipher_authenticate in non-blocksize chunks. Signed-off-by: Jussi Kivilinna --- cipher/Makefile.am | 1 cipher/cipher-ccm.c | 371 ++++++++++++++++++++++ cipher/cipher-internal.h | 48 +++ cipher/cipher.c | 107 ++++++ doc/gcrypt.texi | 16 + src/gcrypt.h.in | 8 tests/basic.c | 771 ++++++++++++++++++++++++++++++++++++++++++++++ tests/benchmark.c | 80 +++++ 8 files changed, 1377 insertions(+), 25 deletions(-) create mode 100644 cipher/cipher-ccm.c diff --git a/cipher/Makefile.am b/cipher/Makefile.am index a2b2c8a..b0efd89 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -40,6 +40,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES) libcipher_la_SOURCES = \ cipher.c cipher-internal.h \ cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \ +cipher-ccm.c \ cipher-selftest.c cipher-selftest.h \ pubkey.c pubkey-internal.h pubkey-util.c \ md.c \ diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c new file mode 100644 index 0000000..e51fa32 --- /dev/null +++ b/cipher/cipher-ccm.c @@ -0,0 +1,371 @@ +/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static unsigned int +do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, + int do_padding) +{ + const unsigned int blocksize = 16; + unsigned char tmp[blocksize]; + unsigned int burn = 0; + unsigned int unused = c->u_mode.ccm.mac_unused; + size_t nblocks; + + if (inlen == 0 && (unused == 0 || !do_padding)) + return 0; + + do + { + if (inlen + unused < blocksize || unused > 0) + { + for (; inlen && unused < blocksize; inlen--) + c->u_mode.ccm.macbuf[unused++] = *inbuf++; + } + if (!inlen) + { + if (!do_padding) + break; + + while (unused < blocksize) + c->u_mode.ccm.macbuf[unused++] = 0; + } + + if (unused > 0) + { + /* Process one block from macbuf. */ + buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + unused = 0; + } + + if (c->bulk.cbc_enc) + { + nblocks = inlen / blocksize; + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1); + inbuf += nblocks * blocksize; + inlen -= nblocks * blocksize; + + wipememory (tmp, sizeof(tmp)); + } + else + { + while (inlen >= blocksize) + { + buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + inlen -= blocksize; + inbuf += blocksize; + } + } + } + while (inlen > 0); + + c->u_mode.ccm.mac_unused = unused; + + if (burn) + burn += 4 * sizeof(void *); + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + size_t L = 15 - noncelen; + size_t L_; + + L_ = L - 1; + + if (!nonce) + return GPG_ERR_INV_ARG; + /* Length field must be 2, 3, ..., or 8. */ + if (L < 2 || L > 8) + return GPG_ERR_INV_LENGTH; + + /* Reset state */ + memset (&c->u_mode, 0, sizeof(c->u_mode)); + memset (&c->marks, 0, sizeof(c->marks)); + memset (&c->u_iv, 0, sizeof(c->u_iv)); + memset (&c->u_ctr, 0, sizeof(c->u_ctr)); + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + + /* Setup CTR */ + c->u_ctr.ctr[0] = L_; + memcpy (&c->u_ctr.ctr[1], nonce, noncelen); + memset (&c->u_ctr.ctr[1 + noncelen], 0, L); + + /* Setup IV */ + c->u_iv.iv[0] = L_; + memcpy (&c->u_iv.iv[1], nonce, noncelen); + /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later + in set_aad. */ + memset (&c->u_iv.iv[1 + noncelen], 0, L); + + c->u_mode.ccm.nonce = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_params (gcry_cipher_hd_t c, size_t encryptlen, + size_t aadlen, size_t taglen) +{ + unsigned int burn = 0; + unsigned char b0[16]; + size_t noncelen = 15 - (c->u_iv.iv[0] + 1); + size_t M = taglen; + size_t M_; + int i; + + M_ = (M - 2) / 2; + + /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */ + if ((M_ * 2 + 2) != M || M < 4 || M > 16) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.ccm.params) + return GPG_ERR_INV_STATE; + + c->u_mode.ccm.authlen = taglen; + c->u_mode.ccm.encryptlen = encryptlen; + c->u_mode.ccm.aadlen = aadlen; + + /* Complete IV setup. */ + c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8; + for (i = 16 - 1; i >= 1 + noncelen; i--) + { + c->u_iv.iv[i] = encryptlen & 0xff; + encryptlen >>= 8; + } + + memcpy (b0, c->u_iv.iv, 16); + memset (c->u_iv.iv, 0, 16); + + set_burn (burn, do_cbc_mac (c, b0, 16, 0)); + + if (aadlen == 0) + { + /* Do nothing. */ + } + else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff) + { + b0[0] = (aadlen >> 8) & 0xff; + b0[1] = aadlen & 0xff; + set_burn (burn, do_cbc_mac (c, b0, 2, 0)); + } + else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xfe; + buf_put_be32(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 6, 0)); + } +#ifdef HAVE_U64_TYPEDEF + else if (aadlen > (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xff; + buf_put_be64(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 10, 0)); + } +#endif + + /* Generate S_0 and increase counter. */ + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0, + c->u_ctr.ctr )); + c->u_ctr.ctr[15]++; + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->u_mode.ccm.params = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, + size_t abuflen) +{ + unsigned int burn; + + if (abuflen > 0 && !abuf) + return GPG_ERR_INV_ARG; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.params || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (abuflen > c->u_mode.ccm.aadlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.aadlen -= abuflen; + burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, int check) +{ + unsigned int burn; + + if (!outbuf || outbuflen == 0) + return GPG_ERR_INV_ARG; + /* Tag length must be same as initial authlen. */ + if (c->u_mode.ccm.authlen != outbuflen) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.params || c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + /* Initial encrypt length must match with length of actual data processed. */ + if (c->u_mode.ccm.encryptlen > 0) + return GPG_ERR_UNFINISHED; + + if (!c->u_mode.ccm.tag) + { + burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ + + /* Add S_0 */ + buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + + wipememory (c->u_ctr.ctr, 16); + wipememory (c->u_mode.ccm.s0, 16); + wipememory (c->u_mode.ccm.macbuf, 16); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + int diff, i; + + /* Constant-time compare. */ + for (i = 0, diff = 0; i < outbuflen; i++) + diff -= !!(outbuf[i] - c->u_iv.iv[i]); + + return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); +} + + +gcry_err_code_t +_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.params || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, inbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +} + + +gcry_err_code_t +_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + gcry_err_code_t err; + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.params || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + if (err) + return err; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, outbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return err; +} + diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index b60ef38..fbaef4f 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -100,7 +100,8 @@ struct gcry_cipher_handle /* The initialization vector. For best performance we make sure that it is properly aligned. In particular some implementations - of bulk operations expect an 16 byte aligned IV. */ + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */ union { cipher_context_alignment_t iv_align; unsigned char iv[MAX_BLOCKSIZE]; @@ -117,6 +118,26 @@ struct gcry_cipher_handle unsigned char lastiv[MAX_BLOCKSIZE]; int unused; /* Number of unused bytes in LASTIV. */ + union { + /* Mode specific storage for CCM mode. */ + struct { + size_t encryptlen; + size_t aadlen; + unsigned int authlen; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int nonce:1;/* Set to 1 if nonce has been set. */ + unsigned int params:1; /* Set to 1 if CCM parameters has been + processed. */ + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ + } ccm; + } u_mode; + /* What follows are two contexts of the cipher in use. The first one needs to be aligned well enough for the cipher operation whereas the second one is a copy created by cipher_setkey and @@ -175,5 +196,30 @@ gcry_err_code_t _gcry_cipher_aeswrap_decrypt const byte *inbuf, unsigned int inbuflen); +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ccm_authenticate +/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen); +gcry_err_code_t _gcry_cipher_ccm_set_params +/* */ (gcry_cipher_hd_t c, size_t encryptedlen, size_t aadlen, + size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); + + #endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/cipher/cipher.c b/cipher/cipher.c index 36c79db..db7f505 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -375,6 +375,13 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, if (! err) switch (mode) { + case GCRY_CIPHER_MODE_CCM: + if (spec->blocksize != GCRY_CCM_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: @@ -613,6 +620,8 @@ cipher_reset (gcry_cipher_hd_t c) memset (c->u_iv.iv, 0, c->spec->blocksize); memset (c->lastiv, 0, c->spec->blocksize); memset (c->u_ctr.ctr, 0, c->spec->blocksize); + memset (&c->u_mode, 0, sizeof c->u_mode); + c->unused = 0; } @@ -718,6 +727,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stencrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -811,6 +824,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stdecrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -885,8 +902,19 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) gcry_error_t _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) { - cipher_setiv (hd, iv, ivlen); - return 0; + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen); + break; + + default: + cipher_setiv (hd, iv, ivlen); + break; + } + return gpg_error (rc); } /* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of @@ -914,34 +942,61 @@ gcry_error_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) { - log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_authenticate (hd, abuf, abuflen); + break; - (void)abuf; - (void)abuflen; + default: + log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) { - log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen); + break; - (void)outtag; - (void)taglen; + default: + log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) { - log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen); + break; - (void)intag; - (void)taglen; + default: + log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } @@ -980,6 +1035,30 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) h->flags &= ~GCRY_CIPHER_CBC_MAC; break; + case GCRYCTL_SET_CCM_PARAMS: + { + size_t params[3]; + size_t encryptedlen; + size_t aadlen; + size_t authtaglen; + + if (h->mode != GCRY_CIPHER_MODE_CCM) + return gcry_error (GPG_ERR_INV_CIPHER_MODE); + + if (!buffer || buflen != 3 * sizeof(size_t)) + return gcry_error (GPG_ERR_INV_ARG); + + /* This command is used to pass additional length parameters needed + by CCM mode to initialize CBC-MAC. */ + memcpy (params, buffer, sizeof(params)); + encryptedlen = params[0]; + aadlen = params[1]; + authtaglen = params[2]; + + rc = _gcry_cipher_ccm_set_params (h, encryptedlen, aadlen, authtaglen); + } + break; + case GCRYCTL_DISABLE_ALGO: /* This command expects NULL for H and BUFFER to point to an integer with the algo number. */ diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 0049fa0..91fe399 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1635,6 +1635,12 @@ may be specified 64 bit (8 byte) shorter than then input buffer. As per specs the input length must be at least 128 bits and the length must be a multiple of 64 bits. + at item GCRY_CIPHER_MODE_CCM + at cindex CCM, Counter with CBC-MAC mode +Counter with CBC-MAC mode is an Authenticated Encryption with +Associated Data (AEAD) block cipher mode, which is specified in +'NIST Special Publication 800-38C' and RFC 3610. + @end table @node Working with cipher handles @@ -1661,11 +1667,13 @@ The cipher mode to use must be specified via @var{mode}. See @xref{Available cipher modes}, for a list of supported cipher modes and the according constants. Note that some modes are incompatible with some algorithms - in particular, stream mode -(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. Any -block cipher mode (@code{GCRY_CIPHER_MODE_ECB}, +(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. The +block cipher modes (@code{GCRY_CIPHER_MODE_ECB}, @code{GCRY_CIPHER_MODE_CBC}, @code{GCRY_CIPHER_MODE_CFB}, - at code{GCRY_CIPHER_MODE_OFB} or @code{GCRY_CIPHER_MODE_CTR}) will work -with any block cipher algorithm. + at code{GCRY_CIPHER_MODE_OFB} and @code{GCRY_CIPHER_MODE_CTR}) will work +with any block cipher algorithm. The @code{GCRY_CIPHER_MODE_CCM} will +only work with block cipher algorithms which have the block size of +16 bytes. The third argument @var{flags} can either be passed as @code{0} or as the bit-wise OR of the following constants. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index f0ae927..63bfd24 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -325,7 +325,8 @@ enum gcry_ctl_cmds GCRYCTL_SET_PREFERRED_RNG_TYPE = 65, GCRYCTL_GET_CURRENT_RNG_TYPE = 66, GCRYCTL_DISABLE_LOCKED_SECMEM = 67, - GCRYCTL_DISABLE_PRIV_DROP = 68 + GCRYCTL_DISABLE_PRIV_DROP = 68, + GCRYCTL_SET_CCM_PARAMS = 69 }; /* Perform various operations defined by CMD. */ @@ -884,7 +885,8 @@ enum gcry_cipher_modes GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ GCRY_CIPHER_MODE_CTR = 6, /* Counter. */ - GCRY_CIPHER_MODE_AESWRAP= 7 /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_AESWRAP= 7, /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_CCM = 8 /* Counter with CBC-MAC. */ }; /* Flags used with the open function. */ @@ -896,6 +898,8 @@ enum gcry_cipher_flags GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */ }; +/* CCM works only with blocks of 128 bits. */ +#define GCRY_CCM_BLOCK_LEN (128 / 8) /* Create a handle for algorithm ALGO to be used in MODE. FLAGS may be given as an bitwise OR of the gcry_cipher_flags values. */ diff --git a/tests/basic.c b/tests/basic.c index 1d6e637..f7771e1 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -1139,6 +1139,776 @@ check_ofb_cipher (void) static void +check_ccm_cipher (void) +{ + static const struct tv + { + int algo; + int keylen; + const char *key; + int noncelen; + const char *nonce; + int aadlen; + const char *aad; + int plainlen; + const char *plaintext; + int cipherlen; + const char *ciphertext; + } tv[] = + { + /* RFC 3610 */ + { GCRY_CIPHER_AES, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\x58\x8C\x97\x9A\x61\xC6\x63\xD2\xF0\x66\xD0\xC2\xC0\xF9\x89\x80\x6D\x5F\x6B\x61\xDA\xC3\x84\x17\xE8\xD1\x2C\xFD\xF9\x26\xE0"}, + { GCRY_CIPHER_AES, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x72\xC9\x1A\x36\xE1\x35\xF8\xCF\x29\x1C\xA8\x94\x08\x5C\x87\xE3\xCC\x15\xC4\x39\xC9\xE4\x3A\x3B\xA0\x91\xD5\x6E\x10\x40\x09\x16"}, + { GCRY_CIPHER_AES, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x51\xB1\xE5\xF4\x4A\x19\x7D\x1D\xA4\x6B\x0F\x8E\x2D\x28\x2A\xE8\x71\xE8\x38\xBB\x64\xDA\x85\x96\x57\x4A\xDA\xA7\x6F\xBD\x9F\xB0\xC5"}, + { GCRY_CIPHER_AES, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xA2\x8C\x68\x65\x93\x9A\x9A\x79\xFA\xAA\x5C\x4C\x2A\x9D\x4A\x91\xCD\xAC\x8C\x96\xC8\x61\xB9\xC9\xE6\x1E\xF1"}, + { GCRY_CIPHER_AES, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\xDC\xF1\xFB\x7B\x5D\x9E\x23\xFB\x9D\x4E\x13\x12\x53\x65\x8A\xD8\x6E\xBD\xCA\x3E\x51\xE8\x3F\x07\x7D\x9C\x2D\x93"}, + { GCRY_CIPHER_AES, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\x6F\xC1\xB0\x11\xF0\x06\x56\x8B\x51\x71\xA4\x2D\x95\x3D\x46\x9B\x25\x70\xA4\xBD\x87\x40\x5A\x04\x43\xAC\x91\xCB\x94"}, + { GCRY_CIPHER_AES, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x01\x35\xD1\xB2\xC9\x5F\x41\xD5\xD1\xD4\xFE\xC1\x85\xD1\x66\xB8\x09\x4E\x99\x9D\xFE\xD9\x6C\x04\x8C\x56\x60\x2C\x97\xAC\xBB\x74\x90"}, + { GCRY_CIPHER_AES, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x7B\x75\x39\x9A\xC0\x83\x1D\xD2\xF0\xBB\xD7\x58\x79\xA2\xFD\x8F\x6C\xAE\x6B\x6C\xD9\xB7\xDB\x24\xC1\x7B\x44\x33\xF4\x34\x96\x3F\x34\xB4"}, + { GCRY_CIPHER_AES, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x82\x53\x1A\x60\xCC\x24\x94\x5A\x4B\x82\x79\x18\x1A\xB5\xC8\x4D\xF2\x1C\xE7\xF9\xB7\x3F\x42\xE1\x97\xEA\x9C\x07\xE5\x6B\x5E\xB1\x7E\x5F\x4E"}, + { GCRY_CIPHER_AES, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\x07\x34\x25\x94\x15\x77\x85\x15\x2B\x07\x40\x98\x33\x0A\xBB\x14\x1B\x94\x7B\x56\x6A\xA9\x40\x6B\x4D\x99\x99\x88\xDD"}, + { GCRY_CIPHER_AES, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x67\x6B\xB2\x03\x80\xB0\xE3\x01\xE8\xAB\x79\x59\x0A\x39\x6D\xA7\x8B\x83\x49\x34\xF5\x3A\xA2\xE9\x10\x7A\x8B\x6C\x02\x2C"}, + { GCRY_CIPHER_AES, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\xC0\xFF\xA0\xD6\xF0\x5B\xDB\x67\xF2\x4D\x43\xA4\x33\x8D\x2A\xA4\xBE\xD7\xB2\x0E\x43\xCD\x1A\xA3\x16\x62\xE7\xAD\x65\xD6\xDB"}, + { GCRY_CIPHER_AES, /* Packet Vector #13 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x41\x2B\x4E\xA9\xCD\xBE\x3C\x96\x96\x76\x6C\xFA", + 8, "\x0B\xE1\xA8\x8B\xAC\xE0\x18\xB1", + 23, + "\x08\xE8\xCF\x97\xD8\x20\xEA\x25\x84\x60\xE9\x6A\xD9\xCF\x52\x89\x05\x4D\x89\x5C\xEA\xC4\x7C", + 31, + "\x4C\xB9\x7F\x86\xA2\xA4\x68\x9A\x87\x79\x47\xAB\x80\x91\xEF\x53\x86\xA6\xFF\xBD\xD0\x80\xF8\xE7\x8C\xF7\xCB\x0C\xDD\xD7\xB3"}, + { GCRY_CIPHER_AES, /* Packet Vector #14 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x33\x56\x8E\xF7\xB2\x63\x3C\x96\x96\x76\x6C\xFA", + 8, "\x63\x01\x8F\x76\xDC\x8A\x1B\xCB", + 24, + "\x90\x20\xEA\x6F\x91\xBD\xD8\x5A\xFA\x00\x39\xBA\x4B\xAF\xF9\xBF\xB7\x9C\x70\x28\x94\x9C\xD0\xEC", + 32, + "\x4C\xCB\x1E\x7C\xA9\x81\xBE\xFA\xA0\x72\x6C\x55\xD3\x78\x06\x12\x98\xC8\x5C\x92\x81\x4A\xBC\x33\xC5\x2E\xE8\x1D\x7D\x77\xC0\x8A"}, + { GCRY_CIPHER_AES, /* Packet Vector #15 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x10\x3F\xE4\x13\x36\x71\x3C\x96\x96\x76\x6C\xFA", + 8, "\xAA\x6C\xFA\x36\xCA\xE8\x6B\x40", + 25, + "\xB9\x16\xE0\xEA\xCC\x1C\x00\xD7\xDC\xEC\x68\xEC\x0B\x3B\xBB\x1A\x02\xDE\x8A\x2D\x1A\xA3\x46\x13\x2E", + 33, + "\xB1\xD2\x3A\x22\x20\xDD\xC0\xAC\x90\x0D\x9A\xA0\x3C\x61\xFC\xF4\xA5\x59\xA4\x41\x77\x67\x08\x97\x08\xA7\x76\x79\x6E\xDB\x72\x35\x06"}, + { GCRY_CIPHER_AES, /* Packet Vector #16 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x76\x4C\x63\xB8\x05\x8E\x3C\x96\x96\x76\x6C\xFA", + 12, "\xD0\xD0\x73\x5C\x53\x1E\x1B\xEC\xF0\x49\xC2\x44", + 19, + "\x12\xDA\xAC\x56\x30\xEF\xA5\x39\x6F\x77\x0C\xE1\xA6\x6B\x21\xF7\xB2\x10\x1C", + 27, + "\x14\xD2\x53\xC3\x96\x7B\x70\x60\x9B\x7C\xBB\x7C\x49\x91\x60\x28\x32\x45\x26\x9A\x6F\x49\x97\x5B\xCA\xDE\xAF"}, + { GCRY_CIPHER_AES, /* Packet Vector #17 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xF8\xB6\x78\x09\x4E\x3B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x77\xB6\x0F\x01\x1C\x03\xE1\x52\x58\x99\xBC\xAE", + 20, + "\xE8\x8B\x6A\x46\xC7\x8D\x63\xE5\x2E\xB8\xC5\x46\xEF\xB5\xDE\x6F\x75\xE9\xCC\x0D", + 28, + "\x55\x45\xFF\x1A\x08\x5E\xE2\xEF\xBF\x52\xB2\xE0\x4B\xEE\x1E\x23\x36\xC7\x3E\x3F\x76\x2C\x0C\x77\x44\xFE\x7E\x3C"}, + { GCRY_CIPHER_AES, /* Packet Vector #18 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xD5\x60\x91\x2D\x3F\x70\x3C\x96\x96\x76\x6C\xFA", + 12, "\xCD\x90\x44\xD2\xB7\x1F\xDB\x81\x20\xEA\x60\xC0", + 21, + "\x64\x35\xAC\xBA\xFB\x11\xA8\x2E\x2F\x07\x1D\x7C\xA4\xA5\xEB\xD9\x3A\x80\x3B\xA8\x7F", + 29, + "\x00\x97\x69\xEC\xAB\xDF\x48\x62\x55\x94\xC5\x92\x51\xE6\x03\x57\x22\x67\x5E\x04\xC8\x47\x09\x9E\x5A\xE0\x70\x45\x51"}, + { GCRY_CIPHER_AES, /* Packet Vector #19 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x42\xFF\xF8\xF1\x95\x1C\x3C\x96\x96\x76\x6C\xFA", + 8, "\xD8\x5B\xC7\xE6\x9F\x94\x4F\xB8", + 23, + "\x8A\x19\xB9\x50\xBC\xF7\x1A\x01\x8E\x5E\x67\x01\xC9\x17\x87\x65\x98\x09\xD6\x7D\xBE\xDD\x18", + 33, + "\xBC\x21\x8D\xAA\x94\x74\x27\xB6\xDB\x38\x6A\x99\xAC\x1A\xEF\x23\xAD\xE0\xB5\x29\x39\xCB\x6A\x63\x7C\xF9\xBE\xC2\x40\x88\x97\xC6\xBA"}, + { GCRY_CIPHER_AES, /* Packet Vector #20 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x92\x0F\x40\xE5\x6C\xDC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x74\xA0\xEB\xC9\x06\x9F\x5B\x37", + 24, + "\x17\x61\x43\x3C\x37\xC5\xA3\x5F\xC1\xF3\x9F\x40\x63\x02\xEB\x90\x7C\x61\x63\xBE\x38\xC9\x84\x37", + 34, + "\x58\x10\xE6\xFD\x25\x87\x40\x22\xE8\x03\x61\xA4\x78\xE3\xE9\xCF\x48\x4A\xB0\x4F\x44\x7E\xFF\xF6\xF0\xA4\x77\xCC\x2F\xC9\xBF\x54\x89\x44"}, + { GCRY_CIPHER_AES, /* Packet Vector #21 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x27\xCA\x0C\x71\x20\xBC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x44\xA3\xAA\x3A\xAE\x64\x75\xCA", + 25, + "\xA4\x34\xA8\xE5\x85\x00\xC6\xE4\x15\x30\x53\x88\x62\xD6\x86\xEA\x9E\x81\x30\x1B\x5A\xE4\x22\x6B\xFA", + 35, + "\xF2\xBE\xED\x7B\xC5\x09\x8E\x83\xFE\xB5\xB3\x16\x08\xF8\xE2\x9C\x38\x81\x9A\x89\xC8\xE7\x76\xF1\x54\x4D\x41\x51\xA4\xED\x3A\x8B\x87\xB9\xCE"}, + { GCRY_CIPHER_AES, /* Packet Vector #22 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x5B\x8C\xCB\xCD\x9A\xF8\x3C\x96\x96\x76\x6C\xFA", + 12, "\xEC\x46\xBB\x63\xB0\x25\x20\xC3\x3C\x49\xFD\x70", + 19, + "\xB9\x6B\x49\xE2\x1D\x62\x17\x41\x63\x28\x75\xDB\x7F\x6C\x92\x43\xD2\xD7\xC2", + 29, + "\x31\xD7\x50\xA0\x9D\xA3\xED\x7F\xDD\xD4\x9A\x20\x32\xAA\xBF\x17\xEC\x8E\xBF\x7D\x22\xC8\x08\x8C\x66\x6B\xE5\xC1\x97"}, + { GCRY_CIPHER_AES, /* Packet Vector #23 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x3E\xBE\x94\x04\x4B\x9A\x3C\x96\x96\x76\x6C\xFA", + 12, "\x47\xA6\x5A\xC7\x8B\x3D\x59\x42\x27\xE8\x5E\x71", + 20, + "\xE2\xFC\xFB\xB8\x80\x44\x2C\x73\x1B\xF9\x51\x67\xC8\xFF\xD7\x89\x5E\x33\x70\x76", + 30, + "\xE8\x82\xF1\xDB\xD3\x8C\xE3\xED\xA7\xC2\x3F\x04\xDD\x65\x07\x1E\xB4\x13\x42\xAC\xDF\x7E\x00\xDC\xCE\xC7\xAE\x52\x98\x7D"}, + { GCRY_CIPHER_AES, /* Packet Vector #24 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x8D\x49\x3B\x30\xAE\x8B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x6E\x37\xA6\xEF\x54\x6D\x95\x5D\x34\xAB\x60\x59", + 21, + "\xAB\xF2\x1C\x0B\x02\xFE\xB8\x8F\x85\x6D\xF4\xA3\x73\x81\xBC\xE3\xCC\x12\x85\x17\xD4", + 31, + "\xF3\x29\x05\xB8\x8A\x64\x1B\x04\xB9\xC9\xFF\xB5\x8C\xC3\x90\x90\x0F\x3D\xA1\x2A\xB1\x6D\xCE\x9E\x82\xEF\xA1\x6D\xA6\x20\x59"}, + /* RFC 5528 */ + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\xBA\x73\x71\x85\xE7\x19\x31\x04\x92\xF3\x8A\x5F\x12\x51\xDA\x55\xFA\xFB\xC9\x49\x84\x8A\x0D\xFC\xAE\xCE\x74\x6B\x3D\xB9\xAD"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x5D\x25\x64\xBF\x8E\xAF\xE1\xD9\x95\x26\xEC\x01\x6D\x1B\xF0\x42\x4C\xFB\xD2\xCD\x62\x84\x8F\x33\x60\xB2\x29\x5D\xF2\x42\x83\xE8"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x81\xF6\x63\xD6\xC7\x78\x78\x17\xF9\x20\x36\x08\xB9\x82\xAD\x15\xDC\x2B\xBD\x87\xD7\x56\xF7\x92\x04\xF5\x51\xD6\x68\x2F\x23\xAA\x46"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xCA\xEF\x1E\x82\x72\x11\xB0\x8F\x7B\xD9\x0F\x08\xC7\x72\x88\xC0\x70\xA4\xA0\x8B\x3A\x93\x3A\x63\xE4\x97\xA0"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\x2A\xD3\xBA\xD9\x4F\xC5\x2E\x92\xBE\x43\x8E\x82\x7C\x10\x23\xB9\x6A\x8A\x77\x25\x8F\xA1\x7B\xA7\xF3\x31\xDB\x09"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\xFE\xA5\x48\x0B\xA5\x3F\xA8\xD3\xC3\x44\x22\xAA\xCE\x4D\xE6\x7F\xFA\x3B\xB7\x3B\xAB\xAB\x36\xA1\xEE\x4F\xE0\xFE\x28"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x54\x53\x20\x26\xE5\x4C\x11\x9A\x8D\x36\xD9\xEC\x6E\x1E\xD9\x74\x16\xC8\x70\x8C\x4B\x5C\x2C\xAC\xAF\xA3\xBC\xCF\x7A\x4E\xBF\x95\x73"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x8A\xD1\x9B\x00\x1A\x87\xD1\x48\xF4\xD9\x2B\xEF\x34\x52\x5C\xCC\xE3\xA6\x3C\x65\x12\xA6\xF5\x75\x73\x88\xE4\x91\x3E\xF1\x47\x01\xF4\x41"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x5D\xB0\x8D\x62\x40\x7E\x6E\x31\xD6\x0F\x9C\xA2\xC6\x04\x74\x21\x9A\xC0\xBE\x50\xC0\xD4\xA5\x77\x87\x94\xD6\xE2\x30\xCD\x25\xC9\xFE\xBF\x87"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\xDB\x11\x8C\xCE\xC1\xB8\x76\x1C\x87\x7C\xD8\x96\x3A\x67\xD6\xF3\xBB\xBC\x5C\xD0\x92\x99\xEB\x11\xF3\x12\xF2\x32\x37"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x7C\xC8\x3D\x8D\xC4\x91\x03\x52\x5B\x48\x3D\xC5\xCA\x7E\xA9\xAB\x81\x2B\x70\x56\x07\x9D\xAF\xFA\xDA\x16\xCC\xCF\x2C\x4E"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\x2C\xD3\x5B\x88\x20\xD2\x3E\x7A\xA3\x51\xB0\xE9\x2F\xC7\x93\x67\x23\x8B\x2C\xC7\x48\xCB\xB9\x4C\x29\x47\x79\x3D\x64\xAF\x75"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #13 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xA9\x70\x11\x0E\x19\x27\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x6B\x7F\x46\x45\x07\xFA\xE4\x96", + 23, + "\xC6\xB5\xF3\xE6\xCA\x23\x11\xAE\xF7\x47\x2B\x20\x3E\x73\x5E\xA5\x61\xAD\xB1\x7D\x56\xC5\xA3", + 31, + "\xA4\x35\xD7\x27\x34\x8D\xDD\x22\x90\x7F\x7E\xB8\xF5\xFD\xBB\x4D\x93\x9D\xA6\x52\x4D\xB4\xF6\x45\x58\xC0\x2D\x25\xB1\x27\xEE"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #14 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x83\xCD\x8C\xE0\xCB\x42\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x98\x66\x05\xB4\x3D\xF1\x5D\xE7", + 24, + "\x01\xF6\xCE\x67\x64\xC5\x74\x48\x3B\xB0\x2E\x6B\xBF\x1E\x0A\xBD\x26\xA2\x25\x72\xB4\xD8\x0E\xE7", + 32, + "\x8A\xE0\x52\x50\x8F\xBE\xCA\x93\x2E\x34\x6F\x05\xE0\xDC\x0D\xFB\xCF\x93\x9E\xAF\xFA\x3E\x58\x7C\x86\x7D\x6E\x1C\x48\x70\x38\x06"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #15 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x5F\x54\x95\x0B\x18\xF2\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x48\xF2\xE7\xE1\xA7\x67\x1A\x51", + 25, + "\xCD\xF1\xD8\x40\x6F\xC2\xE9\x01\x49\x53\x89\x70\x05\xFB\xFB\x8B\xA5\x72\x76\xF9\x24\x04\x60\x8E\x08", + 33, + "\x08\xB6\x7E\xE2\x1C\x8B\xF2\x6E\x47\x3E\x40\x85\x99\xE9\xC0\x83\x6D\x6A\xF0\xBB\x18\xDF\x55\x46\x6C\xA8\x08\x78\xA7\x90\x47\x6D\xE5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #16 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xEC\x60\x08\x63\x31\x9A\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xDE\x97\xDF\x3B\x8C\xBD\x6D\x8E\x50\x30\xDA\x4C", + 19, + "\xB0\x05\xDC\xFA\x0B\x59\x18\x14\x26\xA9\x61\x68\x5A\x99\x3D\x8C\x43\x18\x5B", + 27, + "\x63\xB7\x8B\x49\x67\xB1\x9E\xDB\xB7\x33\xCD\x11\x14\xF6\x4E\xB2\x26\x08\x93\x68\xC3\x54\x82\x8D\x95\x0C\xC5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #17 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x60\xCF\xF1\xA3\x1E\xA1\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA5\xEE\x93\xE4\x57\xDF\x05\x46\x6E\x78\x2D\xCF", + 20, + "\x2E\x20\x21\x12\x98\x10\x5F\x12\x9D\x5E\xD9\x5B\x93\xF7\x2D\x30\xB2\xFA\xCC\xD7", + 28, + "\x0B\xC6\xBB\xE2\xA8\xB9\x09\xF4\x62\x9E\xE6\xDC\x14\x8D\xA4\x44\x10\xE1\x8A\xF4\x31\x47\x38\x32\x76\xF6\x6A\x9F"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #18 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x0F\x85\xCD\x99\x5C\x97\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x24\xAA\x1B\xF9\xA5\xCD\x87\x61\x82\xA2\x50\x74", + 21, + "\x26\x45\x94\x1E\x75\x63\x2D\x34\x91\xAF\x0F\xC0\xC9\x87\x6C\x3B\xE4\xAA\x74\x68\xC9", + 29, + "\x22\x2A\xD6\x32\xFA\x31\xD6\xAF\x97\x0C\x34\x5F\x7E\x77\xCA\x3B\xD0\xDC\x25\xB3\x40\xA1\xA3\xD3\x1F\x8D\x4B\x44\xB7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #19 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC2\x9B\x2C\xAA\xC4\xCD\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x69\x19\x46\xB9\xCA\x07\xBE\x87", + 23, + "\x07\x01\x35\xA6\x43\x7C\x9D\xB1\x20\xCD\x61\xD8\xF6\xC3\x9C\x3E\xA1\x25\xFD\x95\xA0\xD2\x3D", + 33, + "\x05\xB8\xE1\xB9\xC4\x9C\xFD\x56\xCF\x13\x0A\xA6\x25\x1D\xC2\xEC\xC0\x6C\xCC\x50\x8F\xE6\x97\xA0\x06\x6D\x57\xC8\x4B\xEC\x18\x27\x68"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #20 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x2C\x6B\x75\x95\xEE\x62\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xD0\xC5\x4E\xCB\x84\x62\x7D\xC4", + 24, + "\xC8\xC0\x88\x0E\x6C\x63\x6E\x20\x09\x3D\xD6\x59\x42\x17\xD2\xE1\x88\x77\xDB\x26\x4E\x71\xA5\xCC", + 34, + "\x54\xCE\xB9\x68\xDE\xE2\x36\x11\x57\x5E\xC0\x03\xDF\xAA\x1C\xD4\x88\x49\xBD\xF5\xAE\x2E\xDB\x6B\x7F\xA7\x75\xB1\x50\xED\x43\x83\xC5\xA9"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #21 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC5\x3C\xD4\xC2\xAA\x24\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xE2\x85\xE0\xE4\x80\x8C\xDA\x3D", + 25, + "\xF7\x5D\xAA\x07\x10\xC4\xE6\x42\x97\x79\x4D\xC2\xB7\xD2\xA2\x07\x57\xB1\xAA\x4E\x44\x80\x02\xFF\xAB", + 35, + "\xB1\x40\x45\x46\xBF\x66\x72\x10\xCA\x28\xE3\x09\xB3\x9B\xD6\xCA\x7E\x9F\xC8\x28\x5F\xE6\x98\xD4\x3C\xD2\x0A\x02\xE0\xBD\xCA\xED\x20\x10\xD3"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #22 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xBE\xE9\x26\x7F\xBA\xDC\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x6C\xAE\xF9\x94\x11\x41\x57\x0D\x7C\x81\x34\x05", + 19, + "\xC2\x38\x82\x2F\xAC\x5F\x98\xFF\x92\x94\x05\xB0\xAD\x12\x7A\x4E\x41\x85\x4E", + 29, + "\x94\xC8\x95\x9C\x11\x56\x9A\x29\x78\x31\xA7\x21\x00\x58\x57\xAB\x61\xB8\x7A\x2D\xEA\x09\x36\xB6\xEB\x5F\x62\x5F\x5D"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #23 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xDF\xA8\xB1\x24\x50\x07\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x36\xA5\x2C\xF1\x6B\x19\xA2\x03\x7A\xB7\x01\x1E", + 20, + "\x4D\xBF\x3E\x77\x4A\xD2\x45\xE5\xD5\x89\x1F\x9D\x1C\x32\xA0\xAE\x02\x2C\x85\xD7", + 30, + "\x58\x69\xE3\xAA\xD2\x44\x7C\x74\xE0\xFC\x05\xF9\xA4\xEA\x74\x57\x7F\x4D\xE8\xCA\x89\x24\x76\x42\x96\xAD\x04\x11\x9C\xE7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #24 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x3B\x8F\xD8\xD3\xA9\x37\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA4\xD4\x99\xF7\x84\x19\x72\x8C\x19\x17\x8B\x0C", + 21, + "\x9D\xC9\xED\xAE\x2F\xF5\xDF\x86\x36\xE8\xC6\xDE\x0E\xED\x55\xF7\x86\x7E\x33\x33\x7D", + 31, + "\x4B\x19\x81\x56\x39\x3B\x0F\x77\x96\x08\x6A\xAF\xB4\x54\xF8\xC3\xF0\x34\xCC\xA9\x66\x94\x5F\x1F\xCE\xA7\xE1\x1B\xEE\x6A\x2F"} + }; + static const int cut[] = { 0, 1, 8, 10, 16, 19, -1 }; + gcry_cipher_hd_t hde, hdd; + unsigned char out[MAX_DATA_LEN]; + size_t ctl_params[3]; + int split, aadsplit; + size_t j, i, keylen, blklen, authlen; + gcry_error_t err = 0; + + if (verbose) + fprintf (stderr, " Starting CCM checks.\n"); + + for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) + { + if (verbose) + fprintf (stderr, " checking CCM mode for %s [%i]\n", + gcry_cipher_algo_name (tv[i].algo), + tv[i].algo); + + for (j = 0; j < sizeof (cut) / sizeof (cut[0]); j++) + { + split = cut[j] < 0 ? tv[i].plainlen : cut[j]; + if (tv[i].plainlen < split) + continue; + + err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + keylen = gcry_cipher_get_algo_keylen(tv[i].algo); + if (!keylen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_keylen failed\n"); + return; + } + + err = gcry_cipher_setkey (hde, tv[i].key, keylen); + if (!err) + err = gcry_cipher_setkey (hdd, tv[i].key, keylen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + blklen = gcry_cipher_get_algo_blklen(tv[i].algo); + if (!blklen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_blklen failed\n"); + return; + } + + err = gcry_cipher_setiv (hde, tv[i].nonce, tv[i].noncelen); + if (!err) + err = gcry_cipher_setiv (hdd, tv[i].nonce, tv[i].noncelen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + authlen = tv[i].cipherlen - tv[i].plainlen; + ctl_params[0] = tv[i].plainlen; /* encryptedlen */ + ctl_params[1] = tv[i].aadlen; /* aadlen */ + ctl_params[2] = authlen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_PARAMS, ctl_params, + sizeof(ctl_params)); + if (!err) + err = gcry_cipher_ctl (hdd, GCRYCTL_SET_CCM_PARAMS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm, gcry_cipher_ctl GCRYCTL_SET_CCM_PARAMS failed:" + "%s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + aadsplit = split > tv[i].aadlen ? 0 : split; + + err = gcry_cipher_authenticate (hde, tv[i].aad, + tv[i].aadlen - aadsplit); + if (!err) + err = gcry_cipher_authenticate (hde, + &tv[i].aad[tv[i].aadlen - aadsplit], + aadsplit); + if (!err) + err = gcry_cipher_authenticate (hdd, tv[i].aad, + tv[i].aadlen - aadsplit); + if (!err) + err = gcry_cipher_authenticate (hdd, + &tv[i].aad[tv[i].aadlen - aadsplit], + aadsplit); + if (err) + { + fail ("cipher-ccm, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, tv[i].plaintext, + tv[i].plainlen - split); + if (!err) + err = gcry_cipher_encrypt (hde, &out[tv[i].plainlen - split], + MAX_DATA_LEN - (tv[i].plainlen - split), + &tv[i].plaintext[tv[i].plainlen - split], + split); + if (err) + { + fail ("cipher-ccm, gcry_cipher_encrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_gettag (hde, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_gettag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].ciphertext, out, tv[i].cipherlen)) + fail ("cipher-ccm, encrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_decrypt (hdd, out, tv[i].plainlen - split, NULL, 0); + if (!err) + err = gcry_cipher_decrypt (hdd, &out[tv[i].plainlen - split], split, + NULL, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_decrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].plaintext, out, tv[i].plainlen)) + fail ("cipher-ccm, decrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_checktag (hdd, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_checktag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + } + } + + /* Large buffer tests. */ + + /* Test encoding of aadlen > 0xfeff. */ + { + static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19}; + static const char tag[]={0x9C,0x76,0xE7,0x33,0xD5,0x15,0xB3,0x6C, + 0xBA,0x76,0x95,0xF7,0xFB,0x91}; + char buf[1024]; + size_t enclen = 0x20000; + size_t aadlen = 0x20000; + size_t taglen = sizeof(tag); + + err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + err = gcry_cipher_setkey (hde, key, sizeof (key)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + err = gcry_cipher_setiv (hde, iv, sizeof (iv)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + ctl_params[0] = enclen; /* encryptedlen */ + ctl_params[1] = aadlen; /* aadlen */ + ctl_params[2] = taglen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_PARAMS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_ctl GCRYCTL_SET_CCM_PARAMS failed:" + "%s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + memset (buf, 0xaa, sizeof(buf)); + + for (i = 0; i < aadlen; i += sizeof(buf)) + { + err = gcry_cipher_authenticate (hde, buf, sizeof (buf)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + for (i = 0; i < enclen; i += sizeof(buf)) + { + memset (buf, 0xee, sizeof(buf)); + err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_encrypt failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + err = gcry_cipher_gettag (hde, buf, taglen); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_gettag failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + if (memcmp (buf, tag, taglen) != 0) + fail ("cipher-ccm-large, encrypt mismatch entry\n"); + } + +#if 0 + /* Test encoding of aadlen > 0xffffffff. */ + { + static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19}; + static const char tag[]={0x01,0xB2,0xC3,0x4A,0xA6,0x6A,0x07,0x6D, + 0xBC,0xBD,0xEA,0x17,0xD3,0x73,0xD7,0xD4}; + char buf[1024]; + size_t enclen = (size_t)0xffffffff + 1 + 1024; + size_t aadlen = (size_t)0xffffffff + 1 + 1024; + size_t taglen = sizeof(tag); + + err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + err = gcry_cipher_setkey (hde, key, sizeof (key)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + err = gcry_cipher_setiv (hde, iv, sizeof (iv)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + ctl_params[0] = enclen; /* encryptedlen */ + ctl_params[1] = aadlen; /* aadlen */ + ctl_params[2] = taglen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_PARAMS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_ctl GCRYCTL_SET_CCM_PARAMS failed:" + "%s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + memset (buf, 0xaa, sizeof(buf)); + + for (i = 0; i < aadlen; i += sizeof(buf)) + { + err = gcry_cipher_authenticate (hde, buf, sizeof (buf)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + for (i = 0; i < enclen; i += sizeof(buf)) + { + memset (buf, 0xee, sizeof(buf)); + err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_encrypt failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + err = gcry_cipher_gettag (hde, buf, taglen); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_gettag failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + if (memcmp (buf, tag, taglen) != 0) + fail ("cipher-ccm-huge, encrypt mismatch entry\n"); + } +#endif + + if (verbose) + fprintf (stderr, " Completed CCM checks.\n"); +} + + +static void check_stream_cipher (void) { struct tv @@ -2455,6 +3225,7 @@ check_cipher_modes(void) check_ctr_cipher (); check_cfb_cipher (); check_ofb_cipher (); + check_ccm_cipher (); check_stream_cipher (); check_stream_cipher_large_block (); diff --git a/tests/benchmark.c b/tests/benchmark.c index ecda0d3..a9b31f7 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -435,6 +435,40 @@ md_bench ( const char *algoname ) fflush (stdout); } + +static void ccm_aead_init(gcry_cipher_hd_t hd, size_t buflen, int authlen) +{ + const int _L = 4; + const int noncelen = 15 - _L; + char nonce[noncelen]; + size_t params[3]; + gcry_error_t err = GPG_ERR_NO_ERROR; + + memset (nonce, 0x33, noncelen); + + err = gcry_cipher_setiv (hd, nonce, noncelen); + if (err) + { + fprintf (stderr, "gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } + + params[0] = buflen; /* encryptedlen */ + params[1] = 0; /* aadlen */ + params[2] = authlen; /* authtaglen */ + err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_PARAMS, params, sizeof(params)); + if (err) + { + fprintf (stderr, "gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } +} + + static void cipher_bench ( const char *algoname ) { @@ -448,12 +482,21 @@ cipher_bench ( const char *algoname ) char *raw_outbuf, *raw_buf; size_t allocated_buflen, buflen; int repetitions; - static struct { int mode; const char *name; int blocked; } modes[] = { + static const struct { + int mode; + const char *name; + int blocked; + void (* const aead_init)(gcry_cipher_hd_t hd, size_t buflen, int authlen); + int req_blocksize; + int authlen; + } modes[] = { { GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1 }, { GCRY_CIPHER_MODE_CBC, " CBC", 1 }, { GCRY_CIPHER_MODE_CFB, " CFB", 0 }, { GCRY_CIPHER_MODE_OFB, " OFB", 0 }, { GCRY_CIPHER_MODE_CTR, " CTR", 0 }, + { GCRY_CIPHER_MODE_CCM, " CCM", 0, + ccm_aead_init, GCRY_CCM_BLOCK_LEN, 8 }, { GCRY_CIPHER_MODE_STREAM, "", 0 }, {0} }; @@ -542,9 +585,16 @@ cipher_bench ( const char *algoname ) for (modeidx=0; modes[modeidx].mode; modeidx++) { if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM) - | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) + || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) continue; + if (modes[modeidx].req_blocksize > 0 + && blklen != modes[modeidx].req_blocksize) + { + printf (" %7s %7s", "-", "-" ); + continue; + } + for (i=0; i < sizeof buf; i++) buf[i] = i; @@ -585,7 +635,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_gettag (hd, outbuf, modes[modeidx].authlen); + } + else + { + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + } } stop_timer (); @@ -632,7 +693,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_decrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_checktag (hd, outbuf, modes[modeidx].authlen); + if (gpg_err_code (err) == GPG_ERR_CHECKSUM) + err = gpg_error (GPG_ERR_NO_ERROR); + } + else + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); } stop_timer (); printf (" %s", elapsed_time ()); From wk at gnupg.org Mon Oct 21 12:43:58 2013 From: wk at gnupg.org (Werner Koch) Date: Mon, 21 Oct 2013 12:43:58 +0200 Subject: ECDSA for Edwards curve In-Reply-To: <1382341573.3497.1.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Mon, 21 Oct 2013 16:46:13 +0900") References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> <87ppr5jnbm.fsf@vigenere.g10code.de> <87iowwiefw.fsf@vigenere.g10code.de> <1382341573.3497.1.camel@cfw2.gniibe.org> Message-ID: <87sivuewep.fsf@vigenere.g10code.de> On Mon, 21 Oct 2013 09:46, gniibe at fsij.org said: > I think that I figure out the issue of failure. Me too. By assuming a bug in the code it took me lots of hours to come to the right conclusion :-(. > In the function nist_generate_key, when we change the private key "d" > into -d, it assumes Weierstrass curve, where negative point of (x, y) > is (x, -y). > > However, for Twisted Edwards curve, negative point of (u, v) is (-u, v). Yeah. The question is why we should use that compression form for the Edwards curve. The very reason for the Ed25519/ECDSA hack is a special need of GNUNET which can't be fulfilled by the standard ED25519 key generation. Jivsov's black box key generation algorithm would fix the problem but be unusable for GNUNET as well. > Or, we could change the code so that we can have interfaces of > getting/setting affine point in the representation of corresponding > Weierstrass curve (x, y) for Twisted Edwards curve. And public key is > specified by Weierstrass curve representation. Or forget about Ed25519 and use P-256 directly? Needs to be discussed with the GNUnet folks. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From jussi.kivilinna at iki.fi Mon Oct 21 14:40:59 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 21 Oct 2013 15:40:59 +0300 Subject: [PATCH] mpi: allow building with clang on ARM Message-ID: <20131021124059.29895.67299.stgit@localhost6.localdomain6> * mpi/longlong.h [__arm__] (add_ssaaaa, sub_ddmmss, umul_ppmm) (count_leading_zeros): Do not cast assembly output arguments. [__arm__] (umul_ppmm): Remove the extra '%' ahead of assembly comment. [_ARM_ARCH >= 4] (umul_ppmm): Use correct inputs and outputs instead of registers. -- Signed-off-by: Jussi Kivilinna --- mpi/longlong.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mpi/longlong.h b/mpi/longlong.h index c2ab9c5..8c0bd45 100644 --- a/mpi/longlong.h +++ b/mpi/longlong.h @@ -213,8 +213,8 @@ extern UDItype __udiv_qrnnd (); #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("adds %1, %4, %5\n" \ "adc %0, %2, %3" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "%r" ((USItype)(ah)), \ "rI" ((USItype)(bh)), \ "%r" ((USItype)(al)), \ @@ -222,15 +222,15 @@ extern UDItype __udiv_qrnnd (); #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subs %1, %4, %5\n" \ "sbc %0, %2, %3" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "r" ((USItype)(ah)), \ "rI" ((USItype)(bh)), \ "r" ((USItype)(al)), \ "rI" ((USItype)(bl)) __CLOBBER_CC) #if (defined __ARM_ARCH && __ARM_ARCH <= 3) #define umul_ppmm(xh, xl, a, b) \ - __asm__ ("%@ Inlined umul_ppmm\n" \ + __asm__ ("@ Inlined umul_ppmm\n" \ "mov %|r0, %2, lsr #16 @ AAAA\n" \ "mov %|r2, %3, lsr #16 @ BBBB\n" \ "bic %|r1, %2, %|r0, lsl #16 @ aaaa\n" \ @@ -243,17 +243,17 @@ extern UDItype __udiv_qrnnd (); "addcs %|r2, %|r2, #65536\n" \ "adds %1, %|r1, %|r0, lsl #16\n" \ "adc %0, %|r2, %|r0, lsr #16" \ - : "=&r" ((USItype)(xh)), \ - "=r" ((USItype)(xl)) \ + : "=&r" ((xh)), \ + "=r" ((xl)) \ : "r" ((USItype)(a)), \ "r" ((USItype)(b)) \ : "r0", "r1", "r2" __CLOBBER_CC) #else /* __ARM_ARCH >= 4 */ #define umul_ppmm(xh, xl, a, b) \ - __asm__ ("%@ Inlined umul_ppmm\n" \ - "umull %r1, %r0, %r2, %r3" \ - : "=&r" ((USItype)(xh)), \ - "=r" ((USItype)(xl)) \ + __asm__ ("@ Inlined umul_ppmm\n" \ + "umull %1, %0, %2, %3" \ + : "=&r" ((xh)), \ + "=r" ((xl)) \ : "r" ((USItype)(a)), \ "r" ((USItype)(b)) \ : "r0", "r1") @@ -263,7 +263,7 @@ extern UDItype __udiv_qrnnd (); #if (defined __ARM_ARCH && __ARM_ARCH >= 5) #define count_leading_zeros(count, x) \ __asm__ ("clz %0, %1" \ - : "=r" ((USItype)(count)) \ + : "=r" ((count)) \ : "r" ((USItype)(x))) #endif /* __ARM_ARCH >= 5 */ #endif /* __arm__ */ From jussi.kivilinna at iki.fi Mon Oct 21 15:21:21 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 21 Oct 2013 16:21:21 +0300 Subject: [PATCH] twofish: add ARMv6 assembly implementation Message-ID: <20131021132121.23604.99408.stgit@localhost6.localdomain6> * cipher/Makefile.am: Add 'twofish-armv6.S'. * cipher/twofish-armv6.S: New. * cipher/twofish.c (USE_ARMV6_ASM): New macro. [USE_ARMV6_ASM] (_gcry_twofish_armv6_encrypt_block) (_gcry_twofish_armv6_decrypt_block): New prototypes. [USE_AMDV6_ASM] (twofish_encrypt, twofish_decrypt): Add. [USE_AMD64_ASM] (do_twofish_encrypt, do_twofish_decrypt): Remove. (_gcry_twofish_ctr_enc, _gcry_twofish_cfb_dec): Use 'twofish_encrypt' instead of 'do_twofish_encrypt'. (_gcry_twofish_cbc_dec): Use 'twofish_decrypt' instead of 'do_twofish_decrypt'. * configure.ac [arm]: Add 'twofish-armv6.lo'. -- Add optimized ARMv6 assembly implementation for Twofish. Implementation is tuned for Cortex-A8. Unaligned access handling is done in assembly part. For now, only enable this on little-endian systems as big-endian correctness have not been tested yet. Old (gcc-4.8) vs new (twofish-asm), Cortex-A8 (on armhf): ECB/Stream CBC CFB OFB CTR CCM --------------- --------------- --------------- --------------- --------------- --------------- TWOFISH 1.23x 1.25x 1.16x 1.26x 1.16x 1.30x 1.18x 1.17x 1.23x 1.23x 1.22x 1.22x Signed-off-by: Jussi Kivilinna --- cipher/Makefile.am | 2 cipher/twofish-armv6.S | 365 ++++++++++++++++++++++++++++++++++++++++++++++++ cipher/twofish.c | 88 ++++++++---- configure.ac | 4 + 4 files changed, 432 insertions(+), 27 deletions(-) create mode 100644 cipher/twofish-armv6.S diff --git a/cipher/Makefile.am b/cipher/Makefile.am index b0efd89..3d8149a 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -80,7 +80,7 @@ sha512.c sha512-armv7-neon.S \ stribog.c \ tiger.c \ whirlpool.c \ -twofish.c twofish-amd64.S \ +twofish.c twofish-amd64.S twofish-armv6.S \ rfc2268.c \ camellia.c camellia.h camellia-glue.c camellia-aesni-avx-amd64.S \ camellia-aesni-avx2-amd64.S camellia-armv6.S diff --git a/cipher/twofish-armv6.S b/cipher/twofish-armv6.S new file mode 100644 index 0000000..b76ab37 --- /dev/null +++ b/cipher/twofish-armv6.S @@ -0,0 +1,365 @@ +/* twofish-armv6.S - ARM assembly implementation of Twofish cipher + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) +#ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS + +.text + +.syntax unified +.arm + +/* structure of TWOFISH_context: */ +#define s0 0 +#define s1 ((s0) + 4 * 256) +#define s2 ((s1) + 4 * 256) +#define s3 ((s2) + 4 * 256) +#define w ((s3) + 4 * 256) +#define k ((w) + 4 * 8) + +/* register macros */ +#define CTX %r0 +#define CTXs0 %r0 +#define CTXs1 %r1 +#define CTXs3 %r7 + +#define RA %r3 +#define RB %r4 +#define RC %r5 +#define RD %r6 + +#define RX %r2 +#define RY %ip + +#define RMASK %lr + +#define RT0 %r8 +#define RT1 %r9 +#define RT2 %r10 +#define RT3 %r11 + +/* helper macros */ +#define ldr_unaligned_le(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 0)]; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 3)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 0)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 1)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 2)]; \ + strb rtmp0, [rdst, #((offs) + 3)]; + +#ifndef __ARMEL__ + /* bswap on big-endian */ + #define host_to_le(reg) \ + rev reg, reg; + #define le_to_host(reg) \ + rev reg, reg; +#else + /* nop on little-endian */ + #define host_to_le(reg) /*_*/ + #define le_to_host(reg) /*_*/ +#endif + +#define ldr_input_aligned_le(rin, a, b, c, d) \ + ldr a, [rin, #0]; \ + ldr b, [rin, #4]; \ + le_to_host(a); \ + ldr c, [rin, #8]; \ + le_to_host(b); \ + ldr d, [rin, #12]; \ + le_to_host(c); \ + le_to_host(d); + +#define str_output_aligned_le(rout, a, b, c, d) \ + le_to_host(a); \ + le_to_host(b); \ + str a, [rout, #0]; \ + le_to_host(c); \ + str b, [rout, #4]; \ + le_to_host(d); \ + str c, [rout, #8]; \ + str d, [rout, #12]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads/writes allowed */ + #define ldr_input_le(rin, ra, rb, rc, rd, rtmp) \ + ldr_input_aligned_le(rin, ra, rb, rc, rd) + + #define str_output_le(rout, ra, rb, rc, rd, rtmp0, rtmp1) \ + str_output_aligned_le(rout, ra, rb, rc, rd) +#else + /* need to handle unaligned reads/writes by byte reads */ + #define ldr_input_le(rin, ra, rb, rc, rd, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_le(ra, rin, 0, rtmp0); \ + ldr_unaligned_le(rb, rin, 4, rtmp0); \ + ldr_unaligned_le(rc, rin, 8, rtmp0); \ + ldr_unaligned_le(rd, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + ldr_input_aligned_le(rin, ra, rb, rc, rd); \ + 2:; + + #define str_output_le(rout, ra, rb, rc, rd, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_le(ra, rout, 0, rtmp0, rtmp1); \ + str_unaligned_le(rb, rout, 4, rtmp0, rtmp1); \ + str_unaligned_le(rc, rout, 8, rtmp0, rtmp1); \ + str_unaligned_le(rd, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + str_output_aligned_le(rout, ra, rb, rc, rd); \ + 2:; +#endif + +/********************************************************************** + 1-way twofish + **********************************************************************/ +#define encrypt_round(a, b, rc, rd, n, ror_a, adj_a) \ + and RT0, RMASK, b, lsr#(8 - 2); \ + and RY, RMASK, b, lsr#(16 - 2); \ + add RT0, RT0, #(s2 - s1); \ + and RT1, RMASK, b, lsr#(24 - 2); \ + ldr RY, [CTXs3, RY]; \ + and RT2, RMASK, b, lsl#(2); \ + ldr RT0, [CTXs1, RT0]; \ + and RT3, RMASK, a, lsr#(16 - 2 + (adj_a)); \ + ldr RT1, [CTXs0, RT1]; \ + and RX, RMASK, a, lsr#(8 - 2 + (adj_a)); \ + ldr RT2, [CTXs1, RT2]; \ + add RT3, RT3, #(s2 - s1); \ + ldr RX, [CTXs1, RX]; \ + ror_a(a); \ + \ + eor RY, RY, RT0; \ + ldr RT3, [CTXs1, RT3]; \ + and RT0, RMASK, a, lsl#(2); \ + eor RY, RY, RT1; \ + and RT1, RMASK, a, lsr#(24 - 2); \ + eor RY, RY, RT2; \ + ldr RT0, [CTXs0, RT0]; \ + eor RX, RX, RT3; \ + ldr RT1, [CTXs3, RT1]; \ + eor RX, RX, RT0; \ + \ + ldr RT3, [CTXs3, #(k - s3 + 8 * (n) + 4)]; \ + eor RX, RX, RT1; \ + ldr RT2, [CTXs3, #(k - s3 + 8 * (n))]; \ + \ + add RT0, RX, RY, lsl #1; \ + add RX, RX, RY; \ + add RT0, RT0, RT3; \ + add RX, RX, RT2; \ + eor rd, RT0, rd, ror #31; \ + eor rc, rc, RX; + +#define dummy(x) /*_*/ + +#define ror1(r) \ + ror r, r, #1; + +#define decrypt_round(a, b, rc, rd, n, ror_b, adj_b) \ + and RT3, RMASK, b, lsl#(2 - (adj_b)); \ + and RT1, RMASK, b, lsr#(8 - 2 + (adj_b)); \ + ror_b(b); \ + and RT2, RMASK, a, lsl#(2); \ + and RT0, RMASK, a, lsr#(8 - 2); \ + \ + ldr RY, [CTXs1, RT3]; \ + add RT1, RT1, #(s2 - s1); \ + ldr RX, [CTXs0, RT2]; \ + and RT3, RMASK, b, lsr#(16 - 2); \ + ldr RT1, [CTXs1, RT1]; \ + and RT2, RMASK, a, lsr#(16 - 2); \ + ldr RT0, [CTXs1, RT0]; \ + \ + add RT2, RT2, #(s2 - s1); \ + ldr RT3, [CTXs3, RT3]; \ + eor RY, RY, RT1; \ + \ + and RT1, RMASK, b, lsr#(24 - 2); \ + eor RX, RX, RT0; \ + ldr RT2, [CTXs1, RT2]; \ + and RT0, RMASK, a, lsr#(24 - 2); \ + \ + ldr RT1, [CTXs0, RT1]; \ + \ + eor RY, RY, RT3; \ + ldr RT0, [CTXs3, RT0]; \ + eor RX, RX, RT2; \ + eor RY, RY, RT1; \ + \ + ldr RT1, [CTXs3, #(k - s3 + 8 * (n) + 4)]; \ + eor RX, RX, RT0; \ + ldr RT2, [CTXs3, #(k - s3 + 8 * (n))]; \ + \ + add RT0, RX, RY, lsl #1; \ + add RX, RX, RY; \ + add RT0, RT0, RT1; \ + add RX, RX, RT2; \ + eor rd, rd, RT0; \ + eor rc, RX, rc, ror #31; + +#define first_encrypt_cycle(nc) \ + encrypt_round(RA, RB, RC, RD, (nc) * 2, dummy, 0); \ + encrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); + +#define encrypt_cycle(nc) \ + encrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); \ + encrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); + +#define last_encrypt_cycle(nc) \ + encrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); \ + encrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); \ + ror1(RA); + +#define first_decrypt_cycle(nc) \ + decrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, dummy, 0); \ + decrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); + +#define decrypt_cycle(nc) \ + decrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); \ + decrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); + +#define last_decrypt_cycle(nc) \ + decrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); \ + decrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); \ + ror1(RD); + +.align 3 +.global _gcry_twofish_armv6_encrypt_block +.type _gcry_twofish_armv6_encrypt_block,%function; + +_gcry_twofish_armv6_encrypt_block: + /* input: + * %r0: ctx + * %r1: dst + * %r2: src + */ + push {%r1, %r4-%r11, %ip, %lr}; + + add RY, CTXs0, #w; + + ldr_input_le(%r2, RA, RB, RC, RD, RT0); + + /* Input whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + add CTXs3, CTXs0, #(s3 - s0); + add CTXs1, CTXs0, #(s1 - s0); + mov RMASK, #(0xff << 2); + eor RA, RA, RT0; + eor RB, RB, RT1; + eor RC, RC, RT2; + eor RD, RD, RT3; + + first_encrypt_cycle(0); + encrypt_cycle(1); + encrypt_cycle(2); + encrypt_cycle(3); + encrypt_cycle(4); + encrypt_cycle(5); + encrypt_cycle(6); + last_encrypt_cycle(7); + + add RY, CTXs3, #(w + 4*4 - s3); + pop {%r1}; /* dst */ + + /* Output whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + eor RC, RC, RT0; + eor RD, RD, RT1; + eor RA, RA, RT2; + eor RB, RB, RT3; + + str_output_le(%r1, RC, RD, RA, RB, RT0, RT1); + + pop {%r4-%r11, %ip, %lr}; + bx %lr; +.ltorg +.size _gcry_twofish_armv6_encrypt_block,.-_gcry_twofish_armv6_encrypt_block; + +.align 3 +.global _gcry_twofish_armv6_decrypt_block +.type _gcry_twofish_armv6_decrypt_block,%function; + +_gcry_twofish_armv6_decrypt_block: + /* input: + * %r0: ctx + * %r1: dst + * %r2: src + */ + push {%r1, %r4-%r11, %ip, %lr}; + + add CTXs3, CTXs0, #(s3 - s0); + + ldr_input_le(%r2, RC, RD, RA, RB, RT0); + + add RY, CTXs3, #(w + 4*4 - s3); + add CTXs3, CTXs0, #(s3 - s0); + + /* Input whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + add CTXs1, CTXs0, #(s1 - s0); + mov RMASK, #(0xff << 2); + eor RC, RC, RT0; + eor RD, RD, RT1; + eor RA, RA, RT2; + eor RB, RB, RT3; + + first_decrypt_cycle(7); + decrypt_cycle(6); + decrypt_cycle(5); + decrypt_cycle(4); + decrypt_cycle(3); + decrypt_cycle(2); + decrypt_cycle(1); + last_decrypt_cycle(0); + + add RY, CTXs0, #w; + pop {%r1}; /* dst */ + + /* Output whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + eor RA, RA, RT0; + eor RB, RB, RT1; + eor RC, RC, RT2; + eor RD, RD, RT3; + + str_output_le(%r1, RA, RB, RC, RD, RT0, RT1); + + pop {%r4-%r11, %ip, %lr}; + bx %lr; +.size _gcry_twofish_armv6_decrypt_block,.-_gcry_twofish_armv6_decrypt_block; + +#endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/ +#endif /*__ARM_ARCH >= 6*/ diff --git a/cipher/twofish.c b/cipher/twofish.c index 993ad0f..d2cabbe 100644 --- a/cipher/twofish.c +++ b/cipher/twofish.c @@ -57,6 +57,14 @@ # define USE_AMD64_ASM 1 #endif +/* USE_ARMV6_ASM indicates whether to use ARMv6 assembly code. */ +#undef USE_ARMV6_ASM +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) +# if defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) +# define USE_ARMV6_ASM 1 +# endif +#endif + /* Prototype for the self-test function. */ static const char *selftest(void); @@ -746,7 +754,16 @@ extern void _gcry_twofish_amd64_cbc_dec(const TWOFISH_context *c, byte *out, extern void _gcry_twofish_amd64_cfb_dec(const TWOFISH_context *c, byte *out, const byte *in, byte *iv); -#else /*!USE_AMD64_ASM*/ +#elif defined(USE_ARMV6_ASM) + +/* Assembly implementations of Twofish. */ +extern void _gcry_twofish_armv6_encrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +extern void _gcry_twofish_armv6_decrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +#else /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ /* Macros to compute the g() function in the encryption and decryption * rounds. G1 is the straight g() function; G2 includes the 8-bit @@ -812,21 +829,25 @@ extern void _gcry_twofish_amd64_cfb_dec(const TWOFISH_context *c, byte *out, #ifdef USE_AMD64_ASM -static void -do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in) +static unsigned int +twofish_encrypt (void *context, byte *out, const byte *in) { + TWOFISH_context *ctx = context; _gcry_twofish_amd64_encrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); } +#elif defined(USE_ARMV6_ASM) + static unsigned int twofish_encrypt (void *context, byte *out, const byte *in) { TWOFISH_context *ctx = context; - _gcry_twofish_amd64_encrypt_block(ctx, out, in); + _gcry_twofish_armv6_encrypt_block(ctx, out, in); return /*burn_stack*/ (4*sizeof (void*)); } -#else /*!USE_AMD64_ASM*/ +#else /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ static void do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in) @@ -868,28 +889,32 @@ twofish_encrypt (void *context, byte *out, const byte *in) return /*burn_stack*/ (24+3*sizeof (void*)); } -#endif /*!USE_AMD64_ASM*/ +#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ /* Decrypt one block. in and out may be the same. */ #ifdef USE_AMD64_ASM -static void -do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in) +static unsigned int +twofish_decrypt (void *context, byte *out, const byte *in) { + TWOFISH_context *ctx = context; _gcry_twofish_amd64_decrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); } +#elif defined(USE_ARMV6_ASM) + static unsigned int twofish_decrypt (void *context, byte *out, const byte *in) { TWOFISH_context *ctx = context; - _gcry_twofish_amd64_decrypt_block(ctx, out, in); + _gcry_twofish_armv6_decrypt_block(ctx, out, in); return /*burn_stack*/ (4*sizeof (void*)); } -#else /*!USE_AMD64_ASM*/ +#else /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ static void do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in) @@ -932,7 +957,7 @@ twofish_decrypt (void *context, byte *out, const byte *in) return /*burn_stack*/ (24+3*sizeof (void*)); } -#endif /*!USE_AMD64_ASM*/ +#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ @@ -947,14 +972,11 @@ _gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char tmpbuf[TWOFISH_BLOCKSIZE]; - int burn_stack_depth = 24 + 3 * sizeof (void*); + unsigned int burn, burn_stack_depth = 0; int i; #ifdef USE_AMD64_ASM { - if (nblocks >= 3 && burn_stack_depth < 8 * sizeof(void*)) - burn_stack_depth = 8 * sizeof(void*); - /* Process data in 3 block chunks. */ while (nblocks >= 3) { @@ -963,6 +985,10 @@ _gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, nblocks -= 3; outbuf += 3 * TWOFISH_BLOCKSIZE; inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 8 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; } /* Use generic code to handle smaller chunks... */ @@ -973,7 +999,10 @@ _gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, for ( ;nblocks; nblocks-- ) { /* Encrypt the counter. */ - do_twofish_encrypt(ctx, tmpbuf, ctr); + burn = twofish_encrypt(ctx, tmpbuf, ctr); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + /* XOR the input with the encrypted counter and store in output. */ buf_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE); outbuf += TWOFISH_BLOCKSIZE; @@ -1002,13 +1031,10 @@ _gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char savebuf[TWOFISH_BLOCKSIZE]; - int burn_stack_depth = 24 + 3 * sizeof (void*); + unsigned int burn, burn_stack_depth = 0; #ifdef USE_AMD64_ASM { - if (nblocks >= 3 && burn_stack_depth < 9 * sizeof(void*)) - burn_stack_depth = 9 * sizeof(void*); - /* Process data in 3 block chunks. */ while (nblocks >= 3) { @@ -1017,6 +1043,10 @@ _gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, nblocks -= 3; outbuf += 3 * TWOFISH_BLOCKSIZE; inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 9 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; } /* Use generic code to handle smaller chunks... */ @@ -1029,7 +1059,9 @@ _gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, OUTBUF. */ memcpy(savebuf, inbuf, TWOFISH_BLOCKSIZE); - do_twofish_decrypt (ctx, outbuf, inbuf); + burn = twofish_decrypt (ctx, outbuf, inbuf); + if (burn > burn_stack_depth) + burn_stack_depth = burn; buf_xor(outbuf, outbuf, iv, TWOFISH_BLOCKSIZE); memcpy(iv, savebuf, TWOFISH_BLOCKSIZE); @@ -1051,13 +1083,10 @@ _gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, TWOFISH_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; - int burn_stack_depth = 24 + 3 * sizeof (void*); + unsigned int burn, burn_stack_depth = 0; #ifdef USE_AMD64_ASM { - if (nblocks >= 3 && burn_stack_depth < 8 * sizeof(void*)) - burn_stack_depth = 8 * sizeof(void*); - /* Process data in 3 block chunks. */ while (nblocks >= 3) { @@ -1066,6 +1095,10 @@ _gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, nblocks -= 3; outbuf += 3 * TWOFISH_BLOCKSIZE; inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 8 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; } /* Use generic code to handle smaller chunks... */ @@ -1074,7 +1107,10 @@ _gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, for ( ;nblocks; nblocks-- ) { - do_twofish_encrypt(ctx, iv, iv); + burn = twofish_encrypt(ctx, iv, iv); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + buf_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE); outbuf += TWOFISH_BLOCKSIZE; inbuf += TWOFISH_BLOCKSIZE; diff --git a/configure.ac b/configure.ac index a803b5f..66fb6b9 100644 --- a/configure.ac +++ b/configure.ac @@ -1479,6 +1479,10 @@ if test "$found" = "1" ; then # Build with the assembly implementation GCRYPT_CIPHERS="$GCRYPT_CIPHERS twofish-amd64.lo" ;; + arm*-*-*) + # Build with the assembly implementation + GCRYPT_CIPHERS="$GCRYPT_CIPHERS twofish-armv6.lo" + ;; esac fi From dbaryshkov at gmail.com Mon Oct 21 17:35:53 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Mon, 21 Oct 2013 19:35:53 +0400 Subject: [PATCH] twofish: add ARMv6 assembly implementation In-Reply-To: <20131021132121.23604.99408.stgit@localhost6.localdomain6> References: <20131021132121.23604.99408.stgit@localhost6.localdomain6> Message-ID: Hello, On Mon, Oct 21, 2013 at 5:21 PM, Jussi Kivilinna wrote: > * cipher/Makefile.am: Add 'twofish-armv6.S'. > * cipher/twofish-armv6.S: New. > * cipher/twofish.c (USE_ARMV6_ASM): New macro. > [USE_ARMV6_ASM] (_gcry_twofish_armv6_encrypt_block) > (_gcry_twofish_armv6_decrypt_block): New prototypes. > [USE_AMDV6_ASM] (twofish_encrypt, twofish_decrypt): Add. > [USE_AMD64_ASM] (do_twofish_encrypt, do_twofish_decrypt): Remove. > (_gcry_twofish_ctr_enc, _gcry_twofish_cfb_dec): Use 'twofish_encrypt' > instead of 'do_twofish_encrypt'. > (_gcry_twofish_cbc_dec): Use 'twofish_decrypt' instead of > 'do_twofish_decrypt'. > * configure.ac [arm]: Add 'twofish-armv6.lo'. Some time ago I have looked into adapting asm optimizations to earlier ARM cores. The main problem was rev instruction, which I conditionally replaced with 4 insns. My current code is present at https://github.com/GostCrypt/libgcrypt/commits/arm-opt . The main remaining issue is HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS test in configure.ac. It is too restrictive. E.g. it fails if gcc is configured to default to armv4te. Also it has .thumb directive, however all assembler files are compiled in arm mode. If I comment out add.w and ,thumb/.code16 lines, I can build code even for armv4 (no thumb), qemu-verified. Code built for armv4t/armv5te successfully verified on armv5te core (XScale). Would you have any suggestions on improving/adapting this configure test? -- With best wishes Dmitry From wk at gnupg.org Mon Oct 21 17:34:40 2013 From: wk at gnupg.org (Werner Koch) Date: Mon, 21 Oct 2013 17:34:40 +0200 Subject: ECDSA for Edwards curve In-Reply-To: <87sivuewep.fsf@vigenere.g10code.de> (Werner Koch's message of "Mon, 21 Oct 2013 12:43:58 +0200") References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> <87ppr5jnbm.fsf@vigenere.g10code.de> <87iowwiefw.fsf@vigenere.g10code.de> <1382341573.3497.1.camel@cfw2.gniibe.org> <87sivuewep.fsf@vigenere.g10code.de> Message-ID: <878uxmeiy7.fsf@vigenere.g10code.de> On Mon, 21 Oct 2013 12:43, wk at gnupg.org said: > Or forget about Ed25519 and use P-256 directly? Needs to be discussed > with the GNUnet folks. There is an easier way to do that. We only have 255 bit thus the there is one spare bit to represent the sign. This is similar to what EdDSA does, pretty easy and sufficient for the GNUNET case. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From wk at gnupg.org Mon Oct 21 17:41:37 2013 From: wk at gnupg.org (Werner Koch) Date: Mon, 21 Oct 2013 17:41:37 +0200 Subject: [PATCH 1/2] [v2] Add API to support AEAD cipher modes In-Reply-To: <52650232.7080009@iki.fi> (Jussi Kivilinna's message of "Mon, 21 Oct 2013 13:30:10 +0300") References: <20131020120313.21970.15918.stgit@localhost6.localdomain6> <52650232.7080009@iki.fi> Message-ID: <874n8aeimm.fsf@vigenere.g10code.de> On Mon, 21 Oct 2013 12:30, jussi.kivilinna at iki.fi said: > Ok, I changed API back to _authenticate() and added GCRYCTL_SET_CCM_PARAMS I still think that _setaad is a better symbol name than _authenticate. The use of new GCRYCTL codes should be limited because it bypasses type checking. However, for the length paramteer of CCM, I think the use of GCRYCTL_SET_CCM_LENGTH is fine. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From jussi.kivilinna at iki.fi Mon Oct 21 21:34:55 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 21 Oct 2013 22:34:55 +0300 Subject: [PATCH] twofish: add ARMv6 assembly implementation In-Reply-To: References: <20131021132121.23604.99408.stgit@localhost6.localdomain6> Message-ID: <526581DF.6070308@iki.fi> On 21.10.2013 18:35, Dmitry Eremin-Solenikov wrote: > Hello, > > On Mon, Oct 21, 2013 at 5:21 PM, Jussi Kivilinna wrote: >> * cipher/Makefile.am: Add 'twofish-armv6.S'. >> * cipher/twofish-armv6.S: New. >> * cipher/twofish.c (USE_ARMV6_ASM): New macro. >> [USE_ARMV6_ASM] (_gcry_twofish_armv6_encrypt_block) >> (_gcry_twofish_armv6_decrypt_block): New prototypes. >> [USE_AMDV6_ASM] (twofish_encrypt, twofish_decrypt): Add. >> [USE_AMD64_ASM] (do_twofish_encrypt, do_twofish_decrypt): Remove. >> (_gcry_twofish_ctr_enc, _gcry_twofish_cfb_dec): Use 'twofish_encrypt' >> instead of 'do_twofish_encrypt'. >> (_gcry_twofish_cbc_dec): Use 'twofish_decrypt' instead of >> 'do_twofish_decrypt'. >> * configure.ac [arm]: Add 'twofish-armv6.lo'. > > Some time ago I have looked into adapting asm optimizations to earlier > ARM cores. > The main problem was rev instruction, which I conditionally replaced > with 4 insns. > My current code is present at > https://github.com/GostCrypt/libgcrypt/commits/arm-opt . Nice. > > The main remaining issue is HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS test > in configure.ac. It is too restrictive. E.g. it fails if gcc is > configured to default to armv4te. > Also it has .thumb directive, however all assembler files are compiled > in arm mode. > If I comment out add.w and ,thumb/.code16 lines, I can build code even for armv4 > (no thumb), qemu-verified. Code built for armv4t/armv5te successfully > verified on armv5te > core (XScale). Would you have any suggestions on improving/adapting > this configure test? Well, what I try to do here is to check that '.syntax unified' works and is not ignored by assembler. But if asm code works even if '.syntax unified' is ignored, that part of check can be removed. So following should/might be enough: AC_CACHE_CHECK([whether GCC assembler is compatible for ARM assembly implementations], [gcry_cv_gcc_arm_platform_as_ok], [gcry_cv_gcc_arm_platform_as_ok=no AC_COMPILE_IFELSE([AC_LANG_SOURCE( [[__asm__( ".syntax unified\n\t" ".arm\n\t" "asmfunc:\n\t" "add %r0, %r4, %r8, ror #12;\n\t" /* Test if '.type' and '.size' are supported. */ ".size asmfunc,.-asmfunc;\n\t" ".type asmfunc,%function;\n\t" );]])], [gcry_cv_gcc_arm_platform_as_ok=yes])]) -Jussi From jussi.kivilinna at iki.fi Mon Oct 21 21:40:57 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Mon, 21 Oct 2013 22:40:57 +0300 Subject: [PATCH 1/2] [v2] Add API to support AEAD cipher modes In-Reply-To: <874n8aeimm.fsf@vigenere.g10code.de> References: <20131020120313.21970.15918.stgit@localhost6.localdomain6> <52650232.7080009@iki.fi> <874n8aeimm.fsf@vigenere.g10code.de> Message-ID: <52658349.4050609@iki.fi> On 21.10.2013 18:41, Werner Koch wrote: > On Mon, 21 Oct 2013 12:30, jussi.kivilinna at iki.fi said: > >> Ok, I changed API back to _authenticate() and added GCRYCTL_SET_CCM_PARAMS > > I still think that _setaad is a better symbol name than _authenticate. > I think _authenticate would be better if block cipher based MACs are to be added. So we'd have _authenticate for buffers to MAC modes and AAD buffers to AEAD modes. _setaad makes it should more AEAD specific. > The use of new GCRYCTL codes should be limited because it bypasses type > checking. However, for the length paramteer of CCM, I think the use of > GCRYCTL_SET_CCM_LENGTH is fine. Ok. -Jussi > > > Salam-Shalom, > > Werner > From gniibe at fsij.org Tue Oct 22 07:24:55 2013 From: gniibe at fsij.org (NIIBE Yutaka) Date: Tue, 22 Oct 2013 14:24:55 +0900 Subject: ECDSA for Edwards curve In-Reply-To: <878uxmeiy7.fsf@vigenere.g10code.de> References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> <87ppr5jnbm.fsf@vigenere.g10code.de> <87iowwiefw.fsf@vigenere.g10code.de> <1382341573.3497.1.camel@cfw2.gniibe.org> <87sivuewep.fsf@vigenere.g10code.de> <878uxmeiy7.fsf@vigenere.g10code.de> Message-ID: <1382419495.5358.2.camel@cfw2.gniibe.org> On 2013-10-21 at 17:34 +0200, Werner Koch wrote: > There is an easier way to do that. We only have 255 bit thus the there > is one spare bit to represent the sign. This is similar to what EdDSA > does, pretty easy and sufficient for the GNUNET case. Aside from how to encode/decode the point, here is the fix to get compliant key. This fixes the failure of keygen program. diff --git a/cipher/ecc.c b/cipher/ecc.c index 6f3cbbd..2774718 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -178,27 +178,33 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx, * dropped because we know that it's a minimum of the two * possibilities without any loss of security. */ { - gcry_mpi_t x, y, p_y; + gcry_mpi_t x, y, negative; const unsigned int pbits = mpi_get_nbits (E->p); x = mpi_new (pbits); y = mpi_new (pbits); - p_y = mpi_new (pbits); + negative = mpi_new (pbits); if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx)) log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q"); - mpi_sub (p_y, E->p, y); /* p_y = p - y */ + if (E->model == MPI_EC_WEIERSTRASS) + mpi_sub (negative, E->p, y); /* negative = p - y */ + else + mpi_sub (negative, E->p, x); /* negative = p - x */ - if (mpi_cmp (p_y, y) < 0) /* p - y < p */ + if (mpi_cmp (negative, y) < 0) /* p - y < p */ { /* We need to end up with -Q; this assures that new Q's y is the smallest one */ mpi_sub (sk->d, E->n, sk->d); /* d = order - d */ - gcry_mpi_point_snatch_set (&sk->Q, x, p_y, mpi_alloc_set_ui (1)); + if (E->model == MPI_EC_WEIERSTRASS) + gcry_mpi_point_snatch_set (&sk->Q, x, negative, mpi_alloc_set_ui (1)); + else + gcry_mpi_point_snatch_set (&sk->Q, negative, y, mpi_alloc_set_ui (1)); - if (DBG_CIPHER) - log_debug ("ecgen converted Q to a compliant point\n"); + if (DBG_CIPHER) + log_debug ("ecgen converted Q to a compliant point\n"); } else /* p - y >= p */ { @@ -207,10 +213,17 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx, if (DBG_CIPHER) log_debug ("ecgen didn't need to convert Q to a compliant point\n"); - mpi_free (p_y); - mpi_free (x); + mpi_free (negative); + if (E->model == MPI_EC_WEIERSTRASS) + mpi_free (x); + else + mpi_free (y); } - mpi_free (y); + + if (E->model == MPI_EC_WEIERSTRASS) + mpi_free (y); + else + mpi_free (x); } /* Now we can test our keys (this should never fail!). */ -- From wk at gnupg.org Tue Oct 22 09:17:46 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 22 Oct 2013 09:17:46 +0200 Subject: [PATCH 1/2] [v2] Add API to support AEAD cipher modes In-Reply-To: <52658349.4050609@iki.fi> (Jussi Kivilinna's message of "Mon, 21 Oct 2013 22:40:57 +0300") References: <20131020120313.21970.15918.stgit@localhost6.localdomain6> <52650232.7080009@iki.fi> <874n8aeimm.fsf@vigenere.g10code.de> <52658349.4050609@iki.fi> Message-ID: <87mwm1dbad.fsf@vigenere.g10code.de> On Mon, 21 Oct 2013 21:40, jussi.kivilinna at iki.fi said: > I think _authenticate would be better if block cipher based MACs are to be > added. So we'd have _authenticate for buffers to MAC modes and AAD buffers > to AEAD modes. _setaad makes it should more AEAD specific. I am not convinced, but I am okay with _authenticate. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From cvs at cvs.gnupg.org Tue Oct 22 12:48:58 2013 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Tue, 22 Oct 2013 12:48:58 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-319-ga5a277a Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via a5a277a9016ccb34f1858a65e0ed1791b2fc3db3 (commit) from f7711e6eb5f02d03c74911f6f037ab28075e7c0d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a5a277a9016ccb34f1858a65e0ed1791b2fc3db3 Author: NIIBE Yutaka Date: Tue Oct 22 12:47:11 2013 +0200 ecc: Correct compliant key generation for Edwards curves. * cipher/ecc.c: Add case for Edwards curves. Signed-off-by: Werner Koch diff --git a/cipher/ecc.c b/cipher/ecc.c index 6f3cbbd..2774718 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -178,27 +178,33 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx, * dropped because we know that it's a minimum of the two * possibilities without any loss of security. */ { - gcry_mpi_t x, y, p_y; + gcry_mpi_t x, y, negative; const unsigned int pbits = mpi_get_nbits (E->p); x = mpi_new (pbits); y = mpi_new (pbits); - p_y = mpi_new (pbits); + negative = mpi_new (pbits); if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx)) log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q"); - mpi_sub (p_y, E->p, y); /* p_y = p - y */ + if (E->model == MPI_EC_WEIERSTRASS) + mpi_sub (negative, E->p, y); /* negative = p - y */ + else + mpi_sub (negative, E->p, x); /* negative = p - x */ - if (mpi_cmp (p_y, y) < 0) /* p - y < p */ + if (mpi_cmp (negative, y) < 0) /* p - y < p */ { /* We need to end up with -Q; this assures that new Q's y is the smallest one */ mpi_sub (sk->d, E->n, sk->d); /* d = order - d */ - gcry_mpi_point_snatch_set (&sk->Q, x, p_y, mpi_alloc_set_ui (1)); + if (E->model == MPI_EC_WEIERSTRASS) + gcry_mpi_point_snatch_set (&sk->Q, x, negative, mpi_alloc_set_ui (1)); + else + gcry_mpi_point_snatch_set (&sk->Q, negative, y, mpi_alloc_set_ui (1)); - if (DBG_CIPHER) - log_debug ("ecgen converted Q to a compliant point\n"); + if (DBG_CIPHER) + log_debug ("ecgen converted Q to a compliant point\n"); } else /* p - y >= p */ { @@ -207,10 +213,17 @@ nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx, if (DBG_CIPHER) log_debug ("ecgen didn't need to convert Q to a compliant point\n"); - mpi_free (p_y); - mpi_free (x); + mpi_free (negative); + if (E->model == MPI_EC_WEIERSTRASS) + mpi_free (x); + else + mpi_free (y); } - mpi_free (y); + + if (E->model == MPI_EC_WEIERSTRASS) + mpi_free (y); + else + mpi_free (x); } /* Now we can test our keys (this should never fail!). */ ----------------------------------------------------------------------- Summary of changes: cipher/ecc.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From wk at gnupg.org Tue Oct 22 12:44:14 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 22 Oct 2013 12:44:14 +0200 Subject: ECDSA for Edwards curve In-Reply-To: <1382419495.5358.2.camel@cfw2.gniibe.org> (NIIBE Yutaka's message of "Tue, 22 Oct 2013 14:24:55 +0900") References: <1381867004-21231-1-git-send-email-dbaryshkov@gmail.com> <1381867004-21231-3-git-send-email-dbaryshkov@gmail.com> <87ppr5jnbm.fsf@vigenere.g10code.de> <87iowwiefw.fsf@vigenere.g10code.de> <1382341573.3497.1.camel@cfw2.gniibe.org> <87sivuewep.fsf@vigenere.g10code.de> <878uxmeiy7.fsf@vigenere.g10code.de> <1382419495.5358.2.camel@cfw2.gniibe.org> Message-ID: <8738ntd1q9.fsf@vigenere.g10code.de> On Tue, 22 Oct 2013 07:24, gniibe at fsij.org said: > Aside from how to encode/decode the point, here is the fix to get > compliant key. This fixes the failure of keygen program. Thanks. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From jussi.kivilinna at iki.fi Tue Oct 22 14:32:02 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Tue, 22 Oct 2013 15:32:02 +0300 Subject: [PATCH 1/2] [v3] Add API to support AEAD cipher modes Message-ID: <20131022123202.6563.15226.stgit@localhost6.localdomain6> * cipher/cipher.c (_gcry_cipher_authenticate, _gcry_cipher_checktag) (_gcry_cipher_gettag): New. * doc/gcrypt.texi: Add documentation for new API functions. * src/visibility.c (gcry_cipher_authenticate, gcry_cipher_checktag) (gcry_cipher_gettag): New. * src/gcrypt.h.in, src/visibility.h: add declarations of these functions. * src/libgcrypt.defs, src/libgcrypt.vers: export functions. -- Authenticated Encryption with Associated Data (AEAD) cipher modes provide authentication tag that can be used to authenticate message. At the same time it allows one to specify additional (unencrypted data) that will be authenticated together with the message. This class of cipher modes requires additional API present in this commit. This patch is based on original patch by Dmitry Eremin-Solenikov. Changes in v2: - Change gcry_cipher_tag to gcry_cipher_checktag and gcry_cipher_gettag for giving tag (checktag) for decryption and reading tag (gettag) after encryption. - Change gcry_cipher_authenticate to gcry_cipher_setaad, since additional parameters needed for some AEAD modes (in this case CCM, which needs the length of encrypted data and tag for MAC initialization). - Add some documentation. Changes in v3: - Change gcry_cipher_setaad back to gcry_cipher_authenticate. Additional parameters (encrypt_len, tag_len, aad_len) for CCM will be given through GCRY_CTL_SET_CCM_LENGTHS. Signed-off-by: Jussi Kivilinna --- cipher/cipher.c | 34 ++++++++++++++++++++++++++++++++++ doc/gcrypt.texi | 35 +++++++++++++++++++++++++++++++++++ src/gcrypt.h.in | 11 +++++++++++ src/libgcrypt.def | 3 +++ src/libgcrypt.vers | 1 + src/visibility.c | 27 +++++++++++++++++++++++++++ src/visibility.h | 9 +++++++++ 7 files changed, 120 insertions(+) diff --git a/cipher/cipher.c b/cipher/cipher.c index 75d42d1..36c79db 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -910,6 +910,40 @@ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return 0; } +gcry_error_t +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen) +{ + log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + + (void)abuf; + (void)abuflen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + + (void)outtag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + + (void)intag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + gcry_error_t gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 473c484..0049fa0 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1731,6 +1731,10 @@ matches the requirement of the selected algorithm and mode. This function is also used with the Salsa20 stream cipher to set or update the required nonce. In this case it needs to be called after setting the key. + +This function is also used with the AEAD cipher modes to set or +update the required nonce. + @end deftypefun @deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, const void *@var{c}, size_t @var{l}) @@ -1750,6 +1754,37 @@ call to gcry_cipher_setkey and clear the initialization vector. Note that gcry_cipher_reset is implemented as a macro. @end deftypefun +Authenticated Encryption with Associated Data (AEAD) block cipher +modes require the handling of the authentication tag and the additional +authenticated data, which can be done by using the following +functions: + + at deftypefun gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t @var{h}, const void *@var{abuf}, size_t @var{abuflen}) + +Process the buffer @var{abuf} of length @var{abuflen} as the additional +authenticated data (AAD) for AEAD cipher modes. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t @var{h}, void *@var{tag}, size_t @var{taglen}) + +This function is used to read the authentication tag after encryption. +The function finalizes and outputs the authentication tag to the buffer + at var{tag} of length @var{taglen} bytes. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t @var{h}, const void *@var{tag}, size_t @var{taglen}) + +Check the authentication tag after decryption. The authentication +tag is passed as the buffer @var{tag} of length @var{taglen} bytes +and compared to internal authentication tag computed during +decryption. Error code @code{GPG_ERR_CHECKSUM} is returned if +the authentication tag in the buffer @var{tag} does not match +the authentication tag calculated during decryption. + + at end deftypefun + The actual encryption and decryption is done by using one of the following functions. They may be used as often as required to process all the data. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 64cc0e4..f0ae927 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -953,6 +953,17 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen); +/* Provide additional authentication data for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen); + +/* Get authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, + size_t taglen); + +/* Check authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, + size_t taglen); /* Reset the handle to the state after open. */ #define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0) diff --git a/src/libgcrypt.def b/src/libgcrypt.def index ec0c1e3..64ba370 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -255,6 +255,9 @@ EXPORTS gcry_sexp_extract_param @225 + gcry_cipher_authenticate @226 + gcry_cipher_gettag @227 + gcry_cipher_checktag @228 ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index be72aad..93eaa93 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -51,6 +51,7 @@ GCRYPT_1.6 { gcry_cipher_info; gcry_cipher_map_name; gcry_cipher_mode_from_oid; gcry_cipher_open; gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr; + gcry_cipher_authenticate; gcry_cipher_gettag; gcry_cipher_checktag; gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl; gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey; diff --git a/src/visibility.c b/src/visibility.c index 848925e..1f7bb3a 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -713,6 +713,33 @@ gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return _gcry_cipher_setctr (hd, ctr, ctrlen); } +gcry_error_t +gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_authenticate (hd, abuf, abuflen); +} + +gcry_error_t +gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_gettag (hd, outtag, taglen); +} + +gcry_error_t +gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_checktag (hd, intag, taglen); +} + gcry_error_t gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/src/visibility.h b/src/visibility.h index 1c8f047..b2fa4c0 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -81,6 +81,9 @@ #define gcry_cipher_setkey _gcry_cipher_setkey #define gcry_cipher_setiv _gcry_cipher_setiv #define gcry_cipher_setctr _gcry_cipher_setctr +#define gcry_cipher_authenticate _gcry_cipher_authenticate +#define gcry_cipher_checktag _gcry_cipher_checktag +#define gcry_cipher_gettag _gcry_cipher_gettag #define gcry_cipher_ctl _gcry_cipher_ctl #define gcry_cipher_decrypt _gcry_cipher_decrypt #define gcry_cipher_encrypt _gcry_cipher_encrypt @@ -297,6 +300,9 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, #undef gcry_cipher_setkey #undef gcry_cipher_setiv #undef gcry_cipher_setctr +#undef gcry_cipher_authenticate +#undef gcry_cipher_checktag +#undef gcry_cipher_gettag #undef gcry_cipher_ctl #undef gcry_cipher_decrypt #undef gcry_cipher_encrypt @@ -474,6 +480,9 @@ MARK_VISIBLE (gcry_cipher_close) MARK_VISIBLE (gcry_cipher_setkey) MARK_VISIBLE (gcry_cipher_setiv) MARK_VISIBLE (gcry_cipher_setctr) +MARK_VISIBLE (gcry_cipher_authenticate) +MARK_VISIBLE (gcry_cipher_checktag) +MARK_VISIBLE (gcry_cipher_gettag) MARK_VISIBLE (gcry_cipher_ctl) MARK_VISIBLE (gcry_cipher_decrypt) MARK_VISIBLE (gcry_cipher_encrypt) From jussi.kivilinna at iki.fi Tue Oct 22 14:32:07 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Tue, 22 Oct 2013 15:32:07 +0300 Subject: [PATCH 2/2] [v4] Add Counter with CBC-MAC mode (CCM) In-Reply-To: <20131022123202.6563.15226.stgit@localhost6.localdomain6> References: <20131022123202.6563.15226.stgit@localhost6.localdomain6> Message-ID: <20131022123207.6563.4124.stgit@localhost6.localdomain6> * cipher/Makefile.am: Add 'cipher-ccm.c'. * cipher/cipher-ccm.c: New. * cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode'. (_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt) (_gcry_cipher_ccm_set_nonce, _gcry_cipher_ccm_authenticate) (_gcry_cipher_ccm_get_tag, _gcry_cipher_ccm_check_tag) (_gcry_cipher_ccm_set_lengths): New prototypes. * cipher/cipher.c (gcry_cipher_open, cipher_encrypt, cipher_decrypt) (_gcry_cipher_setiv, _gcry_cipher_authenticate, _gcry_cipher_gettag) (_gcry_cipher_checktag, gry_cipher_ctl): Add handling for CCM mode. * doc/gcrypt.texi: Add documentation for GCRY_CIPHER_MODE_CCM. * src/gcrypt.h.in (gcry_cipher_modes): Add 'GCRY_CIPHER_MODE_CCM'. (gcry_ctl_cmds): Add 'GCRYCTL_SET_CCM_LENGTHS'. (GCRY_CCM_BLOCK_LEN): New. * tests/basic.c (check_ccm_cipher): New. (check_cipher_modes): Call 'check_ccm_cipher'. * tests/benchmark.c (ccm_aead_init): New. (cipher_bench): Add handling for AEAD modes and add CCM benchmarking. -- Patch adds CCM (Counter with CBC-MAC) mode as defined in RFC 3610 and NIST Special Publication 800-38C. Example for encrypting message (split in two buffers; buf1, buf2) and authenticating additional non-encrypted data (split in two buffers; aadbuf1, aadbuf2) with authentication tag length of eigth bytes: size_t params[3]; taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1) + len(buf2); /* 0: enclen */ params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3); gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1)); gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2)); gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_encrypt(h, buf2, len(buf2), buf2, len(buf2)); gcry_cipher_gettag(h, tag, taglen); Example for decrypting above message and checking authentication tag: size_t params[3]; taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1) + len(buf2); /* 0: enclen */ params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3); gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1)); gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2)); gcry_cipher_decrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_decrypt(h, buf2, len(buf2), buf2, len(buf2)); err = gcry_cipher_checktag(h, tag, taglen); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) { /* Authentication failed. */ } else if (err == 0) { /* Authentication ok. */ } Example for encrypting message without additional authenticated data: size_t params[3]; taglen = 10; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1); /* 0: enclen */ params[1] = 0; /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3); gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_gettag(h, tag, taglen); To reset CCM state for cipher handle, one can either set new nonce or use 'gcry_cipher_reset'. This implementation reuses existing CTR mode code for encryption/decryption and is there for able to process multiple buffers that are not multiple of blocksize. AAD data maybe also be passed into gcry_cipher_authenticate in non-blocksize chunks. [v4]: GCRYCTL_SET_CCM_PARAMS => GCRY_SET_CCM_LENGTHS Signed-off-by: Jussi Kivilinna --- cipher/Makefile.am | 1 cipher/cipher-ccm.c | 371 ++++++++++++++++++++++ cipher/cipher-internal.h | 48 +++ cipher/cipher.c | 107 ++++++ doc/gcrypt.texi | 16 + src/gcrypt.h.in | 8 tests/basic.c | 771 ++++++++++++++++++++++++++++++++++++++++++++++ tests/benchmark.c | 80 +++++ 8 files changed, 1377 insertions(+), 25 deletions(-) create mode 100644 cipher/cipher-ccm.c diff --git a/cipher/Makefile.am b/cipher/Makefile.am index a2b2c8a..b0efd89 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -40,6 +40,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES) libcipher_la_SOURCES = \ cipher.c cipher-internal.h \ cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \ +cipher-ccm.c \ cipher-selftest.c cipher-selftest.h \ pubkey.c pubkey-internal.h pubkey-util.c \ md.c \ diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c new file mode 100644 index 0000000..ce67b40 --- /dev/null +++ b/cipher/cipher-ccm.c @@ -0,0 +1,371 @@ +/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static unsigned int +do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, + int do_padding) +{ + const unsigned int blocksize = 16; + unsigned char tmp[blocksize]; + unsigned int burn = 0; + unsigned int unused = c->u_mode.ccm.mac_unused; + size_t nblocks; + + if (inlen == 0 && (unused == 0 || !do_padding)) + return 0; + + do + { + if (inlen + unused < blocksize || unused > 0) + { + for (; inlen && unused < blocksize; inlen--) + c->u_mode.ccm.macbuf[unused++] = *inbuf++; + } + if (!inlen) + { + if (!do_padding) + break; + + while (unused < blocksize) + c->u_mode.ccm.macbuf[unused++] = 0; + } + + if (unused > 0) + { + /* Process one block from macbuf. */ + buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + unused = 0; + } + + if (c->bulk.cbc_enc) + { + nblocks = inlen / blocksize; + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1); + inbuf += nblocks * blocksize; + inlen -= nblocks * blocksize; + + wipememory (tmp, sizeof(tmp)); + } + else + { + while (inlen >= blocksize) + { + buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + inlen -= blocksize; + inbuf += blocksize; + } + } + } + while (inlen > 0); + + c->u_mode.ccm.mac_unused = unused; + + if (burn) + burn += 4 * sizeof(void *); + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + size_t L = 15 - noncelen; + size_t L_; + + L_ = L - 1; + + if (!nonce) + return GPG_ERR_INV_ARG; + /* Length field must be 2, 3, ..., or 8. */ + if (L < 2 || L > 8) + return GPG_ERR_INV_LENGTH; + + /* Reset state */ + memset (&c->u_mode, 0, sizeof(c->u_mode)); + memset (&c->marks, 0, sizeof(c->marks)); + memset (&c->u_iv, 0, sizeof(c->u_iv)); + memset (&c->u_ctr, 0, sizeof(c->u_ctr)); + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + + /* Setup CTR */ + c->u_ctr.ctr[0] = L_; + memcpy (&c->u_ctr.ctr[1], nonce, noncelen); + memset (&c->u_ctr.ctr[1 + noncelen], 0, L); + + /* Setup IV */ + c->u_iv.iv[0] = L_; + memcpy (&c->u_iv.iv[1], nonce, noncelen); + /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later + in set_aad. */ + memset (&c->u_iv.iv[1 + noncelen], 0, L); + + c->u_mode.ccm.nonce = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, size_t encryptlen, + size_t aadlen, size_t taglen) +{ + unsigned int burn = 0; + unsigned char b0[16]; + size_t noncelen = 15 - (c->u_iv.iv[0] + 1); + size_t M = taglen; + size_t M_; + int i; + + M_ = (M - 2) / 2; + + /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */ + if ((M_ * 2 + 2) != M || M < 4 || M > 16) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.ccm.lengths) + return GPG_ERR_INV_STATE; + + c->u_mode.ccm.authlen = taglen; + c->u_mode.ccm.encryptlen = encryptlen; + c->u_mode.ccm.aadlen = aadlen; + + /* Complete IV setup. */ + c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8; + for (i = 16 - 1; i >= 1 + noncelen; i--) + { + c->u_iv.iv[i] = encryptlen & 0xff; + encryptlen >>= 8; + } + + memcpy (b0, c->u_iv.iv, 16); + memset (c->u_iv.iv, 0, 16); + + set_burn (burn, do_cbc_mac (c, b0, 16, 0)); + + if (aadlen == 0) + { + /* Do nothing. */ + } + else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff) + { + b0[0] = (aadlen >> 8) & 0xff; + b0[1] = aadlen & 0xff; + set_burn (burn, do_cbc_mac (c, b0, 2, 0)); + } + else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xfe; + buf_put_be32(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 6, 0)); + } +#ifdef HAVE_U64_TYPEDEF + else if (aadlen > (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xff; + buf_put_be64(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 10, 0)); + } +#endif + + /* Generate S_0 and increase counter. */ + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0, + c->u_ctr.ctr )); + c->u_ctr.ctr[15]++; + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->u_mode.ccm.lengths = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, + size_t abuflen) +{ + unsigned int burn; + + if (abuflen > 0 && !abuf) + return GPG_ERR_INV_ARG; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (abuflen > c->u_mode.ccm.aadlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.aadlen -= abuflen; + burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, int check) +{ + unsigned int burn; + + if (!outbuf || outbuflen == 0) + return GPG_ERR_INV_ARG; + /* Tag length must be same as initial authlen. */ + if (c->u_mode.ccm.authlen != outbuflen) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + /* Initial encrypt length must match with length of actual data processed. */ + if (c->u_mode.ccm.encryptlen > 0) + return GPG_ERR_UNFINISHED; + + if (!c->u_mode.ccm.tag) + { + burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ + + /* Add S_0 */ + buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + + wipememory (c->u_ctr.ctr, 16); + wipememory (c->u_mode.ccm.s0, 16); + wipememory (c->u_mode.ccm.macbuf, 16); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + int diff, i; + + /* Constant-time compare. */ + for (i = 0, diff = 0; i < outbuflen; i++) + diff -= !!(outbuf[i] - c->u_iv.iv[i]); + + return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); +} + + +gcry_err_code_t +_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, inbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +} + + +gcry_err_code_t +_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + gcry_err_code_t err; + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + if (err) + return err; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, outbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return err; +} + diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index b60ef38..981caa8 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -100,7 +100,8 @@ struct gcry_cipher_handle /* The initialization vector. For best performance we make sure that it is properly aligned. In particular some implementations - of bulk operations expect an 16 byte aligned IV. */ + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */ union { cipher_context_alignment_t iv_align; unsigned char iv[MAX_BLOCKSIZE]; @@ -117,6 +118,26 @@ struct gcry_cipher_handle unsigned char lastiv[MAX_BLOCKSIZE]; int unused; /* Number of unused bytes in LASTIV. */ + union { + /* Mode specific storage for CCM mode. */ + struct { + size_t encryptlen; + size_t aadlen; + unsigned int authlen; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int nonce:1;/* Set to 1 if nonce has been set. */ + unsigned int lengths:1; /* Set to 1 if CCM length parameters has been + processed. */ + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ + } ccm; + } u_mode; + /* What follows are two contexts of the cipher in use. The first one needs to be aligned well enough for the cipher operation whereas the second one is a copy created by cipher_setkey and @@ -175,5 +196,30 @@ gcry_err_code_t _gcry_cipher_aeswrap_decrypt const byte *inbuf, unsigned int inbuflen); +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ccm_authenticate +/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen); +gcry_err_code_t _gcry_cipher_ccm_set_lengths +/* */ (gcry_cipher_hd_t c, size_t encryptedlen, size_t aadlen, + size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); + + #endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/cipher/cipher.c b/cipher/cipher.c index 36c79db..44d19a1 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -375,6 +375,13 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, if (! err) switch (mode) { + case GCRY_CIPHER_MODE_CCM: + if (spec->blocksize != GCRY_CCM_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: @@ -613,6 +620,8 @@ cipher_reset (gcry_cipher_hd_t c) memset (c->u_iv.iv, 0, c->spec->blocksize); memset (c->lastiv, 0, c->spec->blocksize); memset (c->u_ctr.ctr, 0, c->spec->blocksize); + memset (&c->u_mode, 0, sizeof c->u_mode); + c->unused = 0; } @@ -718,6 +727,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stencrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -811,6 +824,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stdecrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -885,8 +902,19 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) gcry_error_t _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) { - cipher_setiv (hd, iv, ivlen); - return 0; + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen); + break; + + default: + cipher_setiv (hd, iv, ivlen); + break; + } + return gpg_error (rc); } /* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of @@ -914,34 +942,61 @@ gcry_error_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) { - log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_authenticate (hd, abuf, abuflen); + break; - (void)abuf; - (void)abuflen; + default: + log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) { - log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen); + break; - (void)outtag; - (void)taglen; + default: + log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) { - log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen); + break; - (void)intag; - (void)taglen; + default: + log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } @@ -980,6 +1035,30 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) h->flags &= ~GCRY_CIPHER_CBC_MAC; break; + case GCRYCTL_SET_CCM_LENGTHS: + { + size_t params[3]; + size_t encryptedlen; + size_t aadlen; + size_t authtaglen; + + if (h->mode != GCRY_CIPHER_MODE_CCM) + return gcry_error (GPG_ERR_INV_CIPHER_MODE); + + if (!buffer || buflen != 3 * sizeof(size_t)) + return gcry_error (GPG_ERR_INV_ARG); + + /* This command is used to pass additional length parameters needed + by CCM mode to initialize CBC-MAC. */ + memcpy (params, buffer, sizeof(params)); + encryptedlen = params[0]; + aadlen = params[1]; + authtaglen = params[2]; + + rc = _gcry_cipher_ccm_set_lengths (h, encryptedlen, aadlen, authtaglen); + } + break; + case GCRYCTL_DISABLE_ALGO: /* This command expects NULL for H and BUFFER to point to an integer with the algo number. */ diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 0049fa0..91fe399 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1635,6 +1635,12 @@ may be specified 64 bit (8 byte) shorter than then input buffer. As per specs the input length must be at least 128 bits and the length must be a multiple of 64 bits. + at item GCRY_CIPHER_MODE_CCM + at cindex CCM, Counter with CBC-MAC mode +Counter with CBC-MAC mode is an Authenticated Encryption with +Associated Data (AEAD) block cipher mode, which is specified in +'NIST Special Publication 800-38C' and RFC 3610. + @end table @node Working with cipher handles @@ -1661,11 +1667,13 @@ The cipher mode to use must be specified via @var{mode}. See @xref{Available cipher modes}, for a list of supported cipher modes and the according constants. Note that some modes are incompatible with some algorithms - in particular, stream mode -(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. Any -block cipher mode (@code{GCRY_CIPHER_MODE_ECB}, +(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. The +block cipher modes (@code{GCRY_CIPHER_MODE_ECB}, @code{GCRY_CIPHER_MODE_CBC}, @code{GCRY_CIPHER_MODE_CFB}, - at code{GCRY_CIPHER_MODE_OFB} or @code{GCRY_CIPHER_MODE_CTR}) will work -with any block cipher algorithm. + at code{GCRY_CIPHER_MODE_OFB} and @code{GCRY_CIPHER_MODE_CTR}) will work +with any block cipher algorithm. The @code{GCRY_CIPHER_MODE_CCM} will +only work with block cipher algorithms which have the block size of +16 bytes. The third argument @var{flags} can either be passed as @code{0} or as the bit-wise OR of the following constants. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index f0ae927..948202d 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -325,7 +325,8 @@ enum gcry_ctl_cmds GCRYCTL_SET_PREFERRED_RNG_TYPE = 65, GCRYCTL_GET_CURRENT_RNG_TYPE = 66, GCRYCTL_DISABLE_LOCKED_SECMEM = 67, - GCRYCTL_DISABLE_PRIV_DROP = 68 + GCRYCTL_DISABLE_PRIV_DROP = 68, + GCRYCTL_SET_CCM_LENGTHS = 69 }; /* Perform various operations defined by CMD. */ @@ -884,7 +885,8 @@ enum gcry_cipher_modes GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ GCRY_CIPHER_MODE_CTR = 6, /* Counter. */ - GCRY_CIPHER_MODE_AESWRAP= 7 /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_AESWRAP= 7, /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_CCM = 8 /* Counter with CBC-MAC. */ }; /* Flags used with the open function. */ @@ -896,6 +898,8 @@ enum gcry_cipher_flags GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */ }; +/* CCM works only with blocks of 128 bits. */ +#define GCRY_CCM_BLOCK_LEN (128 / 8) /* Create a handle for algorithm ALGO to be used in MODE. FLAGS may be given as an bitwise OR of the gcry_cipher_flags values. */ diff --git a/tests/basic.c b/tests/basic.c index 1d6e637..21af21d 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -1139,6 +1139,776 @@ check_ofb_cipher (void) static void +check_ccm_cipher (void) +{ + static const struct tv + { + int algo; + int keylen; + const char *key; + int noncelen; + const char *nonce; + int aadlen; + const char *aad; + int plainlen; + const char *plaintext; + int cipherlen; + const char *ciphertext; + } tv[] = + { + /* RFC 3610 */ + { GCRY_CIPHER_AES, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\x58\x8C\x97\x9A\x61\xC6\x63\xD2\xF0\x66\xD0\xC2\xC0\xF9\x89\x80\x6D\x5F\x6B\x61\xDA\xC3\x84\x17\xE8\xD1\x2C\xFD\xF9\x26\xE0"}, + { GCRY_CIPHER_AES, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x72\xC9\x1A\x36\xE1\x35\xF8\xCF\x29\x1C\xA8\x94\x08\x5C\x87\xE3\xCC\x15\xC4\x39\xC9\xE4\x3A\x3B\xA0\x91\xD5\x6E\x10\x40\x09\x16"}, + { GCRY_CIPHER_AES, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x51\xB1\xE5\xF4\x4A\x19\x7D\x1D\xA4\x6B\x0F\x8E\x2D\x28\x2A\xE8\x71\xE8\x38\xBB\x64\xDA\x85\x96\x57\x4A\xDA\xA7\x6F\xBD\x9F\xB0\xC5"}, + { GCRY_CIPHER_AES, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xA2\x8C\x68\x65\x93\x9A\x9A\x79\xFA\xAA\x5C\x4C\x2A\x9D\x4A\x91\xCD\xAC\x8C\x96\xC8\x61\xB9\xC9\xE6\x1E\xF1"}, + { GCRY_CIPHER_AES, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\xDC\xF1\xFB\x7B\x5D\x9E\x23\xFB\x9D\x4E\x13\x12\x53\x65\x8A\xD8\x6E\xBD\xCA\x3E\x51\xE8\x3F\x07\x7D\x9C\x2D\x93"}, + { GCRY_CIPHER_AES, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\x6F\xC1\xB0\x11\xF0\x06\x56\x8B\x51\x71\xA4\x2D\x95\x3D\x46\x9B\x25\x70\xA4\xBD\x87\x40\x5A\x04\x43\xAC\x91\xCB\x94"}, + { GCRY_CIPHER_AES, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x01\x35\xD1\xB2\xC9\x5F\x41\xD5\xD1\xD4\xFE\xC1\x85\xD1\x66\xB8\x09\x4E\x99\x9D\xFE\xD9\x6C\x04\x8C\x56\x60\x2C\x97\xAC\xBB\x74\x90"}, + { GCRY_CIPHER_AES, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x7B\x75\x39\x9A\xC0\x83\x1D\xD2\xF0\xBB\xD7\x58\x79\xA2\xFD\x8F\x6C\xAE\x6B\x6C\xD9\xB7\xDB\x24\xC1\x7B\x44\x33\xF4\x34\x96\x3F\x34\xB4"}, + { GCRY_CIPHER_AES, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x82\x53\x1A\x60\xCC\x24\x94\x5A\x4B\x82\x79\x18\x1A\xB5\xC8\x4D\xF2\x1C\xE7\xF9\xB7\x3F\x42\xE1\x97\xEA\x9C\x07\xE5\x6B\x5E\xB1\x7E\x5F\x4E"}, + { GCRY_CIPHER_AES, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\x07\x34\x25\x94\x15\x77\x85\x15\x2B\x07\x40\x98\x33\x0A\xBB\x14\x1B\x94\x7B\x56\x6A\xA9\x40\x6B\x4D\x99\x99\x88\xDD"}, + { GCRY_CIPHER_AES, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x67\x6B\xB2\x03\x80\xB0\xE3\x01\xE8\xAB\x79\x59\x0A\x39\x6D\xA7\x8B\x83\x49\x34\xF5\x3A\xA2\xE9\x10\x7A\x8B\x6C\x02\x2C"}, + { GCRY_CIPHER_AES, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\xC0\xFF\xA0\xD6\xF0\x5B\xDB\x67\xF2\x4D\x43\xA4\x33\x8D\x2A\xA4\xBE\xD7\xB2\x0E\x43\xCD\x1A\xA3\x16\x62\xE7\xAD\x65\xD6\xDB"}, + { GCRY_CIPHER_AES, /* Packet Vector #13 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x41\x2B\x4E\xA9\xCD\xBE\x3C\x96\x96\x76\x6C\xFA", + 8, "\x0B\xE1\xA8\x8B\xAC\xE0\x18\xB1", + 23, + "\x08\xE8\xCF\x97\xD8\x20\xEA\x25\x84\x60\xE9\x6A\xD9\xCF\x52\x89\x05\x4D\x89\x5C\xEA\xC4\x7C", + 31, + "\x4C\xB9\x7F\x86\xA2\xA4\x68\x9A\x87\x79\x47\xAB\x80\x91\xEF\x53\x86\xA6\xFF\xBD\xD0\x80\xF8\xE7\x8C\xF7\xCB\x0C\xDD\xD7\xB3"}, + { GCRY_CIPHER_AES, /* Packet Vector #14 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x33\x56\x8E\xF7\xB2\x63\x3C\x96\x96\x76\x6C\xFA", + 8, "\x63\x01\x8F\x76\xDC\x8A\x1B\xCB", + 24, + "\x90\x20\xEA\x6F\x91\xBD\xD8\x5A\xFA\x00\x39\xBA\x4B\xAF\xF9\xBF\xB7\x9C\x70\x28\x94\x9C\xD0\xEC", + 32, + "\x4C\xCB\x1E\x7C\xA9\x81\xBE\xFA\xA0\x72\x6C\x55\xD3\x78\x06\x12\x98\xC8\x5C\x92\x81\x4A\xBC\x33\xC5\x2E\xE8\x1D\x7D\x77\xC0\x8A"}, + { GCRY_CIPHER_AES, /* Packet Vector #15 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x10\x3F\xE4\x13\x36\x71\x3C\x96\x96\x76\x6C\xFA", + 8, "\xAA\x6C\xFA\x36\xCA\xE8\x6B\x40", + 25, + "\xB9\x16\xE0\xEA\xCC\x1C\x00\xD7\xDC\xEC\x68\xEC\x0B\x3B\xBB\x1A\x02\xDE\x8A\x2D\x1A\xA3\x46\x13\x2E", + 33, + "\xB1\xD2\x3A\x22\x20\xDD\xC0\xAC\x90\x0D\x9A\xA0\x3C\x61\xFC\xF4\xA5\x59\xA4\x41\x77\x67\x08\x97\x08\xA7\x76\x79\x6E\xDB\x72\x35\x06"}, + { GCRY_CIPHER_AES, /* Packet Vector #16 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x76\x4C\x63\xB8\x05\x8E\x3C\x96\x96\x76\x6C\xFA", + 12, "\xD0\xD0\x73\x5C\x53\x1E\x1B\xEC\xF0\x49\xC2\x44", + 19, + "\x12\xDA\xAC\x56\x30\xEF\xA5\x39\x6F\x77\x0C\xE1\xA6\x6B\x21\xF7\xB2\x10\x1C", + 27, + "\x14\xD2\x53\xC3\x96\x7B\x70\x60\x9B\x7C\xBB\x7C\x49\x91\x60\x28\x32\x45\x26\x9A\x6F\x49\x97\x5B\xCA\xDE\xAF"}, + { GCRY_CIPHER_AES, /* Packet Vector #17 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xF8\xB6\x78\x09\x4E\x3B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x77\xB6\x0F\x01\x1C\x03\xE1\x52\x58\x99\xBC\xAE", + 20, + "\xE8\x8B\x6A\x46\xC7\x8D\x63\xE5\x2E\xB8\xC5\x46\xEF\xB5\xDE\x6F\x75\xE9\xCC\x0D", + 28, + "\x55\x45\xFF\x1A\x08\x5E\xE2\xEF\xBF\x52\xB2\xE0\x4B\xEE\x1E\x23\x36\xC7\x3E\x3F\x76\x2C\x0C\x77\x44\xFE\x7E\x3C"}, + { GCRY_CIPHER_AES, /* Packet Vector #18 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xD5\x60\x91\x2D\x3F\x70\x3C\x96\x96\x76\x6C\xFA", + 12, "\xCD\x90\x44\xD2\xB7\x1F\xDB\x81\x20\xEA\x60\xC0", + 21, + "\x64\x35\xAC\xBA\xFB\x11\xA8\x2E\x2F\x07\x1D\x7C\xA4\xA5\xEB\xD9\x3A\x80\x3B\xA8\x7F", + 29, + "\x00\x97\x69\xEC\xAB\xDF\x48\x62\x55\x94\xC5\x92\x51\xE6\x03\x57\x22\x67\x5E\x04\xC8\x47\x09\x9E\x5A\xE0\x70\x45\x51"}, + { GCRY_CIPHER_AES, /* Packet Vector #19 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x42\xFF\xF8\xF1\x95\x1C\x3C\x96\x96\x76\x6C\xFA", + 8, "\xD8\x5B\xC7\xE6\x9F\x94\x4F\xB8", + 23, + "\x8A\x19\xB9\x50\xBC\xF7\x1A\x01\x8E\x5E\x67\x01\xC9\x17\x87\x65\x98\x09\xD6\x7D\xBE\xDD\x18", + 33, + "\xBC\x21\x8D\xAA\x94\x74\x27\xB6\xDB\x38\x6A\x99\xAC\x1A\xEF\x23\xAD\xE0\xB5\x29\x39\xCB\x6A\x63\x7C\xF9\xBE\xC2\x40\x88\x97\xC6\xBA"}, + { GCRY_CIPHER_AES, /* Packet Vector #20 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x92\x0F\x40\xE5\x6C\xDC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x74\xA0\xEB\xC9\x06\x9F\x5B\x37", + 24, + "\x17\x61\x43\x3C\x37\xC5\xA3\x5F\xC1\xF3\x9F\x40\x63\x02\xEB\x90\x7C\x61\x63\xBE\x38\xC9\x84\x37", + 34, + "\x58\x10\xE6\xFD\x25\x87\x40\x22\xE8\x03\x61\xA4\x78\xE3\xE9\xCF\x48\x4A\xB0\x4F\x44\x7E\xFF\xF6\xF0\xA4\x77\xCC\x2F\xC9\xBF\x54\x89\x44"}, + { GCRY_CIPHER_AES, /* Packet Vector #21 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x27\xCA\x0C\x71\x20\xBC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x44\xA3\xAA\x3A\xAE\x64\x75\xCA", + 25, + "\xA4\x34\xA8\xE5\x85\x00\xC6\xE4\x15\x30\x53\x88\x62\xD6\x86\xEA\x9E\x81\x30\x1B\x5A\xE4\x22\x6B\xFA", + 35, + "\xF2\xBE\xED\x7B\xC5\x09\x8E\x83\xFE\xB5\xB3\x16\x08\xF8\xE2\x9C\x38\x81\x9A\x89\xC8\xE7\x76\xF1\x54\x4D\x41\x51\xA4\xED\x3A\x8B\x87\xB9\xCE"}, + { GCRY_CIPHER_AES, /* Packet Vector #22 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x5B\x8C\xCB\xCD\x9A\xF8\x3C\x96\x96\x76\x6C\xFA", + 12, "\xEC\x46\xBB\x63\xB0\x25\x20\xC3\x3C\x49\xFD\x70", + 19, + "\xB9\x6B\x49\xE2\x1D\x62\x17\x41\x63\x28\x75\xDB\x7F\x6C\x92\x43\xD2\xD7\xC2", + 29, + "\x31\xD7\x50\xA0\x9D\xA3\xED\x7F\xDD\xD4\x9A\x20\x32\xAA\xBF\x17\xEC\x8E\xBF\x7D\x22\xC8\x08\x8C\x66\x6B\xE5\xC1\x97"}, + { GCRY_CIPHER_AES, /* Packet Vector #23 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x3E\xBE\x94\x04\x4B\x9A\x3C\x96\x96\x76\x6C\xFA", + 12, "\x47\xA6\x5A\xC7\x8B\x3D\x59\x42\x27\xE8\x5E\x71", + 20, + "\xE2\xFC\xFB\xB8\x80\x44\x2C\x73\x1B\xF9\x51\x67\xC8\xFF\xD7\x89\x5E\x33\x70\x76", + 30, + "\xE8\x82\xF1\xDB\xD3\x8C\xE3\xED\xA7\xC2\x3F\x04\xDD\x65\x07\x1E\xB4\x13\x42\xAC\xDF\x7E\x00\xDC\xCE\xC7\xAE\x52\x98\x7D"}, + { GCRY_CIPHER_AES, /* Packet Vector #24 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x8D\x49\x3B\x30\xAE\x8B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x6E\x37\xA6\xEF\x54\x6D\x95\x5D\x34\xAB\x60\x59", + 21, + "\xAB\xF2\x1C\x0B\x02\xFE\xB8\x8F\x85\x6D\xF4\xA3\x73\x81\xBC\xE3\xCC\x12\x85\x17\xD4", + 31, + "\xF3\x29\x05\xB8\x8A\x64\x1B\x04\xB9\xC9\xFF\xB5\x8C\xC3\x90\x90\x0F\x3D\xA1\x2A\xB1\x6D\xCE\x9E\x82\xEF\xA1\x6D\xA6\x20\x59"}, + /* RFC 5528 */ + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\xBA\x73\x71\x85\xE7\x19\x31\x04\x92\xF3\x8A\x5F\x12\x51\xDA\x55\xFA\xFB\xC9\x49\x84\x8A\x0D\xFC\xAE\xCE\x74\x6B\x3D\xB9\xAD"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x5D\x25\x64\xBF\x8E\xAF\xE1\xD9\x95\x26\xEC\x01\x6D\x1B\xF0\x42\x4C\xFB\xD2\xCD\x62\x84\x8F\x33\x60\xB2\x29\x5D\xF2\x42\x83\xE8"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x81\xF6\x63\xD6\xC7\x78\x78\x17\xF9\x20\x36\x08\xB9\x82\xAD\x15\xDC\x2B\xBD\x87\xD7\x56\xF7\x92\x04\xF5\x51\xD6\x68\x2F\x23\xAA\x46"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xCA\xEF\x1E\x82\x72\x11\xB0\x8F\x7B\xD9\x0F\x08\xC7\x72\x88\xC0\x70\xA4\xA0\x8B\x3A\x93\x3A\x63\xE4\x97\xA0"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\x2A\xD3\xBA\xD9\x4F\xC5\x2E\x92\xBE\x43\x8E\x82\x7C\x10\x23\xB9\x6A\x8A\x77\x25\x8F\xA1\x7B\xA7\xF3\x31\xDB\x09"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\xFE\xA5\x48\x0B\xA5\x3F\xA8\xD3\xC3\x44\x22\xAA\xCE\x4D\xE6\x7F\xFA\x3B\xB7\x3B\xAB\xAB\x36\xA1\xEE\x4F\xE0\xFE\x28"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x54\x53\x20\x26\xE5\x4C\x11\x9A\x8D\x36\xD9\xEC\x6E\x1E\xD9\x74\x16\xC8\x70\x8C\x4B\x5C\x2C\xAC\xAF\xA3\xBC\xCF\x7A\x4E\xBF\x95\x73"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x8A\xD1\x9B\x00\x1A\x87\xD1\x48\xF4\xD9\x2B\xEF\x34\x52\x5C\xCC\xE3\xA6\x3C\x65\x12\xA6\xF5\x75\x73\x88\xE4\x91\x3E\xF1\x47\x01\xF4\x41"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x5D\xB0\x8D\x62\x40\x7E\x6E\x31\xD6\x0F\x9C\xA2\xC6\x04\x74\x21\x9A\xC0\xBE\x50\xC0\xD4\xA5\x77\x87\x94\xD6\xE2\x30\xCD\x25\xC9\xFE\xBF\x87"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\xDB\x11\x8C\xCE\xC1\xB8\x76\x1C\x87\x7C\xD8\x96\x3A\x67\xD6\xF3\xBB\xBC\x5C\xD0\x92\x99\xEB\x11\xF3\x12\xF2\x32\x37"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x7C\xC8\x3D\x8D\xC4\x91\x03\x52\x5B\x48\x3D\xC5\xCA\x7E\xA9\xAB\x81\x2B\x70\x56\x07\x9D\xAF\xFA\xDA\x16\xCC\xCF\x2C\x4E"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\x2C\xD3\x5B\x88\x20\xD2\x3E\x7A\xA3\x51\xB0\xE9\x2F\xC7\x93\x67\x23\x8B\x2C\xC7\x48\xCB\xB9\x4C\x29\x47\x79\x3D\x64\xAF\x75"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #13 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xA9\x70\x11\x0E\x19\x27\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x6B\x7F\x46\x45\x07\xFA\xE4\x96", + 23, + "\xC6\xB5\xF3\xE6\xCA\x23\x11\xAE\xF7\x47\x2B\x20\x3E\x73\x5E\xA5\x61\xAD\xB1\x7D\x56\xC5\xA3", + 31, + "\xA4\x35\xD7\x27\x34\x8D\xDD\x22\x90\x7F\x7E\xB8\xF5\xFD\xBB\x4D\x93\x9D\xA6\x52\x4D\xB4\xF6\x45\x58\xC0\x2D\x25\xB1\x27\xEE"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #14 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x83\xCD\x8C\xE0\xCB\x42\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x98\x66\x05\xB4\x3D\xF1\x5D\xE7", + 24, + "\x01\xF6\xCE\x67\x64\xC5\x74\x48\x3B\xB0\x2E\x6B\xBF\x1E\x0A\xBD\x26\xA2\x25\x72\xB4\xD8\x0E\xE7", + 32, + "\x8A\xE0\x52\x50\x8F\xBE\xCA\x93\x2E\x34\x6F\x05\xE0\xDC\x0D\xFB\xCF\x93\x9E\xAF\xFA\x3E\x58\x7C\x86\x7D\x6E\x1C\x48\x70\x38\x06"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #15 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x5F\x54\x95\x0B\x18\xF2\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x48\xF2\xE7\xE1\xA7\x67\x1A\x51", + 25, + "\xCD\xF1\xD8\x40\x6F\xC2\xE9\x01\x49\x53\x89\x70\x05\xFB\xFB\x8B\xA5\x72\x76\xF9\x24\x04\x60\x8E\x08", + 33, + "\x08\xB6\x7E\xE2\x1C\x8B\xF2\x6E\x47\x3E\x40\x85\x99\xE9\xC0\x83\x6D\x6A\xF0\xBB\x18\xDF\x55\x46\x6C\xA8\x08\x78\xA7\x90\x47\x6D\xE5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #16 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xEC\x60\x08\x63\x31\x9A\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xDE\x97\xDF\x3B\x8C\xBD\x6D\x8E\x50\x30\xDA\x4C", + 19, + "\xB0\x05\xDC\xFA\x0B\x59\x18\x14\x26\xA9\x61\x68\x5A\x99\x3D\x8C\x43\x18\x5B", + 27, + "\x63\xB7\x8B\x49\x67\xB1\x9E\xDB\xB7\x33\xCD\x11\x14\xF6\x4E\xB2\x26\x08\x93\x68\xC3\x54\x82\x8D\x95\x0C\xC5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #17 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x60\xCF\xF1\xA3\x1E\xA1\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA5\xEE\x93\xE4\x57\xDF\x05\x46\x6E\x78\x2D\xCF", + 20, + "\x2E\x20\x21\x12\x98\x10\x5F\x12\x9D\x5E\xD9\x5B\x93\xF7\x2D\x30\xB2\xFA\xCC\xD7", + 28, + "\x0B\xC6\xBB\xE2\xA8\xB9\x09\xF4\x62\x9E\xE6\xDC\x14\x8D\xA4\x44\x10\xE1\x8A\xF4\x31\x47\x38\x32\x76\xF6\x6A\x9F"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #18 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x0F\x85\xCD\x99\x5C\x97\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x24\xAA\x1B\xF9\xA5\xCD\x87\x61\x82\xA2\x50\x74", + 21, + "\x26\x45\x94\x1E\x75\x63\x2D\x34\x91\xAF\x0F\xC0\xC9\x87\x6C\x3B\xE4\xAA\x74\x68\xC9", + 29, + "\x22\x2A\xD6\x32\xFA\x31\xD6\xAF\x97\x0C\x34\x5F\x7E\x77\xCA\x3B\xD0\xDC\x25\xB3\x40\xA1\xA3\xD3\x1F\x8D\x4B\x44\xB7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #19 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC2\x9B\x2C\xAA\xC4\xCD\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x69\x19\x46\xB9\xCA\x07\xBE\x87", + 23, + "\x07\x01\x35\xA6\x43\x7C\x9D\xB1\x20\xCD\x61\xD8\xF6\xC3\x9C\x3E\xA1\x25\xFD\x95\xA0\xD2\x3D", + 33, + "\x05\xB8\xE1\xB9\xC4\x9C\xFD\x56\xCF\x13\x0A\xA6\x25\x1D\xC2\xEC\xC0\x6C\xCC\x50\x8F\xE6\x97\xA0\x06\x6D\x57\xC8\x4B\xEC\x18\x27\x68"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #20 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x2C\x6B\x75\x95\xEE\x62\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xD0\xC5\x4E\xCB\x84\x62\x7D\xC4", + 24, + "\xC8\xC0\x88\x0E\x6C\x63\x6E\x20\x09\x3D\xD6\x59\x42\x17\xD2\xE1\x88\x77\xDB\x26\x4E\x71\xA5\xCC", + 34, + "\x54\xCE\xB9\x68\xDE\xE2\x36\x11\x57\x5E\xC0\x03\xDF\xAA\x1C\xD4\x88\x49\xBD\xF5\xAE\x2E\xDB\x6B\x7F\xA7\x75\xB1\x50\xED\x43\x83\xC5\xA9"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #21 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC5\x3C\xD4\xC2\xAA\x24\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xE2\x85\xE0\xE4\x80\x8C\xDA\x3D", + 25, + "\xF7\x5D\xAA\x07\x10\xC4\xE6\x42\x97\x79\x4D\xC2\xB7\xD2\xA2\x07\x57\xB1\xAA\x4E\x44\x80\x02\xFF\xAB", + 35, + "\xB1\x40\x45\x46\xBF\x66\x72\x10\xCA\x28\xE3\x09\xB3\x9B\xD6\xCA\x7E\x9F\xC8\x28\x5F\xE6\x98\xD4\x3C\xD2\x0A\x02\xE0\xBD\xCA\xED\x20\x10\xD3"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #22 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xBE\xE9\x26\x7F\xBA\xDC\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x6C\xAE\xF9\x94\x11\x41\x57\x0D\x7C\x81\x34\x05", + 19, + "\xC2\x38\x82\x2F\xAC\x5F\x98\xFF\x92\x94\x05\xB0\xAD\x12\x7A\x4E\x41\x85\x4E", + 29, + "\x94\xC8\x95\x9C\x11\x56\x9A\x29\x78\x31\xA7\x21\x00\x58\x57\xAB\x61\xB8\x7A\x2D\xEA\x09\x36\xB6\xEB\x5F\x62\x5F\x5D"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #23 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xDF\xA8\xB1\x24\x50\x07\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x36\xA5\x2C\xF1\x6B\x19\xA2\x03\x7A\xB7\x01\x1E", + 20, + "\x4D\xBF\x3E\x77\x4A\xD2\x45\xE5\xD5\x89\x1F\x9D\x1C\x32\xA0\xAE\x02\x2C\x85\xD7", + 30, + "\x58\x69\xE3\xAA\xD2\x44\x7C\x74\xE0\xFC\x05\xF9\xA4\xEA\x74\x57\x7F\x4D\xE8\xCA\x89\x24\x76\x42\x96\xAD\x04\x11\x9C\xE7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #24 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x3B\x8F\xD8\xD3\xA9\x37\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA4\xD4\x99\xF7\x84\x19\x72\x8C\x19\x17\x8B\x0C", + 21, + "\x9D\xC9\xED\xAE\x2F\xF5\xDF\x86\x36\xE8\xC6\xDE\x0E\xED\x55\xF7\x86\x7E\x33\x33\x7D", + 31, + "\x4B\x19\x81\x56\x39\x3B\x0F\x77\x96\x08\x6A\xAF\xB4\x54\xF8\xC3\xF0\x34\xCC\xA9\x66\x94\x5F\x1F\xCE\xA7\xE1\x1B\xEE\x6A\x2F"} + }; + static const int cut[] = { 0, 1, 8, 10, 16, 19, -1 }; + gcry_cipher_hd_t hde, hdd; + unsigned char out[MAX_DATA_LEN]; + size_t ctl_params[3]; + int split, aadsplit; + size_t j, i, keylen, blklen, authlen; + gcry_error_t err = 0; + + if (verbose) + fprintf (stderr, " Starting CCM checks.\n"); + + for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) + { + if (verbose) + fprintf (stderr, " checking CCM mode for %s [%i]\n", + gcry_cipher_algo_name (tv[i].algo), + tv[i].algo); + + for (j = 0; j < sizeof (cut) / sizeof (cut[0]); j++) + { + split = cut[j] < 0 ? tv[i].plainlen : cut[j]; + if (tv[i].plainlen < split) + continue; + + err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + keylen = gcry_cipher_get_algo_keylen(tv[i].algo); + if (!keylen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_keylen failed\n"); + return; + } + + err = gcry_cipher_setkey (hde, tv[i].key, keylen); + if (!err) + err = gcry_cipher_setkey (hdd, tv[i].key, keylen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + blklen = gcry_cipher_get_algo_blklen(tv[i].algo); + if (!blklen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_blklen failed\n"); + return; + } + + err = gcry_cipher_setiv (hde, tv[i].nonce, tv[i].noncelen); + if (!err) + err = gcry_cipher_setiv (hdd, tv[i].nonce, tv[i].noncelen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + authlen = tv[i].cipherlen - tv[i].plainlen; + ctl_params[0] = tv[i].plainlen; /* encryptedlen */ + ctl_params[1] = tv[i].aadlen; /* aadlen */ + ctl_params[2] = authlen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (!err) + err = gcry_cipher_ctl (hdd, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS " + "failed: %s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + aadsplit = split > tv[i].aadlen ? 0 : split; + + err = gcry_cipher_authenticate (hde, tv[i].aad, + tv[i].aadlen - aadsplit); + if (!err) + err = gcry_cipher_authenticate (hde, + &tv[i].aad[tv[i].aadlen - aadsplit], + aadsplit); + if (!err) + err = gcry_cipher_authenticate (hdd, tv[i].aad, + tv[i].aadlen - aadsplit); + if (!err) + err = gcry_cipher_authenticate (hdd, + &tv[i].aad[tv[i].aadlen - aadsplit], + aadsplit); + if (err) + { + fail ("cipher-ccm, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, tv[i].plaintext, + tv[i].plainlen - split); + if (!err) + err = gcry_cipher_encrypt (hde, &out[tv[i].plainlen - split], + MAX_DATA_LEN - (tv[i].plainlen - split), + &tv[i].plaintext[tv[i].plainlen - split], + split); + if (err) + { + fail ("cipher-ccm, gcry_cipher_encrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_gettag (hde, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_gettag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].ciphertext, out, tv[i].cipherlen)) + fail ("cipher-ccm, encrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_decrypt (hdd, out, tv[i].plainlen - split, NULL, 0); + if (!err) + err = gcry_cipher_decrypt (hdd, &out[tv[i].plainlen - split], split, + NULL, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_decrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].plaintext, out, tv[i].plainlen)) + fail ("cipher-ccm, decrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_checktag (hdd, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_checktag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + } + } + + /* Large buffer tests. */ + + /* Test encoding of aadlen > 0xfeff. */ + { + static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19}; + static const char tag[]={0x9C,0x76,0xE7,0x33,0xD5,0x15,0xB3,0x6C, + 0xBA,0x76,0x95,0xF7,0xFB,0x91}; + char buf[1024]; + size_t enclen = 0x20000; + size_t aadlen = 0x20000; + size_t taglen = sizeof(tag); + + err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + err = gcry_cipher_setkey (hde, key, sizeof (key)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + err = gcry_cipher_setiv (hde, iv, sizeof (iv)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + ctl_params[0] = enclen; /* encryptedlen */ + ctl_params[1] = aadlen; /* aadlen */ + ctl_params[2] = taglen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS " + "failed: %s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + memset (buf, 0xaa, sizeof(buf)); + + for (i = 0; i < aadlen; i += sizeof(buf)) + { + err = gcry_cipher_authenticate (hde, buf, sizeof (buf)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + for (i = 0; i < enclen; i += sizeof(buf)) + { + memset (buf, 0xee, sizeof(buf)); + err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_encrypt failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + err = gcry_cipher_gettag (hde, buf, taglen); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_gettag failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + if (memcmp (buf, tag, taglen) != 0) + fail ("cipher-ccm-large, encrypt mismatch entry\n"); + } + +#if 0 + /* Test encoding of aadlen > 0xffffffff. */ + { + static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19}; + static const char tag[]={0x01,0xB2,0xC3,0x4A,0xA6,0x6A,0x07,0x6D, + 0xBC,0xBD,0xEA,0x17,0xD3,0x73,0xD7,0xD4}; + char buf[1024]; + size_t enclen = (size_t)0xffffffff + 1 + 1024; + size_t aadlen = (size_t)0xffffffff + 1 + 1024; + size_t taglen = sizeof(tag); + + err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + err = gcry_cipher_setkey (hde, key, sizeof (key)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + err = gcry_cipher_setiv (hde, iv, sizeof (iv)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + ctl_params[0] = enclen; /* encryptedlen */ + ctl_params[1] = aadlen; /* aadlen */ + ctl_params[2] = taglen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS failed:" + "%s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + memset (buf, 0xaa, sizeof(buf)); + + for (i = 0; i < aadlen; i += sizeof(buf)) + { + err = gcry_cipher_authenticate (hde, buf, sizeof (buf)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + for (i = 0; i < enclen; i += sizeof(buf)) + { + memset (buf, 0xee, sizeof(buf)); + err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_encrypt failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + err = gcry_cipher_gettag (hde, buf, taglen); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_gettag failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + if (memcmp (buf, tag, taglen) != 0) + fail ("cipher-ccm-huge, encrypt mismatch entry\n"); + } +#endif + + if (verbose) + fprintf (stderr, " Completed CCM checks.\n"); +} + + +static void check_stream_cipher (void) { struct tv @@ -2455,6 +3225,7 @@ check_cipher_modes(void) check_ctr_cipher (); check_cfb_cipher (); check_ofb_cipher (); + check_ccm_cipher (); check_stream_cipher (); check_stream_cipher_large_block (); diff --git a/tests/benchmark.c b/tests/benchmark.c index ecda0d3..d3ef1a2 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -435,6 +435,40 @@ md_bench ( const char *algoname ) fflush (stdout); } + +static void ccm_aead_init(gcry_cipher_hd_t hd, size_t buflen, int authlen) +{ + const int _L = 4; + const int noncelen = 15 - _L; + char nonce[noncelen]; + size_t params[3]; + gcry_error_t err = GPG_ERR_NO_ERROR; + + memset (nonce, 0x33, noncelen); + + err = gcry_cipher_setiv (hd, nonce, noncelen); + if (err) + { + fprintf (stderr, "gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } + + params[0] = buflen; /* encryptedlen */ + params[1] = 0; /* aadlen */ + params[2] = authlen; /* authtaglen */ + err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(params)); + if (err) + { + fprintf (stderr, "gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } +} + + static void cipher_bench ( const char *algoname ) { @@ -448,12 +482,21 @@ cipher_bench ( const char *algoname ) char *raw_outbuf, *raw_buf; size_t allocated_buflen, buflen; int repetitions; - static struct { int mode; const char *name; int blocked; } modes[] = { + static const struct { + int mode; + const char *name; + int blocked; + void (* const aead_init)(gcry_cipher_hd_t hd, size_t buflen, int authlen); + int req_blocksize; + int authlen; + } modes[] = { { GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1 }, { GCRY_CIPHER_MODE_CBC, " CBC", 1 }, { GCRY_CIPHER_MODE_CFB, " CFB", 0 }, { GCRY_CIPHER_MODE_OFB, " OFB", 0 }, { GCRY_CIPHER_MODE_CTR, " CTR", 0 }, + { GCRY_CIPHER_MODE_CCM, " CCM", 0, + ccm_aead_init, GCRY_CCM_BLOCK_LEN, 8 }, { GCRY_CIPHER_MODE_STREAM, "", 0 }, {0} }; @@ -542,9 +585,16 @@ cipher_bench ( const char *algoname ) for (modeidx=0; modes[modeidx].mode; modeidx++) { if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM) - | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) + || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) continue; + if (modes[modeidx].req_blocksize > 0 + && blklen != modes[modeidx].req_blocksize) + { + printf (" %7s %7s", "-", "-" ); + continue; + } + for (i=0; i < sizeof buf; i++) buf[i] = i; @@ -585,7 +635,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_gettag (hd, outbuf, modes[modeidx].authlen); + } + else + { + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + } } stop_timer (); @@ -632,7 +693,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_decrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_checktag (hd, outbuf, modes[modeidx].authlen); + if (gpg_err_code (err) == GPG_ERR_CHECKSUM) + err = gpg_error (GPG_ERR_NO_ERROR); + } + else + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); } stop_timer (); printf (" %s", elapsed_time ()); From jussi.kivilinna at iki.fi Tue Oct 22 15:31:56 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Tue, 22 Oct 2013 16:31:56 +0300 Subject: [PATCH] bufhelp: enable unaligned memory accesses for AArch64 (64-bit ARM) Message-ID: <20131022133156.27715.19936.stgit@localhost6.localdomain6> * cipher/bufhelp.h [__aarch64__] (BUFHELP_FAST_UNALIGNED_ACCESS): Set macro on AArch64. -- Signed-off-by: Jussi Kivilinna --- cipher/bufhelp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cipher/bufhelp.h b/cipher/bufhelp.h index 21fac07..198d286 100644 --- a/cipher/bufhelp.h +++ b/cipher/bufhelp.h @@ -35,7 +35,8 @@ #if defined(__i386__) || defined(__x86_64__) || \ defined(__powerpc__) || defined(__powerpc64__) || \ - (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) + (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) || \ + defined(__aarch64__) /* These architectures are able of unaligned memory accesses and can handle those fast. */ From jussi.kivilinna at iki.fi Tue Oct 22 15:49:23 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Tue, 22 Oct 2013 16:49:23 +0300 Subject: [PATCH 1/2] [v3] Add API to support AEAD cipher modes In-Reply-To: <20131022123202.6563.15226.stgit@localhost6.localdomain6> References: <20131022123202.6563.15226.stgit@localhost6.localdomain6> Message-ID: <52668263.9000101@iki.fi> Do these look ok to push? -Jussi On 22.10.2013 15:32, Jussi Kivilinna wrote: > * cipher/cipher.c (_gcry_cipher_authenticate, _gcry_cipher_checktag) > (_gcry_cipher_gettag): New. > * doc/gcrypt.texi: Add documentation for new API functions. > * src/visibility.c (gcry_cipher_authenticate, gcry_cipher_checktag) > (gcry_cipher_gettag): New. > * src/gcrypt.h.in, src/visibility.h: add declarations of these > functions. > * src/libgcrypt.defs, src/libgcrypt.vers: export functions. > -- > > Authenticated Encryption with Associated Data (AEAD) cipher modes > provide authentication tag that can be used to authenticate message. At > the same time it allows one to specify additional (unencrypted data) > that will be authenticated together with the message. This class of > cipher modes requires additional API present in this commit. > > This patch is based on original patch by Dmitry Eremin-Solenikov. > > Changes in v2: > - Change gcry_cipher_tag to gcry_cipher_checktag and gcry_cipher_gettag > for giving tag (checktag) for decryption and reading tag (gettag) after > encryption. > - Change gcry_cipher_authenticate to gcry_cipher_setaad, since > additional parameters needed for some AEAD modes (in this case CCM, > which needs the length of encrypted data and tag for MAC > initialization). > - Add some documentation. > > Changes in v3: > - Change gcry_cipher_setaad back to gcry_cipher_authenticate. Additional > parameters (encrypt_len, tag_len, aad_len) for CCM will be given > through GCRY_CTL_SET_CCM_LENGTHS. > > Signed-off-by: Jussi Kivilinna > --- > cipher/cipher.c | 34 ++++++++++++++++++++++++++++++++++ > doc/gcrypt.texi | 35 +++++++++++++++++++++++++++++++++++ > src/gcrypt.h.in | 11 +++++++++++ > src/libgcrypt.def | 3 +++ > src/libgcrypt.vers | 1 + > src/visibility.c | 27 +++++++++++++++++++++++++++ > src/visibility.h | 9 +++++++++ > 7 files changed, 120 insertions(+) > > diff --git a/cipher/cipher.c b/cipher/cipher.c > index 75d42d1..36c79db 100644 > --- a/cipher/cipher.c > +++ b/cipher/cipher.c > @@ -910,6 +910,40 @@ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) > return 0; > } > > +gcry_error_t > +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, > + size_t abuflen) > +{ > + log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); > + > + (void)abuf; > + (void)abuflen; > + > + return gpg_error (GPG_ERR_INV_CIPHER_MODE); > +} > + > +gcry_error_t > +_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) > +{ > + log_fatal ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); > + > + (void)outtag; > + (void)taglen; > + > + return gpg_error (GPG_ERR_INV_CIPHER_MODE); > +} > + > +gcry_error_t > +_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) > +{ > + log_fatal ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); > + > + (void)intag; > + (void)taglen; > + > + return gpg_error (GPG_ERR_INV_CIPHER_MODE); > +} > + > > gcry_error_t > gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) > diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi > index 473c484..0049fa0 100644 > --- a/doc/gcrypt.texi > +++ b/doc/gcrypt.texi > @@ -1731,6 +1731,10 @@ matches the requirement of the selected algorithm and mode. > This function is also used with the Salsa20 stream cipher to set or > update the required nonce. In this case it needs to be called after > setting the key. > + > +This function is also used with the AEAD cipher modes to set or > +update the required nonce. > + > @end deftypefun > > @deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, const void *@var{c}, size_t @var{l}) > @@ -1750,6 +1754,37 @@ call to gcry_cipher_setkey and clear the initialization vector. > Note that gcry_cipher_reset is implemented as a macro. > @end deftypefun > > +Authenticated Encryption with Associated Data (AEAD) block cipher > +modes require the handling of the authentication tag and the additional > +authenticated data, which can be done by using the following > +functions: > + > + at deftypefun gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t @var{h}, const void *@var{abuf}, size_t @var{abuflen}) > + > +Process the buffer @var{abuf} of length @var{abuflen} as the additional > +authenticated data (AAD) for AEAD cipher modes. > + > + at end deftypefun > + > + at deftypefun gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t @var{h}, void *@var{tag}, size_t @var{taglen}) > + > +This function is used to read the authentication tag after encryption. > +The function finalizes and outputs the authentication tag to the buffer > + at var{tag} of length @var{taglen} bytes. > + > + at end deftypefun > + > + at deftypefun gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t @var{h}, const void *@var{tag}, size_t @var{taglen}) > + > +Check the authentication tag after decryption. The authentication > +tag is passed as the buffer @var{tag} of length @var{taglen} bytes > +and compared to internal authentication tag computed during > +decryption. Error code @code{GPG_ERR_CHECKSUM} is returned if > +the authentication tag in the buffer @var{tag} does not match > +the authentication tag calculated during decryption. > + > + at end deftypefun > + > The actual encryption and decryption is done by using one of the > following functions. They may be used as often as required to process > all the data. > diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in > index 64cc0e4..f0ae927 100644 > --- a/src/gcrypt.h.in > +++ b/src/gcrypt.h.in > @@ -953,6 +953,17 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, > gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd, > const void *iv, size_t ivlen); > > +/* Provide additional authentication data for AEAD modes/ciphers. */ > +gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, > + size_t abuflen); > + > +/* Get authentication tag for AEAD modes/ciphers. */ > +gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, > + size_t taglen); > + > +/* Check authentication tag for AEAD modes/ciphers. */ > +gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, > + size_t taglen); > > /* Reset the handle to the state after open. */ > #define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0) > diff --git a/src/libgcrypt.def b/src/libgcrypt.def > index ec0c1e3..64ba370 100644 > --- a/src/libgcrypt.def > +++ b/src/libgcrypt.def > @@ -255,6 +255,9 @@ EXPORTS > > gcry_sexp_extract_param @225 > > + gcry_cipher_authenticate @226 > + gcry_cipher_gettag @227 > + gcry_cipher_checktag @228 > > > ;; end of file with public symbols for Windows. > diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers > index be72aad..93eaa93 100644 > --- a/src/libgcrypt.vers > +++ b/src/libgcrypt.vers > @@ -51,6 +51,7 @@ GCRYPT_1.6 { > gcry_cipher_info; gcry_cipher_map_name; > gcry_cipher_mode_from_oid; gcry_cipher_open; > gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr; > + gcry_cipher_authenticate; gcry_cipher_gettag; gcry_cipher_checktag; > > gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl; > gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey; > diff --git a/src/visibility.c b/src/visibility.c > index 848925e..1f7bb3a 100644 > --- a/src/visibility.c > +++ b/src/visibility.c > @@ -713,6 +713,33 @@ gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) > return _gcry_cipher_setctr (hd, ctr, ctrlen); > } > > +gcry_error_t > +gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) > +{ > + if (!fips_is_operational ()) > + return gpg_error (fips_not_operational ()); > + > + return _gcry_cipher_authenticate (hd, abuf, abuflen); > +} > + > +gcry_error_t > +gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) > +{ > + if (!fips_is_operational ()) > + return gpg_error (fips_not_operational ()); > + > + return _gcry_cipher_gettag (hd, outtag, taglen); > +} > + > +gcry_error_t > +gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) > +{ > + if (!fips_is_operational ()) > + return gpg_error (fips_not_operational ()); > + > + return _gcry_cipher_checktag (hd, intag, taglen); > +} > + > > gcry_error_t > gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) > diff --git a/src/visibility.h b/src/visibility.h > index 1c8f047..b2fa4c0 100644 > --- a/src/visibility.h > +++ b/src/visibility.h > @@ -81,6 +81,9 @@ > #define gcry_cipher_setkey _gcry_cipher_setkey > #define gcry_cipher_setiv _gcry_cipher_setiv > #define gcry_cipher_setctr _gcry_cipher_setctr > +#define gcry_cipher_authenticate _gcry_cipher_authenticate > +#define gcry_cipher_checktag _gcry_cipher_checktag > +#define gcry_cipher_gettag _gcry_cipher_gettag > #define gcry_cipher_ctl _gcry_cipher_ctl > #define gcry_cipher_decrypt _gcry_cipher_decrypt > #define gcry_cipher_encrypt _gcry_cipher_encrypt > @@ -297,6 +300,9 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, > #undef gcry_cipher_setkey > #undef gcry_cipher_setiv > #undef gcry_cipher_setctr > +#undef gcry_cipher_authenticate > +#undef gcry_cipher_checktag > +#undef gcry_cipher_gettag > #undef gcry_cipher_ctl > #undef gcry_cipher_decrypt > #undef gcry_cipher_encrypt > @@ -474,6 +480,9 @@ MARK_VISIBLE (gcry_cipher_close) > MARK_VISIBLE (gcry_cipher_setkey) > MARK_VISIBLE (gcry_cipher_setiv) > MARK_VISIBLE (gcry_cipher_setctr) > +MARK_VISIBLE (gcry_cipher_authenticate) > +MARK_VISIBLE (gcry_cipher_checktag) > +MARK_VISIBLE (gcry_cipher_gettag) > MARK_VISIBLE (gcry_cipher_ctl) > MARK_VISIBLE (gcry_cipher_decrypt) > MARK_VISIBLE (gcry_cipher_encrypt) > > > _______________________________________________ > Gcrypt-devel mailing list > Gcrypt-devel at gnupg.org > http://lists.gnupg.org/mailman/listinfo/gcrypt-devel > From wk at gnupg.org Tue Oct 22 16:31:13 2013 From: wk at gnupg.org (Werner Koch) Date: Tue, 22 Oct 2013 16:31:13 +0200 Subject: [PATCH 1/2] [v3] Add API to support AEAD cipher modes In-Reply-To: <52668263.9000101@iki.fi> (Jussi Kivilinna's message of "Tue, 22 Oct 2013 16:49:23 +0300") References: <20131022123202.6563.15226.stgit@localhost6.localdomain6> <52668263.9000101@iki.fi> Message-ID: <87fvrt8jim.fsf@vigenere.g10code.de> On Tue, 22 Oct 2013 15:49, jussi.kivilinna at iki.fi said: > Do these look ok to push? Yes; but see below. >> +gcry_error_t >> +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, >> + size_t abuflen) >> +{ >> + log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); >> + >> + (void)abuf; >> + (void)abuflen; >> + >> + return gpg_error (GPG_ERR_INV_CIPHER_MODE); Sure that you want log_fatal here? This calls abort and thus terminates the process. I think it is better to use log_error. Or do you fear that callers do not check the return code? Maybe we can add an error state to gcry_cipher_hd_t to let all further operation fail. Salam-Shalom, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz. From jussi.kivilinna at iki.fi Tue Oct 22 18:21:15 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Tue, 22 Oct 2013 19:21:15 +0300 Subject: [PATCH 1/2] [v3] Add API to support AEAD cipher modes In-Reply-To: <87fvrt8jim.fsf@vigenere.g10code.de> References: <20131022123202.6563.15226.stgit@localhost6.localdomain6> <52668263.9000101@iki.fi> <87fvrt8jim.fsf@vigenere.g10code.de> Message-ID: <5266A5FB.5000903@iki.fi> On 22.10.2013 17:31, Werner Koch wrote: > On Tue, 22 Oct 2013 15:49, jussi.kivilinna at iki.fi said: >> Do these look ok to push? > > Yes; but see below. > >>> +gcry_error_t >>> +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, >>> + size_t abuflen) >>> +{ >>> + log_fatal ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); >>> + >>> + (void)abuf; >>> + (void)abuflen; >>> + >>> + return gpg_error (GPG_ERR_INV_CIPHER_MODE); > > Sure that you want log_fatal here? This calls abort and thus > terminates the process. I think it is better to use log_error. Ok, I'll change to that. > Or do > you fear that callers do not check the return code? Maybe we can add an > error state to gcry_cipher_hd_t to let all further operation fail. I based patch on Dmitry's earlier patch, so I don't know if the use of log_fatal was intended. Maybe logging isn't needed here at all. Earlier use of log_fatal is in gcry_cipher_encrypt/decrypt, where its use probably makes sense. And log_error isn't used elsewhere in cipher.c. -Jussi > > > Salam-Shalom, > > Werner > From jussi.kivilinna at iki.fi Tue Oct 22 18:24:38 2013 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Tue, 22 Oct 2013 19:24:38 +0300 Subject: [PATCH] serpent-amd64: do not use GAS macros In-Reply-To: <877gd58ja9.fsf@vigenere.g10code.de> References: <20131020180142.19195.21145.stgit@localhost6.localdomain6> <877gd58ja9.fsf@vigenere.g10code.de> Message-ID: <5266A6C6.4070607@iki.fi> On 22.10.2013 17:36, Werner Koch wrote: > On Sun, 20 Oct 2013 20:01, jussi.kivilinna at iki.fi said: >> * cipher/serpent-avx2-amd64.S: Remove use of GAS macros. >> * cipher/serpent-sse2-amd64.S: Ditto. >> * configure.ac [HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS]: Do not check >> for GAS macros. > > Always feel free to push fixes for your own code. > Absolutely.. I just want to have some delay on largeish patches so I have some time to catch my own bugs. Such as the broken change for configure.ac in this patch; assembly implementations end up disabled with gcc, but enabled on clang. -Jussi > > Salam-Shalom, > > Werner > From cvs at cvs.gnupg.org Tue Oct 22 18:52:31 2013 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Tue, 22 Oct 2013 18:52:31 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-321-g335d9bf Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 335d9bf7b035815750b63a3a8334d6ce44dc4449 (commit) via 95654041f2aa62f71aac4d8614dafe8433d10f95 (commit) from a5a277a9016ccb34f1858a65e0ed1791b2fc3db3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 335d9bf7b035815750b63a3a8334d6ce44dc4449 Author: Jussi Kivilinna Date: Tue Oct 22 17:07:53 2013 +0300 Add Counter with CBC-MAC mode (CCM) * cipher/Makefile.am: Add 'cipher-ccm.c'. * cipher/cipher-ccm.c: New. * cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode'. (_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt) (_gcry_cipher_ccm_set_nonce, _gcry_cipher_ccm_authenticate) (_gcry_cipher_ccm_get_tag, _gcry_cipher_ccm_check_tag) (_gcry_cipher_ccm_set_lengths): New prototypes. * cipher/cipher.c (gcry_cipher_open, cipher_encrypt, cipher_decrypt) (_gcry_cipher_setiv, _gcry_cipher_authenticate, _gcry_cipher_gettag) (_gcry_cipher_checktag, gry_cipher_ctl): Add handling for CCM mode. * doc/gcrypt.texi: Add documentation for GCRY_CIPHER_MODE_CCM. * src/gcrypt.h.in (gcry_cipher_modes): Add 'GCRY_CIPHER_MODE_CCM'. (gcry_ctl_cmds): Add 'GCRYCTL_SET_CCM_LENGTHS'. (GCRY_CCM_BLOCK_LEN): New. * tests/basic.c (check_ccm_cipher): New. (check_cipher_modes): Call 'check_ccm_cipher'. * tests/benchmark.c (ccm_aead_init): New. (cipher_bench): Add handling for AEAD modes and add CCM benchmarking. -- Patch adds CCM (Counter with CBC-MAC) mode as defined in RFC 3610 and NIST Special Publication 800-38C. Example for encrypting message (split in two buffers; buf1, buf2) and authenticating additional non-encrypted data (split in two buffers; aadbuf1, aadbuf2) with authentication tag length of eigth bytes: size_t params[3]; taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1) + len(buf2); /* 0: enclen */ params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3); gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1)); gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2)); gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_encrypt(h, buf2, len(buf2), buf2, len(buf2)); gcry_cipher_gettag(h, tag, taglen); Example for decrypting above message and checking authentication tag: size_t params[3]; taglen = 8; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1) + len(buf2); /* 0: enclen */ params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3); gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1)); gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2)); gcry_cipher_decrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_decrypt(h, buf2, len(buf2), buf2, len(buf2)); err = gcry_cipher_checktag(h, tag, taglen); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) { /* Authentication failed. */ } else if (err == 0) { /* Authentication ok. */ } Example for encrypting message without additional authenticated data: size_t params[3]; taglen = 10; gcry_cipher_setkey(h, key, len(key)); gcry_cipher_setiv(h, nonce, len(nonce)); params[0] = len(buf1); /* 0: enclen */ params[1] = 0; /* 1: aadlen */ params[2] = taglen; /* 2: authtaglen */ gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3); gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1)); gcry_cipher_gettag(h, tag, taglen); To reset CCM state for cipher handle, one can either set new nonce or use 'gcry_cipher_reset'. This implementation reuses existing CTR mode code for encryption/decryption and is there for able to process multiple buffers that are not multiple of blocksize. AAD data maybe also be passed into gcry_cipher_authenticate in non-blocksize chunks. [v4]: GCRYCTL_SET_CCM_PARAMS => GCRY_SET_CCM_LENGTHS Signed-off-by: Jussi Kivilinna diff --git a/cipher/Makefile.am b/cipher/Makefile.am index a2b2c8a..b0efd89 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -40,6 +40,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES) libcipher_la_SOURCES = \ cipher.c cipher-internal.h \ cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \ +cipher-ccm.c \ cipher-selftest.c cipher-selftest.h \ pubkey.c pubkey-internal.h pubkey-util.c \ md.c \ diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c new file mode 100644 index 0000000..38752d5 --- /dev/null +++ b/cipher/cipher-ccm.c @@ -0,0 +1,370 @@ +/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static unsigned int +do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, + int do_padding) +{ + const unsigned int blocksize = 16; + unsigned char tmp[blocksize]; + unsigned int burn = 0; + unsigned int unused = c->u_mode.ccm.mac_unused; + size_t nblocks; + + if (inlen == 0 && (unused == 0 || !do_padding)) + return 0; + + do + { + if (inlen + unused < blocksize || unused > 0) + { + for (; inlen && unused < blocksize; inlen--) + c->u_mode.ccm.macbuf[unused++] = *inbuf++; + } + if (!inlen) + { + if (!do_padding) + break; + + while (unused < blocksize) + c->u_mode.ccm.macbuf[unused++] = 0; + } + + if (unused > 0) + { + /* Process one block from macbuf. */ + buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + unused = 0; + } + + if (c->bulk.cbc_enc) + { + nblocks = inlen / blocksize; + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1); + inbuf += nblocks * blocksize; + inlen -= nblocks * blocksize; + + wipememory (tmp, sizeof(tmp)); + } + else + { + while (inlen >= blocksize) + { + buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv, + c->u_iv.iv )); + + inlen -= blocksize; + inbuf += blocksize; + } + } + } + while (inlen > 0); + + c->u_mode.ccm.mac_unused = unused; + + if (burn) + burn += 4 * sizeof(void *); + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + size_t L = 15 - noncelen; + size_t L_; + + L_ = L - 1; + + if (!nonce) + return GPG_ERR_INV_ARG; + /* Length field must be 2, 3, ..., or 8. */ + if (L < 2 || L > 8) + return GPG_ERR_INV_LENGTH; + + /* Reset state */ + memset (&c->u_mode, 0, sizeof(c->u_mode)); + memset (&c->marks, 0, sizeof(c->marks)); + memset (&c->u_iv, 0, sizeof(c->u_iv)); + memset (&c->u_ctr, 0, sizeof(c->u_ctr)); + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + + /* Setup CTR */ + c->u_ctr.ctr[0] = L_; + memcpy (&c->u_ctr.ctr[1], nonce, noncelen); + memset (&c->u_ctr.ctr[1 + noncelen], 0, L); + + /* Setup IV */ + c->u_iv.iv[0] = L_; + memcpy (&c->u_iv.iv[1], nonce, noncelen); + /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later + in set_aad. */ + memset (&c->u_iv.iv[1 + noncelen], 0, L); + + c->u_mode.ccm.nonce = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, size_t encryptlen, + size_t aadlen, size_t taglen) +{ + unsigned int burn = 0; + unsigned char b0[16]; + size_t noncelen = 15 - (c->u_iv.iv[0] + 1); + size_t M = taglen; + size_t M_; + int i; + + M_ = (M - 2) / 2; + + /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */ + if ((M_ * 2 + 2) != M || M < 4 || M > 16) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.ccm.lengths) + return GPG_ERR_INV_STATE; + + c->u_mode.ccm.authlen = taglen; + c->u_mode.ccm.encryptlen = encryptlen; + c->u_mode.ccm.aadlen = aadlen; + + /* Complete IV setup. */ + c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8; + for (i = 16 - 1; i >= 1 + noncelen; i--) + { + c->u_iv.iv[i] = encryptlen & 0xff; + encryptlen >>= 8; + } + + memcpy (b0, c->u_iv.iv, 16); + memset (c->u_iv.iv, 0, 16); + + set_burn (burn, do_cbc_mac (c, b0, 16, 0)); + + if (aadlen == 0) + { + /* Do nothing. */ + } + else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff) + { + b0[0] = (aadlen >> 8) & 0xff; + b0[1] = aadlen & 0xff; + set_burn (burn, do_cbc_mac (c, b0, 2, 0)); + } + else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xfe; + buf_put_be32(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 6, 0)); + } +#ifdef HAVE_U64_TYPEDEF + else if (aadlen > (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xff; + buf_put_be64(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 10, 0)); + } +#endif + + /* Generate S_0 and increase counter. */ + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0, + c->u_ctr.ctr )); + c->u_ctr.ctr[15]++; + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->u_mode.ccm.lengths = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, + size_t abuflen) +{ + unsigned int burn; + + if (abuflen > 0 && !abuf) + return GPG_ERR_INV_ARG; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.tag) + return GPG_ERR_INV_STATE; + if (abuflen > c->u_mode.ccm.aadlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.aadlen -= abuflen; + burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, int check) +{ + unsigned int burn; + + if (!outbuf || outbuflen == 0) + return GPG_ERR_INV_ARG; + /* Tag length must be same as initial authlen. */ + if (c->u_mode.ccm.authlen != outbuflen) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + /* Initial encrypt length must match with length of actual data processed. */ + if (c->u_mode.ccm.encryptlen > 0) + return GPG_ERR_UNFINISHED; + + if (!c->u_mode.ccm.tag) + { + burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ + + /* Add S_0 */ + buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + + wipememory (c->u_ctr.ctr, 16); + wipememory (c->u_mode.ccm.s0, 16); + wipememory (c->u_mode.ccm.macbuf, 16); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + int diff, i; + + /* Constant-time compare. */ + for (i = 0, diff = 0; i < outbuflen; i++) + diff -= !!(outbuf[i] - c->u_iv.iv[i]); + + return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); +} + + +gcry_err_code_t +_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, inbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +} + + +gcry_err_code_t +_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + unsigned int outbuflen, const unsigned char *inbuf, + unsigned int inbuflen) +{ + gcry_err_code_t err; + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + if (err) + return err; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, outbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return err; +} diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index b60ef38..981caa8 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -100,7 +100,8 @@ struct gcry_cipher_handle /* The initialization vector. For best performance we make sure that it is properly aligned. In particular some implementations - of bulk operations expect an 16 byte aligned IV. */ + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */ union { cipher_context_alignment_t iv_align; unsigned char iv[MAX_BLOCKSIZE]; @@ -117,6 +118,26 @@ struct gcry_cipher_handle unsigned char lastiv[MAX_BLOCKSIZE]; int unused; /* Number of unused bytes in LASTIV. */ + union { + /* Mode specific storage for CCM mode. */ + struct { + size_t encryptlen; + size_t aadlen; + unsigned int authlen; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int nonce:1;/* Set to 1 if nonce has been set. */ + unsigned int lengths:1; /* Set to 1 if CCM length parameters has been + processed. */ + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ + } ccm; + } u_mode; + /* What follows are two contexts of the cipher in use. The first one needs to be aligned well enough for the cipher operation whereas the second one is a copy created by cipher_setkey and @@ -175,5 +196,30 @@ gcry_err_code_t _gcry_cipher_aeswrap_decrypt const byte *inbuf, unsigned int inbuflen); +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ccm_authenticate +/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen); +gcry_err_code_t _gcry_cipher_ccm_set_lengths +/* */ (gcry_cipher_hd_t c, size_t encryptedlen, size_t aadlen, + size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); + + #endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/cipher/cipher.c b/cipher/cipher.c index d6d3021..5214d26 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -375,6 +375,13 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, if (! err) switch (mode) { + case GCRY_CIPHER_MODE_CCM: + if (spec->blocksize != GCRY_CCM_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: @@ -613,6 +620,8 @@ cipher_reset (gcry_cipher_hd_t c) memset (c->u_iv.iv, 0, c->spec->blocksize); memset (c->lastiv, 0, c->spec->blocksize); memset (c->u_ctr.ctr, 0, c->spec->blocksize); + memset (&c->u_mode, 0, sizeof c->u_mode); + c->unused = 0; } @@ -718,6 +727,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stencrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -811,6 +824,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, inbuf, inbuflen); break; + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_STREAM: c->spec->stdecrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf, inbuflen); @@ -885,8 +902,19 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) gcry_error_t _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) { - cipher_setiv (hd, iv, ivlen); - return 0; + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen); + break; + + default: + cipher_setiv (hd, iv, ivlen); + break; + } + return gpg_error (rc); } /* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of @@ -914,34 +942,61 @@ gcry_error_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) { - log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_authenticate (hd, abuf, abuflen); + break; - (void)abuf; - (void)abuflen; + default: + log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) { - log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen); + break; - (void)outtag; - (void)taglen; + default: + log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } gcry_error_t _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) { - log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen); + break; - (void)intag; - (void)taglen; + default: + log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } - return gpg_error (GPG_ERR_INV_CIPHER_MODE); + return gpg_error (rc); } @@ -980,6 +1035,30 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) h->flags &= ~GCRY_CIPHER_CBC_MAC; break; + case GCRYCTL_SET_CCM_LENGTHS: + { + size_t params[3]; + size_t encryptedlen; + size_t aadlen; + size_t authtaglen; + + if (h->mode != GCRY_CIPHER_MODE_CCM) + return gcry_error (GPG_ERR_INV_CIPHER_MODE); + + if (!buffer || buflen != 3 * sizeof(size_t)) + return gcry_error (GPG_ERR_INV_ARG); + + /* This command is used to pass additional length parameters needed + by CCM mode to initialize CBC-MAC. */ + memcpy (params, buffer, sizeof(params)); + encryptedlen = params[0]; + aadlen = params[1]; + authtaglen = params[2]; + + rc = _gcry_cipher_ccm_set_lengths (h, encryptedlen, aadlen, authtaglen); + } + break; + case GCRYCTL_DISABLE_ALGO: /* This command expects NULL for H and BUFFER to point to an integer with the algo number. */ diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 0049fa0..91fe399 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1635,6 +1635,12 @@ may be specified 64 bit (8 byte) shorter than then input buffer. As per specs the input length must be at least 128 bits and the length must be a multiple of 64 bits. + at item GCRY_CIPHER_MODE_CCM + at cindex CCM, Counter with CBC-MAC mode +Counter with CBC-MAC mode is an Authenticated Encryption with +Associated Data (AEAD) block cipher mode, which is specified in +'NIST Special Publication 800-38C' and RFC 3610. + @end table @node Working with cipher handles @@ -1661,11 +1667,13 @@ The cipher mode to use must be specified via @var{mode}. See @xref{Available cipher modes}, for a list of supported cipher modes and the according constants. Note that some modes are incompatible with some algorithms - in particular, stream mode -(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. Any -block cipher mode (@code{GCRY_CIPHER_MODE_ECB}, +(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. The +block cipher modes (@code{GCRY_CIPHER_MODE_ECB}, @code{GCRY_CIPHER_MODE_CBC}, @code{GCRY_CIPHER_MODE_CFB}, - at code{GCRY_CIPHER_MODE_OFB} or @code{GCRY_CIPHER_MODE_CTR}) will work -with any block cipher algorithm. + at code{GCRY_CIPHER_MODE_OFB} and @code{GCRY_CIPHER_MODE_CTR}) will work +with any block cipher algorithm. The @code{GCRY_CIPHER_MODE_CCM} will +only work with block cipher algorithms which have the block size of +16 bytes. The third argument @var{flags} can either be passed as @code{0} or as the bit-wise OR of the following constants. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index f0ae927..948202d 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -325,7 +325,8 @@ enum gcry_ctl_cmds GCRYCTL_SET_PREFERRED_RNG_TYPE = 65, GCRYCTL_GET_CURRENT_RNG_TYPE = 66, GCRYCTL_DISABLE_LOCKED_SECMEM = 67, - GCRYCTL_DISABLE_PRIV_DROP = 68 + GCRYCTL_DISABLE_PRIV_DROP = 68, + GCRYCTL_SET_CCM_LENGTHS = 69 }; /* Perform various operations defined by CMD. */ @@ -884,7 +885,8 @@ enum gcry_cipher_modes GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ GCRY_CIPHER_MODE_CTR = 6, /* Counter. */ - GCRY_CIPHER_MODE_AESWRAP= 7 /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_AESWRAP= 7, /* AES-WRAP algorithm. */ + GCRY_CIPHER_MODE_CCM = 8 /* Counter with CBC-MAC. */ }; /* Flags used with the open function. */ @@ -896,6 +898,8 @@ enum gcry_cipher_flags GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */ }; +/* CCM works only with blocks of 128 bits. */ +#define GCRY_CCM_BLOCK_LEN (128 / 8) /* Create a handle for algorithm ALGO to be used in MODE. FLAGS may be given as an bitwise OR of the gcry_cipher_flags values. */ diff --git a/tests/basic.c b/tests/basic.c index 1d6e637..21af21d 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -1139,6 +1139,776 @@ check_ofb_cipher (void) static void +check_ccm_cipher (void) +{ + static const struct tv + { + int algo; + int keylen; + const char *key; + int noncelen; + const char *nonce; + int aadlen; + const char *aad; + int plainlen; + const char *plaintext; + int cipherlen; + const char *ciphertext; + } tv[] = + { + /* RFC 3610 */ + { GCRY_CIPHER_AES, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\x58\x8C\x97\x9A\x61\xC6\x63\xD2\xF0\x66\xD0\xC2\xC0\xF9\x89\x80\x6D\x5F\x6B\x61\xDA\xC3\x84\x17\xE8\xD1\x2C\xFD\xF9\x26\xE0"}, + { GCRY_CIPHER_AES, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x72\xC9\x1A\x36\xE1\x35\xF8\xCF\x29\x1C\xA8\x94\x08\x5C\x87\xE3\xCC\x15\xC4\x39\xC9\xE4\x3A\x3B\xA0\x91\xD5\x6E\x10\x40\x09\x16"}, + { GCRY_CIPHER_AES, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x51\xB1\xE5\xF4\x4A\x19\x7D\x1D\xA4\x6B\x0F\x8E\x2D\x28\x2A\xE8\x71\xE8\x38\xBB\x64\xDA\x85\x96\x57\x4A\xDA\xA7\x6F\xBD\x9F\xB0\xC5"}, + { GCRY_CIPHER_AES, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xA2\x8C\x68\x65\x93\x9A\x9A\x79\xFA\xAA\x5C\x4C\x2A\x9D\x4A\x91\xCD\xAC\x8C\x96\xC8\x61\xB9\xC9\xE6\x1E\xF1"}, + { GCRY_CIPHER_AES, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\xDC\xF1\xFB\x7B\x5D\x9E\x23\xFB\x9D\x4E\x13\x12\x53\x65\x8A\xD8\x6E\xBD\xCA\x3E\x51\xE8\x3F\x07\x7D\x9C\x2D\x93"}, + { GCRY_CIPHER_AES, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\x6F\xC1\xB0\x11\xF0\x06\x56\x8B\x51\x71\xA4\x2D\x95\x3D\x46\x9B\x25\x70\xA4\xBD\x87\x40\x5A\x04\x43\xAC\x91\xCB\x94"}, + { GCRY_CIPHER_AES, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x01\x35\xD1\xB2\xC9\x5F\x41\xD5\xD1\xD4\xFE\xC1\x85\xD1\x66\xB8\x09\x4E\x99\x9D\xFE\xD9\x6C\x04\x8C\x56\x60\x2C\x97\xAC\xBB\x74\x90"}, + { GCRY_CIPHER_AES, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x7B\x75\x39\x9A\xC0\x83\x1D\xD2\xF0\xBB\xD7\x58\x79\xA2\xFD\x8F\x6C\xAE\x6B\x6C\xD9\xB7\xDB\x24\xC1\x7B\x44\x33\xF4\x34\x96\x3F\x34\xB4"}, + { GCRY_CIPHER_AES, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x82\x53\x1A\x60\xCC\x24\x94\x5A\x4B\x82\x79\x18\x1A\xB5\xC8\x4D\xF2\x1C\xE7\xF9\xB7\x3F\x42\xE1\x97\xEA\x9C\x07\xE5\x6B\x5E\xB1\x7E\x5F\x4E"}, + { GCRY_CIPHER_AES, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\x07\x34\x25\x94\x15\x77\x85\x15\x2B\x07\x40\x98\x33\x0A\xBB\x14\x1B\x94\x7B\x56\x6A\xA9\x40\x6B\x4D\x99\x99\x88\xDD"}, + { GCRY_CIPHER_AES, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x67\x6B\xB2\x03\x80\xB0\xE3\x01\xE8\xAB\x79\x59\x0A\x39\x6D\xA7\x8B\x83\x49\x34\xF5\x3A\xA2\xE9\x10\x7A\x8B\x6C\x02\x2C"}, + { GCRY_CIPHER_AES, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\xC0\xFF\xA0\xD6\xF0\x5B\xDB\x67\xF2\x4D\x43\xA4\x33\x8D\x2A\xA4\xBE\xD7\xB2\x0E\x43\xCD\x1A\xA3\x16\x62\xE7\xAD\x65\xD6\xDB"}, + { GCRY_CIPHER_AES, /* Packet Vector #13 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x41\x2B\x4E\xA9\xCD\xBE\x3C\x96\x96\x76\x6C\xFA", + 8, "\x0B\xE1\xA8\x8B\xAC\xE0\x18\xB1", + 23, + "\x08\xE8\xCF\x97\xD8\x20\xEA\x25\x84\x60\xE9\x6A\xD9\xCF\x52\x89\x05\x4D\x89\x5C\xEA\xC4\x7C", + 31, + "\x4C\xB9\x7F\x86\xA2\xA4\x68\x9A\x87\x79\x47\xAB\x80\x91\xEF\x53\x86\xA6\xFF\xBD\xD0\x80\xF8\xE7\x8C\xF7\xCB\x0C\xDD\xD7\xB3"}, + { GCRY_CIPHER_AES, /* Packet Vector #14 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x33\x56\x8E\xF7\xB2\x63\x3C\x96\x96\x76\x6C\xFA", + 8, "\x63\x01\x8F\x76\xDC\x8A\x1B\xCB", + 24, + "\x90\x20\xEA\x6F\x91\xBD\xD8\x5A\xFA\x00\x39\xBA\x4B\xAF\xF9\xBF\xB7\x9C\x70\x28\x94\x9C\xD0\xEC", + 32, + "\x4C\xCB\x1E\x7C\xA9\x81\xBE\xFA\xA0\x72\x6C\x55\xD3\x78\x06\x12\x98\xC8\x5C\x92\x81\x4A\xBC\x33\xC5\x2E\xE8\x1D\x7D\x77\xC0\x8A"}, + { GCRY_CIPHER_AES, /* Packet Vector #15 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x10\x3F\xE4\x13\x36\x71\x3C\x96\x96\x76\x6C\xFA", + 8, "\xAA\x6C\xFA\x36\xCA\xE8\x6B\x40", + 25, + "\xB9\x16\xE0\xEA\xCC\x1C\x00\xD7\xDC\xEC\x68\xEC\x0B\x3B\xBB\x1A\x02\xDE\x8A\x2D\x1A\xA3\x46\x13\x2E", + 33, + "\xB1\xD2\x3A\x22\x20\xDD\xC0\xAC\x90\x0D\x9A\xA0\x3C\x61\xFC\xF4\xA5\x59\xA4\x41\x77\x67\x08\x97\x08\xA7\x76\x79\x6E\xDB\x72\x35\x06"}, + { GCRY_CIPHER_AES, /* Packet Vector #16 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x76\x4C\x63\xB8\x05\x8E\x3C\x96\x96\x76\x6C\xFA", + 12, "\xD0\xD0\x73\x5C\x53\x1E\x1B\xEC\xF0\x49\xC2\x44", + 19, + "\x12\xDA\xAC\x56\x30\xEF\xA5\x39\x6F\x77\x0C\xE1\xA6\x6B\x21\xF7\xB2\x10\x1C", + 27, + "\x14\xD2\x53\xC3\x96\x7B\x70\x60\x9B\x7C\xBB\x7C\x49\x91\x60\x28\x32\x45\x26\x9A\x6F\x49\x97\x5B\xCA\xDE\xAF"}, + { GCRY_CIPHER_AES, /* Packet Vector #17 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xF8\xB6\x78\x09\x4E\x3B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x77\xB6\x0F\x01\x1C\x03\xE1\x52\x58\x99\xBC\xAE", + 20, + "\xE8\x8B\x6A\x46\xC7\x8D\x63\xE5\x2E\xB8\xC5\x46\xEF\xB5\xDE\x6F\x75\xE9\xCC\x0D", + 28, + "\x55\x45\xFF\x1A\x08\x5E\xE2\xEF\xBF\x52\xB2\xE0\x4B\xEE\x1E\x23\x36\xC7\x3E\x3F\x76\x2C\x0C\x77\x44\xFE\x7E\x3C"}, + { GCRY_CIPHER_AES, /* Packet Vector #18 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\xD5\x60\x91\x2D\x3F\x70\x3C\x96\x96\x76\x6C\xFA", + 12, "\xCD\x90\x44\xD2\xB7\x1F\xDB\x81\x20\xEA\x60\xC0", + 21, + "\x64\x35\xAC\xBA\xFB\x11\xA8\x2E\x2F\x07\x1D\x7C\xA4\xA5\xEB\xD9\x3A\x80\x3B\xA8\x7F", + 29, + "\x00\x97\x69\xEC\xAB\xDF\x48\x62\x55\x94\xC5\x92\x51\xE6\x03\x57\x22\x67\x5E\x04\xC8\x47\x09\x9E\x5A\xE0\x70\x45\x51"}, + { GCRY_CIPHER_AES, /* Packet Vector #19 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x42\xFF\xF8\xF1\x95\x1C\x3C\x96\x96\x76\x6C\xFA", + 8, "\xD8\x5B\xC7\xE6\x9F\x94\x4F\xB8", + 23, + "\x8A\x19\xB9\x50\xBC\xF7\x1A\x01\x8E\x5E\x67\x01\xC9\x17\x87\x65\x98\x09\xD6\x7D\xBE\xDD\x18", + 33, + "\xBC\x21\x8D\xAA\x94\x74\x27\xB6\xDB\x38\x6A\x99\xAC\x1A\xEF\x23\xAD\xE0\xB5\x29\x39\xCB\x6A\x63\x7C\xF9\xBE\xC2\x40\x88\x97\xC6\xBA"}, + { GCRY_CIPHER_AES, /* Packet Vector #20 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x92\x0F\x40\xE5\x6C\xDC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x74\xA0\xEB\xC9\x06\x9F\x5B\x37", + 24, + "\x17\x61\x43\x3C\x37\xC5\xA3\x5F\xC1\xF3\x9F\x40\x63\x02\xEB\x90\x7C\x61\x63\xBE\x38\xC9\x84\x37", + 34, + "\x58\x10\xE6\xFD\x25\x87\x40\x22\xE8\x03\x61\xA4\x78\xE3\xE9\xCF\x48\x4A\xB0\x4F\x44\x7E\xFF\xF6\xF0\xA4\x77\xCC\x2F\xC9\xBF\x54\x89\x44"}, + { GCRY_CIPHER_AES, /* Packet Vector #21 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x27\xCA\x0C\x71\x20\xBC\x3C\x96\x96\x76\x6C\xFA", + 8, "\x44\xA3\xAA\x3A\xAE\x64\x75\xCA", + 25, + "\xA4\x34\xA8\xE5\x85\x00\xC6\xE4\x15\x30\x53\x88\x62\xD6\x86\xEA\x9E\x81\x30\x1B\x5A\xE4\x22\x6B\xFA", + 35, + "\xF2\xBE\xED\x7B\xC5\x09\x8E\x83\xFE\xB5\xB3\x16\x08\xF8\xE2\x9C\x38\x81\x9A\x89\xC8\xE7\x76\xF1\x54\x4D\x41\x51\xA4\xED\x3A\x8B\x87\xB9\xCE"}, + { GCRY_CIPHER_AES, /* Packet Vector #22 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x5B\x8C\xCB\xCD\x9A\xF8\x3C\x96\x96\x76\x6C\xFA", + 12, "\xEC\x46\xBB\x63\xB0\x25\x20\xC3\x3C\x49\xFD\x70", + 19, + "\xB9\x6B\x49\xE2\x1D\x62\x17\x41\x63\x28\x75\xDB\x7F\x6C\x92\x43\xD2\xD7\xC2", + 29, + "\x31\xD7\x50\xA0\x9D\xA3\xED\x7F\xDD\xD4\x9A\x20\x32\xAA\xBF\x17\xEC\x8E\xBF\x7D\x22\xC8\x08\x8C\x66\x6B\xE5\xC1\x97"}, + { GCRY_CIPHER_AES, /* Packet Vector #23 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x3E\xBE\x94\x04\x4B\x9A\x3C\x96\x96\x76\x6C\xFA", + 12, "\x47\xA6\x5A\xC7\x8B\x3D\x59\x42\x27\xE8\x5E\x71", + 20, + "\xE2\xFC\xFB\xB8\x80\x44\x2C\x73\x1B\xF9\x51\x67\xC8\xFF\xD7\x89\x5E\x33\x70\x76", + 30, + "\xE8\x82\xF1\xDB\xD3\x8C\xE3\xED\xA7\xC2\x3F\x04\xDD\x65\x07\x1E\xB4\x13\x42\xAC\xDF\x7E\x00\xDC\xCE\xC7\xAE\x52\x98\x7D"}, + { GCRY_CIPHER_AES, /* Packet Vector #24 */ + 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B", + 13, "\x00\x8D\x49\x3B\x30\xAE\x8B\x3C\x96\x96\x76\x6C\xFA", + 12, "\x6E\x37\xA6\xEF\x54\x6D\x95\x5D\x34\xAB\x60\x59", + 21, + "\xAB\xF2\x1C\x0B\x02\xFE\xB8\x8F\x85\x6D\xF4\xA3\x73\x81\xBC\xE3\xCC\x12\x85\x17\xD4", + 31, + "\xF3\x29\x05\xB8\x8A\x64\x1B\x04\xB9\xC9\xFF\xB5\x8C\xC3\x90\x90\x0F\x3D\xA1\x2A\xB1\x6D\xCE\x9E\x82\xEF\xA1\x6D\xA6\x20\x59"}, + /* RFC 5528 */ + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #1 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 31, + "\xBA\x73\x71\x85\xE7\x19\x31\x04\x92\xF3\x8A\x5F\x12\x51\xDA\x55\xFA\xFB\xC9\x49\x84\x8A\x0D\xFC\xAE\xCE\x74\x6B\x3D\xB9\xAD"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #2 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 32, + "\x5D\x25\x64\xBF\x8E\xAF\xE1\xD9\x95\x26\xEC\x01\x6D\x1B\xF0\x42\x4C\xFB\xD2\xCD\x62\x84\x8F\x33\x60\xB2\x29\x5D\xF2\x42\x83\xE8"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #3 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 33, + "\x81\xF6\x63\xD6\xC7\x78\x78\x17\xF9\x20\x36\x08\xB9\x82\xAD\x15\xDC\x2B\xBD\x87\xD7\x56\xF7\x92\x04\xF5\x51\xD6\x68\x2F\x23\xAA\x46"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #4 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 27, + "\xCA\xEF\x1E\x82\x72\x11\xB0\x8F\x7B\xD9\x0F\x08\xC7\x72\x88\xC0\x70\xA4\xA0\x8B\x3A\x93\x3A\x63\xE4\x97\xA0"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #5 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 28, + "\x2A\xD3\xBA\xD9\x4F\xC5\x2E\x92\xBE\x43\x8E\x82\x7C\x10\x23\xB9\x6A\x8A\x77\x25\x8F\xA1\x7B\xA7\xF3\x31\xDB\x09"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #6 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 29, + "\xFE\xA5\x48\x0B\xA5\x3F\xA8\xD3\xC3\x44\x22\xAA\xCE\x4D\xE6\x7F\xFA\x3B\xB7\x3B\xAB\xAB\x36\xA1\xEE\x4F\xE0\xFE\x28"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #7 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 23, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 33, + "\x54\x53\x20\x26\xE5\x4C\x11\x9A\x8D\x36\xD9\xEC\x6E\x1E\xD9\x74\x16\xC8\x70\x8C\x4B\x5C\x2C\xAC\xAF\xA3\xBC\xCF\x7A\x4E\xBF\x95\x73"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #8 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 24, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 34, + "\x8A\xD1\x9B\x00\x1A\x87\xD1\x48\xF4\xD9\x2B\xEF\x34\x52\x5C\xCC\xE3\xA6\x3C\x65\x12\xA6\xF5\x75\x73\x88\xE4\x91\x3E\xF1\x47\x01\xF4\x41"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #9 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5", + 8, "\x00\x01\x02\x03\x04\x05\x06\x07", + 25, + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 35, + "\x5D\xB0\x8D\x62\x40\x7E\x6E\x31\xD6\x0F\x9C\xA2\xC6\x04\x74\x21\x9A\xC0\xBE\x50\xC0\xD4\xA5\x77\x87\x94\xD6\xE2\x30\xCD\x25\xC9\xFE\xBF\x87"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #10 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 19, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E", + 29, + "\xDB\x11\x8C\xCE\xC1\xB8\x76\x1C\x87\x7C\xD8\x96\x3A\x67\xD6\xF3\xBB\xBC\x5C\xD0\x92\x99\xEB\x11\xF3\x12\xF2\x32\x37"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #11 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 20, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", + 30, + "\x7C\xC8\x3D\x8D\xC4\x91\x03\x52\x5B\x48\x3D\xC5\xCA\x7E\xA9\xAB\x81\x2B\x70\x56\x07\x9D\xAF\xFA\xDA\x16\xCC\xCF\x2C\x4E"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #12 */ + 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", + 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5", + 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B", + 21, + "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", + 31, + "\x2C\xD3\x5B\x88\x20\xD2\x3E\x7A\xA3\x51\xB0\xE9\x2F\xC7\x93\x67\x23\x8B\x2C\xC7\x48\xCB\xB9\x4C\x29\x47\x79\x3D\x64\xAF\x75"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #13 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xA9\x70\x11\x0E\x19\x27\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x6B\x7F\x46\x45\x07\xFA\xE4\x96", + 23, + "\xC6\xB5\xF3\xE6\xCA\x23\x11\xAE\xF7\x47\x2B\x20\x3E\x73\x5E\xA5\x61\xAD\xB1\x7D\x56\xC5\xA3", + 31, + "\xA4\x35\xD7\x27\x34\x8D\xDD\x22\x90\x7F\x7E\xB8\xF5\xFD\xBB\x4D\x93\x9D\xA6\x52\x4D\xB4\xF6\x45\x58\xC0\x2D\x25\xB1\x27\xEE"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #14 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x83\xCD\x8C\xE0\xCB\x42\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x98\x66\x05\xB4\x3D\xF1\x5D\xE7", + 24, + "\x01\xF6\xCE\x67\x64\xC5\x74\x48\x3B\xB0\x2E\x6B\xBF\x1E\x0A\xBD\x26\xA2\x25\x72\xB4\xD8\x0E\xE7", + 32, + "\x8A\xE0\x52\x50\x8F\xBE\xCA\x93\x2E\x34\x6F\x05\xE0\xDC\x0D\xFB\xCF\x93\x9E\xAF\xFA\x3E\x58\x7C\x86\x7D\x6E\x1C\x48\x70\x38\x06"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #15 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x5F\x54\x95\x0B\x18\xF2\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x48\xF2\xE7\xE1\xA7\x67\x1A\x51", + 25, + "\xCD\xF1\xD8\x40\x6F\xC2\xE9\x01\x49\x53\x89\x70\x05\xFB\xFB\x8B\xA5\x72\x76\xF9\x24\x04\x60\x8E\x08", + 33, + "\x08\xB6\x7E\xE2\x1C\x8B\xF2\x6E\x47\x3E\x40\x85\x99\xE9\xC0\x83\x6D\x6A\xF0\xBB\x18\xDF\x55\x46\x6C\xA8\x08\x78\xA7\x90\x47\x6D\xE5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #16 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xEC\x60\x08\x63\x31\x9A\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xDE\x97\xDF\x3B\x8C\xBD\x6D\x8E\x50\x30\xDA\x4C", + 19, + "\xB0\x05\xDC\xFA\x0B\x59\x18\x14\x26\xA9\x61\x68\x5A\x99\x3D\x8C\x43\x18\x5B", + 27, + "\x63\xB7\x8B\x49\x67\xB1\x9E\xDB\xB7\x33\xCD\x11\x14\xF6\x4E\xB2\x26\x08\x93\x68\xC3\x54\x82\x8D\x95\x0C\xC5"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #17 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x60\xCF\xF1\xA3\x1E\xA1\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA5\xEE\x93\xE4\x57\xDF\x05\x46\x6E\x78\x2D\xCF", + 20, + "\x2E\x20\x21\x12\x98\x10\x5F\x12\x9D\x5E\xD9\x5B\x93\xF7\x2D\x30\xB2\xFA\xCC\xD7", + 28, + "\x0B\xC6\xBB\xE2\xA8\xB9\x09\xF4\x62\x9E\xE6\xDC\x14\x8D\xA4\x44\x10\xE1\x8A\xF4\x31\x47\x38\x32\x76\xF6\x6A\x9F"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #18 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x0F\x85\xCD\x99\x5C\x97\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x24\xAA\x1B\xF9\xA5\xCD\x87\x61\x82\xA2\x50\x74", + 21, + "\x26\x45\x94\x1E\x75\x63\x2D\x34\x91\xAF\x0F\xC0\xC9\x87\x6C\x3B\xE4\xAA\x74\x68\xC9", + 29, + "\x22\x2A\xD6\x32\xFA\x31\xD6\xAF\x97\x0C\x34\x5F\x7E\x77\xCA\x3B\xD0\xDC\x25\xB3\x40\xA1\xA3\xD3\x1F\x8D\x4B\x44\xB7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #19 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC2\x9B\x2C\xAA\xC4\xCD\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\x69\x19\x46\xB9\xCA\x07\xBE\x87", + 23, + "\x07\x01\x35\xA6\x43\x7C\x9D\xB1\x20\xCD\x61\xD8\xF6\xC3\x9C\x3E\xA1\x25\xFD\x95\xA0\xD2\x3D", + 33, + "\x05\xB8\xE1\xB9\xC4\x9C\xFD\x56\xCF\x13\x0A\xA6\x25\x1D\xC2\xEC\xC0\x6C\xCC\x50\x8F\xE6\x97\xA0\x06\x6D\x57\xC8\x4B\xEC\x18\x27\x68"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #20 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x2C\x6B\x75\x95\xEE\x62\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xD0\xC5\x4E\xCB\x84\x62\x7D\xC4", + 24, + "\xC8\xC0\x88\x0E\x6C\x63\x6E\x20\x09\x3D\xD6\x59\x42\x17\xD2\xE1\x88\x77\xDB\x26\x4E\x71\xA5\xCC", + 34, + "\x54\xCE\xB9\x68\xDE\xE2\x36\x11\x57\x5E\xC0\x03\xDF\xAA\x1C\xD4\x88\x49\xBD\xF5\xAE\x2E\xDB\x6B\x7F\xA7\x75\xB1\x50\xED\x43\x83\xC5\xA9"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #21 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xC5\x3C\xD4\xC2\xAA\x24\xB1\x60\xB6\xA3\x1C\x1C", + 8, "\xE2\x85\xE0\xE4\x80\x8C\xDA\x3D", + 25, + "\xF7\x5D\xAA\x07\x10\xC4\xE6\x42\x97\x79\x4D\xC2\xB7\xD2\xA2\x07\x57\xB1\xAA\x4E\x44\x80\x02\xFF\xAB", + 35, + "\xB1\x40\x45\x46\xBF\x66\x72\x10\xCA\x28\xE3\x09\xB3\x9B\xD6\xCA\x7E\x9F\xC8\x28\x5F\xE6\x98\xD4\x3C\xD2\x0A\x02\xE0\xBD\xCA\xED\x20\x10\xD3"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #22 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xBE\xE9\x26\x7F\xBA\xDC\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x6C\xAE\xF9\x94\x11\x41\x57\x0D\x7C\x81\x34\x05", + 19, + "\xC2\x38\x82\x2F\xAC\x5F\x98\xFF\x92\x94\x05\xB0\xAD\x12\x7A\x4E\x41\x85\x4E", + 29, + "\x94\xC8\x95\x9C\x11\x56\x9A\x29\x78\x31\xA7\x21\x00\x58\x57\xAB\x61\xB8\x7A\x2D\xEA\x09\x36\xB6\xEB\x5F\x62\x5F\x5D"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #23 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\xDF\xA8\xB1\x24\x50\x07\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\x36\xA5\x2C\xF1\x6B\x19\xA2\x03\x7A\xB7\x01\x1E", + 20, + "\x4D\xBF\x3E\x77\x4A\xD2\x45\xE5\xD5\x89\x1F\x9D\x1C\x32\xA0\xAE\x02\x2C\x85\xD7", + 30, + "\x58\x69\xE3\xAA\xD2\x44\x7C\x74\xE0\xFC\x05\xF9\xA4\xEA\x74\x57\x7F\x4D\xE8\xCA\x89\x24\x76\x42\x96\xAD\x04\x11\x9C\xE7"}, + { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #24 */ + 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD", + 13, "\x00\x3B\x8F\xD8\xD3\xA9\x37\xB1\x60\xB6\xA3\x1C\x1C", + 12, "\xA4\xD4\x99\xF7\x84\x19\x72\x8C\x19\x17\x8B\x0C", + 21, + "\x9D\xC9\xED\xAE\x2F\xF5\xDF\x86\x36\xE8\xC6\xDE\x0E\xED\x55\xF7\x86\x7E\x33\x33\x7D", + 31, + "\x4B\x19\x81\x56\x39\x3B\x0F\x77\x96\x08\x6A\xAF\xB4\x54\xF8\xC3\xF0\x34\xCC\xA9\x66\x94\x5F\x1F\xCE\xA7\xE1\x1B\xEE\x6A\x2F"} + }; + static const int cut[] = { 0, 1, 8, 10, 16, 19, -1 }; + gcry_cipher_hd_t hde, hdd; + unsigned char out[MAX_DATA_LEN]; + size_t ctl_params[3]; + int split, aadsplit; + size_t j, i, keylen, blklen, authlen; + gcry_error_t err = 0; + + if (verbose) + fprintf (stderr, " Starting CCM checks.\n"); + + for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) + { + if (verbose) + fprintf (stderr, " checking CCM mode for %s [%i]\n", + gcry_cipher_algo_name (tv[i].algo), + tv[i].algo); + + for (j = 0; j < sizeof (cut) / sizeof (cut[0]); j++) + { + split = cut[j] < 0 ? tv[i].plainlen : cut[j]; + if (tv[i].plainlen < split) + continue; + + err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + keylen = gcry_cipher_get_algo_keylen(tv[i].algo); + if (!keylen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_keylen failed\n"); + return; + } + + err = gcry_cipher_setkey (hde, tv[i].key, keylen); + if (!err) + err = gcry_cipher_setkey (hdd, tv[i].key, keylen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + blklen = gcry_cipher_get_algo_blklen(tv[i].algo); + if (!blklen) + { + fail ("cipher-ccm, gcry_cipher_get_algo_blklen failed\n"); + return; + } + + err = gcry_cipher_setiv (hde, tv[i].nonce, tv[i].noncelen); + if (!err) + err = gcry_cipher_setiv (hdd, tv[i].nonce, tv[i].noncelen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + authlen = tv[i].cipherlen - tv[i].plainlen; + ctl_params[0] = tv[i].plainlen; /* encryptedlen */ + ctl_params[1] = tv[i].aadlen; /* aadlen */ + ctl_params[2] = authlen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (!err) + err = gcry_cipher_ctl (hdd, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS " + "failed: %s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + aadsplit = split > tv[i].aadlen ? 0 : split; + + err = gcry_cipher_authenticate (hde, tv[i].aad, + tv[i].aadlen - aadsplit); + if (!err) + err = gcry_cipher_authenticate (hde, + &tv[i].aad[tv[i].aadlen - aadsplit], + aadsplit); + if (!err) + err = gcry_cipher_authenticate (hdd, tv[i].aad, + tv[i].aadlen - aadsplit); + if (!err) + err = gcry_cipher_authenticate (hdd, + &tv[i].aad[tv[i].aadlen - aadsplit], + aadsplit); + if (err) + { + fail ("cipher-ccm, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, tv[i].plaintext, + tv[i].plainlen - split); + if (!err) + err = gcry_cipher_encrypt (hde, &out[tv[i].plainlen - split], + MAX_DATA_LEN - (tv[i].plainlen - split), + &tv[i].plaintext[tv[i].plainlen - split], + split); + if (err) + { + fail ("cipher-ccm, gcry_cipher_encrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + err = gcry_cipher_gettag (hde, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_gettag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].ciphertext, out, tv[i].cipherlen)) + fail ("cipher-ccm, encrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_decrypt (hdd, out, tv[i].plainlen - split, NULL, 0); + if (!err) + err = gcry_cipher_decrypt (hdd, &out[tv[i].plainlen - split], split, + NULL, 0); + if (err) + { + fail ("cipher-ccm, gcry_cipher_decrypt (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + if (memcmp (tv[i].plaintext, out, tv[i].plainlen)) + fail ("cipher-ccm, decrypt mismatch entry %d:%d\n", i, j); + + err = gcry_cipher_checktag (hdd, &out[tv[i].plainlen], authlen); + if (err) + { + fail ("cipher-ccm, gcry_cipher_checktag (%d:%d) failed: %s\n", + i, j, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + } + } + + /* Large buffer tests. */ + + /* Test encoding of aadlen > 0xfeff. */ + { + static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19}; + static const char tag[]={0x9C,0x76,0xE7,0x33,0xD5,0x15,0xB3,0x6C, + 0xBA,0x76,0x95,0xF7,0xFB,0x91}; + char buf[1024]; + size_t enclen = 0x20000; + size_t aadlen = 0x20000; + size_t taglen = sizeof(tag); + + err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + err = gcry_cipher_setkey (hde, key, sizeof (key)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + err = gcry_cipher_setiv (hde, iv, sizeof (iv)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + ctl_params[0] = enclen; /* encryptedlen */ + ctl_params[1] = aadlen; /* aadlen */ + ctl_params[2] = taglen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS " + "failed: %s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + memset (buf, 0xaa, sizeof(buf)); + + for (i = 0; i < aadlen; i += sizeof(buf)) + { + err = gcry_cipher_authenticate (hde, buf, sizeof (buf)); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + for (i = 0; i < enclen; i += sizeof(buf)) + { + memset (buf, 0xee, sizeof(buf)); + err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_encrypt failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + err = gcry_cipher_gettag (hde, buf, taglen); + if (err) + { + fail ("cipher-ccm-large, gcry_cipher_gettag failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + if (memcmp (buf, tag, taglen) != 0) + fail ("cipher-ccm-large, encrypt mismatch entry\n"); + } + +#if 0 + /* Test encoding of aadlen > 0xffffffff. */ + { + static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19}; + static const char tag[]={0x01,0xB2,0xC3,0x4A,0xA6,0x6A,0x07,0x6D, + 0xBC,0xBD,0xEA,0x17,0xD3,0x73,0xD7,0xD4}; + char buf[1024]; + size_t enclen = (size_t)0xffffffff + 1 + 1024; + size_t aadlen = (size_t)0xffffffff + 1 + 1024; + size_t taglen = sizeof(tag); + + err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_open failed: %s\n", + gpg_strerror (err)); + return; + } + + err = gcry_cipher_setkey (hde, key, sizeof (key)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_setkey failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + err = gcry_cipher_setiv (hde, iv, sizeof (iv)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + ctl_params[0] = enclen; /* encryptedlen */ + ctl_params[1] = aadlen; /* aadlen */ + ctl_params[2] = taglen; /* authtaglen */ + err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params, + sizeof(ctl_params)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS failed:" + "%s\n", gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + memset (buf, 0xaa, sizeof(buf)); + + for (i = 0; i < aadlen; i += sizeof(buf)) + { + err = gcry_cipher_authenticate (hde, buf, sizeof (buf)); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_authenticate failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + for (i = 0; i < enclen; i += sizeof(buf)) + { + memset (buf, 0xee, sizeof(buf)); + err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_encrypt failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + } + + err = gcry_cipher_gettag (hde, buf, taglen); + if (err) + { + fail ("cipher-ccm-huge, gcry_cipher_gettag failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hde); + return; + } + + if (memcmp (buf, tag, taglen) != 0) + fail ("cipher-ccm-huge, encrypt mismatch entry\n"); + } +#endif + + if (verbose) + fprintf (stderr, " Completed CCM checks.\n"); +} + + +static void check_stream_cipher (void) { struct tv @@ -2455,6 +3225,7 @@ check_cipher_modes(void) check_ctr_cipher (); check_cfb_cipher (); check_ofb_cipher (); + check_ccm_cipher (); check_stream_cipher (); check_stream_cipher_large_block (); diff --git a/tests/benchmark.c b/tests/benchmark.c index ecda0d3..d3ef1a2 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -435,6 +435,40 @@ md_bench ( const char *algoname ) fflush (stdout); } + +static void ccm_aead_init(gcry_cipher_hd_t hd, size_t buflen, int authlen) +{ + const int _L = 4; + const int noncelen = 15 - _L; + char nonce[noncelen]; + size_t params[3]; + gcry_error_t err = GPG_ERR_NO_ERROR; + + memset (nonce, 0x33, noncelen); + + err = gcry_cipher_setiv (hd, nonce, noncelen); + if (err) + { + fprintf (stderr, "gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } + + params[0] = buflen; /* encryptedlen */ + params[1] = 0; /* aadlen */ + params[2] = authlen; /* authtaglen */ + err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(params)); + if (err) + { + fprintf (stderr, "gcry_cipher_setiv failed: %s\n", + gpg_strerror (err)); + gcry_cipher_close (hd); + exit (1); + } +} + + static void cipher_bench ( const char *algoname ) { @@ -448,12 +482,21 @@ cipher_bench ( const char *algoname ) char *raw_outbuf, *raw_buf; size_t allocated_buflen, buflen; int repetitions; - static struct { int mode; const char *name; int blocked; } modes[] = { + static const struct { + int mode; + const char *name; + int blocked; + void (* const aead_init)(gcry_cipher_hd_t hd, size_t buflen, int authlen); + int req_blocksize; + int authlen; + } modes[] = { { GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1 }, { GCRY_CIPHER_MODE_CBC, " CBC", 1 }, { GCRY_CIPHER_MODE_CFB, " CFB", 0 }, { GCRY_CIPHER_MODE_OFB, " OFB", 0 }, { GCRY_CIPHER_MODE_CTR, " CTR", 0 }, + { GCRY_CIPHER_MODE_CCM, " CCM", 0, + ccm_aead_init, GCRY_CCM_BLOCK_LEN, 8 }, { GCRY_CIPHER_MODE_STREAM, "", 0 }, {0} }; @@ -542,9 +585,16 @@ cipher_bench ( const char *algoname ) for (modeidx=0; modes[modeidx].mode; modeidx++) { if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM) - | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) + || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) continue; + if (modes[modeidx].req_blocksize > 0 + && blklen != modes[modeidx].req_blocksize) + { + printf (" %7s %7s", "-", "-" ); + continue; + } + for (i=0; i < sizeof buf; i++) buf[i] = i; @@ -585,7 +635,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_gettag (hd, outbuf, modes[modeidx].authlen); + } + else + { + err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen); + } } stop_timer (); @@ -632,7 +693,18 @@ cipher_bench ( const char *algoname ) exit (1); } } - err = gcry_cipher_decrypt ( hd, outbuf, buflen, buf, buflen); + if (modes[modeidx].aead_init) + { + (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); + if (err) + break; + err = gcry_cipher_checktag (hd, outbuf, modes[modeidx].authlen); + if (gpg_err_code (err) == GPG_ERR_CHECKSUM) + err = gpg_error (GPG_ERR_NO_ERROR); + } + else + err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen); } stop_timer (); printf (" %s", elapsed_time ()); commit 95654041f2aa62f71aac4d8614dafe8433d10f95 Author: Jussi Kivilinna Date: Tue Oct 22 17:07:53 2013 +0300 Add API to support AEAD cipher modes * cipher/cipher.c (_gcry_cipher_authenticate, _gcry_cipher_checktag) (_gcry_cipher_gettag): New. * doc/gcrypt.texi: Add documentation for new API functions. * src/visibility.c (gcry_cipher_authenticate, gcry_cipher_checktag) (gcry_cipher_gettag): New. * src/gcrypt.h.in, src/visibility.h: add declarations of these functions. * src/libgcrypt.defs, src/libgcrypt.vers: export functions. -- Authenticated Encryption with Associated Data (AEAD) cipher modes provide authentication tag that can be used to authenticate message. At the same time it allows one to specify additional (unencrypted data) that will be authenticated together with the message. This class of cipher modes requires additional API present in this commit. This patch is based on original patch by Dmitry Eremin-Solenikov. Changes in v2: - Change gcry_cipher_tag to gcry_cipher_checktag and gcry_cipher_gettag for giving tag (checktag) for decryption and reading tag (gettag) after encryption. - Change gcry_cipher_authenticate to gcry_cipher_setaad, since additional parameters needed for some AEAD modes (in this case CCM, which needs the length of encrypted data and tag for MAC initialization). - Add some documentation. Changes in v3: - Change gcry_cipher_setaad back to gcry_cipher_authenticate. Additional parameters (encrypt_len, tag_len, aad_len) for CCM will be given through GCRY_CTL_SET_CCM_LENGTHS. Changes in v4: - log_fatal => log_error Signed-off-by: Jussi Kivilinna diff --git a/cipher/cipher.c b/cipher/cipher.c index 75d42d1..d6d3021 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -910,6 +910,40 @@ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return 0; } +gcry_error_t +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen) +{ + log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + + (void)abuf; + (void)abuflen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + + (void)outtag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + +gcry_error_t +_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + + (void)intag; + (void)taglen; + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + gcry_error_t gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 473c484..0049fa0 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1731,6 +1731,10 @@ matches the requirement of the selected algorithm and mode. This function is also used with the Salsa20 stream cipher to set or update the required nonce. In this case it needs to be called after setting the key. + +This function is also used with the AEAD cipher modes to set or +update the required nonce. + @end deftypefun @deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, const void *@var{c}, size_t @var{l}) @@ -1750,6 +1754,37 @@ call to gcry_cipher_setkey and clear the initialization vector. Note that gcry_cipher_reset is implemented as a macro. @end deftypefun +Authenticated Encryption with Associated Data (AEAD) block cipher +modes require the handling of the authentication tag and the additional +authenticated data, which can be done by using the following +functions: + + at deftypefun gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t @var{h}, const void *@var{abuf}, size_t @var{abuflen}) + +Process the buffer @var{abuf} of length @var{abuflen} as the additional +authenticated data (AAD) for AEAD cipher modes. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t @var{h}, void *@var{tag}, size_t @var{taglen}) + +This function is used to read the authentication tag after encryption. +The function finalizes and outputs the authentication tag to the buffer + at var{tag} of length @var{taglen} bytes. + + at end deftypefun + + at deftypefun gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t @var{h}, const void *@var{tag}, size_t @var{taglen}) + +Check the authentication tag after decryption. The authentication +tag is passed as the buffer @var{tag} of length @var{taglen} bytes +and compared to internal authentication tag computed during +decryption. Error code @code{GPG_ERR_CHECKSUM} is returned if +the authentication tag in the buffer @var{tag} does not match +the authentication tag calculated during decryption. + + at end deftypefun + The actual encryption and decryption is done by using one of the following functions. They may be used as often as required to process all the data. diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 64cc0e4..f0ae927 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -953,6 +953,17 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen); +/* Provide additional authentication data for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen); + +/* Get authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, + size_t taglen); + +/* Check authentication tag for AEAD modes/ciphers. */ +gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, + size_t taglen); /* Reset the handle to the state after open. */ #define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0) diff --git a/src/libgcrypt.def b/src/libgcrypt.def index ec0c1e3..64ba370 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -255,6 +255,9 @@ EXPORTS gcry_sexp_extract_param @225 + gcry_cipher_authenticate @226 + gcry_cipher_gettag @227 + gcry_cipher_checktag @228 ;; end of file with public symbols for Windows. diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index be72aad..93eaa93 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -51,6 +51,7 @@ GCRYPT_1.6 { gcry_cipher_info; gcry_cipher_map_name; gcry_cipher_mode_from_oid; gcry_cipher_open; gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr; + gcry_cipher_authenticate; gcry_cipher_gettag; gcry_cipher_checktag; gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl; gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey; diff --git a/src/visibility.c b/src/visibility.c index 848925e..1f7bb3a 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -713,6 +713,33 @@ gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) return _gcry_cipher_setctr (hd, ctr, ctrlen); } +gcry_error_t +gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_authenticate (hd, abuf, abuflen); +} + +gcry_error_t +gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_gettag (hd, outtag, taglen); +} + +gcry_error_t +gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + + return _gcry_cipher_checktag (hd, intag, taglen); +} + gcry_error_t gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) diff --git a/src/visibility.h b/src/visibility.h index 1c8f047..b2fa4c0 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -81,6 +81,9 @@ #define gcry_cipher_setkey _gcry_cipher_setkey #define gcry_cipher_setiv _gcry_cipher_setiv #define gcry_cipher_setctr _gcry_cipher_setctr +#define gcry_cipher_authenticate _gcry_cipher_authenticate +#define gcry_cipher_checktag _gcry_cipher_checktag +#define gcry_cipher_gettag _gcry_cipher_gettag #define gcry_cipher_ctl _gcry_cipher_ctl #define gcry_cipher_decrypt _gcry_cipher_decrypt #define gcry_cipher_encrypt _gcry_cipher_encrypt @@ -297,6 +300,9 @@ gcry_err_code_t gcry_md_get (gcry_md_hd_t hd, int algo, #undef gcry_cipher_setkey #undef gcry_cipher_setiv #undef gcry_cipher_setctr +#undef gcry_cipher_authenticate +#undef gcry_cipher_checktag +#undef gcry_cipher_gettag #undef gcry_cipher_ctl #undef gcry_cipher_decrypt #undef gcry_cipher_encrypt @@ -474,6 +480,9 @@ MARK_VISIBLE (gcry_cipher_close) MARK_VISIBLE (gcry_cipher_setkey) MARK_VISIBLE (gcry_cipher_setiv) MARK_VISIBLE (gcry_cipher_setctr) +MARK_VISIBLE (gcry_cipher_authenticate) +MARK_VISIBLE (gcry_cipher_checktag) +MARK_VISIBLE (gcry_cipher_gettag) MARK_VISIBLE (gcry_cipher_ctl) MARK_VISIBLE (gcry_cipher_decrypt) MARK_VISIBLE (gcry_cipher_encrypt) ----------------------------------------------------------------------- Summary of changes: cipher/Makefile.am | 1 + cipher/cipher-ccm.c | 370 ++++++++++++++++++++++ cipher/cipher-internal.h | 48 ++- cipher/cipher.c | 117 ++++++- doc/gcrypt.texi | 51 ++- src/gcrypt.h.in | 19 +- src/libgcrypt.def | 3 + src/libgcrypt.vers | 1 + src/visibility.c | 27 ++ src/visibility.h | 9 + tests/basic.c | 771 ++++++++++++++++++++++++++++++++++++++++++++++ tests/benchmark.c | 80 ++++- 12 files changed, 1484 insertions(+), 13 deletions(-) create mode 100644 cipher/cipher-ccm.c hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From cvs at cvs.gnupg.org Tue Oct 22 19:20:55 2013 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Tue, 22 Oct 2013 19:20:55 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-324-g98674fd Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 98674fdaa30ab22a3ac86ca05d688b5b6112895d (commit) via e67c67321ce240c93dd0fa2b21c649c0a8e233f7 (commit) via c7efaa5fe0ee92e321a7b49d56752cc12eb75fe0 (commit) from 335d9bf7b035815750b63a3a8334d6ce44dc4449 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 98674fdaa30ab22a3ac86ca05d688b5b6112895d Author: Jussi Kivilinna Date: Tue Oct 22 17:07:53 2013 +0300 twofish: add ARMv6 assembly implementation * cipher/Makefile.am: Add 'twofish-armv6.S'. * cipher/twofish-armv6.S: New. * cipher/twofish.c (USE_ARMV6_ASM): New macro. [USE_ARMV6_ASM] (_gcry_twofish_armv6_encrypt_block) (_gcry_twofish_armv6_decrypt_block): New prototypes. [USE_AMDV6_ASM] (twofish_encrypt, twofish_decrypt): Add. [USE_AMD64_ASM] (do_twofish_encrypt, do_twofish_decrypt): Remove. (_gcry_twofish_ctr_enc, _gcry_twofish_cfb_dec): Use 'twofish_encrypt' instead of 'do_twofish_encrypt'. (_gcry_twofish_cbc_dec): Use 'twofish_decrypt' instead of 'do_twofish_decrypt'. * configure.ac [arm]: Add 'twofish-armv6.lo'. -- Add optimized ARMv6 assembly implementation for Twofish. Implementation is tuned for Cortex-A8. Unaligned access handling is done in assembly part. For now, only enable this on little-endian systems as big-endian correctness have not been tested yet. Old (gcc-4.8) vs new (twofish-asm), Cortex-A8 (on armhf): ECB/Stream CBC CFB OFB CTR CCM --------------- --------------- --------------- --------------- --------------- --------------- TWOFISH 1.23x 1.25x 1.16x 1.26x 1.16x 1.30x 1.18x 1.17x 1.23x 1.23x 1.22x 1.22x Signed-off-by: Jussi Kivilinna diff --git a/cipher/Makefile.am b/cipher/Makefile.am index b0efd89..3d8149a 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -80,7 +80,7 @@ sha512.c sha512-armv7-neon.S \ stribog.c \ tiger.c \ whirlpool.c \ -twofish.c twofish-amd64.S \ +twofish.c twofish-amd64.S twofish-armv6.S \ rfc2268.c \ camellia.c camellia.h camellia-glue.c camellia-aesni-avx-amd64.S \ camellia-aesni-avx2-amd64.S camellia-armv6.S diff --git a/cipher/twofish-armv6.S b/cipher/twofish-armv6.S new file mode 100644 index 0000000..b76ab37 --- /dev/null +++ b/cipher/twofish-armv6.S @@ -0,0 +1,365 @@ +/* twofish-armv6.S - ARM assembly implementation of Twofish cipher + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) +#ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS + +.text + +.syntax unified +.arm + +/* structure of TWOFISH_context: */ +#define s0 0 +#define s1 ((s0) + 4 * 256) +#define s2 ((s1) + 4 * 256) +#define s3 ((s2) + 4 * 256) +#define w ((s3) + 4 * 256) +#define k ((w) + 4 * 8) + +/* register macros */ +#define CTX %r0 +#define CTXs0 %r0 +#define CTXs1 %r1 +#define CTXs3 %r7 + +#define RA %r3 +#define RB %r4 +#define RC %r5 +#define RD %r6 + +#define RX %r2 +#define RY %ip + +#define RMASK %lr + +#define RT0 %r8 +#define RT1 %r9 +#define RT2 %r10 +#define RT3 %r11 + +/* helper macros */ +#define ldr_unaligned_le(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 0)]; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 3)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 0)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 1)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 2)]; \ + strb rtmp0, [rdst, #((offs) + 3)]; + +#ifndef __ARMEL__ + /* bswap on big-endian */ + #define host_to_le(reg) \ + rev reg, reg; + #define le_to_host(reg) \ + rev reg, reg; +#else + /* nop on little-endian */ + #define host_to_le(reg) /*_*/ + #define le_to_host(reg) /*_*/ +#endif + +#define ldr_input_aligned_le(rin, a, b, c, d) \ + ldr a, [rin, #0]; \ + ldr b, [rin, #4]; \ + le_to_host(a); \ + ldr c, [rin, #8]; \ + le_to_host(b); \ + ldr d, [rin, #12]; \ + le_to_host(c); \ + le_to_host(d); + +#define str_output_aligned_le(rout, a, b, c, d) \ + le_to_host(a); \ + le_to_host(b); \ + str a, [rout, #0]; \ + le_to_host(c); \ + str b, [rout, #4]; \ + le_to_host(d); \ + str c, [rout, #8]; \ + str d, [rout, #12]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads/writes allowed */ + #define ldr_input_le(rin, ra, rb, rc, rd, rtmp) \ + ldr_input_aligned_le(rin, ra, rb, rc, rd) + + #define str_output_le(rout, ra, rb, rc, rd, rtmp0, rtmp1) \ + str_output_aligned_le(rout, ra, rb, rc, rd) +#else + /* need to handle unaligned reads/writes by byte reads */ + #define ldr_input_le(rin, ra, rb, rc, rd, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_le(ra, rin, 0, rtmp0); \ + ldr_unaligned_le(rb, rin, 4, rtmp0); \ + ldr_unaligned_le(rc, rin, 8, rtmp0); \ + ldr_unaligned_le(rd, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + ldr_input_aligned_le(rin, ra, rb, rc, rd); \ + 2:; + + #define str_output_le(rout, ra, rb, rc, rd, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_le(ra, rout, 0, rtmp0, rtmp1); \ + str_unaligned_le(rb, rout, 4, rtmp0, rtmp1); \ + str_unaligned_le(rc, rout, 8, rtmp0, rtmp1); \ + str_unaligned_le(rd, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + str_output_aligned_le(rout, ra, rb, rc, rd); \ + 2:; +#endif + +/********************************************************************** + 1-way twofish + **********************************************************************/ +#define encrypt_round(a, b, rc, rd, n, ror_a, adj_a) \ + and RT0, RMASK, b, lsr#(8 - 2); \ + and RY, RMASK, b, lsr#(16 - 2); \ + add RT0, RT0, #(s2 - s1); \ + and RT1, RMASK, b, lsr#(24 - 2); \ + ldr RY, [CTXs3, RY]; \ + and RT2, RMASK, b, lsl#(2); \ + ldr RT0, [CTXs1, RT0]; \ + and RT3, RMASK, a, lsr#(16 - 2 + (adj_a)); \ + ldr RT1, [CTXs0, RT1]; \ + and RX, RMASK, a, lsr#(8 - 2 + (adj_a)); \ + ldr RT2, [CTXs1, RT2]; \ + add RT3, RT3, #(s2 - s1); \ + ldr RX, [CTXs1, RX]; \ + ror_a(a); \ + \ + eor RY, RY, RT0; \ + ldr RT3, [CTXs1, RT3]; \ + and RT0, RMASK, a, lsl#(2); \ + eor RY, RY, RT1; \ + and RT1, RMASK, a, lsr#(24 - 2); \ + eor RY, RY, RT2; \ + ldr RT0, [CTXs0, RT0]; \ + eor RX, RX, RT3; \ + ldr RT1, [CTXs3, RT1]; \ + eor RX, RX, RT0; \ + \ + ldr RT3, [CTXs3, #(k - s3 + 8 * (n) + 4)]; \ + eor RX, RX, RT1; \ + ldr RT2, [CTXs3, #(k - s3 + 8 * (n))]; \ + \ + add RT0, RX, RY, lsl #1; \ + add RX, RX, RY; \ + add RT0, RT0, RT3; \ + add RX, RX, RT2; \ + eor rd, RT0, rd, ror #31; \ + eor rc, rc, RX; + +#define dummy(x) /*_*/ + +#define ror1(r) \ + ror r, r, #1; + +#define decrypt_round(a, b, rc, rd, n, ror_b, adj_b) \ + and RT3, RMASK, b, lsl#(2 - (adj_b)); \ + and RT1, RMASK, b, lsr#(8 - 2 + (adj_b)); \ + ror_b(b); \ + and RT2, RMASK, a, lsl#(2); \ + and RT0, RMASK, a, lsr#(8 - 2); \ + \ + ldr RY, [CTXs1, RT3]; \ + add RT1, RT1, #(s2 - s1); \ + ldr RX, [CTXs0, RT2]; \ + and RT3, RMASK, b, lsr#(16 - 2); \ + ldr RT1, [CTXs1, RT1]; \ + and RT2, RMASK, a, lsr#(16 - 2); \ + ldr RT0, [CTXs1, RT0]; \ + \ + add RT2, RT2, #(s2 - s1); \ + ldr RT3, [CTXs3, RT3]; \ + eor RY, RY, RT1; \ + \ + and RT1, RMASK, b, lsr#(24 - 2); \ + eor RX, RX, RT0; \ + ldr RT2, [CTXs1, RT2]; \ + and RT0, RMASK, a, lsr#(24 - 2); \ + \ + ldr RT1, [CTXs0, RT1]; \ + \ + eor RY, RY, RT3; \ + ldr RT0, [CTXs3, RT0]; \ + eor RX, RX, RT2; \ + eor RY, RY, RT1; \ + \ + ldr RT1, [CTXs3, #(k - s3 + 8 * (n) + 4)]; \ + eor RX, RX, RT0; \ + ldr RT2, [CTXs3, #(k - s3 + 8 * (n))]; \ + \ + add RT0, RX, RY, lsl #1; \ + add RX, RX, RY; \ + add RT0, RT0, RT1; \ + add RX, RX, RT2; \ + eor rd, rd, RT0; \ + eor rc, RX, rc, ror #31; + +#define first_encrypt_cycle(nc) \ + encrypt_round(RA, RB, RC, RD, (nc) * 2, dummy, 0); \ + encrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); + +#define encrypt_cycle(nc) \ + encrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); \ + encrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); + +#define last_encrypt_cycle(nc) \ + encrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); \ + encrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); \ + ror1(RA); + +#define first_decrypt_cycle(nc) \ + decrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, dummy, 0); \ + decrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); + +#define decrypt_cycle(nc) \ + decrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); \ + decrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); + +#define last_decrypt_cycle(nc) \ + decrypt_round(RC, RD, RA, RB, (nc) * 2 + 1, ror1, 1); \ + decrypt_round(RA, RB, RC, RD, (nc) * 2, ror1, 1); \ + ror1(RD); + +.align 3 +.global _gcry_twofish_armv6_encrypt_block +.type _gcry_twofish_armv6_encrypt_block,%function; + +_gcry_twofish_armv6_encrypt_block: + /* input: + * %r0: ctx + * %r1: dst + * %r2: src + */ + push {%r1, %r4-%r11, %ip, %lr}; + + add RY, CTXs0, #w; + + ldr_input_le(%r2, RA, RB, RC, RD, RT0); + + /* Input whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + add CTXs3, CTXs0, #(s3 - s0); + add CTXs1, CTXs0, #(s1 - s0); + mov RMASK, #(0xff << 2); + eor RA, RA, RT0; + eor RB, RB, RT1; + eor RC, RC, RT2; + eor RD, RD, RT3; + + first_encrypt_cycle(0); + encrypt_cycle(1); + encrypt_cycle(2); + encrypt_cycle(3); + encrypt_cycle(4); + encrypt_cycle(5); + encrypt_cycle(6); + last_encrypt_cycle(7); + + add RY, CTXs3, #(w + 4*4 - s3); + pop {%r1}; /* dst */ + + /* Output whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + eor RC, RC, RT0; + eor RD, RD, RT1; + eor RA, RA, RT2; + eor RB, RB, RT3; + + str_output_le(%r1, RC, RD, RA, RB, RT0, RT1); + + pop {%r4-%r11, %ip, %lr}; + bx %lr; +.ltorg +.size _gcry_twofish_armv6_encrypt_block,.-_gcry_twofish_armv6_encrypt_block; + +.align 3 +.global _gcry_twofish_armv6_decrypt_block +.type _gcry_twofish_armv6_decrypt_block,%function; + +_gcry_twofish_armv6_decrypt_block: + /* input: + * %r0: ctx + * %r1: dst + * %r2: src + */ + push {%r1, %r4-%r11, %ip, %lr}; + + add CTXs3, CTXs0, #(s3 - s0); + + ldr_input_le(%r2, RC, RD, RA, RB, RT0); + + add RY, CTXs3, #(w + 4*4 - s3); + add CTXs3, CTXs0, #(s3 - s0); + + /* Input whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + add CTXs1, CTXs0, #(s1 - s0); + mov RMASK, #(0xff << 2); + eor RC, RC, RT0; + eor RD, RD, RT1; + eor RA, RA, RT2; + eor RB, RB, RT3; + + first_decrypt_cycle(7); + decrypt_cycle(6); + decrypt_cycle(5); + decrypt_cycle(4); + decrypt_cycle(3); + decrypt_cycle(2); + decrypt_cycle(1); + last_decrypt_cycle(0); + + add RY, CTXs0, #w; + pop {%r1}; /* dst */ + + /* Output whitening */ + ldm RY, {RT0, RT1, RT2, RT3}; + eor RA, RA, RT0; + eor RB, RB, RT1; + eor RC, RC, RT2; + eor RD, RD, RT3; + + str_output_le(%r1, RA, RB, RC, RD, RT0, RT1); + + pop {%r4-%r11, %ip, %lr}; + bx %lr; +.size _gcry_twofish_armv6_decrypt_block,.-_gcry_twofish_armv6_decrypt_block; + +#endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/ +#endif /*__ARM_ARCH >= 6*/ diff --git a/cipher/twofish.c b/cipher/twofish.c index 993ad0f..d2cabbe 100644 --- a/cipher/twofish.c +++ b/cipher/twofish.c @@ -57,6 +57,14 @@ # define USE_AMD64_ASM 1 #endif +/* USE_ARMV6_ASM indicates whether to use ARMv6 assembly code. */ +#undef USE_ARMV6_ASM +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) +# if defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) +# define USE_ARMV6_ASM 1 +# endif +#endif + /* Prototype for the self-test function. */ static const char *selftest(void); @@ -746,7 +754,16 @@ extern void _gcry_twofish_amd64_cbc_dec(const TWOFISH_context *c, byte *out, extern void _gcry_twofish_amd64_cfb_dec(const TWOFISH_context *c, byte *out, const byte *in, byte *iv); -#else /*!USE_AMD64_ASM*/ +#elif defined(USE_ARMV6_ASM) + +/* Assembly implementations of Twofish. */ +extern void _gcry_twofish_armv6_encrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +extern void _gcry_twofish_armv6_decrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +#else /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ /* Macros to compute the g() function in the encryption and decryption * rounds. G1 is the straight g() function; G2 includes the 8-bit @@ -812,21 +829,25 @@ extern void _gcry_twofish_amd64_cfb_dec(const TWOFISH_context *c, byte *out, #ifdef USE_AMD64_ASM -static void -do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in) +static unsigned int +twofish_encrypt (void *context, byte *out, const byte *in) { + TWOFISH_context *ctx = context; _gcry_twofish_amd64_encrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); } +#elif defined(USE_ARMV6_ASM) + static unsigned int twofish_encrypt (void *context, byte *out, const byte *in) { TWOFISH_context *ctx = context; - _gcry_twofish_amd64_encrypt_block(ctx, out, in); + _gcry_twofish_armv6_encrypt_block(ctx, out, in); return /*burn_stack*/ (4*sizeof (void*)); } -#else /*!USE_AMD64_ASM*/ +#else /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ static void do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in) @@ -868,28 +889,32 @@ twofish_encrypt (void *context, byte *out, const byte *in) return /*burn_stack*/ (24+3*sizeof (void*)); } -#endif /*!USE_AMD64_ASM*/ +#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ /* Decrypt one block. in and out may be the same. */ #ifdef USE_AMD64_ASM -static void -do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in) +static unsigned int +twofish_decrypt (void *context, byte *out, const byte *in) { + TWOFISH_context *ctx = context; _gcry_twofish_amd64_decrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); } +#elif defined(USE_ARMV6_ASM) + static unsigned int twofish_decrypt (void *context, byte *out, const byte *in) { TWOFISH_context *ctx = context; - _gcry_twofish_amd64_decrypt_block(ctx, out, in); + _gcry_twofish_armv6_decrypt_block(ctx, out, in); return /*burn_stack*/ (4*sizeof (void*)); } -#else /*!USE_AMD64_ASM*/ +#else /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ static void do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in) @@ -932,7 +957,7 @@ twofish_decrypt (void *context, byte *out, const byte *in) return /*burn_stack*/ (24+3*sizeof (void*)); } -#endif /*!USE_AMD64_ASM*/ +#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/ @@ -947,14 +972,11 @@ _gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char tmpbuf[TWOFISH_BLOCKSIZE]; - int burn_stack_depth = 24 + 3 * sizeof (void*); + unsigned int burn, burn_stack_depth = 0; int i; #ifdef USE_AMD64_ASM { - if (nblocks >= 3 && burn_stack_depth < 8 * sizeof(void*)) - burn_stack_depth = 8 * sizeof(void*); - /* Process data in 3 block chunks. */ while (nblocks >= 3) { @@ -963,6 +985,10 @@ _gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, nblocks -= 3; outbuf += 3 * TWOFISH_BLOCKSIZE; inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 8 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; } /* Use generic code to handle smaller chunks... */ @@ -973,7 +999,10 @@ _gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, for ( ;nblocks; nblocks-- ) { /* Encrypt the counter. */ - do_twofish_encrypt(ctx, tmpbuf, ctr); + burn = twofish_encrypt(ctx, tmpbuf, ctr); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + /* XOR the input with the encrypted counter and store in output. */ buf_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE); outbuf += TWOFISH_BLOCKSIZE; @@ -1002,13 +1031,10 @@ _gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char savebuf[TWOFISH_BLOCKSIZE]; - int burn_stack_depth = 24 + 3 * sizeof (void*); + unsigned int burn, burn_stack_depth = 0; #ifdef USE_AMD64_ASM { - if (nblocks >= 3 && burn_stack_depth < 9 * sizeof(void*)) - burn_stack_depth = 9 * sizeof(void*); - /* Process data in 3 block chunks. */ while (nblocks >= 3) { @@ -1017,6 +1043,10 @@ _gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, nblocks -= 3; outbuf += 3 * TWOFISH_BLOCKSIZE; inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 9 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; } /* Use generic code to handle smaller chunks... */ @@ -1029,7 +1059,9 @@ _gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, OUTBUF. */ memcpy(savebuf, inbuf, TWOFISH_BLOCKSIZE); - do_twofish_decrypt (ctx, outbuf, inbuf); + burn = twofish_decrypt (ctx, outbuf, inbuf); + if (burn > burn_stack_depth) + burn_stack_depth = burn; buf_xor(outbuf, outbuf, iv, TWOFISH_BLOCKSIZE); memcpy(iv, savebuf, TWOFISH_BLOCKSIZE); @@ -1051,13 +1083,10 @@ _gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, TWOFISH_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; - int burn_stack_depth = 24 + 3 * sizeof (void*); + unsigned int burn, burn_stack_depth = 0; #ifdef USE_AMD64_ASM { - if (nblocks >= 3 && burn_stack_depth < 8 * sizeof(void*)) - burn_stack_depth = 8 * sizeof(void*); - /* Process data in 3 block chunks. */ while (nblocks >= 3) { @@ -1066,6 +1095,10 @@ _gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, nblocks -= 3; outbuf += 3 * TWOFISH_BLOCKSIZE; inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 8 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; } /* Use generic code to handle smaller chunks... */ @@ -1074,7 +1107,10 @@ _gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, for ( ;nblocks; nblocks-- ) { - do_twofish_encrypt(ctx, iv, iv); + burn = twofish_encrypt(ctx, iv, iv); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + buf_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE); outbuf += TWOFISH_BLOCKSIZE; inbuf += TWOFISH_BLOCKSIZE; diff --git a/configure.ac b/configure.ac index 8fb14e2..739a650 100644 --- a/configure.ac +++ b/configure.ac @@ -1480,6 +1480,10 @@ if test "$found" = "1" ; then # Build with the assembly implementation GCRYPT_CIPHERS="$GCRYPT_CIPHERS twofish-amd64.lo" ;; + arm*-*-*) + # Build with the assembly implementation + GCRYPT_CIPHERS="$GCRYPT_CIPHERS twofish-armv6.lo" + ;; esac fi commit e67c67321ce240c93dd0fa2b21c649c0a8e233f7 Author: Jussi Kivilinna Date: Tue Oct 22 17:07:53 2013 +0300 mpi: allow building with clang on ARM * mpi/longlong.h [__arm__] (add_ssaaaa, sub_ddmmss, umul_ppmm) (count_leading_zeros): Do not cast assembly output arguments. [__arm__] (umul_ppmm): Remove the extra '%' ahead of assembly comment. [_ARM_ARCH >= 4] (umul_ppmm): Use correct inputs and outputs instead of registers. -- Signed-off-by: Jussi Kivilinna diff --git a/mpi/longlong.h b/mpi/longlong.h index c2ab9c5..8c8260e 100644 --- a/mpi/longlong.h +++ b/mpi/longlong.h @@ -213,8 +213,8 @@ extern UDItype __udiv_qrnnd (); #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("adds %1, %4, %5\n" \ "adc %0, %2, %3" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "%r" ((USItype)(ah)), \ "rI" ((USItype)(bh)), \ "%r" ((USItype)(al)), \ @@ -222,15 +222,15 @@ extern UDItype __udiv_qrnnd (); #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subs %1, %4, %5\n" \ "sbc %0, %2, %3" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" ((sh)), \ + "=&r" ((sl)) \ : "r" ((USItype)(ah)), \ "rI" ((USItype)(bh)), \ "r" ((USItype)(al)), \ "rI" ((USItype)(bl)) __CLOBBER_CC) #if (defined __ARM_ARCH && __ARM_ARCH <= 3) #define umul_ppmm(xh, xl, a, b) \ - __asm__ ("%@ Inlined umul_ppmm\n" \ + __asm__ ("@ Inlined umul_ppmm\n" \ "mov %|r0, %2, lsr #16 @ AAAA\n" \ "mov %|r2, %3, lsr #16 @ BBBB\n" \ "bic %|r1, %2, %|r0, lsl #16 @ aaaa\n" \ @@ -243,27 +243,26 @@ extern UDItype __udiv_qrnnd (); "addcs %|r2, %|r2, #65536\n" \ "adds %1, %|r1, %|r0, lsl #16\n" \ "adc %0, %|r2, %|r0, lsr #16" \ - : "=&r" ((USItype)(xh)), \ - "=r" ((USItype)(xl)) \ + : "=&r" ((xh)), \ + "=r" ((xl)) \ : "r" ((USItype)(a)), \ "r" ((USItype)(b)) \ : "r0", "r1", "r2" __CLOBBER_CC) #else /* __ARM_ARCH >= 4 */ #define umul_ppmm(xh, xl, a, b) \ - __asm__ ("%@ Inlined umul_ppmm\n" \ - "umull %r1, %r0, %r2, %r3" \ - : "=&r" ((USItype)(xh)), \ - "=r" ((USItype)(xl)) \ + __asm__ ("@ Inlined umul_ppmm\n" \ + "umull %1, %0, %2, %3" \ + : "=&r" ((xh)), \ + "=r" ((xl)) \ : "r" ((USItype)(a)), \ - "r" ((USItype)(b)) \ - : "r0", "r1") + "r" ((USItype)(b))) #endif /* __ARM_ARCH >= 4 */ #define UMUL_TIME 20 #define UDIV_TIME 100 #if (defined __ARM_ARCH && __ARM_ARCH >= 5) #define count_leading_zeros(count, x) \ __asm__ ("clz %0, %1" \ - : "=r" ((USItype)(count)) \ + : "=r" ((count)) \ : "r" ((USItype)(x))) #endif /* __ARM_ARCH >= 5 */ #endif /* __arm__ */ commit c7efaa5fe0ee92e321a7b49d56752cc12eb75fe0 Author: Jussi Kivilinna Date: Tue Oct 22 17:07:53 2013 +0300 serpent-amd64: do not use GAS macros * cipher/serpent-avx2-amd64.S: Remove use of GAS macros. * cipher/serpent-sse2-amd64.S: Ditto. * configure.ac [HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS]: Do not check for GAS macros. -- This way we have better portability; for example, when compiling with clang on x86-64, the assembly implementations are now enabled and working. Signed-off-by: Jussi Kivilinna diff --git a/cipher/serpent-avx2-amd64.S b/cipher/serpent-avx2-amd64.S index c726e7b..8a76ab1 100644 --- a/cipher/serpent-avx2-amd64.S +++ b/cipher/serpent-avx2-amd64.S @@ -36,51 +36,36 @@ #define CTX %rdi /* vector registers */ -.set RA0, %ymm0 -.set RA1, %ymm1 -.set RA2, %ymm2 -.set RA3, %ymm3 -.set RA4, %ymm4 - -.set RB0, %ymm5 -.set RB1, %ymm6 -.set RB2, %ymm7 -.set RB3, %ymm8 -.set RB4, %ymm9 - -.set RNOT, %ymm10 -.set RTMP0, %ymm11 -.set RTMP1, %ymm12 -.set RTMP2, %ymm13 -.set RTMP3, %ymm14 -.set RTMP4, %ymm15 - -.set RNOTx, %xmm10 -.set RTMP0x, %xmm11 -.set RTMP1x, %xmm12 -.set RTMP2x, %xmm13 -.set RTMP3x, %xmm14 -.set RTMP4x, %xmm15 +#define RA0 %ymm0 +#define RA1 %ymm1 +#define RA2 %ymm2 +#define RA3 %ymm3 +#define RA4 %ymm4 + +#define RB0 %ymm5 +#define RB1 %ymm6 +#define RB2 %ymm7 +#define RB3 %ymm8 +#define RB4 %ymm9 + +#define RNOT %ymm10 +#define RTMP0 %ymm11 +#define RTMP1 %ymm12 +#define RTMP2 %ymm13 +#define RTMP3 %ymm14 +#define RTMP4 %ymm15 + +#define RNOTx %xmm10 +#define RTMP0x %xmm11 +#define RTMP1x %xmm12 +#define RTMP2x %xmm13 +#define RTMP3x %xmm14 +#define RTMP4x %xmm15 /********************************************************************** helper macros **********************************************************************/ -/* preprocessor macro for renaming vector registers using GAS macros */ -#define sbox_reg_rename(r0, r1, r2, r3, r4, \ - new_r0, new_r1, new_r2, new_r3, new_r4) \ - .set rename_reg0, new_r0; \ - .set rename_reg1, new_r1; \ - .set rename_reg2, new_r2; \ - .set rename_reg3, new_r3; \ - .set rename_reg4, new_r4; \ - \ - .set r0, rename_reg0; \ - .set r1, rename_reg1; \ - .set r2, rename_reg2; \ - .set r3, rename_reg3; \ - .set r4, rename_reg4; - /* vector 32-bit rotation to left */ #define vec_rol(reg, nleft, tmp) \ vpslld $(nleft), reg, tmp; \ @@ -128,9 +113,7 @@ vpxor r4, r2, r2; vpxor RNOT, r4, r4; \ vpor r1, r4, r4; vpxor r3, r1, r1; \ vpxor r4, r1, r1; vpor r0, r3, r3; \ - vpxor r3, r1, r1; vpxor r3, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r0,r3); + vpxor r3, r1, r1; vpxor r3, r4, r4; #define SBOX0_INVERSE(r0, r1, r2, r3, r4) \ vpxor RNOT, r2, r2; vmovdqa r1, r4; \ @@ -143,9 +126,7 @@ vpxor r1, r2, r2; vpxor r0, r3, r3; \ vpxor r1, r3, r3; \ vpand r3, r2, r2; \ - vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r4,r1,r3,r2); + vpxor r2, r4, r4; #define SBOX1(r0, r1, r2, r3, r4) \ vpxor RNOT, r0, r0; vpxor RNOT, r2, r2; \ @@ -157,9 +138,7 @@ vpand r4, r2, r2; vpxor r1, r0, r0; \ vpand r2, r1, r1; \ vpxor r0, r1, r1; vpand r2, r0, r0; \ - vpxor r4, r0, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r0,r3,r1,r4); + vpxor r4, r0, r0; #define SBOX1_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r1, r4; vpxor r3, r1, r1; \ @@ -172,9 +151,7 @@ vpxor r1, r4, r4; vpor r0, r1, r1; \ vpxor r0, r1, r1; \ vpor r4, r1, r1; \ - vpxor r1, r3, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r0,r3,r2,r1); + vpxor r1, r3, r3; #define SBOX2(r0, r1, r2, r3, r4) \ vmovdqa r0, r4; vpand r2, r0, r0; \ @@ -184,9 +161,7 @@ vmovdqa r3, r1; vpor r4, r3, r3; \ vpxor r0, r3, r3; vpand r1, r0, r0; \ vpxor r0, r4, r4; vpxor r3, r1, r1; \ - vpxor r4, r1, r1; vpxor RNOT, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r3,r1,r4,r0); + vpxor r4, r1, r1; vpxor RNOT, r4, r4; #define SBOX2_INVERSE(r0, r1, r2, r3, r4) \ vpxor r3, r2, r2; vpxor r0, r3, r3; \ @@ -198,9 +173,7 @@ vpor r0, r2, r2; vpxor RNOT, r3, r3; \ vpxor r3, r2, r2; vpxor r3, r0, r0; \ vpand r1, r0, r0; vpxor r4, r3, r3; \ - vpxor r0, r3, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r3,r0); + vpxor r0, r3, r3; #define SBOX3(r0, r1, r2, r3, r4) \ vmovdqa r0, r4; vpor r3, r0, r0; \ @@ -212,9 +185,7 @@ vpxor r2, r4, r4; vpor r0, r1, r1; \ vpxor r2, r1, r1; vpxor r3, r0, r0; \ vmovdqa r1, r2; vpor r3, r1, r1; \ - vpxor r0, r1, r1; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r3,r4,r0); + vpxor r0, r1, r1; #define SBOX3_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r2, r4; vpxor r1, r2, r2; \ @@ -226,9 +197,7 @@ vpxor r1, r3, r3; vpxor r0, r1, r1; \ vpor r2, r1, r1; vpxor r3, r0, r0; \ vpxor r4, r1, r1; \ - vpxor r1, r0, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r1,r3,r0,r4); + vpxor r1, r0, r0; #define SBOX4(r0, r1, r2, r3, r4) \ vpxor r3, r1, r1; vpxor RNOT, r3, r3; \ @@ -240,9 +209,7 @@ vpxor r0, r3, r3; vpor r1, r4, r4; \ vpxor r0, r4, r4; vpor r3, r0, r0; \ vpxor r2, r0, r0; vpand r3, r2, r2; \ - vpxor RNOT, r0, r0; vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r0,r3,r2); + vpxor RNOT, r0, r0; vpxor r2, r4, r4; #define SBOX4_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r2, r4; vpand r3, r2, r2; \ @@ -255,9 +222,7 @@ vpand r0, r2, r2; vpxor r0, r3, r3; \ vpxor r4, r2, r2; \ vpor r3, r2, r2; vpxor r0, r3, r3; \ - vpxor r1, r2, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r3,r2,r4,r1); + vpxor r1, r2, r2; #define SBOX5(r0, r1, r2, r3, r4) \ vpxor r1, r0, r0; vpxor r3, r1, r1; \ @@ -269,9 +234,7 @@ vpxor r2, r4, r4; vpxor r0, r2, r2; \ vpand r3, r0, r0; vpxor RNOT, r2, r2; \ vpxor r4, r0, r0; vpor r3, r4, r4; \ - vpxor r4, r2, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r3,r0,r2,r4); + vpxor r4, r2, r2; #define SBOX5_INVERSE(r0, r1, r2, r3, r4) \ vpxor RNOT, r1, r1; vmovdqa r3, r4; \ @@ -283,9 +246,7 @@ vpxor r3, r1, r1; vpxor r2, r4, r4; \ vpand r4, r3, r3; vpxor r1, r4, r4; \ vpxor r4, r3, r3; vpxor RNOT, r4, r4; \ - vpxor r0, r3, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r3,r2,r0); + vpxor r0, r3, r3; #define SBOX6(r0, r1, r2, r3, r4) \ vpxor RNOT, r2, r2; vmovdqa r3, r4; \ @@ -297,9 +258,7 @@ vpxor r2, r0, r0; vpxor r3, r4, r4; \ vpxor r0, r4, r4; vpxor RNOT, r3, r3; \ vpand r4, r2, r2; \ - vpxor r3, r2, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r1,r4,r2,r3); + vpxor r3, r2, r2; #define SBOX6_INVERSE(r0, r1, r2, r3, r4) \ vpxor r2, r0, r0; vmovdqa r2, r4; \ @@ -310,9 +269,7 @@ vpxor r1, r4, r4; vpand r3, r1, r1; \ vpxor r0, r1, r1; vpxor r3, r0, r0; \ vpor r2, r0, r0; vpxor r1, r3, r3; \ - vpxor r0, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r4,r3,r0); + vpxor r0, r4, r4; #define SBOX7(r0, r1, r2, r3, r4) \ vmovdqa r1, r4; vpor r2, r1, r1; \ @@ -325,9 +282,7 @@ vpxor r1, r2, r2; vpand r0, r1, r1; \ vpxor r4, r1, r1; vpxor RNOT, r2, r2; \ vpor r0, r2, r2; \ - vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r3,r1,r0,r2); + vpxor r2, r4, r4; #define SBOX7_INVERSE(r0, r1, r2, r3, r4) \ vmovdqa r2, r4; vpxor r0, r2, r2; \ @@ -339,9 +294,7 @@ vpor r2, r0, r0; vpxor r1, r4, r4; \ vpxor r3, r0, r0; vpxor r4, r3, r3; \ vpor r0, r4, r4; vpxor r2, r3, r3; \ - vpxor r2, r4, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r3,r0,r1,r4,r2); + vpxor r2, r4, r4; /* Apply SBOX number WHICH to to the block. */ #define SBOX(which, r0, r1, r2, r3, r4) \ @@ -402,49 +355,51 @@ /* Apply a Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - LINEAR_TRANSFORMATION (a0, a1, a2, a3, a4); \ - LINEAR_TRANSFORMATION (b0, b1, b2, b3, b4); \ - .set round, (round + 1); +#define ROUND(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + LINEAR_TRANSFORMATION (na0, na1, na2, na3, na4); \ + LINEAR_TRANSFORMATION (nb0, nb1, nb2, nb3, nb4); /* Apply the last Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND_LAST(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - .set round, (round + 1); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round + 1); +#define ROUND_LAST(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, ((round) + 1)); \ + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, ((round) + 1)); /* Apply an inverse Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ +#define ROUND_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ LINEAR_TRANSFORMATION_INVERSE (a0, a1, a2, a3, a4); \ LINEAR_TRANSFORMATION_INVERSE (b0, b1, b2, b3, b4); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); /* Apply the first inverse Serpent round to sixteen parallel blocks. This macro increments `round'. */ -#define ROUND_FIRST_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); \ +#define ROUND_FIRST_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, ((round) + 1)); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, ((round) + 1)); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); .text @@ -456,72 +411,82 @@ __serpent_enc_blk16: * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: sixteen parallel * plaintext blocks * output: - * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: sixteen parallel + * RA4, RA1, RA2, RA0, RB4, RB1, RB2, RB0: sixteen parallel * ciphertext blocks */ - /* record input vector names for __serpent_enc_blk16 */ - .set enc_in_a0, RA0 - .set enc_in_a1, RA1 - .set enc_in_a2, RA2 - .set enc_in_a3, RA3 - .set enc_in_b0, RB0 - .set enc_in_b1, RB1 - .set enc_in_b2, RB2 - .set enc_in_b3, RB3 - vpcmpeqd RNOT, RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 0 - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_LAST (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); - transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - - /* record output vector names for __serpent_enc_blk16 */ - .set enc_out_a0, RA0 - .set enc_out_a1, RA1 - .set enc_out_a2, RA2 - .set enc_out_a3, RA3 - .set enc_out_b0, RB0 - .set enc_out_b1, RB1 - .set enc_out_b2, RB2 - .set enc_out_b3, RB3 + ROUND (0, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (1, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (2, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (3, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (4, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (5, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (6, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND (7, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + ROUND (8, 0, RA4, RA1, RA2, RA0, RA3, RA1, RA3, RA2, RA4, RA0, + RB4, RB1, RB2, RB0, RB3, RB1, RB3, RB2, RB4, RB0); + ROUND (9, 1, RA1, RA3, RA2, RA4, RA0, RA2, RA1, RA4, RA3, RA0, + RB1, RB3, RB2, RB4, RB0, RB2, RB1, RB4, RB3, RB0); + ROUND (10, 2, RA2, RA1, RA4, RA3, RA0, RA4, RA3, RA1, RA0, RA2, + RB2, RB1, RB4, RB3, RB0, RB4, RB3, RB1, RB0, RB2); + ROUND (11, 3, RA4, RA3, RA1, RA0, RA2, RA3, RA1, RA0, RA2, RA4, + RB4, RB3, RB1, RB0, RB2, RB3, RB1, RB0, RB2, RB4); + ROUND (12, 4, RA3, RA1, RA0, RA2, RA4, RA1, RA4, RA3, RA2, RA0, + RB3, RB1, RB0, RB2, RB4, RB1, RB4, RB3, RB2, RB0); + ROUND (13, 5, RA1, RA4, RA3, RA2, RA0, RA4, RA2, RA1, RA3, RA0, + RB1, RB4, RB3, RB2, RB0, RB4, RB2, RB1, RB3, RB0); + ROUND (14, 6, RA4, RA2, RA1, RA3, RA0, RA4, RA2, RA0, RA1, RA3, + RB4, RB2, RB1, RB3, RB0, RB4, RB2, RB0, RB1, RB3); + ROUND (15, 7, RA4, RA2, RA0, RA1, RA3, RA3, RA1, RA2, RA4, RA0, + RB4, RB2, RB0, RB1, RB3, RB3, RB1, RB2, RB4, RB0); + ROUND (16, 0, RA3, RA1, RA2, RA4, RA0, RA1, RA0, RA2, RA3, RA4, + RB3, RB1, RB2, RB4, RB0, RB1, RB0, RB2, RB3, RB4); + ROUND (17, 1, RA1, RA0, RA2, RA3, RA4, RA2, RA1, RA3, RA0, RA4, + RB1, RB0, RB2, RB3, RB4, RB2, RB1, RB3, RB0, RB4); + ROUND (18, 2, RA2, RA1, RA3, RA0, RA4, RA3, RA0, RA1, RA4, RA2, + RB2, RB1, RB3, RB0, RB4, RB3, RB0, RB1, RB4, RB2); + ROUND (19, 3, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA4, RA2, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB4, RB2, RB3); + ROUND (20, 4, RA0, RA1, RA4, RA2, RA3, RA1, RA3, RA0, RA2, RA4, + RB0, RB1, RB4, RB2, RB3, RB1, RB3, RB0, RB2, RB4); + ROUND (21, 5, RA1, RA3, RA0, RA2, RA4, RA3, RA2, RA1, RA0, RA4, + RB1, RB3, RB0, RB2, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND (22, 6, RA3, RA2, RA1, RA0, RA4, RA3, RA2, RA4, RA1, RA0, + RB3, RB2, RB1, RB0, RB4, RB3, RB2, RB4, RB1, RB0); + ROUND (23, 7, RA3, RA2, RA4, RA1, RA0, RA0, RA1, RA2, RA3, RA4, + RB3, RB2, RB4, RB1, RB0, RB0, RB1, RB2, RB3, RB4); + ROUND (24, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (25, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (26, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (27, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (28, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (29, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (30, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND_LAST (31, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + + transpose_4x4(RA4, RA1, RA2, RA0, RA3, RTMP0, RTMP1); + transpose_4x4(RB4, RB1, RB2, RB0, RB3, RTMP0, RTMP1); ret; .size __serpent_enc_blk16,.-__serpent_enc_blk16; @@ -538,69 +503,81 @@ __serpent_dec_blk16: * plaintext blocks */ - /* record input vector names for __serpent_dec_blk16 */ - .set dec_in_a0, RA0 - .set dec_in_a1, RA1 - .set dec_in_a2, RA2 - .set dec_in_a3, RA3 - .set dec_in_b0, RB0 - .set dec_in_b1, RB1 - .set dec_in_b2, RB2 - .set dec_in_b3, RB3 - vpcmpeqd RNOT, RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 32 - ROUND_FIRST_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); + ROUND_FIRST_INVERSE (31, 7, RA0, RA1, RA2, RA3, RA4, + RA3, RA0, RA1, RA4, RA2, + RB0, RB1, RB2, RB3, RB4, + RB3, RB0, RB1, RB4, RB2); + ROUND_INVERSE (30, 6, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA2, RA4, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB2, RB4, RB3); + ROUND_INVERSE (29, 5, RA0, RA1, RA2, RA4, RA3, RA1, RA3, RA4, RA2, RA0, + RB0, RB1, RB2, RB4, RB3, RB1, RB3, RB4, RB2, RB0); + ROUND_INVERSE (28, 4, RA1, RA3, RA4, RA2, RA0, RA1, RA2, RA4, RA0, RA3, + RB1, RB3, RB4, RB2, RB0, RB1, RB2, RB4, RB0, RB3); + ROUND_INVERSE (27, 3, RA1, RA2, RA4, RA0, RA3, RA4, RA2, RA0, RA1, RA3, + RB1, RB2, RB4, RB0, RB3, RB4, RB2, RB0, RB1, RB3); + ROUND_INVERSE (26, 2, RA4, RA2, RA0, RA1, RA3, RA2, RA3, RA0, RA1, RA4, + RB4, RB2, RB0, RB1, RB3, RB2, RB3, RB0, RB1, RB4); + ROUND_INVERSE (25, 1, RA2, RA3, RA0, RA1, RA4, RA4, RA2, RA1, RA0, RA3, + RB2, RB3, RB0, RB1, RB4, RB4, RB2, RB1, RB0, RB3); + ROUND_INVERSE (24, 0, RA4, RA2, RA1, RA0, RA3, RA4, RA3, RA2, RA0, RA1, + RB4, RB2, RB1, RB0, RB3, RB4, RB3, RB2, RB0, RB1); + ROUND_INVERSE (23, 7, RA4, RA3, RA2, RA0, RA1, RA0, RA4, RA3, RA1, RA2, + RB4, RB3, RB2, RB0, RB1, RB0, RB4, RB3, RB1, RB2); + ROUND_INVERSE (22, 6, RA0, RA4, RA3, RA1, RA2, RA4, RA3, RA2, RA1, RA0, + RB0, RB4, RB3, RB1, RB2, RB4, RB3, RB2, RB1, RB0); + ROUND_INVERSE (21, 5, RA4, RA3, RA2, RA1, RA0, RA3, RA0, RA1, RA2, RA4, + RB4, RB3, RB2, RB1, RB0, RB3, RB0, RB1, RB2, RB4); + ROUND_INVERSE (20, 4, RA3, RA0, RA1, RA2, RA4, RA3, RA2, RA1, RA4, RA0, + RB3, RB0, RB1, RB2, RB4, RB3, RB2, RB1, RB4, RB0); + ROUND_INVERSE (19, 3, RA3, RA2, RA1, RA4, RA0, RA1, RA2, RA4, RA3, RA0, + RB3, RB2, RB1, RB4, RB0, RB1, RB2, RB4, RB3, RB0); + ROUND_INVERSE (18, 2, RA1, RA2, RA4, RA3, RA0, RA2, RA0, RA4, RA3, RA1, + RB1, RB2, RB4, RB3, RB0, RB2, RB0, RB4, RB3, RB1); + ROUND_INVERSE (17, 1, RA2, RA0, RA4, RA3, RA1, RA1, RA2, RA3, RA4, RA0, + RB2, RB0, RB4, RB3, RB1, RB1, RB2, RB3, RB4, RB0); + ROUND_INVERSE (16, 0, RA1, RA2, RA3, RA4, RA0, RA1, RA0, RA2, RA4, RA3, + RB1, RB2, RB3, RB4, RB0, RB1, RB0, RB2, RB4, RB3); + ROUND_INVERSE (15, 7, RA1, RA0, RA2, RA4, RA3, RA4, RA1, RA0, RA3, RA2, + RB1, RB0, RB2, RB4, RB3, RB4, RB1, RB0, RB3, RB2); + ROUND_INVERSE (14, 6, RA4, RA1, RA0, RA3, RA2, RA1, RA0, RA2, RA3, RA4, + RB4, RB1, RB0, RB3, RB2, RB1, RB0, RB2, RB3, RB4); + ROUND_INVERSE (13, 5, RA1, RA0, RA2, RA3, RA4, RA0, RA4, RA3, RA2, RA1, + RB1, RB0, RB2, RB3, RB4, RB0, RB4, RB3, RB2, RB1); + ROUND_INVERSE (12, 4, RA0, RA4, RA3, RA2, RA1, RA0, RA2, RA3, RA1, RA4, + RB0, RB4, RB3, RB2, RB1, RB0, RB2, RB3, RB1, RB4); + ROUND_INVERSE (11, 3, RA0, RA2, RA3, RA1, RA4, RA3, RA2, RA1, RA0, RA4, + RB0, RB2, RB3, RB1, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND_INVERSE (10, 2, RA3, RA2, RA1, RA0, RA4, RA2, RA4, RA1, RA0, RA3, + RB3, RB2, RB1, RB0, RB4, RB2, RB4, RB1, RB0, RB3); + ROUND_INVERSE (9, 1, RA2, RA4, RA1, RA0, RA3, RA3, RA2, RA0, RA1, RA4, + RB2, RB4, RB1, RB0, RB3, RB3, RB2, RB0, RB1, RB4); + ROUND_INVERSE (8, 0, RA3, RA2, RA0, RA1, RA4, RA3, RA4, RA2, RA1, RA0, + RB3, RB2, RB0, RB1, RB4, RB3, RB4, RB2, RB1, RB0); + ROUND_INVERSE (7, 7, RA3, RA4, RA2, RA1, RA0, RA1, RA3, RA4, RA0, RA2, + RB3, RB4, RB2, RB1, RB0, RB1, RB3, RB4, RB0, RB2); + ROUND_INVERSE (6, 6, RA1, RA3, RA4, RA0, RA2, RA3, RA4, RA2, RA0, RA1, + RB1, RB3, RB4, RB0, RB2, RB3, RB4, RB2, RB0, RB1); + ROUND_INVERSE (5, 5, RA3, RA4, RA2, RA0, RA1, RA4, RA1, RA0, RA2, RA3, + RB3, RB4, RB2, RB0, RB1, RB4, RB1, RB0, RB2, RB3); + ROUND_INVERSE (4, 4, RA4, RA1, RA0, RA2, RA3, RA4, RA2, RA0, RA3, RA1, + RB4, RB1, RB0, RB2, RB3, RB4, RB2, RB0, RB3, RB1); + ROUND_INVERSE (3, 3, RA4, RA2, RA0, RA3, RA1, RA0, RA2, RA3, RA4, RA1, + RB4, RB2, RB0, RB3, RB1, RB0, RB2, RB3, RB4, RB1); + ROUND_INVERSE (2, 2, RA0, RA2, RA3, RA4, RA1, RA2, RA1, RA3, RA4, RA0, + RB0, RB2, RB3, RB4, RB1, RB2, RB1, RB3, RB4, RB0); + ROUND_INVERSE (1, 1, RA2, RA1, RA3, RA4, RA0, RA0, RA2, RA4, RA3, RA1, + RB2, RB1, RB3, RB4, RB0, RB0, RB2, RB4, RB3, RB1); + ROUND_INVERSE (0, 0, RA0, RA2, RA4, RA3, RA1, RA0, RA1, RA2, RA3, RA4, + RB0, RB2, RB4, RB3, RB1, RB0, RB1, RB2, RB3, RB4); transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - /* record output vector names for __serpent_dec_blk16 */ - .set dec_out_a0, RA0 - .set dec_out_a1, RA1 - .set dec_out_a2, RA2 - .set dec_out_a3, RA3 - .set dec_out_b0, RB0 - .set dec_out_b1, RB1 - .set dec_out_b2, RB2 - .set dec_out_b3, RB3 - ret; .size __serpent_dec_blk16,.-__serpent_dec_blk16; @@ -623,15 +600,6 @@ _gcry_serpent_avx2_ctr_enc: vzeroupper; - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - vbroadcasti128 .Lbswap128_mask RIP, RTMP3; vpcmpeqd RNOT, RNOT, RNOT; vpsrldq $8, RNOT, RNOT; /* ab: -1:0 ; cd: -1:0 */ @@ -703,32 +671,23 @@ _gcry_serpent_avx2_ctr_enc: call __serpent_enc_blk16; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - vpxor (0 * 32)(%rdx), RA0, RA0; + vpxor (0 * 32)(%rdx), RA4, RA4; vpxor (1 * 32)(%rdx), RA1, RA1; vpxor (2 * 32)(%rdx), RA2, RA2; - vpxor (3 * 32)(%rdx), RA3, RA3; - vpxor (4 * 32)(%rdx), RB0, RB0; + vpxor (3 * 32)(%rdx), RA0, RA0; + vpxor (4 * 32)(%rdx), RB4, RB4; vpxor (5 * 32)(%rdx), RB1, RB1; vpxor (6 * 32)(%rdx), RB2, RB2; - vpxor (7 * 32)(%rdx), RB3, RB3; + vpxor (7 * 32)(%rdx), RB0, RB0; - vmovdqu RA0, (0 * 32)(%rsi); + vmovdqu RA4, (0 * 32)(%rsi); vmovdqu RA1, (1 * 32)(%rsi); vmovdqu RA2, (2 * 32)(%rsi); - vmovdqu RA3, (3 * 32)(%rsi); - vmovdqu RB0, (4 * 32)(%rsi); + vmovdqu RA0, (3 * 32)(%rsi); + vmovdqu RB4, (4 * 32)(%rsi); vmovdqu RB1, (5 * 32)(%rsi); vmovdqu RB2, (6 * 32)(%rsi); - vmovdqu RB3, (7 * 32)(%rsi); + vmovdqu RB0, (7 * 32)(%rsi); vzeroall; @@ -748,15 +707,6 @@ _gcry_serpent_avx2_cbc_dec: vzeroupper; - .set RA0, dec_in_a0 - .set RA1, dec_in_a1 - .set RA2, dec_in_a2 - .set RA3, dec_in_a3 - .set RB0, dec_in_b0 - .set RB1, dec_in_b1 - .set RB2, dec_in_b2 - .set RB3, dec_in_b3 - vmovdqu (0 * 32)(%rdx), RA0; vmovdqu (1 * 32)(%rdx), RA1; vmovdqu (2 * 32)(%rdx), RA2; @@ -768,15 +718,6 @@ _gcry_serpent_avx2_cbc_dec: call __serpent_dec_blk16; - .set RA0, dec_out_a0 - .set RA1, dec_out_a1 - .set RA2, dec_out_a2 - .set RA3, dec_out_a3 - .set RB0, dec_out_b0 - .set RB1, dec_out_b1 - .set RB2, dec_out_b2 - .set RB3, dec_out_b3 - vmovdqu (%rcx), RNOTx; vinserti128 $1, (%rdx), RNOT, RNOT; vpxor RNOT, RA0, RA0; @@ -817,15 +758,6 @@ _gcry_serpent_avx2_cfb_dec: vzeroupper; - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - /* Load input */ vmovdqu (%rcx), RNOTx; vinserti128 $1, (%rdx), RNOT, RA0; @@ -843,32 +775,23 @@ _gcry_serpent_avx2_cfb_dec: call __serpent_enc_blk16; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - vpxor (0 * 32)(%rdx), RA0, RA0; + vpxor (0 * 32)(%rdx), RA4, RA4; vpxor (1 * 32)(%rdx), RA1, RA1; vpxor (2 * 32)(%rdx), RA2, RA2; - vpxor (3 * 32)(%rdx), RA3, RA3; - vpxor (4 * 32)(%rdx), RB0, RB0; + vpxor (3 * 32)(%rdx), RA0, RA0; + vpxor (4 * 32)(%rdx), RB4, RB4; vpxor (5 * 32)(%rdx), RB1, RB1; vpxor (6 * 32)(%rdx), RB2, RB2; - vpxor (7 * 32)(%rdx), RB3, RB3; + vpxor (7 * 32)(%rdx), RB0, RB0; - vmovdqu RA0, (0 * 32)(%rsi); + vmovdqu RA4, (0 * 32)(%rsi); vmovdqu RA1, (1 * 32)(%rsi); vmovdqu RA2, (2 * 32)(%rsi); - vmovdqu RA3, (3 * 32)(%rsi); - vmovdqu RB0, (4 * 32)(%rsi); + vmovdqu RA0, (3 * 32)(%rsi); + vmovdqu RB4, (4 * 32)(%rsi); vmovdqu RB1, (5 * 32)(%rsi); vmovdqu RB2, (6 * 32)(%rsi); - vmovdqu RB3, (7 * 32)(%rsi); + vmovdqu RB0, (7 * 32)(%rsi); vzeroall; diff --git a/cipher/serpent-sse2-amd64.S b/cipher/serpent-sse2-amd64.S index a5cf353..516126b 100644 --- a/cipher/serpent-sse2-amd64.S +++ b/cipher/serpent-sse2-amd64.S @@ -35,42 +35,27 @@ #define CTX %rdi /* vector registers */ -.set RA0, %xmm0 -.set RA1, %xmm1 -.set RA2, %xmm2 -.set RA3, %xmm3 -.set RA4, %xmm4 - -.set RB0, %xmm5 -.set RB1, %xmm6 -.set RB2, %xmm7 -.set RB3, %xmm8 -.set RB4, %xmm9 - -.set RNOT, %xmm10 -.set RTMP0, %xmm11 -.set RTMP1, %xmm12 -.set RTMP2, %xmm13 +#define RA0 %xmm0 +#define RA1 %xmm1 +#define RA2 %xmm2 +#define RA3 %xmm3 +#define RA4 %xmm4 + +#define RB0 %xmm5 +#define RB1 %xmm6 +#define RB2 %xmm7 +#define RB3 %xmm8 +#define RB4 %xmm9 + +#define RNOT %xmm10 +#define RTMP0 %xmm11 +#define RTMP1 %xmm12 +#define RTMP2 %xmm13 /********************************************************************** helper macros **********************************************************************/ -/* preprocessor macro for renaming vector registers using GAS macros */ -#define sbox_reg_rename(r0, r1, r2, r3, r4, \ - new_r0, new_r1, new_r2, new_r3, new_r4) \ - .set rename_reg0, new_r0; \ - .set rename_reg1, new_r1; \ - .set rename_reg2, new_r2; \ - .set rename_reg3, new_r3; \ - .set rename_reg4, new_r4; \ - \ - .set r0, rename_reg0; \ - .set r1, rename_reg1; \ - .set r2, rename_reg2; \ - .set r3, rename_reg3; \ - .set r4, rename_reg4; - /* vector 32-bit rotation to left */ #define vec_rol(reg, nleft, tmp) \ movdqa reg, tmp; \ @@ -147,9 +132,7 @@ pxor r4, r2; pxor RNOT, r4; \ por r1, r4; pxor r3, r1; \ pxor r4, r1; por r0, r3; \ - pxor r3, r1; pxor r3, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r0,r3); + pxor r3, r1; pxor r3, r4; #define SBOX0_INVERSE(r0, r1, r2, r3, r4) \ pxor RNOT, r2; movdqa r1, r4; \ @@ -162,9 +145,7 @@ pxor r1, r2; pxor r0, r3; \ pxor r1, r3; \ pand r3, r2; \ - pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r4,r1,r3,r2); + pxor r2, r4; #define SBOX1(r0, r1, r2, r3, r4) \ pxor RNOT, r0; pxor RNOT, r2; \ @@ -176,9 +157,7 @@ pand r4, r2; pxor r1, r0; \ pand r2, r1; \ pxor r0, r1; pand r2, r0; \ - pxor r4, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r0,r3,r1,r4); + pxor r4, r0; #define SBOX1_INVERSE(r0, r1, r2, r3, r4) \ movdqa r1, r4; pxor r3, r1; \ @@ -191,9 +170,7 @@ pxor r1, r4; por r0, r1; \ pxor r0, r1; \ por r4, r1; \ - pxor r1, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r0,r3,r2,r1); + pxor r1, r3; #define SBOX2(r0, r1, r2, r3, r4) \ movdqa r0, r4; pand r2, r0; \ @@ -203,9 +180,7 @@ movdqa r3, r1; por r4, r3; \ pxor r0, r3; pand r1, r0; \ pxor r0, r4; pxor r3, r1; \ - pxor r4, r1; pxor RNOT, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r3,r1,r4,r0); + pxor r4, r1; pxor RNOT, r4; #define SBOX2_INVERSE(r0, r1, r2, r3, r4) \ pxor r3, r2; pxor r0, r3; \ @@ -217,9 +192,7 @@ por r0, r2; pxor RNOT, r3; \ pxor r3, r2; pxor r3, r0; \ pand r1, r0; pxor r4, r3; \ - pxor r0, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r2,r3,r0); + pxor r0, r3; #define SBOX3(r0, r1, r2, r3, r4) \ movdqa r0, r4; por r3, r0; \ @@ -231,9 +204,7 @@ pxor r2, r4; por r0, r1; \ pxor r2, r1; pxor r3, r0; \ movdqa r1, r2; por r3, r1; \ - pxor r0, r1; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r3,r4,r0); + pxor r0, r1; #define SBOX3_INVERSE(r0, r1, r2, r3, r4) \ movdqa r2, r4; pxor r1, r2; \ @@ -245,9 +216,7 @@ pxor r1, r3; pxor r0, r1; \ por r2, r1; pxor r3, r0; \ pxor r4, r1; \ - pxor r1, r0; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r2,r1,r3,r0,r4); + pxor r1, r0; #define SBOX4(r0, r1, r2, r3, r4) \ pxor r3, r1; pxor RNOT, r3; \ @@ -259,9 +228,7 @@ pxor r0, r3; por r1, r4; \ pxor r0, r4; por r3, r0; \ pxor r2, r0; pand r3, r2; \ - pxor RNOT, r0; pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r0,r3,r2); + pxor RNOT, r0; pxor r2, r4; #define SBOX4_INVERSE(r0, r1, r2, r3, r4) \ movdqa r2, r4; pand r3, r2; \ @@ -274,9 +241,7 @@ pand r0, r2; pxor r0, r3; \ pxor r4, r2; \ por r3, r2; pxor r0, r3; \ - pxor r1, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r3,r2,r4,r1); + pxor r1, r2; #define SBOX5(r0, r1, r2, r3, r4) \ pxor r1, r0; pxor r3, r1; \ @@ -288,9 +253,7 @@ pxor r2, r4; pxor r0, r2; \ pand r3, r0; pxor RNOT, r2; \ pxor r4, r0; por r3, r4; \ - pxor r4, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r3,r0,r2,r4); + pxor r4, r2; #define SBOX5_INVERSE(r0, r1, r2, r3, r4) \ pxor RNOT, r1; movdqa r3, r4; \ @@ -302,9 +265,7 @@ pxor r3, r1; pxor r2, r4; \ pand r4, r3; pxor r1, r4; \ pxor r4, r3; pxor RNOT, r4; \ - pxor r0, r3; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r4,r3,r2,r0); + pxor r0, r3; #define SBOX6(r0, r1, r2, r3, r4) \ pxor RNOT, r2; movdqa r3, r4; \ @@ -316,9 +277,7 @@ pxor r2, r0; pxor r3, r4; \ pxor r0, r4; pxor RNOT, r3; \ pand r4, r2; \ - pxor r3, r2; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r0,r1,r4,r2,r3); + pxor r3, r2; #define SBOX6_INVERSE(r0, r1, r2, r3, r4) \ pxor r2, r0; movdqa r2, r4; \ @@ -329,9 +288,7 @@ pxor r1, r4; pand r3, r1; \ pxor r0, r1; pxor r3, r0; \ por r2, r0; pxor r1, r3; \ - pxor r0, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r1,r2,r4,r3,r0); + pxor r0, r4; #define SBOX7(r0, r1, r2, r3, r4) \ movdqa r1, r4; por r2, r1; \ @@ -344,9 +301,7 @@ pxor r1, r2; pand r0, r1; \ pxor r4, r1; pxor RNOT, r2; \ por r0, r2; \ - pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r4,r3,r1,r0,r2); + pxor r2, r4; #define SBOX7_INVERSE(r0, r1, r2, r3, r4) \ movdqa r2, r4; pxor r0, r2; \ @@ -358,9 +313,7 @@ por r2, r0; pxor r1, r4; \ pxor r3, r0; pxor r4, r3; \ por r0, r4; pxor r2, r3; \ - pxor r2, r4; \ - \ - sbox_reg_rename(r0,r1,r2,r3,r4, r3,r0,r1,r4,r2); + pxor r2, r4; /* Apply SBOX number WHICH to to the block. */ #define SBOX(which, r0, r1, r2, r3, r4) \ @@ -425,49 +378,51 @@ /* Apply a Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - LINEAR_TRANSFORMATION (a0, a1, a2, a3, a4); \ - LINEAR_TRANSFORMATION (b0, b1, b2, b3, b4); \ - .set round, (round + 1); +#define ROUND(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + LINEAR_TRANSFORMATION (na0, na1, na2, na3, na4); \ + LINEAR_TRANSFORMATION (nb0, nb1, nb2, nb3, nb4); /* Apply the last Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND_LAST(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - SBOX (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - SBOX (which, b0, b1, b2, b3, b4); \ - .set round, (round + 1); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round + 1); +#define ROUND_LAST(round, which, a0, a1, a2, a3, a4, na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + SBOX (which, a0, a1, a2, a3, a4); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ + SBOX (which, b0, b1, b2, b3, b4); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, ((round) + 1)); \ + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, ((round) + 1)); /* Apply an inverse Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ +#define ROUND_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ LINEAR_TRANSFORMATION_INVERSE (a0, a1, a2, a3, a4); \ LINEAR_TRANSFORMATION_INVERSE (b0, b1, b2, b3, b4); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); /* Apply the first inverse Serpent round to eight parallel blocks. This macro increments `round'. */ -#define ROUND_FIRST_INVERSE(which, a0, a1, a2, a3, a4, b0, b1, b2, b3, b4) \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); \ +#define ROUND_FIRST_INVERSE(round, which, a0, a1, a2, a3, a4, \ + na0, na1, na2, na3, na4, \ + b0, b1, b2, b3, b4, \ + nb0, nb1, nb2, nb3, nb4) \ + BLOCK_XOR_KEY (a0, a1, a2, a3, a4, ((round) + 1)); \ + BLOCK_XOR_KEY (b0, b1, b2, b3, b4, ((round) + 1)); \ SBOX_INVERSE (which, a0, a1, a2, a3, a4); \ - BLOCK_XOR_KEY (a0, a1, a2, a3, a4, round); \ + BLOCK_XOR_KEY (na0, na1, na2, na3, na4, round); \ SBOX_INVERSE (which, b0, b1, b2, b3, b4); \ - BLOCK_XOR_KEY (b0, b1, b2, b3, b4, round); \ - .set round, (round - 1); + BLOCK_XOR_KEY (nb0, nb1, nb2, nb3, nb4, round); .text @@ -479,72 +434,82 @@ __serpent_enc_blk8: * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel plaintext * blocks * output: - * RA0, RA1, RA2, RA3, RB0, RB1, RB2, RB3: eight parallel + * RA4, RA1, RA2, RA0, RB4, RB1, RB2, RB0: eight parallel * ciphertext blocks */ - /* record input vector names for __serpent_enc_blk8 */ - .set enc_in_a0, RA0 - .set enc_in_a1, RA1 - .set enc_in_a2, RA2 - .set enc_in_a3, RA3 - .set enc_in_b0, RB0 - .set enc_in_b1, RB1 - .set enc_in_b2, RB2 - .set enc_in_b3, RB3 - pcmpeqd RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 0 - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_LAST (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); - transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - - /* record output vector names for __serpent_enc_blk8 */ - .set enc_out_a0, RA0 - .set enc_out_a1, RA1 - .set enc_out_a2, RA2 - .set enc_out_a3, RA3 - .set enc_out_b0, RB0 - .set enc_out_b1, RB1 - .set enc_out_b2, RB2 - .set enc_out_b3, RB3 + ROUND (0, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (1, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (2, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (3, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (4, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (5, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (6, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND (7, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + ROUND (8, 0, RA4, RA1, RA2, RA0, RA3, RA1, RA3, RA2, RA4, RA0, + RB4, RB1, RB2, RB0, RB3, RB1, RB3, RB2, RB4, RB0); + ROUND (9, 1, RA1, RA3, RA2, RA4, RA0, RA2, RA1, RA4, RA3, RA0, + RB1, RB3, RB2, RB4, RB0, RB2, RB1, RB4, RB3, RB0); + ROUND (10, 2, RA2, RA1, RA4, RA3, RA0, RA4, RA3, RA1, RA0, RA2, + RB2, RB1, RB4, RB3, RB0, RB4, RB3, RB1, RB0, RB2); + ROUND (11, 3, RA4, RA3, RA1, RA0, RA2, RA3, RA1, RA0, RA2, RA4, + RB4, RB3, RB1, RB0, RB2, RB3, RB1, RB0, RB2, RB4); + ROUND (12, 4, RA3, RA1, RA0, RA2, RA4, RA1, RA4, RA3, RA2, RA0, + RB3, RB1, RB0, RB2, RB4, RB1, RB4, RB3, RB2, RB0); + ROUND (13, 5, RA1, RA4, RA3, RA2, RA0, RA4, RA2, RA1, RA3, RA0, + RB1, RB4, RB3, RB2, RB0, RB4, RB2, RB1, RB3, RB0); + ROUND (14, 6, RA4, RA2, RA1, RA3, RA0, RA4, RA2, RA0, RA1, RA3, + RB4, RB2, RB1, RB3, RB0, RB4, RB2, RB0, RB1, RB3); + ROUND (15, 7, RA4, RA2, RA0, RA1, RA3, RA3, RA1, RA2, RA4, RA0, + RB4, RB2, RB0, RB1, RB3, RB3, RB1, RB2, RB4, RB0); + ROUND (16, 0, RA3, RA1, RA2, RA4, RA0, RA1, RA0, RA2, RA3, RA4, + RB3, RB1, RB2, RB4, RB0, RB1, RB0, RB2, RB3, RB4); + ROUND (17, 1, RA1, RA0, RA2, RA3, RA4, RA2, RA1, RA3, RA0, RA4, + RB1, RB0, RB2, RB3, RB4, RB2, RB1, RB3, RB0, RB4); + ROUND (18, 2, RA2, RA1, RA3, RA0, RA4, RA3, RA0, RA1, RA4, RA2, + RB2, RB1, RB3, RB0, RB4, RB3, RB0, RB1, RB4, RB2); + ROUND (19, 3, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA4, RA2, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB4, RB2, RB3); + ROUND (20, 4, RA0, RA1, RA4, RA2, RA3, RA1, RA3, RA0, RA2, RA4, + RB0, RB1, RB4, RB2, RB3, RB1, RB3, RB0, RB2, RB4); + ROUND (21, 5, RA1, RA3, RA0, RA2, RA4, RA3, RA2, RA1, RA0, RA4, + RB1, RB3, RB0, RB2, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND (22, 6, RA3, RA2, RA1, RA0, RA4, RA3, RA2, RA4, RA1, RA0, + RB3, RB2, RB1, RB0, RB4, RB3, RB2, RB4, RB1, RB0); + ROUND (23, 7, RA3, RA2, RA4, RA1, RA0, RA0, RA1, RA2, RA3, RA4, + RB3, RB2, RB4, RB1, RB0, RB0, RB1, RB2, RB3, RB4); + ROUND (24, 0, RA0, RA1, RA2, RA3, RA4, RA1, RA4, RA2, RA0, RA3, + RB0, RB1, RB2, RB3, RB4, RB1, RB4, RB2, RB0, RB3); + ROUND (25, 1, RA1, RA4, RA2, RA0, RA3, RA2, RA1, RA0, RA4, RA3, + RB1, RB4, RB2, RB0, RB3, RB2, RB1, RB0, RB4, RB3); + ROUND (26, 2, RA2, RA1, RA0, RA4, RA3, RA0, RA4, RA1, RA3, RA2, + RB2, RB1, RB0, RB4, RB3, RB0, RB4, RB1, RB3, RB2); + ROUND (27, 3, RA0, RA4, RA1, RA3, RA2, RA4, RA1, RA3, RA2, RA0, + RB0, RB4, RB1, RB3, RB2, RB4, RB1, RB3, RB2, RB0); + ROUND (28, 4, RA4, RA1, RA3, RA2, RA0, RA1, RA0, RA4, RA2, RA3, + RB4, RB1, RB3, RB2, RB0, RB1, RB0, RB4, RB2, RB3); + ROUND (29, 5, RA1, RA0, RA4, RA2, RA3, RA0, RA2, RA1, RA4, RA3, + RB1, RB0, RB4, RB2, RB3, RB0, RB2, RB1, RB4, RB3); + ROUND (30, 6, RA0, RA2, RA1, RA4, RA3, RA0, RA2, RA3, RA1, RA4, + RB0, RB2, RB1, RB4, RB3, RB0, RB2, RB3, RB1, RB4); + ROUND_LAST (31, 7, RA0, RA2, RA3, RA1, RA4, RA4, RA1, RA2, RA0, RA3, + RB0, RB2, RB3, RB1, RB4, RB4, RB1, RB2, RB0, RB3); + + transpose_4x4(RA4, RA1, RA2, RA0, RA3, RTMP0, RTMP1); + transpose_4x4(RB4, RB1, RB2, RB0, RB3, RTMP0, RTMP1); ret; .size __serpent_enc_blk8,.-__serpent_enc_blk8; @@ -561,69 +526,81 @@ __serpent_dec_blk8: * blocks */ - /* record input vector names for __serpent_dec_blk8 */ - .set dec_in_a0, RA0 - .set dec_in_a1, RA1 - .set dec_in_a2, RA2 - .set dec_in_a3, RA3 - .set dec_in_b0, RB0 - .set dec_in_b1, RB1 - .set dec_in_b2, RB2 - .set dec_in_b3, RB3 - pcmpeqd RNOT, RNOT; transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - .set round, 32 - ROUND_FIRST_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (7, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (6, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (5, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (4, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (3, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (2, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (1, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); - ROUND_INVERSE (0, RA0, RA1, RA2, RA3, RA4, RB0, RB1, RB2, RB3, RB4); + ROUND_FIRST_INVERSE (31, 7, RA0, RA1, RA2, RA3, RA4, + RA3, RA0, RA1, RA4, RA2, + RB0, RB1, RB2, RB3, RB4, + RB3, RB0, RB1, RB4, RB2); + ROUND_INVERSE (30, 6, RA3, RA0, RA1, RA4, RA2, RA0, RA1, RA2, RA4, RA3, + RB3, RB0, RB1, RB4, RB2, RB0, RB1, RB2, RB4, RB3); + ROUND_INVERSE (29, 5, RA0, RA1, RA2, RA4, RA3, RA1, RA3, RA4, RA2, RA0, + RB0, RB1, RB2, RB4, RB3, RB1, RB3, RB4, RB2, RB0); + ROUND_INVERSE (28, 4, RA1, RA3, RA4, RA2, RA0, RA1, RA2, RA4, RA0, RA3, + RB1, RB3, RB4, RB2, RB0, RB1, RB2, RB4, RB0, RB3); + ROUND_INVERSE (27, 3, RA1, RA2, RA4, RA0, RA3, RA4, RA2, RA0, RA1, RA3, + RB1, RB2, RB4, RB0, RB3, RB4, RB2, RB0, RB1, RB3); + ROUND_INVERSE (26, 2, RA4, RA2, RA0, RA1, RA3, RA2, RA3, RA0, RA1, RA4, + RB4, RB2, RB0, RB1, RB3, RB2, RB3, RB0, RB1, RB4); + ROUND_INVERSE (25, 1, RA2, RA3, RA0, RA1, RA4, RA4, RA2, RA1, RA0, RA3, + RB2, RB3, RB0, RB1, RB4, RB4, RB2, RB1, RB0, RB3); + ROUND_INVERSE (24, 0, RA4, RA2, RA1, RA0, RA3, RA4, RA3, RA2, RA0, RA1, + RB4, RB2, RB1, RB0, RB3, RB4, RB3, RB2, RB0, RB1); + ROUND_INVERSE (23, 7, RA4, RA3, RA2, RA0, RA1, RA0, RA4, RA3, RA1, RA2, + RB4, RB3, RB2, RB0, RB1, RB0, RB4, RB3, RB1, RB2); + ROUND_INVERSE (22, 6, RA0, RA4, RA3, RA1, RA2, RA4, RA3, RA2, RA1, RA0, + RB0, RB4, RB3, RB1, RB2, RB4, RB3, RB2, RB1, RB0); + ROUND_INVERSE (21, 5, RA4, RA3, RA2, RA1, RA0, RA3, RA0, RA1, RA2, RA4, + RB4, RB3, RB2, RB1, RB0, RB3, RB0, RB1, RB2, RB4); + ROUND_INVERSE (20, 4, RA3, RA0, RA1, RA2, RA4, RA3, RA2, RA1, RA4, RA0, + RB3, RB0, RB1, RB2, RB4, RB3, RB2, RB1, RB4, RB0); + ROUND_INVERSE (19, 3, RA3, RA2, RA1, RA4, RA0, RA1, RA2, RA4, RA3, RA0, + RB3, RB2, RB1, RB4, RB0, RB1, RB2, RB4, RB3, RB0); + ROUND_INVERSE (18, 2, RA1, RA2, RA4, RA3, RA0, RA2, RA0, RA4, RA3, RA1, + RB1, RB2, RB4, RB3, RB0, RB2, RB0, RB4, RB3, RB1); + ROUND_INVERSE (17, 1, RA2, RA0, RA4, RA3, RA1, RA1, RA2, RA3, RA4, RA0, + RB2, RB0, RB4, RB3, RB1, RB1, RB2, RB3, RB4, RB0); + ROUND_INVERSE (16, 0, RA1, RA2, RA3, RA4, RA0, RA1, RA0, RA2, RA4, RA3, + RB1, RB2, RB3, RB4, RB0, RB1, RB0, RB2, RB4, RB3); + ROUND_INVERSE (15, 7, RA1, RA0, RA2, RA4, RA3, RA4, RA1, RA0, RA3, RA2, + RB1, RB0, RB2, RB4, RB3, RB4, RB1, RB0, RB3, RB2); + ROUND_INVERSE (14, 6, RA4, RA1, RA0, RA3, RA2, RA1, RA0, RA2, RA3, RA4, + RB4, RB1, RB0, RB3, RB2, RB1, RB0, RB2, RB3, RB4); + ROUND_INVERSE (13, 5, RA1, RA0, RA2, RA3, RA4, RA0, RA4, RA3, RA2, RA1, + RB1, RB0, RB2, RB3, RB4, RB0, RB4, RB3, RB2, RB1); + ROUND_INVERSE (12, 4, RA0, RA4, RA3, RA2, RA1, RA0, RA2, RA3, RA1, RA4, + RB0, RB4, RB3, RB2, RB1, RB0, RB2, RB3, RB1, RB4); + ROUND_INVERSE (11, 3, RA0, RA2, RA3, RA1, RA4, RA3, RA2, RA1, RA0, RA4, + RB0, RB2, RB3, RB1, RB4, RB3, RB2, RB1, RB0, RB4); + ROUND_INVERSE (10, 2, RA3, RA2, RA1, RA0, RA4, RA2, RA4, RA1, RA0, RA3, + RB3, RB2, RB1, RB0, RB4, RB2, RB4, RB1, RB0, RB3); + ROUND_INVERSE (9, 1, RA2, RA4, RA1, RA0, RA3, RA3, RA2, RA0, RA1, RA4, + RB2, RB4, RB1, RB0, RB3, RB3, RB2, RB0, RB1, RB4); + ROUND_INVERSE (8, 0, RA3, RA2, RA0, RA1, RA4, RA3, RA4, RA2, RA1, RA0, + RB3, RB2, RB0, RB1, RB4, RB3, RB4, RB2, RB1, RB0); + ROUND_INVERSE (7, 7, RA3, RA4, RA2, RA1, RA0, RA1, RA3, RA4, RA0, RA2, + RB3, RB4, RB2, RB1, RB0, RB1, RB3, RB4, RB0, RB2); + ROUND_INVERSE (6, 6, RA1, RA3, RA4, RA0, RA2, RA3, RA4, RA2, RA0, RA1, + RB1, RB3, RB4, RB0, RB2, RB3, RB4, RB2, RB0, RB1); + ROUND_INVERSE (5, 5, RA3, RA4, RA2, RA0, RA1, RA4, RA1, RA0, RA2, RA3, + RB3, RB4, RB2, RB0, RB1, RB4, RB1, RB0, RB2, RB3); + ROUND_INVERSE (4, 4, RA4, RA1, RA0, RA2, RA3, RA4, RA2, RA0, RA3, RA1, + RB4, RB1, RB0, RB2, RB3, RB4, RB2, RB0, RB3, RB1); + ROUND_INVERSE (3, 3, RA4, RA2, RA0, RA3, RA1, RA0, RA2, RA3, RA4, RA1, + RB4, RB2, RB0, RB3, RB1, RB0, RB2, RB3, RB4, RB1); + ROUND_INVERSE (2, 2, RA0, RA2, RA3, RA4, RA1, RA2, RA1, RA3, RA4, RA0, + RB0, RB2, RB3, RB4, RB1, RB2, RB1, RB3, RB4, RB0); + ROUND_INVERSE (1, 1, RA2, RA1, RA3, RA4, RA0, RA0, RA2, RA4, RA3, RA1, + RB2, RB1, RB3, RB4, RB0, RB0, RB2, RB4, RB3, RB1); + ROUND_INVERSE (0, 0, RA0, RA2, RA4, RA3, RA1, RA0, RA1, RA2, RA3, RA4, + RB0, RB2, RB4, RB3, RB1, RB0, RB1, RB2, RB3, RB4); transpose_4x4(RA0, RA1, RA2, RA3, RA4, RTMP0, RTMP1); transpose_4x4(RB0, RB1, RB2, RB3, RB4, RTMP0, RTMP1); - /* record output vector names for __serpent_dec_blk8 */ - .set dec_out_a0, RA0 - .set dec_out_a1, RA1 - .set dec_out_a2, RA2 - .set dec_out_a3, RA3 - .set dec_out_b0, RB0 - .set dec_out_b1, RB1 - .set dec_out_b2, RB2 - .set dec_out_b3, RB3 - ret; .size __serpent_dec_blk8,.-__serpent_dec_blk8; @@ -638,15 +615,6 @@ _gcry_serpent_sse2_ctr_enc: * %rcx: iv (big endian, 128bit) */ - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - /* load IV and byteswap */ movdqu (%rcx), RA0; movdqa RA0, RTMP0; @@ -729,42 +697,35 @@ _gcry_serpent_sse2_ctr_enc: call __serpent_enc_blk8; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - pxor_u((0 * 16)(%rdx), RA0, RTMP0); + pxor_u((0 * 16)(%rdx), RA4, RTMP0); pxor_u((1 * 16)(%rdx), RA1, RTMP0); pxor_u((2 * 16)(%rdx), RA2, RTMP0); - pxor_u((3 * 16)(%rdx), RA3, RTMP0); - pxor_u((4 * 16)(%rdx), RB0, RTMP0); + pxor_u((3 * 16)(%rdx), RA0, RTMP0); + pxor_u((4 * 16)(%rdx), RB4, RTMP0); pxor_u((5 * 16)(%rdx), RB1, RTMP0); pxor_u((6 * 16)(%rdx), RB2, RTMP0); - pxor_u((7 * 16)(%rdx), RB3, RTMP0); + pxor_u((7 * 16)(%rdx), RB0, RTMP0); - movdqu RA0, (0 * 16)(%rsi); + movdqu RA4, (0 * 16)(%rsi); movdqu RA1, (1 * 16)(%rsi); movdqu RA2, (2 * 16)(%rsi); - movdqu RA3, (3 * 16)(%rsi); - movdqu RB0, (4 * 16)(%rsi); + movdqu RA0, (3 * 16)(%rsi); + movdqu RB4, (4 * 16)(%rsi); movdqu RB1, (5 * 16)(%rsi); movdqu RB2, (6 * 16)(%rsi); - movdqu RB3, (7 * 16)(%rsi); + movdqu RB0, (7 * 16)(%rsi); /* clear the used registers */ pxor RA0, RA0; pxor RA1, RA1; pxor RA2, RA2; pxor RA3, RA3; + pxor RA4, RA4; pxor RB0, RB0; pxor RB1, RB1; pxor RB2, RB2; pxor RB3, RB3; + pxor RB4, RB4; pxor RTMP0, RTMP0; pxor RTMP1, RTMP1; pxor RTMP2, RTMP2; @@ -784,15 +745,6 @@ _gcry_serpent_sse2_cbc_dec: * %rcx: iv */ - .set RA0, dec_in_a0 - .set RA1, dec_in_a1 - .set RA2, dec_in_a2 - .set RA3, dec_in_a3 - .set RB0, dec_in_b0 - .set RB1, dec_in_b1 - .set RB2, dec_in_b2 - .set RB3, dec_in_b3 - movdqu (0 * 16)(%rdx), RA0; movdqu (1 * 16)(%rdx), RA1; movdqu (2 * 16)(%rdx), RA2; @@ -804,15 +756,6 @@ _gcry_serpent_sse2_cbc_dec: call __serpent_dec_blk8; - .set RA0, dec_out_a0 - .set RA1, dec_out_a1 - .set RA2, dec_out_a2 - .set RA3, dec_out_a3 - .set RB0, dec_out_b0 - .set RB1, dec_out_b1 - .set RB2, dec_out_b2 - .set RB3, dec_out_b3 - movdqu (7 * 16)(%rdx), RNOT; pxor_u((%rcx), RA0, RTMP0); pxor_u((0 * 16)(%rdx), RA1, RTMP0); @@ -838,10 +781,12 @@ _gcry_serpent_sse2_cbc_dec: pxor RA1, RA1; pxor RA2, RA2; pxor RA3, RA3; + pxor RA4, RA4; pxor RB0, RB0; pxor RB1, RB1; pxor RB2, RB2; pxor RB3, RB3; + pxor RB4, RB4; pxor RTMP0, RTMP0; pxor RTMP1, RTMP1; pxor RTMP2, RTMP2; @@ -861,15 +806,6 @@ _gcry_serpent_sse2_cfb_dec: * %rcx: iv */ - .set RA0, enc_in_a0 - .set RA1, enc_in_a1 - .set RA2, enc_in_a2 - .set RA3, enc_in_a3 - .set RB0, enc_in_b0 - .set RB1, enc_in_b1 - .set RB2, enc_in_b2 - .set RB3, enc_in_b3 - /* Load input */ movdqu (%rcx), RA0; movdqu 0 * 16(%rdx), RA1; @@ -886,42 +822,35 @@ _gcry_serpent_sse2_cfb_dec: call __serpent_enc_blk8; - .set RA0, enc_out_a0 - .set RA1, enc_out_a1 - .set RA2, enc_out_a2 - .set RA3, enc_out_a3 - .set RB0, enc_out_b0 - .set RB1, enc_out_b1 - .set RB2, enc_out_b2 - .set RB3, enc_out_b3 - - pxor_u((0 * 16)(%rdx), RA0, RTMP0); + pxor_u((0 * 16)(%rdx), RA4, RTMP0); pxor_u((1 * 16)(%rdx), RA1, RTMP0); pxor_u((2 * 16)(%rdx), RA2, RTMP0); - pxor_u((3 * 16)(%rdx), RA3, RTMP0); - pxor_u((4 * 16)(%rdx), RB0, RTMP0); + pxor_u((3 * 16)(%rdx), RA0, RTMP0); + pxor_u((4 * 16)(%rdx), RB4, RTMP0); pxor_u((5 * 16)(%rdx), RB1, RTMP0); pxor_u((6 * 16)(%rdx), RB2, RTMP0); - pxor_u((7 * 16)(%rdx), RB3, RTMP0); + pxor_u((7 * 16)(%rdx), RB0, RTMP0); - movdqu RA0, (0 * 16)(%rsi); + movdqu RA4, (0 * 16)(%rsi); movdqu RA1, (1 * 16)(%rsi); movdqu RA2, (2 * 16)(%rsi); - movdqu RA3, (3 * 16)(%rsi); - movdqu RB0, (4 * 16)(%rsi); + movdqu RA0, (3 * 16)(%rsi); + movdqu RB4, (4 * 16)(%rsi); movdqu RB1, (5 * 16)(%rsi); movdqu RB2, (6 * 16)(%rsi); - movdqu RB3, (7 * 16)(%rsi); + movdqu RB0, (7 * 16)(%rsi); /* clear the used registers */ pxor RA0, RA0; pxor RA1, RA1; pxor RA2, RA2; pxor RA3, RA3; + pxor RA4, RA4; pxor RB0, RB0; pxor RB1, RB1; pxor RB2, RB2; pxor RB3, RB3; + pxor RB4, RB4; pxor RTMP0, RTMP0; pxor RTMP1, RTMP1; pxor RTMP2, RTMP2; diff --git a/configure.ac b/configure.ac index 1460dfd..8fb14e2 100644 --- a/configure.ac +++ b/configure.ac @@ -1034,17 +1034,12 @@ if test $amd64_as_feature_detection = yes; then [gcry_cv_gcc_amd64_platform_as_ok=no AC_COMPILE_IFELSE([AC_LANG_SOURCE( [[__asm__( - /* Test if '.set' is supported by underlying assembler. */ - ".set a0, %rax\n\t" - ".set b0, %rdx\n\t" - "asmfunc:\n\t" - "movq a0, b0;\n\t" /* Fails here if .set ignored by as. */ - /* Test if '.type' and '.size' are supported. */ /* These work only on ELF targets. */ /* TODO: add COFF (mingw64, cygwin64) support to assembly * implementations. Mingw64/cygwin64 also require additional * work because they use different calling convention. */ + "asmfunc:\n\t" ".size asmfunc,.-asmfunc;\n\t" ".type asmfunc, at function;\n\t" );]])], ----------------------------------------------------------------------- Summary of changes: cipher/Makefile.am | 2 +- cipher/serpent-avx2-amd64.S | 519 ++++++++++++++++++------------------------- cipher/serpent-sse2-amd64.S | 507 ++++++++++++++++++------------------------ cipher/twofish-armv6.S | 365 ++++++++++++++++++++++++++++++ cipher/twofish.c | 88 +++++--- configure.ac | 11 +- mpi/longlong.h | 27 ++- 7 files changed, 885 insertions(+), 634 deletions(-) create mode 100644 cipher/twofish-armv6.S hooks/post-receive -- The GNU crypto library http://git.gnupg.org _______________________________________________ Gnupg-commits mailing list Gnupg-commits at gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-commits From dbaryshkov at gmail.com Tue Oct 22 21:29:25 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Tue, 22 Oct 2013 23:29:25 +0400 Subject: [PATCH 1/3] Correct ASM assembly test in configure.ac Message-ID: <1382470167-11975-1-git-send-email-dbaryshkov@gmail.com> * configure.ac: correct HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS test to require neither ARMv6, nor thumb mode. Our assembly code works perfectly even on ARMv4 now. Signed-off-by: Dmitry Eremin-Solenikov --- configure.ac | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 739a650..58916e8 100644 --- a/configure.ac +++ b/configure.ac @@ -1109,11 +1109,10 @@ AC_CACHE_CHECK([whether GCC assembler is compatible for ARM assembly implementat [[__asm__( /* Test if assembler supports UAL syntax. */ ".syntax unified\n\t" - ".thumb\n\t" /* thumb-2 in UAL, thumb-1 otherwise. */ - ".code 16\n\t" + ".arm\n\t" /* our assembly code is in ARM mode */ /* Following causes error if assembler ignored '.syntax unified'. */ "asmfunc:\n\t" - "add.w %r0, %r4, %r8, ror #12;\n\t" + "add %r0, %r0, %r4, ror #12;\n\t" /* Test if '.type' and '.size' are supported. */ ".size asmfunc,.-asmfunc;\n\t" -- 1.8.4.rc3 From dbaryshkov at gmail.com Tue Oct 22 21:29:26 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Tue, 22 Oct 2013 23:29:26 +0400 Subject: [PATCH 2/3] mpi: enable assembler on all arm architectures In-Reply-To: <1382470167-11975-1-git-send-email-dbaryshkov@gmail.com> References: <1382470167-11975-1-git-send-email-dbaryshkov@gmail.com> Message-ID: <1382470167-11975-2-git-send-email-dbaryshkov@gmail.com> * mpi/config.links: remove check for arm >= v6 * mpi/armv6 => mpi/arm: rename directory to reflect that is is generic enough -- MPI ARM assembly do not depend on CPU being armv6. Verified on PXA255: Before: Algorithm generate 100*sign 100*verify ------------------------------------------------ RSA 1024 bit 3990ms 57980ms 1680ms RSA 2048 bit 59620ms 389430ms 5690ms RSA 3072 bit 535850ms 1223200ms 12000ms RSA 4096 bit 449350ms 2707370ms 20050ms After: Algorithm generate 100*sign 100*verify ------------------------------------------------ RSA 1024 bit 2190ms 13730ms 320ms RSA 2048 bit 12750ms 67640ms 810ms RSA 3072 bit 110520ms 166100ms 1350ms RSA 4096 bit 100870ms 357560ms 2170ms Signed-off-by: Dmitry Eremin-Solenikov --- mpi/arm/mpi-asm-defs.h | 4 ++ mpi/arm/mpih-add1.S | 76 +++++++++++++++++++++++++++++++++++ mpi/arm/mpih-mul1.S | 80 +++++++++++++++++++++++++++++++++++++ mpi/arm/mpih-mul2.S | 94 ++++++++++++++++++++++++++++++++++++++++++++ mpi/arm/mpih-mul3.S | 100 +++++++++++++++++++++++++++++++++++++++++++++++ mpi/arm/mpih-sub1.S | 77 ++++++++++++++++++++++++++++++++++++ mpi/armv6/mpi-asm-defs.h | 4 -- mpi/armv6/mpih-add1.S | 76 ----------------------------------- mpi/armv6/mpih-mul1.S | 80 ------------------------------------- mpi/armv6/mpih-mul2.S | 94 -------------------------------------------- mpi/armv6/mpih-mul3.S | 100 ----------------------------------------------- mpi/armv6/mpih-sub1.S | 77 ------------------------------------ mpi/config.links | 11 ++---- 13 files changed, 434 insertions(+), 439 deletions(-) create mode 100644 mpi/arm/mpi-asm-defs.h create mode 100644 mpi/arm/mpih-add1.S create mode 100644 mpi/arm/mpih-mul1.S create mode 100644 mpi/arm/mpih-mul2.S create mode 100644 mpi/arm/mpih-mul3.S create mode 100644 mpi/arm/mpih-sub1.S delete mode 100644 mpi/armv6/mpi-asm-defs.h delete mode 100644 mpi/armv6/mpih-add1.S delete mode 100644 mpi/armv6/mpih-mul1.S delete mode 100644 mpi/armv6/mpih-mul2.S delete mode 100644 mpi/armv6/mpih-mul3.S delete mode 100644 mpi/armv6/mpih-sub1.S diff --git a/mpi/arm/mpi-asm-defs.h b/mpi/arm/mpi-asm-defs.h new file mode 100644 index 0000000..047d1f5 --- /dev/null +++ b/mpi/arm/mpi-asm-defs.h @@ -0,0 +1,4 @@ +/* This file defines some basic constants for the MPI machinery. We + * need to define the types on a per-CPU basis, so it is done with + * this file here. */ +#define BYTES_PER_MPI_LIMB (SIZEOF_UNSIGNED_LONG) diff --git a/mpi/arm/mpih-add1.S b/mpi/arm/mpih-add1.S new file mode 100644 index 0000000..60ea4c3 --- /dev/null +++ b/mpi/arm/mpih-add1.S @@ -0,0 +1,76 @@ +/* ARMv6 add_n -- Add two limb vectors of the same length > 0 and store + * sum in a third limb vector. + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * Note: This code is heavily based on the GNU MP Library (version 4.2.1). + */ + +#include "sysdep.h" +#include "asm-syntax.h" + +.syntax unified +.arm + +/******************* + * mpi_limb_t + * _gcry_mpih_add_n( mpi_ptr_t res_ptr, %r0 + * mpi_ptr_t s1_ptr, %r1 + * mpi_ptr_t s2_ptr, %r2 + * mpi_size_t size) %r3 + */ + +.text + +.globl _gcry_mpih_add_n +.type _gcry_mpih_add_n,%function +_gcry_mpih_add_n: + push {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %lr}; + cmn %r0, #0; /* clear carry flag */ + + tst %r3, #3; + beq .Large_loop; + +.Loop: + ldr %r4, [%r1], #4; + sub %r3, #1; + ldr %lr, [%r2], #4; + adcs %r4, %lr; + tst %r3, #3; + str %r4, [%r0], #4; + bne .Loop; + + teq %r3, #0; + beq .Lend; + +.Large_loop: + ldm %r1!, {%r4, %r6, %r8, %r10}; + ldm %r2!, {%r5, %r7, %r9, %lr}; + sub %r3, #4; + adcs %r4, %r5; + adcs %r6, %r7; + adcs %r8, %r9; + adcs %r10, %lr; + teq %r3, #0; + stm %r0!, {%r4, %r6, %r8, %r10}; + bne .Large_loop; + +.Lend: + adc %r0, %r3, #0; + pop {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %pc}; +.size _gcry_mpih_add_n,.-_gcry_mpih_add_n; diff --git a/mpi/arm/mpih-mul1.S b/mpi/arm/mpih-mul1.S new file mode 100644 index 0000000..0aa41ef --- /dev/null +++ b/mpi/arm/mpih-mul1.S @@ -0,0 +1,80 @@ +/* ARMv6 mul_1 -- Multiply a limb vector with a limb and store the result in + * a second limb vector. + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * Note: This code is heavily based on the GNU MP Library (version 4.2.1). + */ + +#include "sysdep.h" +#include "asm-syntax.h" + +.syntax unified +.arm + +/******************* + * mpi_limb_t + * _gcry_mpih_mul_1( mpi_ptr_t res_ptr, %r0 + * mpi_ptr_t s1_ptr, %r1 + * mpi_size_t s1_size, %r2 + * mpi_limb_t s2_limb) %r3 + */ + +.text + +.globl _gcry_mpih_mul_1 +.type _gcry_mpih_mul_1,%function +_gcry_mpih_mul_1: + push {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %r11, %lr}; + mov %r4, #0; + + tst %r2, #3; + beq .Large_loop; + +.Loop: + ldr %r5, [%r1], #4; + mov %lr, #0; + umlal %r4, %lr, %r5, %r3; + sub %r2, #1; + str %r4, [%r0], #4; + tst %r2, #3; + mov %r4, %lr; + bne .Loop; + + teq %r2, #0; + beq .Lend; + +.Large_loop: + ldm %r1!, {%r5, %r6, %r7, %r8}; + mov %r9, #0; + mov %r10, #0; + umlal %r4, %r9, %r5, %r3; + mov %r11, #0; + umlal %r9, %r10, %r6, %r3; + str %r4, [%r0], #4; + mov %r4, #0; + umlal %r10, %r11, %r7, %r3; + subs %r2, #4; + umlal %r11, %r4, %r8, %r3; + stm %r0!, {%r9, %r10, %r11}; + bne .Large_loop; + +.Lend: + mov %r0, %r4; + pop {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %r11, %pc}; +.size _gcry_mpih_mul_1,.-_gcry_mpih_mul_1; diff --git a/mpi/arm/mpih-mul2.S b/mpi/arm/mpih-mul2.S new file mode 100644 index 0000000..a7eb8a1 --- /dev/null +++ b/mpi/arm/mpih-mul2.S @@ -0,0 +1,94 @@ +/* ARMv6 mul_2 -- Multiply a limb vector with a limb and add the result to + * a second limb vector. + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * Note: This code is heavily based on the GNU MP Library (version 4.2.1). + */ + +#include "sysdep.h" +#include "asm-syntax.h" + +.syntax unified +.arm + +/******************* + * mpi_limb_t + * _gcry_mpih_addmul_1( mpi_ptr_t res_ptr, %r0 + * mpi_ptr_t s1_ptr, %r1 + * mpi_size_t s1_size, %r2 + * mpi_limb_t s2_limb) %r3 + */ + +.text + +.globl _gcry_mpih_addmul_1 +.type _gcry_mpih_addmul_1,%function +_gcry_mpih_addmul_1: + push {%r4, %r5, %r6, %r8, %r10, %lr}; + mov %lr, #0; + cmn %r0, #0; /* clear carry flag */ + + tst %r2, #3; + beq .Large_loop; +.Loop: + ldr %r5, [%r1], #4; + ldr %r4, [%r0]; + sub %r2, #1; + adcs %r4, %lr; + mov %lr, #0; + umlal %r4, %lr, %r5, %r3; + tst %r2, #3; + str %r4, [%r0], #4; + bne .Loop; + + teq %r2, #0; + beq .Lend; + +.Large_loop: + ldr %r5, [%r1], #4; + ldm %r0, {%r4, %r6, %r8, %r10}; + + sub %r2, #4; + adcs %r4, %lr; + mov %lr, #0; + umlal %r4, %lr, %r5, %r3; + + ldr %r5, [%r1], #4; + adcs %r6, %lr; + mov %lr, #0; + umlal %r6, %lr, %r5, %r3; + + ldr %r5, [%r1], #4; + adcs %r8, %lr; + mov %lr, #0; + umlal %r8, %lr, %r5, %r3; + + ldr %r5, [%r1], #4; + adcs %r10, %lr; + mov %lr, #0; + umlal %r10, %lr, %r5, %r3; + + teq %r2, #0; + stm %r0!, {%r4, %r6, %r8, %r10}; + bne .Large_loop; + +.Lend: + adc %r0, %lr, #0; + pop {%r4, %r5, %r6, %r8, %r10, %pc}; +.size _gcry_mpih_addmul_1,.-_gcry_mpih_addmul_1; diff --git a/mpi/arm/mpih-mul3.S b/mpi/arm/mpih-mul3.S new file mode 100644 index 0000000..034929e --- /dev/null +++ b/mpi/arm/mpih-mul3.S @@ -0,0 +1,100 @@ +/* ARMv6 mul_3 -- Multiply a limb vector with a limb and subtract the result + * from a second limb vector. + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * Note: This code is heavily based on the GNU MP Library (version 4.2.1). + */ + +#include "sysdep.h" +#include "asm-syntax.h" + +.syntax unified +.arm + +/******************* + * mpi_limb_t + * _gcry_mpih_submul_1( mpi_ptr_t res_ptr, %r0 + * mpi_ptr_t s1_ptr, %r1 + * mpi_size_t s1_size, %r2 + * mpi_limb_t s2_limb) %r3 + */ + +.text + +.globl _gcry_mpih_submul_1 +.type _gcry_mpih_submul_1,%function +_gcry_mpih_submul_1: + push {%r4, %r5, %r6, %r8, %r9, %r10, %lr}; + mov %lr, #0; + cmp %r0, #0; /* prepare carry flag for sbc */ + + tst %r2, #3; + beq .Large_loop; +.Loop: + ldr %r5, [%r1], #4; + mov %r4, %lr; + mov %lr, #0; + ldr %r6, [%r0]; + umlal %r4, %lr, %r5, %r3; + sub %r2, #1; + sbcs %r4, %r6, %r4; + tst %r2, #3; + str %r4, [%r0], #4; + bne .Loop; + + teq %r2, #0; + beq .Lend; + +.Large_loop: + ldr %r5, [%r1], #4; + mov %r9, #0; + ldr %r4, [%r0, #0]; + + umlal %lr, %r9, %r5, %r3; + ldr %r6, [%r0, #4]; + ldr %r5, [%r1], #4; + sbcs %r4, %r4, %lr; + + mov %lr, #0; + umlal %r9, %lr, %r5, %r3; + ldr %r8, [%r0, #8]; + ldr %r5, [%r1], #4; + sbcs %r6, %r6, %r9; + + mov %r9, #0; + umlal %lr, %r9, %r5, %r3; + ldr %r10, [%r0, #12]; + ldr %r5, [%r1], #4; + sbcs %r8, %r8, %lr; + + mov %lr, #0; + umlal %r9, %lr, %r5, %r3; + sub %r2, #4; + sbcs %r10, %r10, %r9; + + teq %r2, #0; + stm %r0!, {%r4, %r6, %r8, %r10}; + bne .Large_loop; + +.Lend: + it cc + movcc %r2, #1; + add %r0, %lr, %r2; + pop {%r4, %r5, %r6, %r8, %r9, %r10, %pc}; +.size _gcry_mpih_submul_1,.-_gcry_mpih_submul_1; diff --git a/mpi/arm/mpih-sub1.S b/mpi/arm/mpih-sub1.S new file mode 100644 index 0000000..77d05eb --- /dev/null +++ b/mpi/arm/mpih-sub1.S @@ -0,0 +1,77 @@ +/* ARMv6 sub_n -- Subtract two limb vectors of the same length > 0 and store + * sum in a third limb vector. + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * Note: This code is heavily based on the GNU MP Library (version 4.2.1). + */ + +#include "sysdep.h" +#include "asm-syntax.h" + +.syntax unified +.arm + +/******************* + * mpi_limb_t + * _gcry_mpih_sub_n( mpi_ptr_t res_ptr, %r0 + * mpi_ptr_t s1_ptr, %r1 + * mpi_ptr_t s2_ptr, %r2 + * mpi_size_t size) %r3 + */ + +.text + +.globl _gcry_mpih_sub_n +.type _gcry_mpih_sub_n,%function +_gcry_mpih_sub_n: + push {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %lr}; + cmp %r0, #0; /* prepare carry flag for sub */ + + tst %r3, #3; + beq .Large_loop; + +.Loop: + ldr %r4, [%r1], #4; + sub %r3, #1; + ldr %lr, [%r2], #4; + sbcs %r4, %lr; + tst %r3, #3; + str %r4, [%r0], #4; + bne .Loop; + + teq %r3, #0; + beq .Lend; + +.Large_loop: + ldm %r1!, {%r4, %r6, %r8, %r10}; + sub %r3, #4; + ldm %r2!, {%r5, %r7, %r9, %lr}; + sbcs %r4, %r5; + sbcs %r6, %r7; + sbcs %r8, %r9; + sbcs %r10, %lr; + teq %r3, #0; + stm %r0!, {%r4, %r6, %r8, %r10}; + bne .Large_loop; + +.Lend: + sbc %r0, %r3, #0; + neg %r0, %r0; + pop {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %pc}; +.size _gcry_mpih_sub_n,.-_gcry_mpih_sub_n; diff --git a/mpi/armv6/mpi-asm-defs.h b/mpi/armv6/mpi-asm-defs.h deleted file mode 100644 index 047d1f5..0000000 --- a/mpi/armv6/mpi-asm-defs.h +++ /dev/null @@ -1,4 +0,0 @@ -/* This file defines some basic constants for the MPI machinery. We - * need to define the types on a per-CPU basis, so it is done with - * this file here. */ -#define BYTES_PER_MPI_LIMB (SIZEOF_UNSIGNED_LONG) diff --git a/mpi/armv6/mpih-add1.S b/mpi/armv6/mpih-add1.S deleted file mode 100644 index 60ea4c3..0000000 --- a/mpi/armv6/mpih-add1.S +++ /dev/null @@ -1,76 +0,0 @@ -/* ARMv6 add_n -- Add two limb vectors of the same length > 0 and store - * sum in a third limb vector. - * - * Copyright ? 2013 Jussi Kivilinna - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - * - * Note: This code is heavily based on the GNU MP Library (version 4.2.1). - */ - -#include "sysdep.h" -#include "asm-syntax.h" - -.syntax unified -.arm - -/******************* - * mpi_limb_t - * _gcry_mpih_add_n( mpi_ptr_t res_ptr, %r0 - * mpi_ptr_t s1_ptr, %r1 - * mpi_ptr_t s2_ptr, %r2 - * mpi_size_t size) %r3 - */ - -.text - -.globl _gcry_mpih_add_n -.type _gcry_mpih_add_n,%function -_gcry_mpih_add_n: - push {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %lr}; - cmn %r0, #0; /* clear carry flag */ - - tst %r3, #3; - beq .Large_loop; - -.Loop: - ldr %r4, [%r1], #4; - sub %r3, #1; - ldr %lr, [%r2], #4; - adcs %r4, %lr; - tst %r3, #3; - str %r4, [%r0], #4; - bne .Loop; - - teq %r3, #0; - beq .Lend; - -.Large_loop: - ldm %r1!, {%r4, %r6, %r8, %r10}; - ldm %r2!, {%r5, %r7, %r9, %lr}; - sub %r3, #4; - adcs %r4, %r5; - adcs %r6, %r7; - adcs %r8, %r9; - adcs %r10, %lr; - teq %r3, #0; - stm %r0!, {%r4, %r6, %r8, %r10}; - bne .Large_loop; - -.Lend: - adc %r0, %r3, #0; - pop {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %pc}; -.size _gcry_mpih_add_n,.-_gcry_mpih_add_n; diff --git a/mpi/armv6/mpih-mul1.S b/mpi/armv6/mpih-mul1.S deleted file mode 100644 index 0aa41ef..0000000 --- a/mpi/armv6/mpih-mul1.S +++ /dev/null @@ -1,80 +0,0 @@ -/* ARMv6 mul_1 -- Multiply a limb vector with a limb and store the result in - * a second limb vector. - * - * Copyright ? 2013 Jussi Kivilinna - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - * - * Note: This code is heavily based on the GNU MP Library (version 4.2.1). - */ - -#include "sysdep.h" -#include "asm-syntax.h" - -.syntax unified -.arm - -/******************* - * mpi_limb_t - * _gcry_mpih_mul_1( mpi_ptr_t res_ptr, %r0 - * mpi_ptr_t s1_ptr, %r1 - * mpi_size_t s1_size, %r2 - * mpi_limb_t s2_limb) %r3 - */ - -.text - -.globl _gcry_mpih_mul_1 -.type _gcry_mpih_mul_1,%function -_gcry_mpih_mul_1: - push {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %r11, %lr}; - mov %r4, #0; - - tst %r2, #3; - beq .Large_loop; - -.Loop: - ldr %r5, [%r1], #4; - mov %lr, #0; - umlal %r4, %lr, %r5, %r3; - sub %r2, #1; - str %r4, [%r0], #4; - tst %r2, #3; - mov %r4, %lr; - bne .Loop; - - teq %r2, #0; - beq .Lend; - -.Large_loop: - ldm %r1!, {%r5, %r6, %r7, %r8}; - mov %r9, #0; - mov %r10, #0; - umlal %r4, %r9, %r5, %r3; - mov %r11, #0; - umlal %r9, %r10, %r6, %r3; - str %r4, [%r0], #4; - mov %r4, #0; - umlal %r10, %r11, %r7, %r3; - subs %r2, #4; - umlal %r11, %r4, %r8, %r3; - stm %r0!, {%r9, %r10, %r11}; - bne .Large_loop; - -.Lend: - mov %r0, %r4; - pop {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %r11, %pc}; -.size _gcry_mpih_mul_1,.-_gcry_mpih_mul_1; diff --git a/mpi/armv6/mpih-mul2.S b/mpi/armv6/mpih-mul2.S deleted file mode 100644 index a7eb8a1..0000000 --- a/mpi/armv6/mpih-mul2.S +++ /dev/null @@ -1,94 +0,0 @@ -/* ARMv6 mul_2 -- Multiply a limb vector with a limb and add the result to - * a second limb vector. - * - * Copyright ? 2013 Jussi Kivilinna - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - * - * Note: This code is heavily based on the GNU MP Library (version 4.2.1). - */ - -#include "sysdep.h" -#include "asm-syntax.h" - -.syntax unified -.arm - -/******************* - * mpi_limb_t - * _gcry_mpih_addmul_1( mpi_ptr_t res_ptr, %r0 - * mpi_ptr_t s1_ptr, %r1 - * mpi_size_t s1_size, %r2 - * mpi_limb_t s2_limb) %r3 - */ - -.text - -.globl _gcry_mpih_addmul_1 -.type _gcry_mpih_addmul_1,%function -_gcry_mpih_addmul_1: - push {%r4, %r5, %r6, %r8, %r10, %lr}; - mov %lr, #0; - cmn %r0, #0; /* clear carry flag */ - - tst %r2, #3; - beq .Large_loop; -.Loop: - ldr %r5, [%r1], #4; - ldr %r4, [%r0]; - sub %r2, #1; - adcs %r4, %lr; - mov %lr, #0; - umlal %r4, %lr, %r5, %r3; - tst %r2, #3; - str %r4, [%r0], #4; - bne .Loop; - - teq %r2, #0; - beq .Lend; - -.Large_loop: - ldr %r5, [%r1], #4; - ldm %r0, {%r4, %r6, %r8, %r10}; - - sub %r2, #4; - adcs %r4, %lr; - mov %lr, #0; - umlal %r4, %lr, %r5, %r3; - - ldr %r5, [%r1], #4; - adcs %r6, %lr; - mov %lr, #0; - umlal %r6, %lr, %r5, %r3; - - ldr %r5, [%r1], #4; - adcs %r8, %lr; - mov %lr, #0; - umlal %r8, %lr, %r5, %r3; - - ldr %r5, [%r1], #4; - adcs %r10, %lr; - mov %lr, #0; - umlal %r10, %lr, %r5, %r3; - - teq %r2, #0; - stm %r0!, {%r4, %r6, %r8, %r10}; - bne .Large_loop; - -.Lend: - adc %r0, %lr, #0; - pop {%r4, %r5, %r6, %r8, %r10, %pc}; -.size _gcry_mpih_addmul_1,.-_gcry_mpih_addmul_1; diff --git a/mpi/armv6/mpih-mul3.S b/mpi/armv6/mpih-mul3.S deleted file mode 100644 index 034929e..0000000 --- a/mpi/armv6/mpih-mul3.S +++ /dev/null @@ -1,100 +0,0 @@ -/* ARMv6 mul_3 -- Multiply a limb vector with a limb and subtract the result - * from a second limb vector. - * - * Copyright ? 2013 Jussi Kivilinna - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - * - * Note: This code is heavily based on the GNU MP Library (version 4.2.1). - */ - -#include "sysdep.h" -#include "asm-syntax.h" - -.syntax unified -.arm - -/******************* - * mpi_limb_t - * _gcry_mpih_submul_1( mpi_ptr_t res_ptr, %r0 - * mpi_ptr_t s1_ptr, %r1 - * mpi_size_t s1_size, %r2 - * mpi_limb_t s2_limb) %r3 - */ - -.text - -.globl _gcry_mpih_submul_1 -.type _gcry_mpih_submul_1,%function -_gcry_mpih_submul_1: - push {%r4, %r5, %r6, %r8, %r9, %r10, %lr}; - mov %lr, #0; - cmp %r0, #0; /* prepare carry flag for sbc */ - - tst %r2, #3; - beq .Large_loop; -.Loop: - ldr %r5, [%r1], #4; - mov %r4, %lr; - mov %lr, #0; - ldr %r6, [%r0]; - umlal %r4, %lr, %r5, %r3; - sub %r2, #1; - sbcs %r4, %r6, %r4; - tst %r2, #3; - str %r4, [%r0], #4; - bne .Loop; - - teq %r2, #0; - beq .Lend; - -.Large_loop: - ldr %r5, [%r1], #4; - mov %r9, #0; - ldr %r4, [%r0, #0]; - - umlal %lr, %r9, %r5, %r3; - ldr %r6, [%r0, #4]; - ldr %r5, [%r1], #4; - sbcs %r4, %r4, %lr; - - mov %lr, #0; - umlal %r9, %lr, %r5, %r3; - ldr %r8, [%r0, #8]; - ldr %r5, [%r1], #4; - sbcs %r6, %r6, %r9; - - mov %r9, #0; - umlal %lr, %r9, %r5, %r3; - ldr %r10, [%r0, #12]; - ldr %r5, [%r1], #4; - sbcs %r8, %r8, %lr; - - mov %lr, #0; - umlal %r9, %lr, %r5, %r3; - sub %r2, #4; - sbcs %r10, %r10, %r9; - - teq %r2, #0; - stm %r0!, {%r4, %r6, %r8, %r10}; - bne .Large_loop; - -.Lend: - it cc - movcc %r2, #1; - add %r0, %lr, %r2; - pop {%r4, %r5, %r6, %r8, %r9, %r10, %pc}; -.size _gcry_mpih_submul_1,.-_gcry_mpih_submul_1; diff --git a/mpi/armv6/mpih-sub1.S b/mpi/armv6/mpih-sub1.S deleted file mode 100644 index 77d05eb..0000000 --- a/mpi/armv6/mpih-sub1.S +++ /dev/null @@ -1,77 +0,0 @@ -/* ARMv6 sub_n -- Subtract two limb vectors of the same length > 0 and store - * sum in a third limb vector. - * - * Copyright ? 2013 Jussi Kivilinna - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - * - * Note: This code is heavily based on the GNU MP Library (version 4.2.1). - */ - -#include "sysdep.h" -#include "asm-syntax.h" - -.syntax unified -.arm - -/******************* - * mpi_limb_t - * _gcry_mpih_sub_n( mpi_ptr_t res_ptr, %r0 - * mpi_ptr_t s1_ptr, %r1 - * mpi_ptr_t s2_ptr, %r2 - * mpi_size_t size) %r3 - */ - -.text - -.globl _gcry_mpih_sub_n -.type _gcry_mpih_sub_n,%function -_gcry_mpih_sub_n: - push {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %lr}; - cmp %r0, #0; /* prepare carry flag for sub */ - - tst %r3, #3; - beq .Large_loop; - -.Loop: - ldr %r4, [%r1], #4; - sub %r3, #1; - ldr %lr, [%r2], #4; - sbcs %r4, %lr; - tst %r3, #3; - str %r4, [%r0], #4; - bne .Loop; - - teq %r3, #0; - beq .Lend; - -.Large_loop: - ldm %r1!, {%r4, %r6, %r8, %r10}; - sub %r3, #4; - ldm %r2!, {%r5, %r7, %r9, %lr}; - sbcs %r4, %r5; - sbcs %r6, %r7; - sbcs %r8, %r9; - sbcs %r10, %lr; - teq %r3, #0; - stm %r0!, {%r4, %r6, %r8, %r10}; - bne .Large_loop; - -.Lend: - sbc %r0, %r3, #0; - neg %r0, %r0; - pop {%r4, %r5, %r6, %r7, %r8, %r9, %r10, %pc}; -.size _gcry_mpih_sub_n,.-_gcry_mpih_sub_n; diff --git a/mpi/config.links b/mpi/config.links index 9fb4f10..90d1077 100644 --- a/mpi/config.links +++ b/mpi/config.links @@ -138,14 +138,9 @@ case "${host}" in ;; arm*-*-*) if test "$gcry_cv_gcc_arm_platform_as_ok" = "yes" ; then - if test "$gcry_cv_cc_arm_arch_is_v6" = "yes" ; then - echo '/* configured for armv6 */' >>./mpi/asm-syntax.h - path="armv6" - mpi_cpu_arch="arm" - else - echo '/* No assembler modules configured */' >>./mpi/asm-syntax.h - path="" - fi + echo '/* configured for arm */' >>./mpi/asm-syntax.h + path="arm" + mpi_cpu_arch="arm" else echo '/* No assembler modules configured */' >>./mpi/asm-syntax.h path="" -- 1.8.4.rc3 From dbaryshkov at gmail.com Tue Oct 22 21:29:27 2013 From: dbaryshkov at gmail.com (Dmitry Eremin-Solenikov) Date: Tue, 22 Oct 2013 23:29:27 +0400 Subject: [PATCH 3/3] Enable assembler optimizations on earlier ARM cores In-Reply-To: <1382470167-11975-1-git-send-email-dbaryshkov@gmail.com> References: <1382470167-11975-1-git-send-email-dbaryshkov@gmail.com> Message-ID: <1382470167-11975-3-git-send-email-dbaryshkov@gmail.com> * cipher/blowfish-armv6.S => cipher/blowfish-arm.S: adapt to pre-armv6 CPUs. * cipher/blowfish.c: enable assembly on armv4/armv5 little-endian CPUs. * cipher/camellia-armv6.S => cipher/camellia-arm.S: adapt to pre-armv6 CPUs. * cipher/camellia.c, cipher-camellia-glue.c: enable assembly on armv4/armv5 little-endian CPUs. * cipher/cast5-armv6.S => cipher/cast5-arm.S: adapt to pre-armv6 CPUs. * cipher/cast5.c: enable assembly on armv4/armv5 little-endian CPUs. * cipher/rijndael-armv6.S => cipher/rijndael-arm.S: adapt to pre-armv6 CPUs. * cipher/rijndael.c: enable assembly on armv4/armv5 little-endian CPUs. * cipher/twofish-armv6.S => cipher/twofish-arm.S: adapt to pre-armv6 CPUs. * cipher/twofish.c: enable assembly on armv4/armv5 little-endian CPUs. -- Our ARMv6 assembly optimized code can be easily adapted to earlier CPUs. The only incompatible place is rev instruction used to do byte swapping. Replace it on <= ARMv6 with a series of 4 instructions. Compare: ECB/Stream CBC CFB OFB CTR --------------- --------------- --------------- --------------- --------------- AES 620ms 610ms 650ms 680ms 620ms 630ms 660ms 660ms 630ms 630ms CAMELLIA128 720ms 720ms 780ms 790ms 770ms 760ms 780ms 780ms 770ms 760ms CAMELLIA256 910ms 910ms 970ms 970ms 960ms 950ms 970ms 970ms 960ms 950ms CAST5 820ms 820ms 930ms 920ms 890ms 860ms 930ms 920ms 880ms 890ms BLOWFISH 550ms 560ms 650ms 660ms 630ms 600ms 660ms 650ms 610ms 620ms ECB/Stream CBC CFB OFB CTR --------------- --------------- --------------- --------------- --------------- AES 130ms 140ms 180ms 200ms 160ms 170ms 190ms 200ms 170ms 170ms CAMELLIA128 150ms 160ms 210ms 220ms 200ms 190ms 210ms 220ms 190ms 190ms CAMELLIA256 180ms 180ms 260ms 240ms 240ms 230ms 250ms 250ms 230ms 230ms CAST5 170ms 160ms 270ms 120ms 240ms 130ms 260ms 270ms 130ms 120ms BLOWFISH 160ms 150ms 260ms 110ms 230ms 120ms 250ms 260ms 110ms 120ms Signed-off-by: Dmitry Eremin-Solenikov --- cipher/Makefile.am | 8 +- cipher/blowfish-arm.S | 743 +++++++++++++++++++++++++++++++++++++++++ cipher/blowfish-armv6.S | 730 ----------------------------------------- cipher/blowfish.c | 44 +-- cipher/camellia-arm.S | 616 ++++++++++++++++++++++++++++++++++ cipher/camellia-armv6.S | 604 ---------------------------------- cipher/camellia-glue.c | 14 +- cipher/camellia.c | 8 +- cipher/camellia.h | 2 +- cipher/cast5-arm.S | 715 ++++++++++++++++++++++++++++++++++++++++ cipher/cast5-armv6.S | 702 --------------------------------------- cipher/cast5.c | 44 +-- cipher/rijndael-arm.S | 853 ++++++++++++++++++++++++++++++++++++++++++++++++ cipher/rijndael-armv6.S | 853 ------------------------------------------------ cipher/rijndael.c | 36 +- cipher/twofish-arm.S | 365 +++++++++++++++++++++ cipher/twofish-armv6.S | 365 --------------------- cipher/twofish.c | 8 +- configure.ac | 10 +- 19 files changed, 3379 insertions(+), 3341 deletions(-) create mode 100644 cipher/blowfish-arm.S delete mode 100644 cipher/blowfish-armv6.S create mode 100644 cipher/camellia-arm.S delete mode 100644 cipher/camellia-armv6.S create mode 100644 cipher/cast5-arm.S delete mode 100644 cipher/cast5-armv6.S create mode 100644 cipher/rijndael-arm.S delete mode 100644 cipher/rijndael-armv6.S create mode 100644 cipher/twofish-arm.S delete mode 100644 cipher/twofish-armv6.S diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 3d8149a..e3aed3b 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -56,7 +56,7 @@ rmd.h EXTRA_libcipher_la_SOURCES = \ arcfour.c \ blowfish.c blowfish-amd64.S \ -cast5.c cast5-amd64.S cast5-armv6.S \ +cast5.c cast5-amd64.S cast5-arm.S \ crc.c \ des.c \ dsa.c \ @@ -67,7 +67,7 @@ gost28147.c gost.h \ gostr3411-94.c \ md4.c \ md5.c \ -rijndael.c rijndael-tables.h rijndael-amd64.S rijndael-armv6.S \ +rijndael.c rijndael-tables.h rijndael-amd64.S rijndael-arm.S \ rmd160.c \ rsa.c \ salsa20.c \ @@ -80,10 +80,10 @@ sha512.c sha512-armv7-neon.S \ stribog.c \ tiger.c \ whirlpool.c \ -twofish.c twofish-amd64.S twofish-armv6.S \ +twofish.c twofish-amd64.S twofish-arm.S \ rfc2268.c \ camellia.c camellia.h camellia-glue.c camellia-aesni-avx-amd64.S \ - camellia-aesni-avx2-amd64.S camellia-armv6.S + camellia-aesni-avx2-amd64.S camellia-arm.S if ENABLE_O_FLAG_MUNGING o_flag_munging = sed -e 's/-O\([2-9s][2-9s]*\)/-O1/' -e 's/-Ofast/-O1/g' diff --git a/cipher/blowfish-arm.S b/cipher/blowfish-arm.S new file mode 100644 index 0000000..501b085 --- /dev/null +++ b/cipher/blowfish-arm.S @@ -0,0 +1,743 @@ +/* blowfish-arm.S - ARM assembly implementation of Blowfish cipher + * + * Copyright ? 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(__ARMEL__) +#ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS + +.text + +.syntax unified +.arm + +/* structure of crypto context */ +#define s0 0 +#define s1 (s0 + (1 * 256) * 4) +#define s2 (s0 + (2 * 256) * 4) +#define s3 (s0 + (3 * 256) * 4) +#define p (s3 + (1 * 256) * 4) + +/* register macros */ +#define CTXs0 %r0 +#define CTXs1 %r9 +#define CTXs2 %r8 +#define CTXs3 %r10 +#define RMASK %lr +#define RKEYL %r2 +#define RKEYR %ip + +#define RL0 %r3 +#define RR0 %r4 + +#define RL1 %r9 +#define RR1 %r10 + +#define RT0 %r11 +#define RT1 %r7 +#define RT2 %r5 +#define RT3 %r6 + +/* helper macros */ +#define ldr_unaligned_le(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 0)]; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 3)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 0)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 1)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 2)]; \ + strb rtmp0, [rdst, #((offs) + 3)]; + +#define ldr_unaligned_be(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 3)]; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 0)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_be(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 3)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 2)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 1)]; \ + strb rtmp0, [rdst, #((offs) + 0)]; + +#ifdef __ARMEL__ + #define ldr_unaligned_host ldr_unaligned_le + #define str_unaligned_host str_unaligned_le + + /* bswap on little-endian */ +#ifdef HAVE_ARM_ARCH_V6 + #define host_to_be(reg, rtmp) \ + rev reg, reg; + #define be_to_host(reg, rtmp) \ + rev reg, reg; +#else + #define host_to_be(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; + #define be_to_host(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; +#endif +#else + #define ldr_unaligned_host ldr_unaligned_be + #define str_unaligned_host str_unaligned_be + + /* nop on big-endian */ + #define host_to_be(reg, rtmp) /*_*/ + #define be_to_host(reg, rtmp) /*_*/ +#endif + +#define host_to_host(x, y) /*_*/ + +/*********************************************************************** + * 1-way blowfish + ***********************************************************************/ +#define F(l, r) \ + and RT0, RMASK, l, lsr#(24 - 2); \ + and RT1, RMASK, l, lsr#(16 - 2); \ + ldr RT0, [CTXs0, RT0]; \ + and RT2, RMASK, l, lsr#(8 - 2); \ + ldr RT1, [CTXs1, RT1]; \ + and RT3, RMASK, l, lsl#2; \ + ldr RT2, [CTXs2, RT2]; \ + add RT0, RT1; \ + ldr RT3, [CTXs3, RT3]; \ + eor RT0, RT2; \ + add RT0, RT3; \ + eor r, RT0; + +#define load_roundkey_enc(n) \ + ldr RKEYL, [CTXs2, #((p - s2) + (4 * (n) + 0))]; \ + ldr RKEYR, [CTXs2, #((p - s2) + (4 * (n) + 4))]; + +#define add_roundkey_enc() \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; + +#define round_enc(n) \ + add_roundkey_enc(); \ + load_roundkey_enc(n); \ + \ + F(RL0, RR0); \ + F(RR0, RL0); + +#define load_roundkey_dec(n) \ + ldr RKEYL, [CTXs2, #((p - s2) + (4 * ((n) - 1) + 4))]; \ + ldr RKEYR, [CTXs2, #((p - s2) + (4 * ((n) - 1) + 0))]; + +#define add_roundkey_dec() \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; + +#define round_dec(n) \ + add_roundkey_dec(); \ + load_roundkey_dec(n); \ + \ + F(RL0, RR0); \ + F(RR0, RL0); + +#define read_block_aligned(rin, offs, l0, r0, convert, rtmp) \ + ldr l0, [rin, #((offs) + 0)]; \ + ldr r0, [rin, #((offs) + 4)]; \ + convert(l0, rtmp); \ + convert(r0, rtmp); + +#define write_block_aligned(rout, offs, l0, r0, convert, rtmp) \ + convert(l0, rtmp); \ + convert(r0, rtmp); \ + str l0, [rout, #((offs) + 0)]; \ + str r0, [rout, #((offs) + 4)]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads allowed */ + #define read_block(rin, offs, l0, r0, rtmp0) \ + read_block_aligned(rin, offs, l0, r0, host_to_be) + + #define write_block(rout, offs, r0, l0, rtmp0, rtmp1) \ + write_block_aligned(rout, offs, r0, l0, be_to_host) + + #define read_block_host(rin, offs, l0, r0, rtmp0) \ + read_block_aligned(rin, offs, l0, r0, host_to_host) + + #define write_block_host(rout, offs, r0, l0, rtmp0, rtmp1) \ + write_block_aligned(rout, offs, r0, l0, host_to_host) +#else + /* need to handle unaligned reads by byte reads */ + #define read_block(rin, offs, l0, r0, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_be(l0, rin, (offs) + 0, rtmp0); \ + ldr_unaligned_be(r0, rin, (offs) + 4, rtmp0); \ + b 2f; \ + 1:;\ + read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0); \ + 2:; + + #define write_block(rout, offs, l0, r0, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_be(l0, rout, (offs) + 0, rtmp0, rtmp1); \ + str_unaligned_be(r0, rout, (offs) + 4, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block_aligned(rout, offs, l0, r0, be_to_host, rtmp0); \ + 2:; + + #define read_block_host(rin, offs, l0, r0, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_host(l0, rin, (offs) + 0, rtmp0); \ + ldr_unaligned_host(r0, rin, (offs) + 4, rtmp0); \ + b 2f; \ + 1:;\ + read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0); \ + 2:; + + #define write_block_host(rout, offs, l0, r0, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_host(l0, rout, (offs) + 0, rtmp0, rtmp1); \ + str_unaligned_host(r0, rout, (offs) + 4, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block_aligned(rout, offs, l0, r0, host_to_host); \ + 2:; +#endif + +.align 3 +.type __blowfish_enc_blk1,%function; + +__blowfish_enc_blk1: + /* input: + * preloaded: CTX + * [RL0, RR0]: src + * output: + * [RR0, RL0]: dst + */ + push {%lr}; + + add CTXs1, CTXs0, #(s1 - s0); + add CTXs2, CTXs0, #(s2 - s0); + mov RMASK, #(0xff << 2); /* byte mask */ + add CTXs3, CTXs1, #(s3 - s1); + + load_roundkey_enc(0); + round_enc(2); + round_enc(4); + round_enc(6); + round_enc(8); + round_enc(10); + round_enc(12); + round_enc(14); + round_enc(16); + add_roundkey_enc(); + + pop {%pc}; +.size __blowfish_enc_blk1,.-__blowfish_enc_blk1; + +.align 8 +.globl _gcry_blowfish_arm_do_encrypt +.type _gcry_blowfish_arm_do_encrypt,%function; + +_gcry_blowfish_arm_do_encrypt: + /* input: + * %r0: ctx, CTX + * %r1: u32 *ret_xl + * %r2: u32 *ret_xr + */ + push {%r2, %r4-%r11, %ip, %lr}; + + ldr RL0, [%r1]; + ldr RR0, [%r2]; + + bl __blowfish_enc_blk1; + + pop {%r2}; + str RR0, [%r1]; + str RL0, [%r2]; + + pop {%r4-%r11, %ip, %pc}; +.size _gcry_blowfish_arm_do_encrypt,.-_gcry_blowfish_arm_do_encrypt; + +.align 3 +.global _gcry_blowfish_arm_encrypt_block +.type _gcry_blowfish_arm_encrypt_block,%function; + +_gcry_blowfish_arm_encrypt_block: + /* input: + * %r0: ctx, CTX + * %r1: dst + * %r2: src + */ + push {%r4-%r11, %ip, %lr}; + + read_block(%r2, 0, RL0, RR0, RT0); + + bl __blowfish_enc_blk1; + + write_block(%r1, 0, RR0, RL0, RT0, RT1); + + pop {%r4-%r11, %ip, %pc}; +.size _gcry_blowfish_arm_encrypt_block,.-_gcry_blowfish_arm_encrypt_block; + +.align 3 +.global _gcry_blowfish_arm_decrypt_block +.type _gcry_blowfish_arm_decrypt_block,%function; + +_gcry_blowfish_arm_decrypt_block: + /* input: + * %r0: ctx, CTX + * %r1: dst + * %r2: src + */ + push {%r4-%r11, %ip, %lr}; + + add CTXs1, CTXs0, #(s1 - s0); + add CTXs2, CTXs0, #(s2 - s0); + mov RMASK, #(0xff << 2); /* byte mask */ + add CTXs3, CTXs1, #(s3 - s1); + + read_block(%r2, 0, RL0, RR0, RT0); + + load_roundkey_dec(17); + round_dec(15); + round_dec(13); + round_dec(11); + round_dec(9); + round_dec(7); + round_dec(5); + round_dec(3); + round_dec(1); + add_roundkey_dec(); + + write_block(%r1, 0, RR0, RL0, RT0, RT1); + + pop {%r4-%r11, %ip, %pc}; +.size _gcry_blowfish_arm_decrypt_block,.-_gcry_blowfish_arm_decrypt_block; + +/*********************************************************************** + * 2-way blowfish + ***********************************************************************/ +#define F2(n, l0, r0, l1, r1, set_nextk, dec) \ + \ + and RT0, RMASK, l0, lsr#(24 - 2); \ + and RT1, RMASK, l0, lsr#(16 - 2); \ + and RT2, RMASK, l0, lsr#(8 - 2); \ + add RT1, #(s1 - s0); \ + \ + ldr RT0, [CTXs0, RT0]; \ + and RT3, RMASK, l0, lsl#2; \ + ldr RT1, [CTXs0, RT1]; \ + add RT3, #(s3 - s2); \ + ldr RT2, [CTXs2, RT2]; \ + add RT0, RT1; \ + ldr RT3, [CTXs2, RT3]; \ + \ + and RT1, RMASK, l1, lsr#(24 - 2); \ + eor RT0, RT2; \ + and RT2, RMASK, l1, lsr#(16 - 2); \ + add RT0, RT3; \ + add RT2, #(s1 - s0); \ + and RT3, RMASK, l1, lsr#(8 - 2); \ + eor r0, RT0; \ + \ + ldr RT1, [CTXs0, RT1]; \ + and RT0, RMASK, l1, lsl#2; \ + ldr RT2, [CTXs0, RT2]; \ + add RT0, #(s3 - s2); \ + ldr RT3, [CTXs2, RT3]; \ + add RT1, RT2; \ + ldr RT0, [CTXs2, RT0]; \ + \ + and RT2, RMASK, r0, lsr#(24 - 2); \ + eor RT1, RT3; \ + and RT3, RMASK, r0, lsr#(16 - 2); \ + add RT1, RT0; \ + add RT3, #(s1 - s0); \ + and RT0, RMASK, r0, lsr#(8 - 2); \ + eor r1, RT1; \ + \ + ldr RT2, [CTXs0, RT2]; \ + and RT1, RMASK, r0, lsl#2; \ + ldr RT3, [CTXs0, RT3]; \ + add RT1, #(s3 - s2); \ + ldr RT0, [CTXs2, RT0]; \ + add RT2, RT3; \ + ldr RT1, [CTXs2, RT1]; \ + \ + and RT3, RMASK, r1, lsr#(24 - 2); \ + eor RT2, RT0; \ + and RT0, RMASK, r1, lsr#(16 - 2); \ + add RT2, RT1; \ + add RT0, #(s1 - s0); \ + and RT1, RMASK, r1, lsr#(8 - 2); \ + eor l0, RT2; \ + \ + ldr RT3, [CTXs0, RT3]; \ + and RT2, RMASK, r1, lsl#2; \ + ldr RT0, [CTXs0, RT0]; \ + add RT2, #(s3 - s2); \ + ldr RT1, [CTXs2, RT1]; \ + eor l1, RKEYL; \ + ldr RT2, [CTXs2, RT2]; \ + \ + eor r0, RKEYR; \ + add RT3, RT0; \ + eor r1, RKEYR; \ + eor RT3, RT1; \ + eor l0, RKEYL; \ + add RT3, RT2; \ + set_nextk(RKEYL, (p - s2) + (4 * (n) + ((dec) * 4))); \ + eor l1, RT3; \ + set_nextk(RKEYR, (p - s2) + (4 * (n) + (!(dec) * 4))); + +#define load_n_add_roundkey_enc2(n) \ + load_roundkey_enc(n); \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; \ + eor RL1, RKEYL; \ + eor RR1, RKEYR; \ + load_roundkey_enc((n) + 2); + +#define next_key(reg, offs) \ + ldr reg, [CTXs2, #(offs)]; + +#define dummy(x, y) /* do nothing */ + +#define round_enc2(n, load_next_key) \ + F2((n) + 2, RL0, RR0, RL1, RR1, load_next_key, 0); + +#define load_n_add_roundkey_dec2(n) \ + load_roundkey_dec(n); \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; \ + eor RL1, RKEYL; \ + eor RR1, RKEYR; \ + load_roundkey_dec((n) - 2); + +#define round_dec2(n, load_next_key) \ + F2((n) - 3, RL0, RR0, RL1, RR1, load_next_key, 1); + +#define read_block2_aligned(rin, l0, r0, l1, r1, convert, rtmp) \ + ldr l0, [rin, #(0)]; \ + ldr r0, [rin, #(4)]; \ + convert(l0, rtmp); \ + ldr l1, [rin, #(8)]; \ + convert(r0, rtmp); \ + ldr r1, [rin, #(12)]; \ + convert(l1, rtmp); \ + convert(r1, rtmp); + +#define write_block2_aligned(rout, l0, r0, l1, r1, convert, rtmp) \ + convert(l0, rtmp); \ + convert(r0, rtmp); \ + convert(l1, rtmp); \ + str l0, [rout, #(0)]; \ + convert(r1, rtmp); \ + str r0, [rout, #(4)]; \ + str l1, [rout, #(8)]; \ + str r1, [rout, #(12)]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads allowed */ + #define read_block2(rin, l0, r0, l1, r1, rtmp0) \ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0) + + #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0) + + #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0) + + #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0) +#else + /* need to handle unaligned reads by byte reads */ + #define read_block2(rin, l0, r0, l1, r1, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_be(l0, rin, 0, rtmp0); \ + ldr_unaligned_be(r0, rin, 4, rtmp0); \ + ldr_unaligned_be(l1, rin, 8, rtmp0); \ + ldr_unaligned_be(r1, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0); \ + 2:; + + #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_be(l0, rout, 0, rtmp0, rtmp1); \ + str_unaligned_be(r0, rout, 4, rtmp0, rtmp1); \ + str_unaligned_be(l1, rout, 8, rtmp0, rtmp1); \ + str_unaligned_be(r1, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0); \ + 2:; + + #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_host(l0, rin, 0, rtmp0); \ + ldr_unaligned_host(r0, rin, 4, rtmp0); \ + ldr_unaligned_host(l1, rin, 8, rtmp0); \ + ldr_unaligned_host(r1, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0); \ + 2:; + + #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_host(l0, rout, 0, rtmp0, rtmp1); \ + str_unaligned_host(r0, rout, 4, rtmp0, rtmp1); \ + str_unaligned_host(l1, rout, 8, rtmp0, rtmp1); \ + str_unaligned_host(r1, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0); \ + 2:; +#endif + +.align 3 +.type _gcry_blowfish_arm_enc_blk2,%function; + +_gcry_blowfish_arm_enc_blk2: + /* input: + * preloaded: CTX + * [RL0, RR0], [RL1, RR1]: src + * output: + * [RR0, RL0], [RR1, RL1]: dst + */ + push {RT0,%lr}; + + add CTXs2, CTXs0, #(s2 - s0); + mov RMASK, #(0xff << 2); /* byte mask */ + + load_n_add_roundkey_enc2(0); + round_enc2(2, next_key); + round_enc2(4, next_key); + round_enc2(6, next_key); + round_enc2(8, next_key); + round_enc2(10, next_key); + round_enc2(12, next_key); + round_enc2(14, next_key); + round_enc2(16, dummy); + + host_to_be(RR0, RT0); + host_to_be(RL0, RT0); + host_to_be(RR1, RT0); + host_to_be(RL1, RT0); + + pop {RT0,%pc}; +.size _gcry_blowfish_arm_enc_blk2,.-_gcry_blowfish_arm_enc_blk2; + +.align 3 +.globl _gcry_blowfish_arm_cfb_dec; +.type _gcry_blowfish_arm_cfb_dec,%function; + +_gcry_blowfish_arm_cfb_dec: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit) + */ + push {%r2, %r4-%r11, %ip, %lr}; + + mov %lr, %r3; + + /* Load input (iv/%r3 is aligned, src/%r2 might not be) */ + ldm %r3, {RL0, RR0}; + host_to_be(RL0, RT0); + host_to_be(RR0, RT0); + read_block(%r2, 0, RL1, RR1, RT0); + + /* Update IV, load src[1] and save to iv[0] */ + read_block_host(%r2, 8, %r5, %r6, RT0); + stm %lr, {%r5, %r6}; + + bl _gcry_blowfish_arm_enc_blk2; + /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */ + + /* %r1: dst, %r0: %src */ + pop {%r0}; + + /* dst = src ^ result */ + read_block2_host(%r0, %r5, %r6, %r7, %r8, %lr); + eor %r5, %r4; + eor %r6, %r3; + eor %r7, %r10; + eor %r8, %r9; + write_block2_host(%r1, %r5, %r6, %r7, %r8, %r9, %r10); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_blowfish_arm_cfb_dec,.-_gcry_blowfish_arm_cfb_dec; + +.align 3 +.globl _gcry_blowfish_arm_ctr_enc; +.type _gcry_blowfish_arm_ctr_enc,%function; + +_gcry_blowfish_arm_ctr_enc: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit, big-endian) + */ + push {%r2, %r4-%r11, %ip, %lr}; + + mov %lr, %r3; + + /* Load IV (big => host endian) */ +