| 13 | |
| 14 | |
| 15 | def _wrap_core( |
| 16 | wrapping_key: bytes, |
| 17 | a: bytes, |
| 18 | r: list[bytes], |
| 19 | ) -> bytes: |
| 20 | # RFC 3394 Key Wrap - 2.2.1 (index method) |
| 21 | encryptor = Cipher(AES(wrapping_key), ECB()).encryptor() |
| 22 | n = len(r) |
| 23 | for j in range(6): |
| 24 | for i in range(n): |
| 25 | # every encryption operation is a discrete 16 byte chunk (because |
| 26 | # AES has a 128-bit block size) and since we're using ECB it is |
| 27 | # safe to reuse the encryptor for the entire operation |
| 28 | b = encryptor.update(a + r[i]) |
| 29 | a = ( |
| 30 | int.from_bytes(b[:8], byteorder="big") ^ ((n * j) + i + 1) |
| 31 | ).to_bytes(length=8, byteorder="big") |
| 32 | r[i] = b[-8:] |
| 33 | |
| 34 | assert encryptor.finalize() == b"" |
| 35 | |
| 36 | return a + b"".join(r) |
| 37 | |
| 38 | |
| 39 | def aes_key_wrap( |