Add NIST keywrap as a cipher mode

Closes #2003 see also #1658
diff --git a/library/cipher.c b/library/cipher.c
index 9ceea13..8a9b1da 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -63,6 +63,10 @@
 #include "mbedtls/psa_util.h"
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_NIST_KW_C)
+#include "mbedtls/nist_kw.h"
+#endif
+
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
 #else
@@ -1387,6 +1391,21 @@
                                 ilen, iv, ad, ad_len, input, output, tag ) );
     }
 #endif /* MBEDTLS_CHACHAPOLY_C */
+#if defined(MBEDTLS_NIST_KW_C)
+    if( MBEDTLS_MODE_KW == ctx->cipher_info->mode || MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
+    {
+        mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
+                                        MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
+
+        /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
+        if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
+        {
+            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+        }
+
+        return( mbedtls_nist_kw_wrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
+    }
+#endif /* MBEDTLS_NIST_KW_C */
 
     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 }
@@ -1496,6 +1515,21 @@
         return( ret );
     }
 #endif /* MBEDTLS_CHACHAPOLY_C */
+#if defined(MBEDTLS_NIST_KW_C)
+    if( MBEDTLS_MODE_KW == ctx->cipher_info->mode || MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
+    {
+        mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
+                                        MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
+
+        /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
+        if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
+        {
+            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+        }
+
+        return( mbedtls_nist_kw_unwrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
+    }
+#endif /* MBEDTLS_NIST_KW_C */
 
     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 }
diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c
index d4538ed..0199598 100644
--- a/library/cipher_wrap.c
+++ b/library/cipher_wrap.c
@@ -73,6 +73,10 @@
 #include "mbedtls/ccm.h"
 #endif
 
+#if defined(MBEDTLS_NIST_KW_C)
+#include "mbedtls/nist_kw.h"
+#endif
+
 #if defined(MBEDTLS_CIPHER_NULL_CIPHER)
 #include <string.h>
 #endif
@@ -2119,6 +2123,131 @@
 };
 #endif /* defined(MBEDTLS_CIPHER_NULL_CIPHER) */
 
+#if defined(MBEDTLS_NIST_KW_C)
+static void *kw_ctx_alloc( void )
+{
+    void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_nist_kw_context ) );
+
+    if( ctx != NULL )
+        mbedtls_nist_kw_init( (mbedtls_nist_kw_context *) ctx );
+
+    return( ctx );
+}
+
+static void kw_ctx_free( void *ctx )
+{
+    mbedtls_nist_kw_free( ctx );
+    mbedtls_free( ctx );
+}
+
+static int kw_aes_setkey_wrap( void *ctx, const unsigned char *key,
+                                unsigned int key_bitlen )
+{
+    return mbedtls_nist_kw_setkey( (mbedtls_nist_kw_context *) ctx, MBEDTLS_CIPHER_ID_AES,
+                     key, key_bitlen, 1 );
+}
+
+static int kw_aes_setkey_unwrap( void *ctx, const unsigned char *key,
+                                unsigned int key_bitlen )
+{
+    return mbedtls_nist_kw_setkey( (mbedtls_nist_kw_context *) ctx, MBEDTLS_CIPHER_ID_AES,
+                     key, key_bitlen, 0 );
+}
+
+static const mbedtls_cipher_base_t kw_aes_info = {
+    MBEDTLS_CIPHER_ID_AES,
+    NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_OFB)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+    NULL,
+#endif
+    kw_aes_setkey_wrap,
+    kw_aes_setkey_unwrap,
+    kw_ctx_alloc,
+    kw_ctx_free,
+};
+
+static const mbedtls_cipher_info_t aes_128_nist_kw_info = {
+    MBEDTLS_CIPHER_AES_128_KW,
+    MBEDTLS_MODE_KW,
+    128,
+    "AES-128-KW",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_nist_kw_info = {
+    MBEDTLS_CIPHER_AES_192_KW,
+    MBEDTLS_MODE_KW,
+    192,
+    "AES-192-KW",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_nist_kw_info = {
+    MBEDTLS_CIPHER_AES_256_KW,
+    MBEDTLS_MODE_KW,
+    256,
+    "AES-256-KW",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_128_nist_kwp_info = {
+    MBEDTLS_CIPHER_AES_128_KWP,
+    MBEDTLS_MODE_KWP,
+    128,
+    "AES-128-KWP",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_nist_kwp_info = {
+    MBEDTLS_CIPHER_AES_192_KWP,
+    MBEDTLS_MODE_KWP,
+    192,
+    "AES-192-KWP",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_nist_kwp_info = {
+    MBEDTLS_CIPHER_AES_256_KWP,
+    MBEDTLS_MODE_KWP,
+    256,
+    "AES-256-KWP",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+#endif /* MBEDTLS_NIST_KW_C */
+
 const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] =
 {
 #if defined(MBEDTLS_AES_C)
@@ -2259,6 +2388,15 @@
     { MBEDTLS_CIPHER_CHACHA20_POLY1305,    &chachapoly_info },
 #endif
 
+#if defined(MBEDTLS_NIST_KW_C)
+    { MBEDTLS_CIPHER_AES_128_KW,          &aes_128_nist_kw_info },
+    { MBEDTLS_CIPHER_AES_192_KW,          &aes_192_nist_kw_info },
+    { MBEDTLS_CIPHER_AES_256_KW,          &aes_256_nist_kw_info },
+    { MBEDTLS_CIPHER_AES_128_KWP,         &aes_128_nist_kwp_info },
+    { MBEDTLS_CIPHER_AES_192_KWP,         &aes_192_nist_kwp_info },
+    { MBEDTLS_CIPHER_AES_256_KWP,         &aes_256_nist_kwp_info },
+#endif
+
 #if defined(MBEDTLS_CIPHER_NULL_CIPHER)
     { MBEDTLS_CIPHER_NULL,                 &null_cipher_info },
 #endif /* MBEDTLS_CIPHER_NULL_CIPHER */