summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2022-01-05 12:05:40 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2022-01-05 12:05:40 +0900
commit746b8e29969be56e086191dbe93978f7e0355aa0 (patch)
tree3a86cb0e60e9d09813cc347d2ef5ee903e1dad0f
parentf9ba07942b10c72af50bd73c92c4851b6981546e (diff)
downloadlibgcrypt-746b8e29969be56e086191dbe93978f7e0355aa0.tar.gz
cipher: Add an API to retrieve unwrapped key length for KWP.
* cipher/cipher-aeswrap.c (_gcry_cipher_keywrap_decrypt) (_gcry_cipher_keywrap_decrypt_padding): Merged into... (_gcry_cipher_keywrap_decrypt_auto): ... this. Write length information to struct gcry_cipher_handle. * cipher/cipher-internal.h (struct gcry_cipher_handle): Add u_mode.wrap. * cipher/cipher.c (_gcry_cipher_setup_mode_ops): Use _gcry_cipher_keywrap_decrypt_auto. (_gcry_cipher_info): Support GCRYCTL_GET_KEYLEN for GCRY_CIPHER_MODE_AESWRAP. Not that it's not length of KEK, but length of unwrapped key. * tests/aeswrap.c (check_one_with_padding): Add check for length of unwrapped key. -- Fixes-commit: 2914f169f95467b9c789000105773b38ad2dea5a GnuPG-bug-id: 5752 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
-rw-r--r--cipher/cipher-aeswrap.c93
-rw-r--r--cipher/cipher-internal.h14
-rw-r--r--cipher/cipher.c36
-rw-r--r--tests/aeswrap.c33
4 files changed, 94 insertions, 82 deletions
diff --git a/cipher/cipher-aeswrap.c b/cipher/cipher-aeswrap.c
index 86c4897f..62987d0f 100644
--- a/cipher/cipher-aeswrap.c
+++ b/cipher/cipher-aeswrap.c
@@ -259,67 +259,12 @@ unwrap (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, size_t inbuflen)
}
-/* Perform the Key Unwrap algorithm as specified by RFC3394. We
- implement this as a mode usable with any cipher algorithm of
- blocksize 128. */
-gcry_err_code_t
-_gcry_cipher_keywrap_decrypt (gcry_cipher_hd_t c,
- byte *outbuf, size_t outbuflen,
- const byte *inbuf, size_t inbuflen)
-{
- gcry_err_code_t err;
-
- /* We require a cipher with a 128 bit block length. */
- if (c->spec->blocksize != 16)
- return GPG_ERR_INV_LENGTH;
-
- /* The output buffer must be able to hold the input data minus one
- additional block. Fixme: The caller has more restrictive checks
- - we may want to fix them for this mode. */
- if (outbuflen + 8 < inbuflen)
- return GPG_ERR_BUFFER_TOO_SHORT;
- /* Input data must be multiple of 64 bits. */
- if (inbuflen % 8)
- return GPG_ERR_INV_ARG;
-
- /* We need at least three 64 bit blocks. */
- if ((inbuflen / 8) < 3)
- return GPG_ERR_INV_ARG;
-
- err = unwrap (c, outbuf, inbuf, inbuflen);
- if (!err)
- {
- int j, x;
- unsigned char *a;
-
- a = c->lastiv; /* We use c->LASTIV as buffer for A. */
-
- /* If an IV has been set we compare against this Alternative Initial
- Value; if it has not been set we compare against the standard IV. */
- if (c->marks.iv)
- j = memcmp (a, c->u_iv.iv, 8);
- else
- {
- for (j=0, x=0; x < 8; x++)
- if (a[x] != 0xa6)
- {
- j=1;
- break;
- }
- }
-
- if (j)
- err = GPG_ERR_CHECKSUM;
- }
-
- return err;
-}
-
-/* Perform the Key Unwrap algorithm as specified by RFC5649. */
+/* Perform the Key Unwrap algorithm as specified by RFC3394 and
+ RFC5649. */
gcry_err_code_t
-_gcry_cipher_keywrap_decrypt_padding (gcry_cipher_hd_t c,
- byte *outbuf, size_t outbuflen,
- const byte *inbuf, size_t inbuflen)
+_gcry_cipher_keywrap_decrypt_auto (gcry_cipher_hd_t c,
+ byte *outbuf, size_t outbuflen,
+ const byte *inbuf, size_t inbuflen)
{
gcry_err_code_t err;
@@ -365,7 +310,10 @@ _gcry_cipher_keywrap_decrypt_padding (gcry_cipher_hd_t c,
break;
}
if (!err)
- memcpy (outbuf, t+8, plen);
+ {
+ memcpy (outbuf, t+8, 8);
+ memcpy (c->u_mode.wrap.plen, t+4, 4);
+ }
}
}
}
@@ -382,9 +330,11 @@ _gcry_cipher_keywrap_decrypt_padding (gcry_cipher_hd_t c,
a = c->lastiv; /* We use c->LASTIV as buffer for A. */
- if (memcmp (a, icv2, 4))
- err = GPG_ERR_CHECKSUM;
- else
+ /* If an IV has been set we compare against this Alternative Initial
+ Value; if it has not been set we compare against the standard IV. */
+ if (c->marks.iv && !memcmp (a, c->u_iv.iv, 8))
+ memset (c->u_mode.wrap.plen, 0, 4);
+ else if (!memcmp (a, icv2, 4)) /* It's a packet wrapped by KWP. */
{
unsigned int plen = (a[4]<<24) | (a[5]<<16) | (a[6]<<8) | a[7];
int padlen = inbuflen - 8 - plen;
@@ -402,6 +352,21 @@ _gcry_cipher_keywrap_decrypt_padding (gcry_cipher_hd_t c,
break;
}
}
+ if (!err)
+ memcpy (c->u_mode.wrap.plen, a+4, 4);
+ }
+ else /* It's a packet wrapped by KW. */
+ {
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (a[i] != 0xa6)
+ {
+ err = GPG_ERR_CHECKSUM;
+ break;
+ }
+ if (!err)
+ memset (c->u_mode.wrap.plen, 0, 4);
}
}
}
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index 534aa77b..c8a1097a 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -431,6 +431,11 @@ struct gcry_cipher_handle
* cipher context. */
char *ctr_context;
} siv;
+
+ /* Mode specific storage for WRAP mode. */
+ struct {
+ unsigned char plen[4];
+ } wrap;
} u_mode;
/* What follows are two contexts of the cipher in use. The first
@@ -502,16 +507,11 @@ gcry_err_code_t _gcry_cipher_keywrap_encrypt
/* */ (gcry_cipher_hd_t c,
byte *outbuf, size_t outbuflen,
const byte *inbuf, size_t inbuflen);
-gcry_err_code_t _gcry_cipher_keywrap_decrypt
-/* */ (gcry_cipher_hd_t c,
- byte *outbuf, size_t outbuflen,
- const byte *inbuf, size_t inbuflen);
-gcry_err_code_t
-_gcry_cipher_keywrap_encrypt_padding
+gcry_err_code_t _gcry_cipher_keywrap_encrypt_padding
/* */ (gcry_cipher_hd_t c,
byte *outbuf, size_t outbuflen,
const byte *inbuf, size_t inbuflen);
-gcry_err_code_t _gcry_cipher_keywrap_decrypt_padding
+gcry_err_code_t _gcry_cipher_keywrap_decrypt_auto
/* */ (gcry_cipher_hd_t c,
byte *outbuf, size_t outbuflen,
const byte *inbuf, size_t inbuflen);
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 3e2b70a5..d1443a62 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -1359,16 +1359,11 @@ _gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode)
break;
case GCRY_CIPHER_MODE_AESWRAP:
+ c->mode_ops.decrypt = _gcry_cipher_keywrap_decrypt_auto;
if (!(c->flags & GCRY_CIPHER_EXTENDED))
- {
- c->mode_ops.encrypt = _gcry_cipher_keywrap_encrypt;
- c->mode_ops.decrypt = _gcry_cipher_keywrap_decrypt;
- }
+ c->mode_ops.encrypt = _gcry_cipher_keywrap_encrypt;
else
- {
- c->mode_ops.encrypt = _gcry_cipher_keywrap_encrypt_padding;
- c->mode_ops.decrypt = _gcry_cipher_keywrap_decrypt_padding;
- }
+ c->mode_ops.encrypt = _gcry_cipher_keywrap_encrypt_padding;
break;
case GCRY_CIPHER_MODE_CCM:
@@ -1690,6 +1685,12 @@ _gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
* BUFFER must be given as NULL. On success the result is stored
* at NBYTES. The taglen is returned in bytes.
*
+ * GCRYCTL_GET_KEYLEN:
+ * Return the length of the key wrapped for AES-WRAP mode. The
+ * length is encoded in big-endian 4 bytes, when the key is
+ * unwrapped with KWP. Return 00 00 00 00, when the key is
+ * unwrapped with KW.
+ *
* The function returns 0 on success or an error code.
*/
gcry_err_code_t
@@ -1741,6 +1742,25 @@ _gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes)
}
break;
+ case GCRYCTL_GET_KEYLEN:
+ if (!h || !buffer || !nbytes)
+ rc = GPG_ERR_INV_ARG;
+ else
+ {
+ switch (h->mode)
+ {
+ case GCRY_CIPHER_MODE_AESWRAP:
+ *nbytes = 4;
+ memcpy (buffer, h->u_mode.wrap.plen, 4);
+ break;
+
+ default:
+ rc = GPG_ERR_INV_CIPHER_MODE;
+ break;
+ }
+ }
+ break;
+
default:
rc = GPG_ERR_INV_OP;
}
diff --git a/tests/aeswrap.c b/tests/aeswrap.c
index 21632ed3..ed4453bd 100644
--- a/tests/aeswrap.c
+++ b/tests/aeswrap.c
@@ -261,6 +261,15 @@ check_one_with_padding (int algo,
else
{
err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen);
+ if (!err)
+ {
+ unsigned char plen[4];
+ size_t nbytes;
+ err = gcry_cipher_info (hd, GCRYCTL_GET_KEYLEN, plen, &nbytes);
+ if (!err)
+ outbuflen = (plen[0] << 24) | (plen[1] << 16)
+ | (plen[2] << 8) | plen[3];
+ }
}
if (err)
@@ -269,7 +278,7 @@ check_one_with_padding (int algo,
return;
}
- if (memcmp (outbuf, data, datalen))
+ if (outbuflen != datalen || memcmp (outbuf, data, datalen))
{
const unsigned char *s;
int i;
@@ -295,6 +304,15 @@ check_one_with_padding (int algo,
else
{
err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen);
+ if (!err)
+ {
+ unsigned char plen[4];
+ size_t nbytes;
+ err = gcry_cipher_info (hd, GCRYCTL_GET_KEYLEN, plen, &nbytes);
+ if (!err)
+ outbuflen = (plen[0] << 24) | (plen[1] << 16)
+ | (plen[2] << 8) | plen[3];
+ }
}
if (err)
@@ -303,7 +321,7 @@ check_one_with_padding (int algo,
return;
}
- if (memcmp (outbuf, data, datalen))
+ if (outbuflen != datalen || memcmp (outbuf, data, datalen))
fail ("mismatch at decryption(2)(padding)!\n");
/* And once more without a key reset. */
@@ -315,6 +333,15 @@ check_one_with_padding (int algo,
else
{
err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen);
+ if (!err)
+ {
+ unsigned char plen[4];
+ size_t nbytes;
+ err = gcry_cipher_info (hd, GCRYCTL_GET_KEYLEN, plen, &nbytes);
+ if (!err)
+ outbuflen = (plen[0] << 24) | (plen[1] << 16)
+ | (plen[2] << 8) | plen[3];
+ }
}
if (err)
@@ -323,7 +350,7 @@ check_one_with_padding (int algo,
return;
}
- if (memcmp (outbuf, data, datalen))
+ if (outbuflen != datalen || memcmp (outbuf, data, datalen))
fail ("mismatch at decryption(3)(padding)!\n");
gcry_cipher_close (hd);