Hello,

[I'm re-sending this e-mail again because I haven't received any reply and it 
didn't appeared neither on http://rt.openssl.org/NoAuth/Buglist.html nor on 
-devel list.]

Attached patch set adds support for key wrapping mode described in RFC 5649.

This mode allows you to wrap keys of any length in range [1, 2^31] bytes and 
does integrity check after unwrapping. It is an extension of original key 
wrapping algorithm described in RFC 3394 (this is already implemented as 
CRYPTO_128_wrap and works only with 64-bit blocks).

This patch set also adds test for RFC 3394 and RFC 5649 functionality.

I tried to fully describe purpose and implementation directly in the code 
comments.

This patch set is re-implementation from scratch and obsoletes patch attached 
to ticket 2204 from year 2010.


Last patch
0006-crypto-modes-wrap128.c-fix-input-length-validation-t.patch
fixes input validation in current implementation of CRYPTO_128_wrap (RFC 3394).

I have pushed the whole patch set to Github:
https://github.com/spacekpe/openssl/tree/aes_wrap_pad


Thank you for patch review. Have a nice day!

-- 
Petr Spacek  @  Red Hat


>From aa8732d19d6a1bb2f4d4cca22a4d7e74333a9618 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 26 Jun 2014 17:02:30 +0200
Subject: [PATCH] crypto/aes/aes_test.c: add tests for RFC 3394 compliance.

---
 crypto/aes/Makefile   |   3 +-
 crypto/aes/aes_test.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++
 test/Makefile         |  25 +++--
 3 files changed, 277 insertions(+), 16 deletions(-)
 create mode 100644 crypto/aes/aes_test.c

diff --git a/crypto/aes/Makefile b/crypto/aes/Makefile
index cd218c9d980b399da94b7446cc184c40990f84fb..f1dfb2c6489dc5f56980b0ac15b84f6a4e8746e5 100644
--- a/crypto/aes/Makefile
+++ b/crypto/aes/Makefile
@@ -18,8 +18,7 @@ ASFLAGS= $(INCLUDES) $(ASFLAG)
 AFLAGS= $(ASFLAGS)
 
 GENERAL=Makefile
-#TEST=aestest.c
-TEST=
+TEST=aes_test.c
 APPS=
 
 LIB=$(TOP)/libcrypto.a
diff --git a/crypto/aes/aes_test.c b/crypto/aes/aes_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..d2acc93e7954b9edfd6fd1b6757f967c52ba50fc
--- /dev/null
+++ b/crypto/aes/aes_test.c
@@ -0,0 +1,265 @@
+/* crypto/aes/aes_test.c */
+/* Written by Petr Spacek (pspa...@redhat.com).
+ */
+/* ====================================================================
+ * Copyright (c) 2014 Red Hat.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licens...@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "e_os.h"
+
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#ifdef OPENSSL_NO_AES
+int main(int argc, char *argv[])
+{
+	printf("No AES support\n");
+	return(0);
+}
+#else
+#include <openssl/aes.h>
+#include <openssl/modes.h>
+
+struct value {
+	const size_t len;
+	const unsigned char *val;
+	};
+
+struct test {
+	const char *name;
+	const struct value kek;
+	const struct value iv;
+	const struct value ptext;
+	const struct value ctext;
+	const int wrap_ret;
+	const int unwrap_ret;
+	};
+
+#define VALUE(value) {(sizeof(value)-1), ((unsigned char *)value)}
+#define PT_VALUE(value) .ptext = {(sizeof(value)-1), ((unsigned char *)value)}, .unwrap_ret = (sizeof(value)-1)
+#define CT_VALUE(value) .ctext = {(sizeof(value)-1), ((unsigned char *)value)}, .wrap_ret = (sizeof(value)-1)
+
+struct test tests_nopad[] =
+	{
+		/* Test vectors from RFC 3394 section 4. */
+		{
+		"RFC 3394 section 4.1: 128 bits of Key Data with a 128-bit KEK",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"),
+		{0, NULL},
+		PT_VALUE("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"),
+		CT_VALUE("\x1F\xA6\x8B\x0A\x81\x12\xB4\x47\xAE\xF3\x4B\xD8\xFB\x5A\x7B\x82\x9D\x3E\x86\x23\x71\xD2\xCF\xE5"),
+		},
+		{
+		"RFC 3394 section 4.2: 128 bits of Key Data with a 192-bit KEK",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17"),
+		{0, NULL},
+		PT_VALUE("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"),
+		CT_VALUE("\x96\x77\x8B\x25\xAE\x6C\xA4\x35\xF9\x2B\x5B\x97\xC0\x50\xAE\xD2\x46\x8A\xB8\xA1\x7A\xD8\x4E\x5D"),
+		},
+		{
+		"RFC 3394 section 4.3: 128 bits of Key Data with a 256-bit KEK",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		{0, NULL},
+		PT_VALUE("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"),
+		CT_VALUE("\x64\xE8\xC3\xF9\xCE\x0F\x5B\xA2\x63\xE9\x77\x79\x05\x81\x8A\x2A\x93\xC8\x19\x1E\x7D\x6E\x8A\xE7"),
+		},
+		{
+		"RFC 3394 section 4.4: 192 bits of Key Data with a 192-bit KEK",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17"),
+		{0, NULL},
+		PT_VALUE("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03\x04\x05\x06\x07"),
+		CT_VALUE("\x03\x1D\x33\x26\x4E\x15\xD3\x32\x68\xF2\x4E\xC2\x60\x74\x3E\xDC\xE1\xC6\xC7\xDD\xEE\x72\x5A\x93\x6B\xA8\x14\x91\x5C\x67\x62\xD2"),
+		},
+		{
+		"RFC 3394 section 4.5: 192 bits of Key Data with a 256-bit KEK",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		{0, NULL},
+		PT_VALUE("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03\x04\x05\x06\x07"),
+		CT_VALUE("\xA8\xF9\xBC\x16\x12\xC6\x8B\x3F\xF6\xE6\xF4\xFB\xE3\x0E\x71\xE4\x76\x9C\x8B\x80\xA3\x2C\xB8\x95\x8C\xD5\xD1\x7D\x6B\x25\x4D\xA1"),
+		},
+		{
+		"RFC 3394 section 4.6: 256 bits of Key Data with a 256-bit KEK",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		{0, NULL},
+		PT_VALUE("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"),
+		CT_VALUE("\x28\xC9\xF4\x04\xC4\xB8\x10\xF4\xCB\xCC\xB3\x5C\xFB\x87\xF8\x26\x3F\x57\x86\xE2\xD8\x0E\xD3\x26\xCB\xC7\xF0\xE7\x1A\x99\xF4\x3B\xFB\x98\x8B\x9B\x7A\x02\xDD\x21"),
+		},
+		/* Inputs invalid according to RFC 3394 section 2. */
+		{
+		"RFC 3394 section 2  : 0 byte input",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		{0, NULL},
+		.ptext = VALUE(""),
+		.wrap_ret = 0,
+		},
+		{
+		"RFC 3394 section 2  : 0 byte input",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		{0, NULL},
+		.ctext = VALUE(""),
+		.unwrap_ret = 0,
+		},
+		{
+		"RFC 3394 section 2  : 1 byte input",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		{0, NULL},
+		.ptext = VALUE("\x66"),
+		.wrap_ret = 0,
+		},
+		{
+		"RFC 3394 section 2  : 1 byte input",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		{0, NULL},
+		.ctext = VALUE("\x66"),
+		.unwrap_ret = 0,
+		},
+		{
+		NULL
+		}
+	};
+
+void print_hex(const unsigned char *val, size_t len)
+	{
+	size_t i;
+	for (i = 0; i < len; i++)
+		{
+		printf("%02x", val[i]);
+		}
+	}
+
+int compare_results(int got_ret, int exp_ret, const unsigned char *got_out,
+		const unsigned char *exp_out, int len,
+		const char *msg_prefix, const char *name)
+	{
+	if (got_ret != exp_ret)
+		{
+		printf("error in AES %swrap test '%s': "\
+			"got retval %d instead of %d\n",
+			msg_prefix, name, got_ret, exp_ret);
+		}
+	else if (exp_out != NULL && memcmp(got_out, exp_out, len) != 0)
+		{
+		printf("error in AES %swrap test '%s': got\n",
+			msg_prefix, name);
+		print_hex(got_out, len);
+		printf("\ninstead of\n");
+		print_hex(exp_out, len);
+		printf("\n");
+		}
+	else
+		{
+		printf("AES %2swrap test '%s' ok\n", msg_prefix, name);
+		return 0;
+		}
+	return 1;
+	}
+
+int run_tests(struct test *tests,
+		int (*wrap_f)(AES_KEY *key, const unsigned char *iv,
+		unsigned char *out, const unsigned char *in,
+		unsigned int inlen),
+		int (*unwrap_f)(AES_KEY *key, const unsigned char *iv,
+		unsigned char *out, const unsigned char *in,
+		unsigned int inlen))
+	{
+	int ret = 0;
+	int err = 0;
+	struct test *t = tests;
+	unsigned char outbuf[255];
+	AES_KEY kek;
+
+	while (t->name != NULL)
+		{
+		if (t->ptext.val != NULL)
+		{
+			assert(sizeof(outbuf) >= t->ctext.len);
+			ret = AES_set_encrypt_key(t->kek.val, t->kek.len*8,
+							&kek);
+			assert(ret == 0);
+			ret = wrap_f(&kek, t->iv.val, outbuf, t->ptext.val,
+					t->ptext.len);
+			err += compare_results(ret, t->wrap_ret, outbuf,
+						t->ctext.val, t->ctext.len,
+						"", t->name);
+		}
+
+		if (t->ctext.val != NULL)
+			{
+			assert(sizeof(outbuf) >= t->ptext.len);
+			ret = AES_set_decrypt_key(t->kek.val, t->kek.len*8,
+							&kek);
+			assert(ret == 0);
+			ret = unwrap_f(&kek, t->iv.val, outbuf, t->ctext.val,
+					t->ctext.len);
+			err += compare_results(ret, t->unwrap_ret, outbuf,
+						t->ptext.val, t->ptext.len,
+						"un", t->name);
+			}
+
+		t++;
+		}
+
+	return err;
+	}
+
+int main(int argc, char *argv[])
+	{
+	int err = 0;
+	err += run_tests(tests_nopad, AES_wrap_key, AES_unwrap_key);
+
+#ifdef OPENSSL_SYS_NETWARE
+	if (err) printf("ERROR: %d\n", err);
+#endif
+	EXIT(err);
+	return(err);
+	}
+
+#endif
diff --git a/test/Makefile b/test/Makefile
index 1dd7bb91a6426cf624af40ce4d7ca2e48bee2071..660739910fddc86e03d2526663ecc931e2e958ab 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -30,6 +30,7 @@ LIBCRYPTO= -L.. -lcrypto
 LIBSSL= -L.. -lssl
 LIBFIPS= -L.. -lfips
 
+AESTEST=	aes_test
 BNTEST=		bntest
 ECTEST=		ectest
 ECDSATEST=	ecdsatest
@@ -90,7 +91,7 @@ HEARTBEATTEST=  heartbeat_test
 
 TESTS=		alltests
 
-EXE=	$(BNTEST)$(EXE_EXT) $(ECTEST)$(EXE_EXT)  $(ECDSATEST)$(EXE_EXT) $(ECDHTEST)$(EXE_EXT) $(IDEATEST)$(EXE_EXT) \
+EXE=	$(AESTEST)$(EXE_EXT) $(BNTEST)$(EXE_EXT) $(ECTEST)$(EXE_EXT)  $(ECDSATEST)$(EXE_EXT) $(ECDHTEST)$(EXE_EXT) $(IDEATEST)$(EXE_EXT) \
 	$(MD2TEST)$(EXE_EXT)  $(MD4TEST)$(EXE_EXT) $(MD5TEST)$(EXE_EXT) $(HMACTEST)$(EXE_EXT) $(WPTEST)$(EXE_EXT) \
 	$(RC2TEST)$(EXE_EXT) $(RC4TEST)$(EXE_EXT) $(RC5TEST)$(EXE_EXT) \
 	$(DESTEST)$(EXE_EXT) $(SHATEST)$(EXE_EXT) $(SHA1TEST)$(EXE_EXT) $(SHA256TEST)$(EXE_EXT) $(SHA512TEST)$(EXE_EXT) \
@@ -114,7 +115,7 @@ FIPSEXE=$(FIPS_SHATEST)$(EXE_EXT) $(FIPS_DESTEST)$(EXE_EXT) \
 
 # $(METHTEST)$(EXE_EXT)
 
-OBJ=	$(BNTEST).o $(ECTEST).o  $(ECDSATEST).o $(ECDHTEST).o $(IDEATEST).o \
+OBJ=	$(AESTEST).o $(BNTEST).o $(ECTEST).o  $(ECDSATEST).o $(ECDHTEST).o $(IDEATEST).o \
 	$(MD2TEST).o $(MD4TEST).o $(MD5TEST).o \
 	$(HMACTEST).o $(WPTEST).o \
 	$(RC2TEST).o $(RC4TEST).o $(RC5TEST).o \
@@ -131,7 +132,7 @@ OBJ=	$(BNTEST).o $(ECTEST).o  $(ECDSATEST).o $(ECDHTEST).o $(IDEATEST).o \
 	$(EVPTEST).o $(IGETEST).o $(JPAKETEST).o $(V3NAMETEST).o \
 	$(GOST2814789TEST).o $(HEARTBEATTEST).o $(P5_CRPT2_TEST).o
 
-SRC=	$(BNTEST).c $(ECTEST).c  $(ECDSATEST).c $(ECDHTEST).c $(IDEATEST).c \
+SRC=	$(AESTEST).c $(BNTEST).c $(ECTEST).c  $(ECDSATEST).c $(ECDHTEST).c $(IDEATEST).c \
 	$(MD2TEST).c  $(MD4TEST).c $(MD5TEST).c \
 	$(HMACTEST).c $(WPTEST).c \
 	$(RC2TEST).c $(RC4TEST).c $(RC5TEST).c \
@@ -185,16 +186,19 @@ apps:
 	@(cd ..; $(MAKE) DIRS=apps all)
 
 alltests: \
-	test_des test_idea test_sha test_md4 test_md5 test_hmac \
+	test_aes test_des test_idea test_sha test_md4 test_md5 test_hmac \
 	test_md2 test_mdc2 test_wp \
 	test_rmd test_rc2 test_rc4 test_rc5 test_bf test_cast \
 	test_rand test_bn test_ec test_ecdsa test_ecdh \
 	test_enc test_x509 test_rsa test_crl test_sid \
 	test_gen test_req test_pkcs7 test_verify test_dh test_dsa \
 	test_ss test_ca test_engine test_evp test_ssl test_tsa test_ige \
 	test_jpake test_srp test_cms test_v3name test_ocsp \
 	test_gost2814789 test_heartbeat test_p5_crpt2
 
+test_aes: $(AESTEST)$(EXE_EXT)
+	../util/shlib_wrap.sh ./$(AESTEST)
+
 test_evp: $(EVPTEST)$(EXE_EXT) evptests.txt
 	../util/shlib_wrap.sh ./$(EVPTEST) evptests.txt
 
@@ -427,6 +431,9 @@ BUILD_CMD_STATIC=shlib_target=; \
 		LIBDEPS="$(PEX_LIBS) $$LIBRARIES $(EX_LIBS)" \
 		link_app.$${shlib_target}
 
+$(AESTEST)$(EXE_EXT): $(AESTEST).o $(DLIBCRYPTO)
+	@target=$(AESTEST); $(BUILD_CMD)
+
 $(RSATEST)$(EXE_EXT): $(RSATEST).o $(DLIBCRYPTO)
 	@target=$(RSATEST); $(BUILD_CMD)
 
@@ -627,16 +634,6 @@ $(V3NAMETEST)$(EXE_EXT): $(V3NAMETEST).o $(DLIBCRYPTO)
 $(HEARTBEATTEST)$(EXE_EXT): $(HEARTBEATTEST).o $(DLIBCRYPTO)
 	@target=$(HEARTBEATTEST); $(BUILD_CMD_STATIC)
 
-#$(AESTEST).o: $(AESTEST).c
-#	$(CC) -c $(CFLAGS) -DINTERMEDIATE_VALUE_KAT -DTRACE_KAT_MCT $(AESTEST).c
-
-#$(AESTEST)$(EXE_EXT): $(AESTEST).o $(DLIBCRYPTO)
-#	if [ "$(SHLIB_TARGET)" = "hpux-shared" -o "$(SHLIB_TARGET)" = "darwin-shared" ] ; then \
-#	  $(CC) -o $(AESTEST)$(EXE_EXT) $(CFLAGS) $(AESTEST).o $(PEX_LIBS) $(DLIBCRYPTO) $(EX_LIBS) ; \
-#	else \
-#	  $(CC) -o $(AESTEST)$(EXE_EXT) $(CFLAGS) $(AESTEST).o $(PEX_LIBS) $(LIBCRYPTO) $(EX_LIBS) ; \
-#	fi
-
 dummytest$(EXE_EXT): dummytest.o $(DLIBCRYPTO)
 	@target=dummytest; $(BUILD_CMD)
 
-- 
1.9.3

>From c0a37880f4c495b8e8e74893bb4f3fbbc04feb3e Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 26 Jun 2014 18:54:13 +0200
Subject: [PATCH] crypto/modes/wrap128.c: support overlapping input and output
 buffers.

This is going to be especially useful for RFC 5649 implementation.
---
 crypto/aes/aes_test.c  | 6 ++++--
 crypto/modes/wrap128.c | 4 ++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/crypto/aes/aes_test.c b/crypto/aes/aes_test.c
index d2acc93e7954b9edfd6fd1b6757f967c52ba50fc..2ab38dc68d5ba7ebdafe8e836303ffa327b85d4f 100644
--- a/crypto/aes/aes_test.c
+++ b/crypto/aes/aes_test.c
@@ -224,7 +224,8 @@ int run_tests(struct test *tests,
 			ret = AES_set_encrypt_key(t->kek.val, t->kek.len*8,
 							&kek);
 			assert(ret == 0);
-			ret = wrap_f(&kek, t->iv.val, outbuf, t->ptext.val,
+			memcpy(outbuf, t->ptext.val, t->ptext.len);
+			ret = wrap_f(&kek, t->iv.val, outbuf, outbuf,
 					t->ptext.len);
 			err += compare_results(ret, t->wrap_ret, outbuf,
 						t->ctext.val, t->ctext.len,
@@ -237,7 +238,8 @@ int run_tests(struct test *tests,
 			ret = AES_set_decrypt_key(t->kek.val, t->kek.len*8,
 							&kek);
 			assert(ret == 0);
-			ret = unwrap_f(&kek, t->iv.val, outbuf, t->ctext.val,
+			memcpy(outbuf, t->ctext.val, t->ctext.len);
+			ret = unwrap_f(&kek, t->iv.val, outbuf, outbuf,
 					t->ctext.len);
 			err += compare_results(ret, t->unwrap_ret, outbuf,
 						t->ptext.val, t->ptext.len,
diff --git a/crypto/modes/wrap128.c b/crypto/modes/wrap128.c
index 18785320f29ffa9a320ff400151f8b5ee58088bd..8ec4a2f329de0a1b90238c70f9c76463a8a4c77b 100644
--- a/crypto/modes/wrap128.c
+++ b/crypto/modes/wrap128.c
@@ -72,7 +72,7 @@ size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
 		return 0;
 	A = B;
 	t = 1;
-	memcpy(out + 8, in, inlen);
+	memmove(out + 8, in, inlen);
 	if (!iv)
 		iv = default_iv;
 
@@ -111,7 +111,7 @@ size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
 	A = B;
 	t =  6 * (inlen >> 3);
 	memcpy(A, in, 8);
-	memcpy(out, in + 8, inlen);
+	memmove(out, in + 8, inlen);
 	for (j = 0; j < 6; j++)
 		{
 		R = out + inlen - 8;
-- 
1.9.3

>From 36971f17b990fd6e7caa10ae09af9edc17082752 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 27 Jun 2014 10:05:42 +0200
Subject: [PATCH] crypto/modes/wrap128.c: divide unwrapping and IV check to two
 functions.

This is going to be especially useful for RFC 5649 implementation.
---
 crypto/modes/wrap128.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 57 insertions(+), 4 deletions(-)

diff --git a/crypto/modes/wrap128.c b/crypto/modes/wrap128.c
index 8ec4a2f329de0a1b90238c70f9c76463a8a4c77b..fc21a3d1782a561951e655c1a7d63a3ee75ab57f 100644
--- a/crypto/modes/wrap128.c
+++ b/crypto/modes/wrap128.c
@@ -62,6 +62,17 @@ static const unsigned char default_iv[] = {
  */
 #define CRYPTO128_WRAP_MAX (1UL << 31)
 
+/** Wrapping according to RFC 3394 section 2.2.1.
+ *
+ *  @param[in]  iv  IV value. Length = 8 bytes. NULL = use default_iv.
+ *  @param[in]  in  Plain text as n 64-bit blocks.
+ *  @param[out] out Cipher text. Minimal buffer length = (inlen + 8) bytes.
+ *                  Input and output buffers can overlap if block function
+ *                  supports that.
+ *  @return         0 if inlen does not consist of n 64-bit blocks, n > 0
+ *                  or if inlen > CRYPTO128_WRAP_MAX.
+ *                  Output length if wrapping succeeded.
+ */
 size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
 		unsigned char *out,
 		const unsigned char *in, size_t inlen, block128_f block)
@@ -99,9 +110,22 @@ size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
 	return inlen + 8;
 	}
 
-size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
-		unsigned char *out,
-		const unsigned char *in, size_t inlen, block128_f block)
+
+/** Unwrapping according to RFC 3394 section 2.2.2 steps 1-2.
+ *  IV check (step 3) is responsibility of the caller.
+ *
+ *  @param[out] iv  Unchecked IV value. Minimal buffer length = 8 bytes.
+ *  @param[out] out Plain text without IV.
+ *                  Minimal buffer length = (inlen - 8) bytes.
+ *                  Input and output buffers can overlap if block function
+ *                  supports that.
+ *  @return         0 if inlen is out of range [16, CRYPTO128_WRAP_MAX]
+ *                  or if inlen is not multiply of 8.
+ *                  Output length otherwise.
+ */
+static size_t _CRYPTO_128_unwrap_raw(void *key, unsigned char *iv,
+		unsigned char *out, const unsigned char *in,
+		size_t inlen, block128_f block)
 	{
 	unsigned char *A, B[16], *R;
 	size_t i, j, t;
@@ -129,9 +153,38 @@ size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
 			memcpy(R, B + 8, 8);
 			}
 		}
+	memcpy(iv, A, 8);
+	return inlen;
+	}
+
+/** Unwrapping according to RFC 3394 section 2.2.2 including IV check.
+ *  First block of plain text have to match supplied IV otherwise an error is
+ *  returned.
+ *
+ *  @param[in]  iv  Expected IV value. Length = 8 bytes. NULL = use default_iv.
+ *  @param[out] out Plain text without IV.
+ *                  Minimal buffer length = (inlen - 8) bytes.
+ *                  Input and output buffers can overlap if block function
+ *                  supports that.
+ *  @return         0 if inlen is out of range [16, CRYPTO128_WRAP_MAX]
+ *                  or if inlen is not multiply of 8
+ *                  or if IV doesn't match expected value.
+ *                  Output length if unwrapping succeeded and IV matches.
+ */
+size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
+		unsigned char *out, const unsigned char *in, size_t inlen,
+		block128_f block)
+	{
+	int ret;
+	unsigned char got_iv[8];
+
+	ret = _CRYPTO_128_unwrap_raw(key, got_iv, out, in, inlen, block);
+	if (ret != inlen)
+		return ret;
+
 	if (!iv)
 		iv = default_iv;
-	if (memcmp(A, iv, 8))
+	if (memcmp(out, iv, 8))
 		{
 		OPENSSL_cleanse(out, inlen);
 		return 0;
-- 
1.9.3

>From 8a190172ac1009457ab29416d811c73f52775a6e Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 27 Jun 2014 13:23:43 +0200
Subject: [PATCH] crypto/modes/wrap128.c: add RFC 5649 wrapping mode with
 padding.

This mode can wrap any key with length in [1, 2^31] range.

Beware!
This wrapping mode was designed for AES but this implementation allows you
to work with any 128 bit block cipher. (The same applies to original
wrapping mode from RFC 3394 implemented in CRYPTO_128_wrap.)
---
 crypto/modes/modes.h   |   6 ++
 crypto/modes/wrap128.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/crypto/modes/modes.h b/crypto/modes/modes.h
index 9912550a219244e874906d93128807608b3a9c00..e86b6726ba0cf7f32089d72115f959ef62f3139d 100644
--- a/crypto/modes/modes.h
+++ b/crypto/modes/modes.h
@@ -141,3 +141,9 @@ size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
 size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
 		unsigned char *out,
 		const unsigned char *in, size_t inlen, block128_f block);
+int CRYPTO_128_wrap_withpad(void *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen, block128_f block);
+int CRYPTO_128_unwrap_withpad(void *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen, block128_f block);
diff --git a/crypto/modes/wrap128.c b/crypto/modes/wrap128.c
index fc21a3d1782a561951e655c1a7d63a3ee75ab57f..7d344cd2fceaee35a23e05ab277b8c16a21bc0e5 100644
--- a/crypto/modes/wrap128.c
+++ b/crypto/modes/wrap128.c
@@ -1,6 +1,7 @@
 /* crypto/modes/wrap128.c */
 /* Written by Dr Stephen N Henson (st...@openssl.org) for the OpenSSL
  * project.
+ * Mode with padding contributed by Petr Spacek (pspa...@redhat.com).
  */
 /* ====================================================================
  * Copyright (c) 2013 The OpenSSL Project.  All rights reserved.
@@ -51,14 +52,30 @@
  * ====================================================================
  */
 
+/**  Beware!
+ *
+ *  Following wrapping modes were designed for AES but this implementation
+ *  allows you to use them for any 128 bit block cipher.
+ */
+
+/* htonl and ntohl are necessary for (un)wrap_withpad implementation */
+#define USE_SOCKETS
+
 #include "cryptlib.h"
 #include <openssl/modes.h>
 
+/** RFC 3394 section 2.2.3.1 Default Initial Value */
 static const unsigned char default_iv[] = {
   0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
 };
-/* Input size limit: lower than maximum of standards but far larger than
- * anything that will be used in practice.
+
+/** RFC 5649 section 3 Alternative Initial Value 32-bit constant */
+static const unsigned char default_aiv[] = {
+  0xA6, 0x59, 0x59, 0xA6
+};
+
+/** Input size limit: lower than maximum of standards but far larger than
+ *  anything that will be used in practice.
  */
 #define CRYPTO128_WRAP_MAX (1UL << 31)
 
@@ -191,3 +208,147 @@ size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
 		}
 	return inlen;
 	}
+
+/** Wrapping according to RFC 5649 section 4.1.
+ *
+ *  @param[in]  iv   (Non-standard) IV, 4 bytes. NULL = use default_aiv.
+ *  @param[out] out  Cipher text. Minimal buffer length = (inlen + 15) bytes.
+ *                   Input and output buffers can overlap if block function
+ *                   supports that.
+ *  @return          0 if inlen is out of range [1, CRYPTO128_WRAP_MAX].
+ *                   Output length if wrapping succeeded.
+ */
+int CRYPTO_128_wrap_withpad(void *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen, block128_f block)
+	{
+	/* n: number of 64-bit blocks in the padded key data */
+	const unsigned int blocks_padded = (inlen + 8) / 8;
+	const unsigned int padded_len = blocks_padded * 8;
+	const unsigned int padding_len = padded_len - inlen;
+	const uint32_t inlen_net = htonl(inlen);
+	/* RFC 5649 section 3: Alternative Initial Value */
+	unsigned char aiv[8];
+	int ret;
+
+	/* Section 1: use 32-bit fixed field for plaintext ocket length */
+	if (inlen == 0 || inlen >= CRYPTO128_WRAP_MAX)
+		return 0;
+
+	/* Section 3: Alternative Initial Value */
+	if (!icv)
+		memcpy(aiv, default_aiv, 4);
+	else
+		memcpy(aiv, icv, 4); /* Standard doesn't mention this. */
+	memcpy(aiv + 4, &inlen_net, 4);
+
+	if (padded_len == 8)
+		{
+		/* Section 4.1 - special case in step 2:
+		 * If the padded plaintext contains exactly eight octets, then
+		 * prepend the AIV and encrypt the resulting 128-bit block
+		 * using AES in ECB mode. */
+		memmove(out + 8, in, inlen);
+		memcpy(out, aiv, 8);
+		memset(out + 8 + inlen, 0, padding_len);
+		block(out, out, key);
+		ret = 16; /* AIV + padded input */
+		}
+		else
+		{
+		memmove(out, in, inlen);
+		memset(out + inlen, 0, padding_len); /* Section 4.1 step 1 */
+		ret = CRYPTO_128_wrap(key, aiv, out, out, padded_len, block);
+		}
+
+	return ret;
+	}
+
+/** Unwrapping according to RFC 5649 section 4.2.
+ *
+ *  @param[in]  iv   (Non-standard) IV, 4 bytes. NULL = use default_aiv.
+ *  @param[out] out  Plain text. Minimal buffer length = inlen bytes.
+ *                   Input and output buffers can overlap if block function
+ *                   supports that.
+ *  @return          0 if inlen is out of range [16, CRYPTO128_WRAP_MAX],
+ *                   or if inlen is not multiply of 8
+ *                   or if IV and message length indicator doesn't match.
+ *                   Output length if unwrapping succeeded and IV matches.
+ */
+int CRYPTO_128_unwrap_withpad(void *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen, block128_f block)
+	{
+	/* n: number of 64-bit blocks in the padded key data */
+	unsigned int n = inlen / 8 - 1;
+	unsigned int padded_len;
+	unsigned int padding_len;
+	unsigned int ptext_len;
+	uint32_t ptext_len_net;
+	/* RFC 5649 section 3: Alternative Initial Value */
+	unsigned char aiv[8];
+	unsigned char zeros[8] = {0x0};
+	int ret;
+
+	/* Section 4.2: Cipher text length has to be (n+1) 64-bit blocks. */
+	if ((inlen & 0x7) != 0 || inlen < 16 || inlen >= CRYPTO128_WRAP_MAX)
+		return 0;
+
+	memmove(out, in, inlen);
+	if (inlen == 16)
+		{
+		/* Section 4.2 - special case in step 1:
+		 * When n=1, the ciphertext contains exactly two 64-bit
+		 * blocks and they are decrypted as a single AES
+		 * block using AES in ECB mode:
+		 * AIV | P[1] = DEC(K, C[0] | C[1])
+		 */
+		block(out, out, key);
+		memcpy(aiv, out, 8);
+		/* Remove AIV */
+		memmove(out, out + 8, 8);
+		padded_len = 8;
+		}
+		else
+		{
+		padded_len = inlen - 8;
+		ret = _CRYPTO_128_unwrap_raw(key, aiv, out, out, inlen, block);
+		if (padded_len != ret)
+			{
+			OPENSSL_cleanse(out, inlen);
+			return 0;
+			}
+		}
+
+	/* Section 3: AIV checks: Check that MSB(32,A) = A65959A6.
+	 * Optionally a user-supplied value can be used
+	 * (even if standard doesn't mention this). */
+	if ((!icv && memcmp(aiv, default_aiv, 4))
+		|| (icv && memcmp(aiv, icv, 4)))
+		{
+		OPENSSL_cleanse(out, inlen);
+		return 0;
+		}
+
+	/* Check that 8*(n-1) < LSB(32,AIV) <= 8*n.
+	 * If so, let ptext_len = LSB(32,AIV). */
+	memcpy(&ptext_len_net, aiv + 4, 4);
+	ptext_len = ntohl(ptext_len_net);
+	if (8*(n-1) >= ptext_len || ptext_len > 8*n)
+		{
+		OPENSSL_cleanse(out, inlen);
+		return 0;
+		}
+
+	/* Check that the rightmost padding_len octets of the output data
+	 * are zero. */
+	padding_len = padded_len - ptext_len;
+	if (memcmp(out + ptext_len, zeros, padding_len) != 0)
+		{
+		OPENSSL_cleanse(out, inlen);
+		return 0;
+		}
+
+	/* Section 4.2 step 3: Remove padding */
+	return ptext_len;
+	}
-- 
1.9.3

>From 8875023e983684549dfc29973838ec5a92e78df9 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 27 Jun 2014 13:31:07 +0200
Subject: [PATCH] crypto/aes/aes_wrap.c: add RFC 5649 wrapping mode with
 padding.

PKCS#11 name for this mode is CKM_AES_WRAP_PAD. It can be used for
wrapping key data with length in range [1, 2^31].
---
 crypto/aes/aes.h      |  7 ++++++-
 crypto/aes/aes_test.c | 40 ++++++++++++++++++++++++++++++++++++++++
 crypto/aes/aes_wrap.c | 14 ++++++++++++++
 3 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/crypto/aes/aes.h b/crypto/aes/aes.h
index 42cabf96894dd302c7102b285fd4b02ee0731c99..5fff265671aa53cffdb470be2f380faaa5ecba5b 100644
--- a/crypto/aes/aes.h
+++ b/crypto/aes/aes.h
@@ -135,7 +135,12 @@ int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
 int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
 		unsigned char *out,
 		const unsigned char *in, unsigned int inlen);
-
+int AES_wrap_key_withpad(AES_KEY *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen);
+int AES_unwrap_key_withpad(AES_KEY *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen);
 
 #ifdef  __cplusplus
 }
diff --git a/crypto/aes/aes_test.c b/crypto/aes/aes_test.c
index 2ab38dc68d5ba7ebdafe8e836303ffa327b85d4f..6305c9535b5fe8bd24cd0aed0227ae0d3152f5e0 100644
--- a/crypto/aes/aes_test.c
+++ b/crypto/aes/aes_test.c
@@ -166,6 +166,45 @@ struct test tests_nopad[] =
 		}
 	};
 
+struct test tests_withpad[] = {
+	{
+		"RFC 5649 section 6  : wrap 7 octets of key data with a 192-bit KEK",
+		VALUE("\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8"),
+		{0, NULL},
+		PT_VALUE("\x46\x6f\x72\x50\x61\x73\x69"),
+		CT_VALUE("\xaf\xbe\xb0\xf0\x7d\xfb\xf5\x41\x92\x00\xf2\xcc\xb5\x0b\xb2\x4f"),
+	},
+	{
+		"RFC 5649 section 6  : wrap 20 octets of key data with a 192-bit KEK",
+		VALUE("\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8"),
+		{0, NULL},
+		PT_VALUE("\xc3\x7b\x7e\x64\x92\x58\x43\x40\xbe\xd1\x22\x07\x80\x89\x41\x15\x50\x68\xf7\x38"),
+		CT_VALUE("\x13\x8b\xde\xaa\x9b\x8f\xa7\xfc\x61\xf9\x77\x42\xe7\x22\x48\xee\x5a\xe6\xae\x53\x60\xd1\xae\x6a\x5f\x54\xf3\x73\xfa\x54\x3b\x6a")
+	},
+	/* Tests incorrect inputs. */
+	{
+		"RFC 5649 section 4.2: 0 byte input",
+		VALUE("\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8"),
+		.ptext = VALUE(""),
+		.wrap_ret = 0
+	},
+	{
+		"padded unwrap 16 bytes of CT with one bit mangled",
+		VALUE("\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8"),
+		.ctext = VALUE("\x2f\xbe\xb0\xf0\x7d\xfb\xf5\x41\x92\x00\xf2\xcc\xb5\x0b\xb2\x4f"), /* MSB is flipped (first byte should be \xaf) */
+		.unwrap_ret = 0
+	},
+	{
+		"padded unwrap with incorrect IV",
+		VALUE("\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8"),
+		.iv = VALUE("\x12\x34\x56\x78"), /* Correct IV is the default one. */
+		CT_VALUE("\xaf\xbe\xb0\xf0\x7d\xfb\xf5\x41\x92\x00\xf2\xcc\xb5\x0b\xb2\x4f"),
+	},
+	{
+		NULL
+	}
+};
+
 void print_hex(const unsigned char *val, size_t len)
 	{
 	size_t i;
@@ -256,6 +295,7 @@ int main(int argc, char *argv[])
 	{
 	int err = 0;
 	err += run_tests(tests_nopad, AES_wrap_key, AES_unwrap_key);
+	err += run_tests(tests_withpad, AES_wrap_key_withpad, AES_unwrap_key_withpad);
 
 #ifdef OPENSSL_SYS_NETWARE
 	if (err) printf("ERROR: %d\n", err);
diff --git a/crypto/aes/aes_wrap.c b/crypto/aes/aes_wrap.c
index b30df8883fd01f5578a20fa609e0f6278060ab17..2efbe8ab261e43b227bbd8c258025ad3b3d7c9d0 100644
--- a/crypto/aes/aes_wrap.c
+++ b/crypto/aes/aes_wrap.c
@@ -68,3 +68,17 @@ int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
 	{
 	return CRYPTO_128_unwrap(key, iv, out, in, inlen, (block128_f)AES_decrypt);
 	}
+
+int AES_wrap_key_withpad(AES_KEY *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen)
+	{
+	return CRYPTO_128_wrap_withpad(key, icv, out, in, inlen, (block128_f)AES_encrypt);
+	}
+
+int AES_unwrap_key_withpad(AES_KEY *key, const unsigned char *icv,
+		unsigned char *out,
+		const unsigned char *in, unsigned int inlen)
+	{
+	return CRYPTO_128_unwrap_withpad(key, icv, out,	in, inlen, (block128_f)AES_decrypt);
+	}
-- 
1.9.3

>From 3fbd228193ecadb71dfb0b2fbb857e4eee9abcfa Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 27 Jun 2014 14:32:23 +0200
Subject: [PATCH] crypto/modes/wrap128.c: fix input length validation to follow
 RFC 3394.

RFC 3394 section 2 mandates minimal plaintext length to be two 64-bit blocks
so minimal cipher text length has to be three 64-bit blocks.
---
 crypto/aes/aes_test.c  | 16 ++++++++++++++++
 crypto/modes/wrap128.c | 12 ++++++------
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/crypto/aes/aes_test.c b/crypto/aes/aes_test.c
index 6305c9535b5fe8bd24cd0aed0227ae0d3152f5e0..8906c914578f86fe9c4874fe52e2492e9a794a73 100644
--- a/crypto/aes/aes_test.c
+++ b/crypto/aes/aes_test.c
@@ -147,6 +147,7 @@ struct test tests_nopad[] =
 		.ctext = VALUE(""),
 		.unwrap_ret = 0,
 		},
+		/* input length has to be multiply of 8 */
 		{
 		"RFC 3394 section 2  : 1 byte input",
 		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
@@ -161,6 +162,21 @@ struct test tests_nopad[] =
 		.ctext = VALUE("\x66"),
 		.unwrap_ret = 0,
 		},
+		/* wrapping requires at least 2 blocks */
+		{
+		"RFC 3394 section 2  : 1 block input",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		.ptext = VALUE("\x00\x01\x02\x03\x04\x05\x06\x07"),
+		.wrap_ret = 0,
+		},
+		/* unwrapping requires at least 3 blocks */
+		{
+		"RFC 3394 section 2  : 2 blocks input",
+		VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"),
+		.ctext = VALUE("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"),
+		.unwrap_ret = 0,
+		},
+
 		{
 		NULL
 		}
diff --git a/crypto/modes/wrap128.c b/crypto/modes/wrap128.c
index 7d344cd2fceaee35a23e05ab277b8c16a21bc0e5..7a0fd2f8c19aa07276a42fa3bdb3358258b2e28a 100644
--- a/crypto/modes/wrap128.c
+++ b/crypto/modes/wrap128.c
@@ -82,21 +82,21 @@ static const unsigned char default_aiv[] = {
 /** Wrapping according to RFC 3394 section 2.2.1.
  *
  *  @param[in]  iv  IV value. Length = 8 bytes. NULL = use default_iv.
- *  @param[in]  in  Plain text as n 64-bit blocks.
+ *  @param[in]  in  Plain text as n 64-bit blocks, n >= 2.
  *  @param[out] out Cipher text. Minimal buffer length = (inlen + 8) bytes.
  *                  Input and output buffers can overlap if block function
  *                  supports that.
- *  @return         0 if inlen does not consist of n 64-bit blocks, n > 0
+ *  @return         0 if inlen does not consist of n 64-bit blocks, n >= 2.
  *                  or if inlen > CRYPTO128_WRAP_MAX.
  *                  Output length if wrapping succeeded.
  */
 size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
 		unsigned char *out,
 		const unsigned char *in, size_t inlen, block128_f block)
 	{
 	unsigned char *A, B[16], *R;
 	size_t i, j, t;
-	if ((inlen & 0x7) || (inlen < 8) || (inlen > CRYPTO128_WRAP_MAX))
+	if ((inlen & 0x7) || (inlen < 16) || (inlen > CRYPTO128_WRAP_MAX))
 		return 0;
 	A = B;
 	t = 1;
@@ -136,7 +136,7 @@ size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
  *                  Minimal buffer length = (inlen - 8) bytes.
  *                  Input and output buffers can overlap if block function
  *                  supports that.
- *  @return         0 if inlen is out of range [16, CRYPTO128_WRAP_MAX]
+ *  @return         0 if inlen is out of range [24, CRYPTO128_WRAP_MAX]
  *                  or if inlen is not multiply of 8.
  *                  Output length otherwise.
  */
@@ -147,7 +147,7 @@ static size_t _CRYPTO_128_unwrap_raw(void *key, unsigned char *iv,
 	unsigned char *A, B[16], *R;
 	size_t i, j, t;
 	inlen -= 8;
-	if ((inlen & 0x7) || (inlen < 8) || (inlen > CRYPTO128_WRAP_MAX))
+	if ((inlen & 0x7) || (inlen < 16) || (inlen > CRYPTO128_WRAP_MAX))
 		return 0;
 	A = B;
 	t =  6 * (inlen >> 3);
@@ -183,7 +183,7 @@ static size_t _CRYPTO_128_unwrap_raw(void *key, unsigned char *iv,
  *                  Minimal buffer length = (inlen - 8) bytes.
  *                  Input and output buffers can overlap if block function
  *                  supports that.
- *  @return         0 if inlen is out of range [16, CRYPTO128_WRAP_MAX]
+ *  @return         0 if inlen is out of range [24, CRYPTO128_WRAP_MAX]
  *                  or if inlen is not multiply of 8
  *                  or if IV doesn't match expected value.
  *                  Output length if unwrapping succeeded and IV matches.
-- 
1.9.3

Reply via email to