Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/padding.py: 39%
116 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
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.
6import abc
7import typing
9from cryptography import utils
10from cryptography.exceptions import AlreadyFinalized
11from cryptography.hazmat.bindings._rust import (
12 check_ansix923_padding,
13 check_pkcs7_padding,
14)
17class PaddingContext(metaclass=abc.ABCMeta):
18 @abc.abstractmethod
19 def update(self, data: bytes) -> bytes:
20 """
21 Pads the provided bytes and returns any available data as bytes.
22 """
24 @abc.abstractmethod
25 def finalize(self) -> bytes:
26 """
27 Finalize the padding, returns bytes.
28 """
31def _byte_padding_check(block_size: int) -> None:
32 if not (0 <= block_size <= 2040):
33 raise ValueError("block_size must be in range(0, 2041).")
35 if block_size % 8 != 0:
36 raise ValueError("block_size must be a multiple of 8.")
39def _byte_padding_update(
40 buffer_: typing.Optional[bytes], data: bytes, block_size: int
41) -> typing.Tuple[bytes, bytes]:
42 if buffer_ is None:
43 raise AlreadyFinalized("Context was already finalized.")
45 utils._check_byteslike("data", data)
47 buffer_ += bytes(data)
49 finished_blocks = len(buffer_) // (block_size // 8)
51 result = buffer_[: finished_blocks * (block_size // 8)]
52 buffer_ = buffer_[finished_blocks * (block_size // 8) :]
54 return buffer_, result
57def _byte_padding_pad(
58 buffer_: typing.Optional[bytes],
59 block_size: int,
60 paddingfn: typing.Callable[[int], bytes],
61) -> bytes:
62 if buffer_ is None:
63 raise AlreadyFinalized("Context was already finalized.")
65 pad_size = block_size // 8 - len(buffer_)
66 return buffer_ + paddingfn(pad_size)
69def _byte_unpadding_update(
70 buffer_: typing.Optional[bytes], data: bytes, block_size: int
71) -> typing.Tuple[bytes, bytes]:
72 if buffer_ is None:
73 raise AlreadyFinalized("Context was already finalized.")
75 utils._check_byteslike("data", data)
77 buffer_ += bytes(data)
79 finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0)
81 result = buffer_[: finished_blocks * (block_size // 8)]
82 buffer_ = buffer_[finished_blocks * (block_size // 8) :]
84 return buffer_, result
87def _byte_unpadding_check(
88 buffer_: typing.Optional[bytes],
89 block_size: int,
90 checkfn: typing.Callable[[bytes], int],
91) -> bytes:
92 if buffer_ is None:
93 raise AlreadyFinalized("Context was already finalized.")
95 if len(buffer_) != block_size // 8:
96 raise ValueError("Invalid padding bytes.")
98 valid = checkfn(buffer_)
100 if not valid:
101 raise ValueError("Invalid padding bytes.")
103 pad_size = buffer_[-1]
104 return buffer_[:-pad_size]
107class PKCS7:
108 def __init__(self, block_size: int):
109 _byte_padding_check(block_size)
110 self.block_size = block_size
112 def padder(self) -> PaddingContext:
113 return _PKCS7PaddingContext(self.block_size)
115 def unpadder(self) -> PaddingContext:
116 return _PKCS7UnpaddingContext(self.block_size)
119class _PKCS7PaddingContext(PaddingContext):
120 _buffer: typing.Optional[bytes]
122 def __init__(self, block_size: int):
123 self.block_size = block_size
124 # TODO: more copies than necessary, we should use zero-buffer (#193)
125 self._buffer = b""
127 def update(self, data: bytes) -> bytes:
128 self._buffer, result = _byte_padding_update(
129 self._buffer, data, self.block_size
130 )
131 return result
133 def _padding(self, size: int) -> bytes:
134 return bytes([size]) * size
136 def finalize(self) -> bytes:
137 result = _byte_padding_pad(
138 self._buffer, self.block_size, self._padding
139 )
140 self._buffer = None
141 return result
144class _PKCS7UnpaddingContext(PaddingContext):
145 _buffer: typing.Optional[bytes]
147 def __init__(self, block_size: int):
148 self.block_size = block_size
149 # TODO: more copies than necessary, we should use zero-buffer (#193)
150 self._buffer = b""
152 def update(self, data: bytes) -> bytes:
153 self._buffer, result = _byte_unpadding_update(
154 self._buffer, data, self.block_size
155 )
156 return result
158 def finalize(self) -> bytes:
159 result = _byte_unpadding_check(
160 self._buffer, self.block_size, check_pkcs7_padding
161 )
162 self._buffer = None
163 return result
166class ANSIX923:
167 def __init__(self, block_size: int):
168 _byte_padding_check(block_size)
169 self.block_size = block_size
171 def padder(self) -> PaddingContext:
172 return _ANSIX923PaddingContext(self.block_size)
174 def unpadder(self) -> PaddingContext:
175 return _ANSIX923UnpaddingContext(self.block_size)
178class _ANSIX923PaddingContext(PaddingContext):
179 _buffer: typing.Optional[bytes]
181 def __init__(self, block_size: int):
182 self.block_size = block_size
183 # TODO: more copies than necessary, we should use zero-buffer (#193)
184 self._buffer = b""
186 def update(self, data: bytes) -> bytes:
187 self._buffer, result = _byte_padding_update(
188 self._buffer, data, self.block_size
189 )
190 return result
192 def _padding(self, size: int) -> bytes:
193 return bytes([0]) * (size - 1) + bytes([size])
195 def finalize(self) -> bytes:
196 result = _byte_padding_pad(
197 self._buffer, self.block_size, self._padding
198 )
199 self._buffer = None
200 return result
203class _ANSIX923UnpaddingContext(PaddingContext):
204 _buffer: typing.Optional[bytes]
206 def __init__(self, block_size: int):
207 self.block_size = block_size
208 # TODO: more copies than necessary, we should use zero-buffer (#193)
209 self._buffer = b""
211 def update(self, data: bytes) -> bytes:
212 self._buffer, result = _byte_unpadding_update(
213 self._buffer, data, self.block_size
214 )
215 return result
217 def finalize(self) -> bytes:
218 result = _byte_unpadding_check(
219 self._buffer,
220 self.block_size,
221 check_ansix923_padding,
222 )
223 self._buffer = None
224 return result