test_keywrap.doctest - test keywrap functions Copyright (C) 2014-2016 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA >>> from Crypto.Util.number import long_to_bytes >>> from binascii import a2b_hex >>> from pskc.crypto.aeskw import wrap, unwrap Wrap 128 bits of Key Data with a 128-bit KEK (test vector 4.1 from RFC 3394). >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F') >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF') >>> ciphertext = a2b_hex('1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True Wrap 128 bits of Key Data with a 192-bit KEK (test vector 4.2 from RFC 3394). >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F1011121314151617') >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF') >>> ciphertext = a2b_hex('96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True Wrap 128 bits of Key Data with a 256-bit KEK (test vector 4.3 from RFC 3394). >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F') >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF') >>> ciphertext = a2b_hex('64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True Wrap 192 bits of Key Data with a 192-bit KEK (test vector 4.4 from RFC 3394). >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F1011121314151617') >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF0001020304050607') >>> ciphertext = a2b_hex('031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True Wrap 192 bits of Key Data with a 256-bit KEK (test vector 4.5 from RFC 3394). >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F') >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF0001020304050607') >>> ciphertext = a2b_hex('A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True Wrap 256 bits of Key Data with a 256-bit KEK (test vector 4.6 from RFC 3394). >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F') >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F') >>> ciphertext = a2b_hex('28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True Mangling the ciphertext and unwrapping results in an exception: >>> unwrap(b'XX' + ciphertext[2:], key) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... DecryptionError: IV does not match >>> unwrap(ciphertext[:-2] + b'XX', key) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... DecryptionError: IV does not match >>> unwrap(ciphertext[2:], key) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... DecryptionError: Ciphertext length wrong Wrap 20 octets with a 192-bit key (first example from section 6 of RFC 5649). >>> key = a2b_hex('5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8') >>> plaintext = a2b_hex('c37b7e6492584340bed12207808941155068f738') >>> ciphertext = a2b_hex('138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True >>> wrap(plaintext, key, pad=False) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... EncryptionError: Plaintext length wrong >>> unwrap(ciphertext, key, pad=False) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... DecryptionError: IV does not match Wrap 7 octets with a 192-bit key (second example from section 6 of RFC 5649). >>> key = a2b_hex('5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8') >>> plaintext = a2b_hex('466f7250617369') >>> ciphertext = a2b_hex('afbeb0f07dfbf5419200f2ccb50bb24f') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True >>> wrap(plaintext, key, pad=False) # disable padding Traceback (most recent call last): ... EncryptionError: Plaintext length wrong >>> unwrap(ciphertext, key, pad=False) Traceback (most recent call last): ... DecryptionError: Ciphertext length wrong Normally padding is only done if needed but it can be forced. >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F') >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF') >>> ciphertext = a2b_hex('1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True >>> ciphertext = a2b_hex('2cef0c9e30de26016c230cb78bc60d51b1fe083ba0c79cd5') >>> wrap(plaintext, key, pad=True) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True >>> unwrap(ciphertext, key, pad=False) # disabling padding fails IV check Traceback (most recent call last): ... DecryptionError: IV does not match Padding can also be disabled. This also disables the shortcut for small plaintexts as described in RFC 5649. >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F') >>> plaintext = a2b_hex('0011223344556677') >>> ciphertext = a2b_hex('f4740052e82a225174ce86fbd7b805e7') >>> wrap(plaintext, key) == ciphertext True >>> unwrap(ciphertext, key) == plaintext True >>> wrap(plaintext, key, pad=False) # disable padding Traceback (most recent call last): ... EncryptionError: Plaintext length wrong >>> unwrap(ciphertext, key, pad=False) Traceback (most recent call last): ... DecryptionError: Ciphertext length wrong Lastly, an explicit IV can be set but this disables the padding functionality. >>> key = a2b_hex('000102030405060708090A0B0C0D0E0F') >>> plaintext = a2b_hex('0011223344556677') >>> iv = a2b_hex('1010101010101010') >>> wrap(plaintext, key, iv) Traceback (most recent call last): ... EncryptionError: Plaintext length wrong >>> plaintext = a2b_hex('00112233445566778899AABBCCDDEEFF') >>> ciphertext = a2b_hex('4cd926c570e19c35ace71d59a1062dae850e6a709066e0bf') >>> wrap(plaintext, key, iv) == ciphertext True >>> unwrap(ciphertext, key, iv) == plaintext True >>> unwrap(ciphertext, key, a2b_hex('2020202020202020')) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... DecryptionError: IV does not match We can fake padding by specifying an RFC 5649 IV ourselves. The length of 14 works because we have padded the plaintext with two 0 bytes. >>> key = a2b_hex('5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8') >>> plaintext = a2b_hex('c37b7e6492584340bed1220765460000') >>> iv = a2b_hex('a65959a6') + long_to_bytes(14, 4) >>> ciphertext = wrap(plaintext, key, iv=iv) >>> unwrap(ciphertext, key, iv=iv) == plaintext True >>> unwrap(ciphertext, key) == plaintext[:14] True If we mangle the IV to look like an RFC 5649 value but with an invalid padding length we should get an exception. >>> iv = a2b_hex('a65959a6') + long_to_bytes(12, 4) >>> ciphertext = wrap(plaintext, key, iv=iv) >>> unwrap(ciphertext, key, iv=iv) == plaintext True >>> unwrap(ciphertext, key) == plaintext[:12] Traceback (most recent call last): ... DecryptionError: IV does not match