[PATCH] CBC-MAC support
Simon Josefsson
jas@extundo.com
Sat, 22 Mar 2003 00:17:44 +0100
The last typos included here too, as the patches would conflict
otherwise.
PS. By accident one attempt at key derivation support was deleted
after a "cvsco" a few weeks ago, but I'll try again soon.
Index: AUTHORS
===================================================================
RCS file: /cvs/gnupg/libgcrypt/AUTHORS,v
retrieving revision 1.39
diff -u -p -r1.39 AUTHORS
--- AUTHORS 21 Jan 2003 09:06:54 -0000 1.39
+++ AUTHORS 21 Mar 2003 23:09:52 -0000
@@ -50,7 +50,7 @@ Assigns past and future changes.
twoaday@freakmail.de
LIBGCRYPT Simon Josefsson 2002-10-25
-Assigns past and future changes to FSF (cipher/{md4,crc}.c, CTS flag,
+Assigns past and future changes to FSF (cipher/{md4,crc}.c, CTS/MAC flags,
self test improvements)
simon@josefsson.org
@@ -72,7 +72,7 @@ files from Cryptlib. Copyright Peter Gu
Wedgwood 1996-1999.
- Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
Index: NEWS
===================================================================
RCS file: /cvs/gnupg/libgcrypt/NEWS,v
retrieving revision 1.30
diff -u -p -r1.30 NEWS
--- NEWS 19 Mar 2003 11:55:35 -0000 1.30
+++ NEWS 21 Mar 2003 23:09:52 -0000
@@ -11,6 +11,9 @@ Noteworthy changes in version 1.1.13 (un
* The random module won't print the "not enough random bytes
available" anymore. A new progress status is issued instead.
+ * CBC-MAC for block ciphers is now supported, by using a
+ GCRY_CIPHER_CBC_MAC cipher flag.
+
* Interface changes relative to the 1.1.12 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gcry_pk_decrypt ENHANCED: Allows flag to return complete S-expression.
Index: cipher/ChangeLog
===================================================================
RCS file: /cvs/gnupg/libgcrypt/cipher/ChangeLog,v
retrieving revision 1.152
diff -u -p -r1.152 ChangeLog
--- cipher/ChangeLog 19 Mar 2003 11:57:38 -0000 1.152
+++ cipher/ChangeLog 21 Mar 2003 23:09:53 -0000
@@ -1,3 +1,9 @@
+2003-03-22 Simon Josefsson <jas@extundo.com>
+
+ * cipher.c (gcry_cipher_open, do_cbc_encrypt)
+ (gcry_cipher_encrypt): Support GCRY_CIPHER_CBC_MAC.
+ (gcry_cipher_ctl): Support GCRYCTL_SET_CBC_MAC.
+
2003-03-19 Werner Koch <wk@gnupg.org>
* primegen.c (gen_prime): New args EXTRA_CHECK and EXTRA_CHECK_ARG
Index: cipher/cipher.c
===================================================================
RCS file: /cvs/gnupg/libgcrypt/cipher/cipher.c,v
retrieving revision 1.51
diff -u -p -r1.51 cipher.c
--- cipher/cipher.c 4 Mar 2003 18:07:42 -0000 1.51
+++ cipher/cipher.c 21 Mar 2003 23:09:53 -0000
@@ -516,7 +516,9 @@ gcry_cipher_open( int algo, int mode, un
/* check flags */
if( (flags & ~(GCRY_CIPHER_SECURE|
GCRY_CIPHER_ENABLE_SYNC|
- GCRY_CIPHER_CBC_CTS)) ) {
+ GCRY_CIPHER_CBC_CTS|
+ GCRY_CIPHER_CBC_MAC)) ||
+ (flags & GCRY_CIPHER_CBC_CTS & GCRY_CIPHER_CBC_MAC)) {
set_lasterr( GCRYERR_INV_CIPHER_ALGO );
return NULL;
}
@@ -690,7 +692,8 @@ do_cbc_encrypt( GCRY_CIPHER_HD c, byte *
(*c->encrypt)( &c->context.c, outbuf, outbuf );
memcpy(c->iv, outbuf, blocksize );
inbuf += c->blocksize;
- outbuf += c->blocksize;
+ if (!(c->flags & GCRY_CIPHER_CBC_MAC))
+ outbuf += c->blocksize;
}
if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize)
@@ -940,7 +943,7 @@ gcry_cipher_encrypt (GcryCipherHd h, byt
}
else
{
- if ( outsize < inlen )
+ if ( outsize < ((h->flags & GCRY_CIPHER_CBC_MAC) ? h->blocksize : inlen))
rc = GCRYERR_TOO_SHORT;
else if ((h->mode == GCRY_CIPHER_MODE_ECB
|| (h->mode == GCRY_CIPHER_MODE_CBC
@@ -1074,11 +1077,22 @@ gcry_cipher_ctl( GCRY_CIPHER_HD h, int c
break;
case GCRYCTL_SET_CBC_CTS:
if (buflen)
- h->flags |= GCRY_CIPHER_CBC_CTS;
+ if (h->flags & GCRY_CIPHER_CBC_MAC)
+ rc = GCRYERR_INV_FLAG;
+ else
+ h->flags |= GCRY_CIPHER_CBC_CTS;
else
h->flags &= ~GCRY_CIPHER_CBC_CTS;
break;
-
+ case GCRYCTL_SET_CBC_MAC:
+ if (buflen)
+ if (h->flags & GCRY_CIPHER_CBC_CTS)
+ rc = GCRYERR_INV_FLAG;
+ else
+ h->flags |= GCRY_CIPHER_CBC_MAC;
+ else
+ h->flags &= ~GCRY_CIPHER_CBC_MAC;
+ break;
case GCRYCTL_DISABLE_ALGO:
/* this one expects a NULL handle and buffer pointing to an
* integer with the algo number.
Index: doc/ChangeLog
===================================================================
RCS file: /cvs/gnupg/libgcrypt/doc/ChangeLog,v
retrieving revision 1.10
diff -u -p -r1.10 ChangeLog
--- doc/ChangeLog 4 Mar 2003 18:17:05 -0000 1.10
+++ doc/ChangeLog 21 Mar 2003 23:09:53 -0000
@@ -1,3 +1,7 @@
+2003-03-22 Simon Josefsson <jas@extundo.com>
+
+ * gcrypt.texi: Add CBC-MAC.
+
2003-03-04 Moritz Schulte <moritz@g10code.com>
* gcrypt.texi (Cipher Functions): Added gcry_cipher_reset.
Index: doc/gcrypt.texi
===================================================================
RCS file: /cvs/gnupg/libgcrypt/doc/gcrypt.texi,v
retrieving revision 1.10
diff -u -p -r1.10 gcrypt.texi
--- doc/gcrypt.texi 19 Mar 2003 11:59:28 -0000 1.10
+++ doc/gcrypt.texi 21 Mar 2003 23:09:53 -0000
@@ -72,7 +72,7 @@ entitled ``GNU Free Documentation Licens
@top Main Menu
This is Edition @value{EDITION}, last updated @value{UPDATED}, of
@cite{The `Libgcrypt' Reference Manual}, for Version
-@value{VERSION} of the @acronym{GPGME} library.
+@value{VERSION} of the @acronym{Libgcrypt} library.
@end ifnottex
@menu
@@ -396,7 +396,12 @@ This flag enables the CFB sync mode, whi
Libgcrypt's CFB mode implementation to allow for OpenPGP's CFB variant.
See @code{gcry_cipher_sync}.
@item GCRY_CIPHER_CBC_CTS
-Enable cipher text stealing for the CBS mode.
+Enable cipher text stealing (CTS) for the CBC mode. Cannot be used
+simultaneous as GCRY_CIPHER_CBC_MAC.
+@item GCRY_CIPHER_CBC_MAC
+Compute CBC-MAC keyed checksums. This is the same as CBC mode, but
+only output the last block. Cannot be used simultaneous as
+GCRY_CIPHER_CBC_CTS.
@end table
@end deftypefun
@@ -690,6 +695,8 @@ this is the hashed data is highly confid
@item GCRY_MD_FLAG_HMAC
Turn the algorithm into a HMAC message authentication algorithm. Note
that the function @code{gcry_md_setkey} must be used set the MAC key.
+If you want CBC message authenentication codes based on a cipher, see
+@xref{Cipher Functions}.
@end table
@c begin table of hash flags
Index: src/ChangeLog
===================================================================
RCS file: /cvs/gnupg/libgcrypt/src/ChangeLog,v
retrieving revision 1.78
diff -u -p -r1.78 ChangeLog
--- src/ChangeLog 19 Mar 2003 11:59:45 -0000 1.78
+++ src/ChangeLog 21 Mar 2003 23:09:53 -0000
@@ -1,3 +1,7 @@
+2003-03-22 Simon Josefsson <jas@extundo.com>
+
+ * gcrypt.h: Add GCRYCTL_SET_CBC_MAC and GCRY_CIPHER_CBC_MAC.
+
2003-03-19 Werner Koch <wk@gnupg.org>
* g10lib.h: Adjusted primegen.c prototypes.
Index: src/gcrypt.h
===================================================================
RCS file: /cvs/gnupg/libgcrypt/src/gcrypt.h,v
retrieving revision 1.74
diff -u -p -r1.74 gcrypt.h
--- src/gcrypt.h 4 Mar 2003 18:09:33 -0000 1.74
+++ src/gcrypt.h 21 Mar 2003 23:09:53 -0000
@@ -169,6 +169,7 @@ enum gcry_control_cmds
GCRYCTL_RESET,
GCRYCTL_CFB_SYNC,
GCRYCTL_SET_CBC_CTS,
+ GCRYCTL_SET_CBC_MAC,
GCRYCTL_ENABLE_ALGO, /* Not implemented. */
GCRYCTL_DISABLE_ALGO,
GCRYCTL_FINALIZE,
@@ -545,7 +546,8 @@ enum gcry_cipher_flags
{
GCRY_CIPHER_SECURE = 1, /* Allocate in secure memory. */
GCRY_CIPHER_ENABLE_SYNC = 2, /* Enable CFB sync mode. */
- GCRY_CIPHER_CBC_CTS = 4 /* Enable CBC cipher text stealing (CTS). */
+ GCRY_CIPHER_CBC_CTS = 4, /* Enable CBC cipher text stealing (CTS). */
+ GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */
};
Index: tests/ChangeLog
===================================================================
RCS file: /cvs/gnupg/libgcrypt/tests/ChangeLog,v
retrieving revision 1.16
diff -u -p -r1.16 ChangeLog
--- tests/ChangeLog 19 Mar 2003 11:57:55 -0000 1.16
+++ tests/ChangeLog 21 Mar 2003 23:09:53 -0000
@@ -1,3 +1,8 @@
+2003-03-22 Simon Josefsson <jas@extundo.com>
+
+ * basic.c (check_cbc_mac_cipher): New.
+ (main): Use it.
+
2003-03-19 Werner Koch <wk@gnupg.org>
* keygen.c (check_rsa_keys): Don't expect an exponent when asking
Index: tests/basic.c
===================================================================
RCS file: /cvs/gnupg/libgcrypt/tests/basic.c,v
retrieving revision 1.12
diff -u -p -r1.12 basic.c
--- tests/basic.c 19 Mar 2003 11:57:55 -0000 1.12
+++ tests/basic.c 21 Mar 2003 23:09:53 -0000
@@ -1,5 +1,5 @@
/* basic.c - basic regression tests
- * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -88,6 +88,86 @@ die ( const char *format, ... )
#define MAX_DATA_LEN 100
static void
+check_cbc_mac_cipher (void)
+{
+ struct tv {
+ int algo;
+ char key[MAX_DATA_LEN];
+ char plaintext[MAX_DATA_LEN];
+ size_t plaintextlen;
+ char mac[MAX_DATA_LEN];
+ } tv[] = {
+ { GCRY_CIPHER_AES,
+ "chicken teriyaki",
+ "This is a sample plaintext for CBC MAC of sixtyfour bytes.......", 0,
+ "\x23\x8f\x6d\xc7\x53\x6a\x62\x97\x11\xc4\xa5\x16\x43\xea\xb0\xb6" },
+ { GCRY_CIPHER_3DES,
+ "abcdefghABCDEFGH01234567",
+ "This is a sample plaintext for CBC MAC of sixtyfour bytes.......", 0,
+ "\x5c\x11\xf0\x01\x47\xbd\x3d\x3a" },
+ { GCRY_CIPHER_DES,
+ "abcdefgh",
+ "This is a sample plaintext for CBC MAC of sixtyfour bytes.......", 0,
+ "\xfa\x4b\xdf\x9d\xfa\xab\x01\x70" }
+ };
+ GCRY_CIPHER_HD hd;
+ char out[MAX_DATA_LEN];
+ int i;
+
+ for (i = 0; i < sizeof(tv) / sizeof(tv[0]); i++)
+ {
+ hd = gcry_cipher_open (tv[i].algo,
+ GCRY_CIPHER_MODE_CBC,
+ GCRY_CIPHER_CBC_MAC);
+ if (!hd) {
+ fail ("cbc-mac algo %d, grcy_open_cipher failed: %s\n",
+ tv[i].algo, gcry_strerror (-1) );
+ return;
+ }
+
+ if (gcry_cipher_setkey (hd, tv[i].key,
+ gcry_cipher_get_algo_keylen (tv[i].algo))) {
+ fail ("cbc-mac algo %d, gcry_cipher_setkey failed: %s\n",
+ tv[i].algo, gcry_strerror (-1) );
+ gcry_cipher_close (hd);
+ return;
+ }
+
+ if (gcry_cipher_setiv (hd, NULL, 0)) {
+ fail ("cbc-mac algo %d, gcry_cipher_setiv failed: %s\n",
+ tv[i].algo, gcry_strerror (-1) );
+ gcry_cipher_close (hd);
+ return;
+ }
+
+ if ( gcry_cipher_encrypt (hd,
+ out, gcry_cipher_get_algo_blklen(tv[i].algo),
+ tv[i].plaintext,
+ tv[i].plaintextlen ?
+ tv[i].plaintextlen :
+ strlen(tv[i].plaintext))) {
+ fail ("cbc-mac algo %d, gcry_cipher_encrypt failed: %s\n",
+ tv[i].algo, gcry_strerror (-1) );
+ gcry_cipher_close (hd);
+ return;
+ }
+
+#if 0
+ { int j;
+ for (j=0; j < gcry_cipher_get_algo_blklen(tv[i].algo); j++)
+ printf("\\x%02x", out[j] & 0xFF);
+ printf("\n");
+ }
+#endif
+
+ if ( memcmp (tv[i].mac, out, gcry_cipher_get_algo_blklen(tv[i].algo)) )
+ fail ("cbc-mac algo %d, encrypt mismatch entry %d\n", tv[i].algo, i);
+
+ gcry_cipher_close (hd);
+ }
+}
+
+static void
check_aes128_cbc_cts_cipher ()
{
char key[128/8] = "chicken teriyaki";
@@ -600,6 +680,7 @@ main (int argc, char **argv)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
check_ciphers ();
check_aes128_cbc_cts_cipher ();
+ check_cbc_mac_cipher ();
check_digests ();
check_pubkey ();