From 3944a8ce014f9f665a2300e1fa994b872cffa92b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 10:52:24 -0700 Subject: Initial implementation with tests, docs to follow --- cryptography/hazmat/primitives/padding.py | 110 ++++++++++++++++++++++++++++++ tests/hazmat/primitives/test_padding.py | 85 +++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 cryptography/hazmat/primitives/padding.py create mode 100644 tests/hazmat/primitives/test_padding.py diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py new file mode 100644 index 00000000..fbdc487b --- /dev/null +++ b/cryptography/hazmat/primitives/padding.py @@ -0,0 +1,110 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import six + + +class PKCS7(object): + def __init__(self, block_size): + super(PKCS7, self).__init__() + if not (0 <= block_size < 256): + raise ValueError("block_size must be in range(0, 256)") + + if block_size % 8 != 0: + raise ValueError("block_size must be a multiple of 8") + + self.block_size = block_size + + def padder(self): + return _PaddingContext(self.block_size) + + def unpadder(self): + return _UnpaddingContext(self.block_size) + + def pad(self, data): + padder = self.padder() + return padder.update(data) + padder.finalize() + + def unpad(self, data): + unpadder = self.unpadder() + return unpadder.update(data) + unpadder.finalize() + + +class _PaddingContext(object): + def __init__(self, block_size): + super(_PaddingContext, self).__init__() + self.block_size = block_size + # TODO: O(n ** 2) complexity for repeated concatentation, we should use + # zero-buffer + self._buffer = b"" + + def update(self, data): + if self._buffer is None: + raise ValueError("Context was already finalized") + + self._buffer += data + result = b"" + + while len(self._buffer) >= self.block_size // 8: + result += self._buffer[:self.block_size // 8] + self._buffer = self._buffer[self.block_size // 8:] + return result + + def finalize(self): + if self._buffer is None: + raise ValueError("Context was already finalized") + + pad_size = self.block_size // 8 - len(self._buffer) + result = self._buffer + six.int2byte(pad_size) * pad_size + self._buffer = None + return result + + +class _UnpaddingContext(object): + def __init__(self, block_size): + super(_UnpaddingContext, self).__init__() + self.block_size = block_size + # TODO: O(n ** 2) complexity for repeated concatentation, we should use + # zero-buffer + self._buffer = b"" + + def update(self, data): + if self._buffer is None: + raise ValueError("Context was already finalized") + + self._buffer += data + result = b"" + while len(self._buffer) >= 2 * (self.block_size // 8): + result += self._buffer[:self.block_size // 8] + self._buffer = self._buffer[self.block_size // 8:] + return result + + def finalize(self): + if self._buffer is None: + raise ValueError("Context was already finalized") + + if not self._buffer: + raise ValueError("Invalid padding bytes") + + pad_size = six.indexbytes(self._buffer, -1) + + if pad_size > self.block_size // 8: + raise ValueError("Invalid padding bytes") + + for b in six.iterbytes(self._buffer[-pad_size:]): + if b != pad_size: + raise ValueError("Invalid padding bytes") + + res = self._buffer[:-pad_size] + self._buffer = None + return res diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py new file mode 100644 index 00000000..a41edac1 --- /dev/null +++ b/tests/hazmat/primitives/test_padding.py @@ -0,0 +1,85 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from cryptography.hazmat.primitives import padding + + +class TestPKCS7(object): + @pytest.mark.parametrize("size", [127, 4096, -2]) + def test_invalid_block_size(self, size): + with pytest.raises(ValueError): + padding.PKCS7(size) + + @pytest.mark.parametrize(("size", "padded"), [ + (128, b"1111"), + (128, b"1111111111111111"), + (128, b"111111111111111\x06"), + (128, b""), + ]) + def test_invalid_padding(self, size, padded): + padder = padding.PKCS7(size) + + with pytest.raises(ValueError): + padder.unpad(padded) + + @pytest.mark.parametrize(("size", "unpadded", "padded"), [ + ( + 128, + b"1111111111", + b"1111111111\x06\x06\x06\x06\x06\x06", + ), + ( + 128, + b"111111111111111122222222222222", + b"111111111111111122222222222222\x02\x02", + ), + ]) + def test_pad(self, size, unpadded, padded): + padder = padding.PKCS7(size) + assert padder.pad(unpadded) == padded + + @pytest.mark.parametrize(("size", "unpadded", "padded"), [ + ( + 128, + b"1111111111", + b"1111111111\x06\x06\x06\x06\x06\x06", + ), + ( + 128, + b"111111111111111122222222222222", + b"111111111111111122222222222222\x02\x02", + ), + ]) + def test_unpad(self, size, unpadded, padded): + padder = padding.PKCS7(size) + assert padder.unpad(padded) == unpadded + + def test_use_after_finalize(self): + p = padding.PKCS7(128) + + padder = p.padder() + b = padder.finalize() + with pytest.raises(ValueError): + padder.update(b"") + with pytest.raises(ValueError): + padder.finalize() + + unpadder = p.unpadder() + unpadder.update(b) + unpadder.finalize() + with pytest.raises(ValueError): + unpadder.update(b"") + with pytest.raises(ValueError): + unpadder.finalize() -- cgit v1.2.3 From 5f3db274a3b427803ec6f4dc7b50943d6d18c4e6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 10:56:35 -0700 Subject: Start of docs --- docs/hazmat/primitives/index.rst | 1 + docs/hazmat/primitives/padding.rst | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 docs/hazmat/primitives/padding.rst diff --git a/docs/hazmat/primitives/index.rst b/docs/hazmat/primitives/index.rst index 3927f3f0..ee1e251c 100644 --- a/docs/hazmat/primitives/index.rst +++ b/docs/hazmat/primitives/index.rst @@ -14,3 +14,4 @@ Primitives cryptographic-hashes hmac symmetric-encryption + padding diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst new file mode 100644 index 00000000..995ed9f3 --- /dev/null +++ b/docs/hazmat/primitives/padding.rst @@ -0,0 +1,44 @@ +.. danger:: + + This is a "Hazardous Materials" module. You should **ONLY** use it if + you're 100% absolutely sure that you know what you're doing because this + module is full of land mines, dragons, and dinosaurs with laser guns. + + +Padding +======= + + +Padding is a way to take data that may or may not be be a multiple of the block +size for a cipher and extend it out so that it is. This is required for many +block cipher modes as they require the data to be encrypted to be an exact +multiple of the block size. + + +.. class:: cryptography.primitives.padding.PKCS7(block_size) + + PKCS7 padding is a generalization of PKCS5 padding (also known as standard + padding). PKCS7 padding works by appending ``N`` bytes with the value of + ``chr(N)``, where ``N`` is the number of bytes required to make the final + block of data the same size as the block size. A simple example of padding + is: + + .. doctest:: + + >>> from cryptography.primitives import padding + >>> padder = padding.PKCS7(128) + >>> padder.pad(b"1111111111") + '1111111111\x06\x06\x06\x06\x06\x06' + + :param block_size: The size of the block in bits that the data is being + padded to. + + .. method:: pad(data) + + :param data: The data that should be padded. + :rtype bytes: The padded data. + + .. method:: unpad(data) + + :param data: The data that should be unpadded. + :rtype bytes: The unpadded data. -- cgit v1.2.3 From c83d447e0d5364b0a99ada6711384a38f772bb2f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 11:02:06 -0700 Subject: Reference a comment for this --- cryptography/hazmat/primitives/padding.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index fbdc487b..09e4b9f0 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -45,7 +45,7 @@ class _PaddingContext(object): super(_PaddingContext, self).__init__() self.block_size = block_size # TODO: O(n ** 2) complexity for repeated concatentation, we should use - # zero-buffer + # zero-buffer (#193) self._buffer = b"" def update(self, data): @@ -75,7 +75,7 @@ class _UnpaddingContext(object): super(_UnpaddingContext, self).__init__() self.block_size = block_size # TODO: O(n ** 2) complexity for repeated concatentation, we should use - # zero-buffer + # zero-buffer (#193) self._buffer = b"" def update(self, data): -- cgit v1.2.3 From db279d0e383173df65f83541daa4b8f58fc070f4 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 11:08:30 -0700 Subject: Added a PaddingContext interface --- cryptography/hazmat/primitives/interfaces.py | 14 ++++++++++++++ cryptography/hazmat/primitives/padding.py | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 49c19d0e..217490fd 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -45,3 +45,17 @@ class CipherContext(six.with_metaclass(abc.ABCMeta)): """ finalize return bytes """ + + +class PaddingContext(six.with_metaclass(abc.ABCMeta)): + @abc.abstractmethod + def update(self, data): + """ + update takes bytes and return bytes + """ + + @abc.abstractmethod + def finalize(self): + """ + finalize return bytes + """ diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 09e4b9f0..8e2219e1 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -13,6 +13,8 @@ import six +from cryptography.hazmat.primitives import interfaces + class PKCS7(object): def __init__(self, block_size): @@ -40,6 +42,7 @@ class PKCS7(object): return unpadder.update(data) + unpadder.finalize() +@interfaces.register(interfaces.PaddingContext) class _PaddingContext(object): def __init__(self, block_size): super(_PaddingContext, self).__init__() @@ -70,6 +73,7 @@ class _PaddingContext(object): return result +@interfaces.register(interfaces.PaddingContext) class _UnpaddingContext(object): def __init__(self, block_size): super(_UnpaddingContext, self).__init__() -- cgit v1.2.3 From b2d5efdc5a6e7f6df635b4bc60882bb2e5f14a66 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 11:15:30 -0700 Subject: More docs --- docs/hazmat/primitives/padding.rst | 35 ++++++++++++++++++++++++- docs/hazmat/primitives/symmetric-encryption.rst | 15 +++++------ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index 995ed9f3..ebcc6104 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -8,6 +8,7 @@ Padding ======= +.. currentmodule:: cryptography.hazmat.primitives.padding Padding is a way to take data that may or may not be be a multiple of the block size for a cipher and extend it out so that it is. This is required for many @@ -15,7 +16,7 @@ block cipher modes as they require the data to be encrypted to be an exact multiple of the block size. -.. class:: cryptography.primitives.padding.PKCS7(block_size) +.. class:: PKCS7(block_size) PKCS7 padding is a generalization of PKCS5 padding (also known as standard padding). PKCS7 padding works by appending ``N`` bytes with the value of @@ -42,3 +43,35 @@ multiple of the block size. :param data: The data that should be unpadded. :rtype bytes: The unpadded data. + + .. method:: padder() + + :returns: A padding + :class:`~cryptography.hazmat.primitives.interfaces.PaddingContext` + provider. + + .. method:: unpadder() + + :returns: An unpadding + :class:`~cryptography.hazmat.primitives.interfaces.PaddingContext` + provider. + + +.. currentmodule:: cryptography.hazmat.primitives.interfaces + +.. class:: PaddingContext + + When calling ``padder()`` or ``unpadder()`` you will receive an a return + object conforming to the ``PaddingContext`` interface. You can then call + ``update(data)`` with data until you have fed everything into the context. + Once that is done call ``finalize()`` to finish the operation and obtain + the remainder of the data. + + .. method:: update(data) + + :param bytes data: The data you wish to pass into the context. + :return bytes: Returns the data that was padded or unpadded. + + .. method:: finalize() + + :return bytes: Returns the remainder of the data. diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 758a4648..9a5bce07 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -54,18 +54,17 @@ where the encrypter and decrypter both use the same key. .. currentmodule:: cryptography.hazmat.primitives.interfaces -.. class:: CipherContext() - - When calling ``encryptor()`` or ``decryptor()`` on a BlockCipher object you - will receive a return object conforming to the CipherContext interface. You - can then call ``update(data)`` with data until you have fed everything into - the context. Once that is done call ``finalize()`` to finish the operation and - obtain the remainder of the data. +.. class:: CipherContext + When calling ``encryptor()`` or ``decryptor()`` on a ``BlockCipher`` object + you will receive a return object conforming to the ``CipherContext`` + interface. You can then call ``update(data)`` with data until you have fed + everything into the context. Once that is done call ``finalize()`` to + finish the operation and obtain the remainder of the data. .. method:: update(data) - :param bytes data: The text you wish to pass into the context. + :param bytes data: The data you wish to pass into the context. :return bytes: Returns the data that was encrypted or decrypted. .. method:: finalize() -- cgit v1.2.3 From 07082782db43d697627f6eaf2d0b7c8ca209ab6a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 11:18:23 -0700 Subject: typo --- docs/hazmat/primitives/padding.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index ebcc6104..7cbadeb9 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -26,7 +26,7 @@ multiple of the block size. .. doctest:: - >>> from cryptography.primitives import padding + >>> from cryptography.hazmat.primitives import padding >>> padder = padding.PKCS7(128) >>> padder.pad(b"1111111111") '1111111111\x06\x06\x06\x06\x06\x06' -- cgit v1.2.3 From 23aeea2527e5b2f26596488ee1635a9f48713e42 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 11:25:57 -0700 Subject: Fix the naming of these classes --- cryptography/hazmat/primitives/padding.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 8e2219e1..d5fb0326 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -28,10 +28,10 @@ class PKCS7(object): self.block_size = block_size def padder(self): - return _PaddingContext(self.block_size) + return _PKCS7PaddingContext(self.block_size) def unpadder(self): - return _UnpaddingContext(self.block_size) + return _PKCS7UnpaddingContext(self.block_size) def pad(self, data): padder = self.padder() @@ -43,9 +43,9 @@ class PKCS7(object): @interfaces.register(interfaces.PaddingContext) -class _PaddingContext(object): +class _PKCS7PaddingContext(object): def __init__(self, block_size): - super(_PaddingContext, self).__init__() + super(_PKCS7PaddingContext, self).__init__() self.block_size = block_size # TODO: O(n ** 2) complexity for repeated concatentation, we should use # zero-buffer (#193) @@ -74,9 +74,9 @@ class _PaddingContext(object): @interfaces.register(interfaces.PaddingContext) -class _UnpaddingContext(object): +class _PKCS7UnpaddingContext(object): def __init__(self, block_size): - super(_UnpaddingContext, self).__init__() + super(_PKCS7UnpaddingContext, self).__init__() self.block_size = block_size # TODO: O(n ** 2) complexity for repeated concatentation, we should use # zero-buffer (#193) -- cgit v1.2.3 From 22e2eaee0b48318c3a3e5eda7ce9174ac8cfce6a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 11:42:14 -0700 Subject: Removed helper --- cryptography/hazmat/primitives/padding.py | 8 -------- docs/hazmat/primitives/padding.rst | 5 ++++- tests/hazmat/primitives/test_padding.py | 14 +++++++++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index d5fb0326..27a1face 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -33,14 +33,6 @@ class PKCS7(object): def unpadder(self): return _PKCS7UnpaddingContext(self.block_size) - def pad(self, data): - padder = self.padder() - return padder.update(data) + padder.finalize() - - def unpad(self, data): - unpadder = self.unpadder() - return unpadder.update(data) + unpadder.finalize() - @interfaces.register(interfaces.PaddingContext) class _PKCS7PaddingContext(object): diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index 7cbadeb9..1ad2bb83 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -28,7 +28,10 @@ multiple of the block size. >>> from cryptography.hazmat.primitives import padding >>> padder = padding.PKCS7(128) - >>> padder.pad(b"1111111111") + >>> padder = padder.padder() + >>> padder.update(b"1111111111") + '' + >>> padder.finalize() '1111111111\x06\x06\x06\x06\x06\x06' :param block_size: The size of the block in bits that the data is being diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py index a41edac1..c47b6c5c 100644 --- a/tests/hazmat/primitives/test_padding.py +++ b/tests/hazmat/primitives/test_padding.py @@ -31,8 +31,10 @@ class TestPKCS7(object): def test_invalid_padding(self, size, padded): padder = padding.PKCS7(size) + unpadder = padder.unpadder() with pytest.raises(ValueError): - padder.unpad(padded) + unpadder.update(padded) + unpadder.finalize() @pytest.mark.parametrize(("size", "unpadded", "padded"), [ ( @@ -48,7 +50,10 @@ class TestPKCS7(object): ]) def test_pad(self, size, unpadded, padded): padder = padding.PKCS7(size) - assert padder.pad(unpadded) == padded + padder = padder.padder() + result = padder.update(unpadded) + result += padder.finalize() + assert result == padded @pytest.mark.parametrize(("size", "unpadded", "padded"), [ ( @@ -64,7 +69,10 @@ class TestPKCS7(object): ]) def test_unpad(self, size, unpadded, padded): padder = padding.PKCS7(size) - assert padder.unpad(padded) == unpadded + unpadder = padder.unpadder() + result = unpadder.update(padded) + result += unpadder.finalize() + assert result == unpadded def test_use_after_finalize(self): p = padding.PKCS7(128) -- cgit v1.2.3 From f0bec9c3efe7f6def1b9b4ae53f0278e7cfbadba Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 13:35:57 -0700 Subject: Remove removed methods from docs --- docs/hazmat/primitives/padding.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index 1ad2bb83..4b05acd1 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -37,16 +37,6 @@ multiple of the block size. :param block_size: The size of the block in bits that the data is being padded to. - .. method:: pad(data) - - :param data: The data that should be padded. - :rtype bytes: The padded data. - - .. method:: unpad(data) - - :param data: The data that should be unpadded. - :rtype bytes: The unpadded data. - .. method:: padder() :returns: A padding -- cgit v1.2.3 From 25f96e511f1e1bf70393cdd34c83f57a4b45d458 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 14:10:37 -0700 Subject: Optimize + test cases --- cryptography/hazmat/primitives/padding.py | 22 ++++++++++++++-------- tests/hazmat/primitives/test_padding.py | 10 ++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 27a1face..5c7c7e91 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -48,11 +48,12 @@ class _PKCS7PaddingContext(object): raise ValueError("Context was already finalized") self._buffer += data - result = b"" - while len(self._buffer) >= self.block_size // 8: - result += self._buffer[:self.block_size // 8] - self._buffer = self._buffer[self.block_size // 8:] + finished_blocks = len(self._buffer) // (self.block_size // 8) + + result = self._buffer[:finished_blocks * (self.block_size // 8)] + self._buffer = self._buffer[finished_blocks * (self.block_size // 8):] + return result def finalize(self): @@ -79,10 +80,15 @@ class _PKCS7UnpaddingContext(object): raise ValueError("Context was already finalized") self._buffer += data - result = b"" - while len(self._buffer) >= 2 * (self.block_size // 8): - result += self._buffer[:self.block_size // 8] - self._buffer = self._buffer[self.block_size // 8:] + + finished_blocks = max( + len(self._buffer) // (self.block_size // 8) - 1, + 0 + ) + + result = self._buffer[:finished_blocks * (self.block_size // 8)] + self._buffer = self._buffer[finished_blocks * (self.block_size // 8):] + return result def finalize(self): diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py index c47b6c5c..f689dda0 100644 --- a/tests/hazmat/primitives/test_padding.py +++ b/tests/hazmat/primitives/test_padding.py @@ -47,6 +47,16 @@ class TestPKCS7(object): b"111111111111111122222222222222", b"111111111111111122222222222222\x02\x02", ), + ( + 128, + b"1" * 16, + b"1" * 16 + b"\x10" * 16, + ), + ( + 128, + b"1" * 17, + b"1" * 17 + b"\x0F" * 15, + ) ]) def test_pad(self, size, unpadded, padded): padder = padding.PKCS7(size) -- cgit v1.2.3 From 60ad3e182476d84daeb7cff9d333623a688edd61 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 14:26:11 -0700 Subject: Clean up var naming --- docs/hazmat/primitives/padding.rst | 3 +-- tests/hazmat/primitives/test_padding.py | 16 +++++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index 4b05acd1..ba3ddcc0 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -27,8 +27,7 @@ multiple of the block size. .. doctest:: >>> from cryptography.hazmat.primitives import padding - >>> padder = padding.PKCS7(128) - >>> padder = padder.padder() + >>> padder = padding.PKCS7(128).padder() >>> padder.update(b"1111111111") '' >>> padder.finalize() diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py index f689dda0..798b2a77 100644 --- a/tests/hazmat/primitives/test_padding.py +++ b/tests/hazmat/primitives/test_padding.py @@ -29,9 +29,7 @@ class TestPKCS7(object): (128, b""), ]) def test_invalid_padding(self, size, padded): - padder = padding.PKCS7(size) - - unpadder = padder.unpadder() + unpadder = padding.PKCS7(size).unpadder() with pytest.raises(ValueError): unpadder.update(padded) unpadder.finalize() @@ -59,8 +57,7 @@ class TestPKCS7(object): ) ]) def test_pad(self, size, unpadded, padded): - padder = padding.PKCS7(size) - padder = padder.padder() + padder = padding.PKCS7(size).padder() result = padder.update(unpadded) result += padder.finalize() assert result == padded @@ -78,23 +75,20 @@ class TestPKCS7(object): ), ]) def test_unpad(self, size, unpadded, padded): - padder = padding.PKCS7(size) - unpadder = padder.unpadder() + unpadder = padding.PKCS7(size).unpadder() result = unpadder.update(padded) result += unpadder.finalize() assert result == unpadded def test_use_after_finalize(self): - p = padding.PKCS7(128) - - padder = p.padder() + padder = padding.PKCS7(128).padder() b = padder.finalize() with pytest.raises(ValueError): padder.update(b"") with pytest.raises(ValueError): padder.finalize() - unpadder = p.unpadder() + unpadder = padding.PKCS7(128).unpadder() unpadder.update(b) unpadder.finalize() with pytest.raises(ValueError): -- cgit v1.2.3 From 5787fb5dcde454404bfa9c2ec1a601bbafd62404 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 14:38:06 -0700 Subject: raise an error if you unicode --- cryptography/hazmat/primitives/padding.py | 6 ++++++ tests/hazmat/primitives/test_padding.py | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 5c7c7e91..86ea26e3 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -47,6 +47,9 @@ class _PKCS7PaddingContext(object): if self._buffer is None: raise ValueError("Context was already finalized") + if isinstance(data, six.text_type): + raise TypeError("Unicode-objects must be encoded before padding") + self._buffer += data finished_blocks = len(self._buffer) // (self.block_size // 8) @@ -79,6 +82,9 @@ class _PKCS7UnpaddingContext(object): if self._buffer is None: raise ValueError("Context was already finalized") + if isinstance(data, six.text_type): + raise TypeError("Unicode-objects must be encoded before unpadding") + self._buffer += data finished_blocks = max( diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py index 798b2a77..3cefafaf 100644 --- a/tests/hazmat/primitives/test_padding.py +++ b/tests/hazmat/primitives/test_padding.py @@ -13,6 +13,8 @@ import pytest +import six + from cryptography.hazmat.primitives import padding @@ -34,6 +36,14 @@ class TestPKCS7(object): unpadder.update(padded) unpadder.finalize() + def test_non_bytes(self): + padder = padding.PKCS7(128).padder() + with pytest.raises(TypeError): + padder.update(six.u("abc")) + unpadder = padding.PKCS7(128).unpadder() + with pytest.raises(TypeError): + unpadder.update(six.u("abc")) + @pytest.mark.parametrize(("size", "unpadded", "padded"), [ ( 128, -- cgit v1.2.3 From f108871b04c27c557f3e1a7fa3982c6d9d77d7fd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 29 Oct 2013 15:14:28 -0700 Subject: Perform this comparison in a constan ttime fashion --- cryptography/hazmat/primitives/padding.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 86ea26e3..ddcadd89 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -109,9 +109,12 @@ class _PKCS7UnpaddingContext(object): if pad_size > self.block_size // 8: raise ValueError("Invalid padding bytes") + mismatch = 0 for b in six.iterbytes(self._buffer[-pad_size:]): - if b != pad_size: - raise ValueError("Invalid padding bytes") + mismatch |= b ^ pad_size + + if mismatch != 0: + raise ValueError("Invalid padding bytes") res = self._buffer[:-pad_size] self._buffer = None -- cgit v1.2.3