From bf0f464ab62d2e69ebfacd80fad2de46e862fcbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 26 Feb 2016 18:40:20 +0100 Subject: Added support for padding ANSI X.923 --- src/cryptography/hazmat/primitives/padding.py | 37 ++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index f6491eb7..72ebff2b 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -68,12 +68,15 @@ class _PKCS7PaddingContext(object): return result + def _padding(self, size): + return six.int2byte(size) * size + def finalize(self): if self._buffer is None: raise AlreadyFinalized("Context was already finalized.") pad_size = self.block_size // 8 - len(self._buffer) - result = self._buffer + six.int2byte(pad_size) * pad_size + result = self._buffer + self._padding(pad_size) self._buffer = None return result @@ -104,6 +107,11 @@ class _PKCS7UnpaddingContext(object): return result + def _check_padding(self): + return lib.Cryptography_check_pkcs7_padding( + self._buffer, self.block_size // 8 + ) + def finalize(self): if self._buffer is None: raise AlreadyFinalized("Context was already finalized.") @@ -111,9 +119,7 @@ class _PKCS7UnpaddingContext(object): if len(self._buffer) != self.block_size // 8: raise ValueError("Invalid padding bytes.") - valid = lib.Cryptography_check_pkcs7_padding( - self._buffer, self.block_size // 8 - ) + valid = self._check_padding() if not valid: raise ValueError("Invalid padding bytes.") @@ -122,3 +128,26 @@ class _PKCS7UnpaddingContext(object): res = self._buffer[:-pad_size] self._buffer = None return res + + +class ANSIX923(PKCS7): + + def padder(self): + return _ANSIX923PaddingContext(self.block_size) + + def unpadder(self): + return _ANSIX923UnpaddingContext(self.block_size) + + +@utils.register_interface(PaddingContext) +class _ANSIX923PaddingContext(_PKCS7PaddingContext): + + def _padding(self, size): + return six.int2byte(0) * (size - 1) + six.int2byte(size) + + +@utils.register_interface(PaddingContext) +class _ANSIX923UnpaddingContext(_PKCS7UnpaddingContext): + + def _check_padding(self): + return True -- cgit v1.2.3 From f8c230d1ab16905c64baa88322aa0bb4e8f094bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 26 Feb 2016 23:35:39 +0100 Subject: Factorize out common byte padding --- src/cryptography/hazmat/primitives/padding.py | 51 +++++++++++++++++---------- 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index 72ebff2b..08c6ca03 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -28,7 +28,7 @@ class PaddingContext(object): """ -class PKCS7(object): +class _BytePadding(object): def __init__(self, block_size): if not (0 <= block_size < 256): raise ValueError("block_size must be in range(0, 256).") @@ -38,15 +38,8 @@ class PKCS7(object): self.block_size = block_size - def padder(self): - return _PKCS7PaddingContext(self.block_size) - - def unpadder(self): - return _PKCS7UnpaddingContext(self.block_size) - -@utils.register_interface(PaddingContext) -class _PKCS7PaddingContext(object): +class _BytePaddingContext(object): def __init__(self, block_size): self.block_size = block_size # TODO: more copies than necessary, we should use zero-buffer (#193) @@ -69,7 +62,7 @@ class _PKCS7PaddingContext(object): return result def _padding(self, size): - return six.int2byte(size) * size + return NotImplemented def finalize(self): if self._buffer is None: @@ -81,8 +74,7 @@ class _PKCS7PaddingContext(object): return result -@utils.register_interface(PaddingContext) -class _PKCS7UnpaddingContext(object): +class _ByteUnpaddingContext(object): def __init__(self, block_size): self.block_size = block_size # TODO: more copies than necessary, we should use zero-buffer (#193) @@ -108,9 +100,7 @@ class _PKCS7UnpaddingContext(object): return result def _check_padding(self): - return lib.Cryptography_check_pkcs7_padding( - self._buffer, self.block_size // 8 - ) + return NotImplemented def finalize(self): if self._buffer is None: @@ -130,7 +120,32 @@ class _PKCS7UnpaddingContext(object): return res -class ANSIX923(PKCS7): +class PKCS7(_BytePadding): + + def padder(self): + return _PKCS7PaddingContext(self.block_size) + + def unpadder(self): + return _PKCS7UnpaddingContext(self.block_size) + + +@utils.register_interface(PaddingContext) +class _PKCS7PaddingContext(_BytePaddingContext): + + def _padding(self, size): + return six.int2byte(size) * size + + +@utils.register_interface(PaddingContext) +class _PKCS7UnpaddingContext(_ByteUnpaddingContext): + + def _check_padding(self): + return lib.Cryptography_check_pkcs7_padding( + self._buffer, self.block_size // 8 + ) + + +class ANSIX923(_BytePadding): def padder(self): return _ANSIX923PaddingContext(self.block_size) @@ -140,14 +155,14 @@ class ANSIX923(PKCS7): @utils.register_interface(PaddingContext) -class _ANSIX923PaddingContext(_PKCS7PaddingContext): +class _ANSIX923PaddingContext(_BytePaddingContext): def _padding(self, size): return six.int2byte(0) * (size - 1) + six.int2byte(size) @utils.register_interface(PaddingContext) -class _ANSIX923UnpaddingContext(_PKCS7UnpaddingContext): +class _ANSIX923UnpaddingContext(_ByteUnpaddingContext): def _check_padding(self): return True -- cgit v1.2.3 From 94f9ea25b50a3dd2592abfc63385989955e60e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 27 Feb 2016 00:28:39 +0100 Subject: Add padding check for ANSI X.923 All padding bytes must be 0. --- src/_cffi_src/hazmat_src/padding.c | 24 ++++++++++++++++++++++++ src/_cffi_src/hazmat_src/padding.h | 1 + src/cryptography/hazmat/primitives/padding.py | 4 +++- 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/_cffi_src/hazmat_src/padding.c b/src/_cffi_src/hazmat_src/padding.c index 570bad9f..1a0c869d 100644 --- a/src/_cffi_src/hazmat_src/padding.c +++ b/src/_cffi_src/hazmat_src/padding.c @@ -37,3 +37,27 @@ uint8_t Cryptography_check_pkcs7_padding(const uint8_t *data, /* Now check the low bit to see if it's set */ return (mismatch & 1) == 0; } + +uint8_t Cryptography_check_ansix923_padding(const uint8_t *data, + uint8_t block_len) { + uint8_t i; + uint8_t pad_size = data[block_len - 1]; + uint8_t mismatch = 0; + /* Skip the first one with the pad size */ + for (i = 1; i < block_len; i++) { + unsigned int mask = Cryptography_constant_time_lt(i, pad_size); + uint8_t b = data[block_len - 1 - i]; + mismatch |= (mask & b); + } + + /* Check to make sure the pad_size was within the valid range. */ + mismatch |= ~Cryptography_constant_time_lt(0, pad_size); + mismatch |= Cryptography_constant_time_lt(block_len, pad_size); + + /* Make sure any bits set are copied to the lowest bit */ + mismatch |= mismatch >> 4; + mismatch |= mismatch >> 2; + mismatch |= mismatch >> 1; + /* Now check the low bit to see if it's set */ + return (mismatch & 1) == 0; +} diff --git a/src/_cffi_src/hazmat_src/padding.h b/src/_cffi_src/hazmat_src/padding.h index 4d218b1a..fb023c17 100644 --- a/src/_cffi_src/hazmat_src/padding.h +++ b/src/_cffi_src/hazmat_src/padding.h @@ -3,3 +3,4 @@ // repository for complete details. uint8_t Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t); +uint8_t Cryptography_check_ansix923_padding(const uint8_t *, uint8_t); diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index 08c6ca03..81883404 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -165,4 +165,6 @@ class _ANSIX923PaddingContext(_BytePaddingContext): class _ANSIX923UnpaddingContext(_ByteUnpaddingContext): def _check_padding(self): - return True + return lib.Cryptography_check_ansix923_padding( + self._buffer, self.block_size // 8 + ) -- cgit v1.2.3 From 89d47907f112be41a9ea4e684af24d5a74c14336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 27 Feb 2016 15:09:06 +0100 Subject: Make _padding and _check_padding abstractmethod --- src/cryptography/hazmat/primitives/padding.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index 81883404..c6fe656e 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -39,6 +39,7 @@ class _BytePadding(object): self.block_size = block_size +@six.add_metaclass(abc.ABCMeta) class _BytePaddingContext(object): def __init__(self, block_size): self.block_size = block_size @@ -61,8 +62,11 @@ class _BytePaddingContext(object): return result + @abc.abstractmethod def _padding(self, size): - return NotImplemented + """ + Returns the padding for the size. + """ def finalize(self): if self._buffer is None: @@ -74,6 +78,7 @@ class _BytePaddingContext(object): return result +@six.add_metaclass(abc.ABCMeta) class _ByteUnpaddingContext(object): def __init__(self, block_size): self.block_size = block_size @@ -99,8 +104,11 @@ class _ByteUnpaddingContext(object): return result + @abc.abstractmethod def _check_padding(self): - return NotImplemented + """ + Returns if the padding is valid. + """ def finalize(self): if self._buffer is None: -- cgit v1.2.3 From 288027ee43494eff37ee2c558b3683ea94c769ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 14 Mar 2016 00:54:58 +0100 Subject: Don't use subclass --- src/cryptography/hazmat/primitives/padding.py | 200 ++++++++++++++------------ 1 file changed, 112 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index c6fe656e..77fb8f83 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -28,107 +28,76 @@ class PaddingContext(object): """ -class _BytePadding(object): - def __init__(self, block_size): - if not (0 <= block_size < 256): - raise ValueError("block_size must be in range(0, 256).") +def _byte_padding_check(block_size): + 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.") + if block_size % 8 != 0: + raise ValueError("block_size must be a multiple of 8.") - self.block_size = block_size +def _byte_padding_update(buffer_, data, block_size): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") -@six.add_metaclass(abc.ABCMeta) -class _BytePaddingContext(object): - def __init__(self, block_size): - self.block_size = block_size - # TODO: more copies than necessary, we should use zero-buffer (#193) - self._buffer = b"" + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") - def update(self, data): - if self._buffer is None: - raise AlreadyFinalized("Context was already finalized.") + buffer_ += data - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + finished_blocks = len(buffer_) // (block_size // 8) - self._buffer += data + result = buffer_[:finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8):] - finished_blocks = len(self._buffer) // (self.block_size // 8) + return buffer_, result - result = self._buffer[:finished_blocks * (self.block_size // 8)] - self._buffer = self._buffer[finished_blocks * (self.block_size // 8):] - return result +def _byte_padding_pad(buffer_, block_size, paddingfn): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") - @abc.abstractmethod - def _padding(self, size): - """ - Returns the padding for the size. - """ + pad_size = block_size // 8 - len(buffer_) + return buffer_ + paddingfn(pad_size) - def finalize(self): - if self._buffer is None: - raise AlreadyFinalized("Context was already finalized.") - pad_size = self.block_size // 8 - len(self._buffer) - result = self._buffer + self._padding(pad_size) - self._buffer = None - return result +def _byte_unpadding_update(buffer_, data, block_size): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") -@six.add_metaclass(abc.ABCMeta) -class _ByteUnpaddingContext(object): - def __init__(self, block_size): - self.block_size = block_size - # TODO: more copies than necessary, we should use zero-buffer (#193) - self._buffer = b"" - - def update(self, data): - if self._buffer is None: - raise AlreadyFinalized("Context was already finalized.") + buffer_ += data - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0) - self._buffer += data + result = buffer_[:finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8):] - finished_blocks = max( - len(self._buffer) // (self.block_size // 8) - 1, - 0 - ) + return buffer_, result - result = self._buffer[:finished_blocks * (self.block_size // 8)] - self._buffer = self._buffer[finished_blocks * (self.block_size // 8):] - - return result - @abc.abstractmethod - def _check_padding(self): - """ - Returns if the padding is valid. - """ +def _byte_unpadding_check(buffer_, block_size, checkfn): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") - def finalize(self): - if self._buffer is None: - raise AlreadyFinalized("Context was already finalized.") + if len(buffer_) != block_size // 8: + raise ValueError("Invalid padding bytes.") - if len(self._buffer) != self.block_size // 8: - raise ValueError("Invalid padding bytes.") + valid = checkfn(buffer_, block_size // 8) - valid = self._check_padding() + if not valid: + raise ValueError("Invalid padding bytes.") - if not valid: - raise ValueError("Invalid padding bytes.") + pad_size = six.indexbytes(buffer_, -1) + return buffer_[:-pad_size] - pad_size = six.indexbytes(self._buffer, -1) - res = self._buffer[:-pad_size] - self._buffer = None - return res - -class PKCS7(_BytePadding): +class PKCS7(object): + def __init__(self, block_size): + _byte_padding_check(block_size) + self.block_size = block_size def padder(self): return _PKCS7PaddingContext(self.block_size) @@ -138,22 +107,51 @@ class PKCS7(_BytePadding): @utils.register_interface(PaddingContext) -class _PKCS7PaddingContext(_BytePaddingContext): +class _PKCS7PaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data): + self._buffer, result = _byte_padding_update( + self._buffer, data, self.block_size) + return result def _padding(self, size): return six.int2byte(size) * size + def finalize(self): + result = _byte_padding_pad( + self._buffer, self.block_size, self._padding) + self._buffer = None + return result + @utils.register_interface(PaddingContext) -class _PKCS7UnpaddingContext(_ByteUnpaddingContext): +class _PKCS7UnpaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" - def _check_padding(self): - return lib.Cryptography_check_pkcs7_padding( - self._buffer, self.block_size // 8 - ) + def update(self, data): + self._buffer, result = _byte_unpadding_update( + self._buffer, data, self.block_size) + return result + def finalize(self): + result = _byte_unpadding_check( + self._buffer, self.block_size, + lib.Cryptography_check_pkcs7_padding) + self._buffer = None + return result -class ANSIX923(_BytePadding): + +class ANSIX923(object): + def __init__(self, block_size): + _byte_padding_check(block_size) + self.block_size = block_size def padder(self): return _ANSIX923PaddingContext(self.block_size) @@ -163,16 +161,42 @@ class ANSIX923(_BytePadding): @utils.register_interface(PaddingContext) -class _ANSIX923PaddingContext(_BytePaddingContext): +class _ANSIX923PaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data): + self._buffer, result = _byte_padding_update( + self._buffer, data, self.block_size) + return result def _padding(self, size): return six.int2byte(0) * (size - 1) + six.int2byte(size) + def finalize(self): + result = _byte_padding_pad( + self._buffer, self.block_size, self._padding) + self._buffer = None + return result + @utils.register_interface(PaddingContext) -class _ANSIX923UnpaddingContext(_ByteUnpaddingContext): +class _ANSIX923UnpaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" - def _check_padding(self): - return lib.Cryptography_check_ansix923_padding( - self._buffer, self.block_size // 8 - ) + def update(self, data): + self._buffer, result = _byte_unpadding_update( + self._buffer, data, self.block_size) + return result + + def finalize(self): + result = _byte_unpadding_check( + self._buffer, self.block_size, + lib.Cryptography_check_ansix923_padding) + self._buffer = None + return result -- cgit v1.2.3