prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  RFC 5649 support
  RFC 3394 (AES Key Wrap) was added a while back. I'd like to request support for RFC 5649 (AES Key Wrap with Padding), since it builds off of RFC 3394. It looks like OpenSSL handled this back in 2015:
  
  https://rt.openssl.org/Ticket/Display.html?id=3675&user=guest&pass=guest
  
  Is this feasible for cryptography in the not-too-distant future?
  
  Thanks,
  Peter
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/cryptography/hazmat/primitives/keywrap.py`
  Content:
  ```
  1 # This file is dual licensed under the terms of the Apache License, Version
  2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3 # for complete details.
  4 
  5 from __future__ import absolute_import, division, print_function
  6 
  7 import struct
  8 
  9 from cryptography.hazmat.primitives.ciphers import Cipher
  10 from cryptography.hazmat.primitives.ciphers.algorithms import AES
  11 from cryptography.hazmat.primitives.ciphers.modes import ECB
  12 from cryptography.hazmat.primitives.constant_time import bytes_eq
  13 
  14 
  15 def _wrap_core(wrapping_key, a, r, backend):
  16     # RFC 3394 Key Wrap - 2.2.1 (index method)
  17     encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()
  18     n = len(r)
  19     for j in range(6):
  20         for i in range(n):
  21             # every encryption operation is a discrete 16 byte chunk (because
  22             # AES has a 128-bit block size) and since we're using ECB it is
  23             # safe to reuse the encryptor for the entire operation
  24             b = encryptor.update(a + r[i])
  25             # pack/unpack are safe as these are always 64-bit chunks
  26             a = struct.pack(
  27                 ">Q", struct.unpack(">Q", b[:8])[0] ^ ((n * j) + i + 1)
  28             )
  29             r[i] = b[-8:]
  30 
  31     assert encryptor.finalize() == b""
  32 
  33     return a + b"".join(r)
  34 
  35 
  36 def aes_key_wrap(wrapping_key, key_to_wrap, backend):
  37     if len(wrapping_key) not in [16, 24, 32]:
  38         raise ValueError("The wrapping key must be a valid AES key length")
  39 
  40     if len(key_to_wrap) < 16:
  41         raise ValueError("The key to wrap must be at least 16 bytes")
  42 
  43     if len(key_to_wrap) % 8 != 0:
  44         raise ValueError("The key to wrap must be a multiple of 8 bytes")
  45 
  46     a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6"
  47     r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]
  48     return _wrap_core(wrapping_key, a, r, backend)
  49 
  50 
  51 def _unwrap_core(wrapping_key, a, r, backend):
  52     # Implement RFC 3394 Key Unwrap - 2.2.2 (index method)
  53     decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()
  54     n = len(r)
  55     for j in reversed(range(6)):
  56         for i in reversed(range(n)):
  57             # pack/unpack are safe as these are always 64-bit chunks
  58             atr = struct.pack(
  59                 ">Q", struct.unpack(">Q", a)[0] ^ ((n * j) + i + 1)
  60             ) + r[i]
  61             # every decryption operation is a discrete 16 byte chunk so
  62             # it is safe to reuse the decryptor for the entire operation
  63             b = decryptor.update(atr)
  64             a = b[:8]
  65             r[i] = b[-8:]
  66 
  67     assert decryptor.finalize() == b""
  68     return a, r
  69 
  70 
  71 def aes_key_unwrap(wrapping_key, wrapped_key, backend):
  72     if len(wrapped_key) < 24:
  73         raise ValueError("Must be at least 24 bytes")
  74 
  75     if len(wrapped_key) % 8 != 0:
  76         raise ValueError("The wrapped key must be a multiple of 8 bytes")
  77 
  78     if len(wrapping_key) not in [16, 24, 32]:
  79         raise ValueError("The wrapping key must be a valid AES key length")
  80 
  81     aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6"
  82     r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]
  83     a = r.pop(0)
  84     a, r = _unwrap_core(wrapping_key, a, r, backend)
  85     if not bytes_eq(a, aiv):
  86         raise InvalidUnwrap()
  87 
  88     return b"".join(r)
  89 
  90 
  91 class InvalidUnwrap(Exception):
  92     pass
  93
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/cryptography/hazmat/primitives/keywrap.py b/src/cryptography/hazmat/primitives/keywrap.py
  --- a/src/cryptography/hazmat/primitives/keywrap.py
  +++ b/src/cryptography/hazmat/primitives/keywrap.py
  @@ -68,6 +68,63 @@
       return a, r
   
   
  +def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend):
  +    if len(wrapping_key) not in [16, 24, 32]:
  +        raise ValueError("The wrapping key must be a valid AES key length")
  +
  +    aiv = b"\xA6\x59\x59\xA6" + struct.pack(">i", len(key_to_wrap))
  +    # pad the key to wrap if necessary
  +    pad = (8 - (len(key_to_wrap) % 8)) % 8
  +    key_to_wrap = key_to_wrap + b"\x00" * pad
  +    if len(key_to_wrap) == 8:
  +        # RFC 5649 - 4.1 - exactly 8 octets after padding
  +        encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()
  +        b = encryptor.update(aiv + key_to_wrap)
  +        assert encryptor.finalize() == b""
  +        return b
  +    else:
  +        r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]
  +        return _wrap_core(wrapping_key, aiv, r, backend)
  +
  +
  +def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend):
  +    if len(wrapped_key) < 16:
  +        raise ValueError("Must be at least 16 bytes")
  +
  +    if len(wrapping_key) not in [16, 24, 32]:
  +        raise ValueError("The wrapping key must be a valid AES key length")
  +
  +    if len(wrapped_key) == 16:
  +        # RFC 5649 - 4.2 - exactly two 64-bit blocks
  +        decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()
  +        b = decryptor.update(wrapped_key)
  +        assert decryptor.finalize() == b""
  +        a = b[:8]
  +        data = b[8:]
  +        n = 1
  +    else:
  +        r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]
  +        encrypted_aiv = r.pop(0)
  +        n = len(r)
  +        a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend)
  +        data = b"".join(r)
  +
  +    # 1) Check that MSB(32,A) = A65959A6.
  +    # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n.  If so, let
  +    #    MLI = LSB(32,A).
  +    # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of
  +    #    the output data are zero.
  +    (mli,) = struct.unpack(">I", a[4:])
  +    b = (8 * n) - mli
  +    if (
  +        not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") or not
  +        8 * (n - 1) < mli <= 8 * n or not bytes_eq(data[-b:], b"\x00" * b)
  +    ):
  +        raise InvalidUnwrap()
  +
  +    return data[:-b]
  +
  +
   def aes_key_unwrap(wrapping_key, wrapped_key, backend):
       if len(wrapped_key) < 24:
           raise ValueError("Must be at least 24 bytes")
  
verification_info: {"golden_diff": "diff --git a/src/cryptography/hazmat/primitives/keywrap.py b/src/cryptography/hazmat/primitives/keywrap.py\n--- a/src/cryptography/hazmat/primitives/keywrap.py\n+++ b/src/cryptography/hazmat/primitives/keywrap.py\n@@ -68,6 +68,63 @@\n     return a, r\n \n \n+def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend):\n+    if len(wrapping_key) not in [16, 24, 32]:\n+        raise ValueError(\"The wrapping key must be a valid AES key length\")\n+\n+    aiv = b\"\\xA6\\x59\\x59\\xA6\" + struct.pack(\">i\", len(key_to_wrap))\n+    # pad the key to wrap if necessary\n+    pad = (8 - (len(key_to_wrap) % 8)) % 8\n+    key_to_wrap = key_to_wrap + b\"\\x00\" * pad\n+    if len(key_to_wrap) == 8:\n+        # RFC 5649 - 4.1 - exactly 8 octets after padding\n+        encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()\n+        b = encryptor.update(aiv + key_to_wrap)\n+        assert encryptor.finalize() == b\"\"\n+        return b\n+    else:\n+        r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]\n+        return _wrap_core(wrapping_key, aiv, r, backend)\n+\n+\n+def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend):\n+    if len(wrapped_key) < 16:\n+        raise ValueError(\"Must be at least 16 bytes\")\n+\n+    if len(wrapping_key) not in [16, 24, 32]:\n+        raise ValueError(\"The wrapping key must be a valid AES key length\")\n+\n+    if len(wrapped_key) == 16:\n+        # RFC 5649 - 4.2 - exactly two 64-bit blocks\n+        decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()\n+        b = decryptor.update(wrapped_key)\n+        assert decryptor.finalize() == b\"\"\n+        a = b[:8]\n+        data = b[8:]\n+        n = 1\n+    else:\n+        r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]\n+        encrypted_aiv = r.pop(0)\n+        n = len(r)\n+        a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend)\n+        data = b\"\".join(r)\n+\n+    # 1) Check that MSB(32,A) = A65959A6.\n+    # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n.  If so, let\n+    #    MLI = LSB(32,A).\n+    # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of\n+    #    the output data are zero.\n+    (mli,) = struct.unpack(\">I\", a[4:])\n+    b = (8 * n) - mli\n+    if (\n+        not bytes_eq(a[:4], b\"\\xa6\\x59\\x59\\xa6\") or not\n+        8 * (n - 1) < mli <= 8 * n or not bytes_eq(data[-b:], b\"\\x00\" * b)\n+    ):\n+        raise InvalidUnwrap()\n+\n+    return data[:-b]\n+\n+\n def aes_key_unwrap(wrapping_key, wrapped_key, backend):\n     if len(wrapped_key) < 24:\n         raise ValueError(\"Must be at least 24 bytes\")\n", "issue": "RFC 5649 support\nRFC 3394 (AES Key Wrap) was added a while back. I'd like to request support for RFC 5649 (AES Key Wrap with Padding), since it builds off of RFC 3394. It looks like OpenSSL handled this back in 2015:\r\n\r\nhttps://rt.openssl.org/Ticket/Display.html?id=3675&user=guest&pass=guest\r\n\r\nIs this feasible for cryptography in the not-too-distant future?\r\n\r\nThanks,\r\nPeter\n", "before_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport struct\n\nfrom cryptography.hazmat.primitives.ciphers import Cipher\nfrom cryptography.hazmat.primitives.ciphers.algorithms import AES\nfrom cryptography.hazmat.primitives.ciphers.modes import ECB\nfrom cryptography.hazmat.primitives.constant_time import bytes_eq\n\n\ndef _wrap_core(wrapping_key, a, r, backend):\n    # RFC 3394 Key Wrap - 2.2.1 (index method)\n    encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()\n    n = len(r)\n    for j in range(6):\n        for i in range(n):\n            # every encryption operation is a discrete 16 byte chunk (because\n            # AES has a 128-bit block size) and since we're using ECB it is\n            # safe to reuse the encryptor for the entire operation\n            b = encryptor.update(a + r[i])\n            # pack/unpack are safe as these are always 64-bit chunks\n            a = struct.pack(\n                \">Q\", struct.unpack(\">Q\", b[:8])[0] ^ ((n * j) + i + 1)\n            )\n            r[i] = b[-8:]\n\n    assert encryptor.finalize() == b\"\"\n\n    return a + b\"\".join(r)\n\n\ndef aes_key_wrap(wrapping_key, key_to_wrap, backend):\n    if len(wrapping_key) not in [16, 24, 32]:\n        raise ValueError(\"The wrapping key must be a valid AES key length\")\n\n    if len(key_to_wrap) < 16:\n        raise ValueError(\"The key to wrap must be at least 16 bytes\")\n\n    if len(key_to_wrap) % 8 != 0:\n        raise ValueError(\"The key to wrap must be a multiple of 8 bytes\")\n\n    a = b\"\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\"\n    r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]\n    return _wrap_core(wrapping_key, a, r, backend)\n\n\ndef _unwrap_core(wrapping_key, a, r, backend):\n    # Implement RFC 3394 Key Unwrap - 2.2.2 (index method)\n    decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()\n    n = len(r)\n    for j in reversed(range(6)):\n        for i in reversed(range(n)):\n            # pack/unpack are safe as these are always 64-bit chunks\n            atr = struct.pack(\n                \">Q\", struct.unpack(\">Q\", a)[0] ^ ((n * j) + i + 1)\n            ) + r[i]\n            # every decryption operation is a discrete 16 byte chunk so\n            # it is safe to reuse the decryptor for the entire operation\n            b = decryptor.update(atr)\n            a = b[:8]\n            r[i] = b[-8:]\n\n    assert decryptor.finalize() == b\"\"\n    return a, r\n\n\ndef aes_key_unwrap(wrapping_key, wrapped_key, backend):\n    if len(wrapped_key) < 24:\n        raise ValueError(\"Must be at least 24 bytes\")\n\n    if len(wrapped_key) % 8 != 0:\n        raise ValueError(\"The wrapped key must be a multiple of 8 bytes\")\n\n    if len(wrapping_key) not in [16, 24, 32]:\n        raise ValueError(\"The wrapping key must be a valid AES key length\")\n\n    aiv = b\"\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\"\n    r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]\n    a = r.pop(0)\n    a, r = _unwrap_core(wrapping_key, a, r, backend)\n    if not bytes_eq(a, aiv):\n        raise InvalidUnwrap()\n\n    return b\"\".join(r)\n\n\nclass InvalidUnwrap(Exception):\n    pass\n", "path": "src/cryptography/hazmat/primitives/keywrap.py"}], "after_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport struct\n\nfrom cryptography.hazmat.primitives.ciphers import Cipher\nfrom cryptography.hazmat.primitives.ciphers.algorithms import AES\nfrom cryptography.hazmat.primitives.ciphers.modes import ECB\nfrom cryptography.hazmat.primitives.constant_time import bytes_eq\n\n\ndef _wrap_core(wrapping_key, a, r, backend):\n    # RFC 3394 Key Wrap - 2.2.1 (index method)\n    encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()\n    n = len(r)\n    for j in range(6):\n        for i in range(n):\n            # every encryption operation is a discrete 16 byte chunk (because\n            # AES has a 128-bit block size) and since we're using ECB it is\n            # safe to reuse the encryptor for the entire operation\n            b = encryptor.update(a + r[i])\n            # pack/unpack are safe as these are always 64-bit chunks\n            a = struct.pack(\n                \">Q\", struct.unpack(\">Q\", b[:8])[0] ^ ((n * j) + i + 1)\n            )\n            r[i] = b[-8:]\n\n    assert encryptor.finalize() == b\"\"\n\n    return a + b\"\".join(r)\n\n\ndef aes_key_wrap(wrapping_key, key_to_wrap, backend):\n    if len(wrapping_key) not in [16, 24, 32]:\n        raise ValueError(\"The wrapping key must be a valid AES key length\")\n\n    if len(key_to_wrap) < 16:\n        raise ValueError(\"The key to wrap must be at least 16 bytes\")\n\n    if len(key_to_wrap) % 8 != 0:\n        raise ValueError(\"The key to wrap must be a multiple of 8 bytes\")\n\n    a = b\"\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\"\n    r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]\n    return _wrap_core(wrapping_key, a, r, backend)\n\n\ndef _unwrap_core(wrapping_key, a, r, backend):\n    # Implement RFC 3394 Key Unwrap - 2.2.2 (index method)\n    decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()\n    n = len(r)\n    for j in reversed(range(6)):\n        for i in reversed(range(n)):\n            # pack/unpack are safe as these are always 64-bit chunks\n            atr = struct.pack(\n                \">Q\", struct.unpack(\">Q\", a)[0] ^ ((n * j) + i + 1)\n            ) + r[i]\n            # every decryption operation is a discrete 16 byte chunk so\n            # it is safe to reuse the decryptor for the entire operation\n            b = decryptor.update(atr)\n            a = b[:8]\n            r[i] = b[-8:]\n\n    assert decryptor.finalize() == b\"\"\n    return a, r\n\n\ndef aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend):\n    if len(wrapping_key) not in [16, 24, 32]:\n        raise ValueError(\"The wrapping key must be a valid AES key length\")\n\n    aiv = b\"\\xA6\\x59\\x59\\xA6\" + struct.pack(\">i\", len(key_to_wrap))\n    # pad the key to wrap if necessary\n    pad = (8 - (len(key_to_wrap) % 8)) % 8\n    key_to_wrap = key_to_wrap + b\"\\x00\" * pad\n    if len(key_to_wrap) == 8:\n        # RFC 5649 - 4.1 - exactly 8 octets after padding\n        encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()\n        b = encryptor.update(aiv + key_to_wrap)\n        assert encryptor.finalize() == b\"\"\n        return b\n    else:\n        r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]\n        return _wrap_core(wrapping_key, aiv, r, backend)\n\n\ndef aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend):\n    if len(wrapped_key) < 16:\n        raise ValueError(\"Must be at least 16 bytes\")\n\n    if len(wrapping_key) not in [16, 24, 32]:\n        raise ValueError(\"The wrapping key must be a valid AES key length\")\n\n    if len(wrapped_key) == 16:\n        # RFC 5649 - 4.2 - exactly two 64-bit blocks\n        decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()\n        b = decryptor.update(wrapped_key)\n        assert decryptor.finalize() == b\"\"\n        a = b[:8]\n        data = b[8:]\n        n = 1\n    else:\n        r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]\n        encrypted_aiv = r.pop(0)\n        n = len(r)\n        a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend)\n        data = b\"\".join(r)\n\n    # 1) Check that MSB(32,A) = A65959A6.\n    # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n.  If so, let\n    #    MLI = LSB(32,A).\n    # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of\n    #    the output data are zero.\n    (mli,) = struct.unpack(\">I\", a[4:])\n    b = (8 * n) - mli\n    if (\n        not bytes_eq(a[:4], b\"\\xa6\\x59\\x59\\xa6\") or not\n        8 * (n - 1) < mli <= 8 * n or not bytes_eq(data[-b:], b\"\\x00\" * b)\n    ):\n        raise InvalidUnwrap()\n\n    return data[:-b]\n\n\ndef aes_key_unwrap(wrapping_key, wrapped_key, backend):\n    if len(wrapped_key) < 24:\n        raise ValueError(\"Must be at least 24 bytes\")\n\n    if len(wrapped_key) % 8 != 0:\n        raise ValueError(\"The wrapped key must be a multiple of 8 bytes\")\n\n    if len(wrapping_key) not in [16, 24, 32]:\n        raise ValueError(\"The wrapping key must be a valid AES key length\")\n\n    aiv = b\"\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\\xa6\"\n    r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]\n    a = r.pop(0)\n    a, r = _unwrap_core(wrapping_key, a, r, backend)\n    if not bytes_eq(a, aiv):\n        raise InvalidUnwrap()\n\n    return b\"\".join(r)\n\n\nclass InvalidUnwrap(Exception):\n    pass\n", "path": "src/cryptography/hazmat/primitives/keywrap.py"}]}