Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/cryptography/hazmat/primitives/padding.py: 40%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

93 statements  

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. 

4 

5from __future__ import annotations 

6 

7import abc 

8import typing 

9 

10from cryptography import utils 

11from cryptography.exceptions import AlreadyFinalized 

12from cryptography.hazmat.bindings._rust import ( 

13 PKCS7PaddingContext, 

14 PKCS7UnpaddingContext, 

15 check_ansix923_padding, 

16) 

17 

18 

19class PaddingContext(metaclass=abc.ABCMeta): 

20 @abc.abstractmethod 

21 def update(self, data: bytes) -> bytes: 

22 """ 

23 Pads the provided bytes and returns any available data as bytes. 

24 """ 

25 

26 @abc.abstractmethod 

27 def finalize(self) -> bytes: 

28 """ 

29 Finalize the padding, returns bytes. 

30 """ 

31 

32 

33def _byte_padding_check(block_size: int) -> None: 

34 if not (0 <= block_size <= 2040): 

35 raise ValueError("block_size must be in range(0, 2041).") 

36 

37 if block_size % 8 != 0: 

38 raise ValueError("block_size must be a multiple of 8.") 

39 

40 

41def _byte_padding_update( 

42 buffer_: bytes | None, data: bytes, block_size: int 

43) -> tuple[bytes, bytes]: 

44 if buffer_ is None: 

45 raise AlreadyFinalized("Context was already finalized.") 

46 

47 utils._check_byteslike("data", data) 

48 

49 buffer_ += bytes(data) 

50 

51 finished_blocks = len(buffer_) // (block_size // 8) 

52 

53 result = buffer_[: finished_blocks * (block_size // 8)] 

54 buffer_ = buffer_[finished_blocks * (block_size // 8) :] 

55 

56 return buffer_, result 

57 

58 

59def _byte_padding_pad( 

60 buffer_: bytes | None, 

61 block_size: int, 

62 paddingfn: typing.Callable[[int], bytes], 

63) -> bytes: 

64 if buffer_ is None: 

65 raise AlreadyFinalized("Context was already finalized.") 

66 

67 pad_size = block_size // 8 - len(buffer_) 

68 return buffer_ + paddingfn(pad_size) 

69 

70 

71def _byte_unpadding_update( 

72 buffer_: bytes | None, data: bytes, block_size: int 

73) -> tuple[bytes, bytes]: 

74 if buffer_ is None: 

75 raise AlreadyFinalized("Context was already finalized.") 

76 

77 utils._check_byteslike("data", data) 

78 

79 buffer_ += bytes(data) 

80 

81 finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0) 

82 

83 result = buffer_[: finished_blocks * (block_size // 8)] 

84 buffer_ = buffer_[finished_blocks * (block_size // 8) :] 

85 

86 return buffer_, result 

87 

88 

89def _byte_unpadding_check( 

90 buffer_: bytes | None, 

91 block_size: int, 

92 checkfn: typing.Callable[[bytes], int], 

93) -> bytes: 

94 if buffer_ is None: 

95 raise AlreadyFinalized("Context was already finalized.") 

96 

97 if len(buffer_) != block_size // 8: 

98 raise ValueError("Invalid padding bytes.") 

99 

100 valid = checkfn(buffer_) 

101 

102 if not valid: 

103 raise ValueError("Invalid padding bytes.") 

104 

105 pad_size = buffer_[-1] 

106 return buffer_[:-pad_size] 

107 

108 

109class PKCS7: 

110 def __init__(self, block_size: int): 

111 _byte_padding_check(block_size) 

112 self.block_size = block_size 

113 

114 def padder(self) -> PaddingContext: 

115 return PKCS7PaddingContext(self.block_size) 

116 

117 def unpadder(self) -> PaddingContext: 

118 return PKCS7UnpaddingContext(self.block_size) 

119 

120 

121PaddingContext.register(PKCS7PaddingContext) 

122PaddingContext.register(PKCS7UnpaddingContext) 

123 

124 

125class ANSIX923: 

126 def __init__(self, block_size: int): 

127 _byte_padding_check(block_size) 

128 self.block_size = block_size 

129 

130 def padder(self) -> PaddingContext: 

131 return _ANSIX923PaddingContext(self.block_size) 

132 

133 def unpadder(self) -> PaddingContext: 

134 return _ANSIX923UnpaddingContext(self.block_size) 

135 

136 

137class _ANSIX923PaddingContext(PaddingContext): 

138 _buffer: bytes | None 

139 

140 def __init__(self, block_size: int): 

141 self.block_size = block_size 

142 # TODO: more copies than necessary, we should use zero-buffer (#193) 

143 self._buffer = b"" 

144 

145 def update(self, data: bytes) -> bytes: 

146 self._buffer, result = _byte_padding_update( 

147 self._buffer, data, self.block_size 

148 ) 

149 return result 

150 

151 def _padding(self, size: int) -> bytes: 

152 return bytes([0]) * (size - 1) + bytes([size]) 

153 

154 def finalize(self) -> bytes: 

155 result = _byte_padding_pad( 

156 self._buffer, self.block_size, self._padding 

157 ) 

158 self._buffer = None 

159 return result 

160 

161 

162class _ANSIX923UnpaddingContext(PaddingContext): 

163 _buffer: bytes | None 

164 

165 def __init__(self, block_size: int): 

166 self.block_size = block_size 

167 # TODO: more copies than necessary, we should use zero-buffer (#193) 

168 self._buffer = b"" 

169 

170 def update(self, data: bytes) -> bytes: 

171 self._buffer, result = _byte_unpadding_update( 

172 self._buffer, data, self.block_size 

173 ) 

174 return result 

175 

176 def finalize(self) -> bytes: 

177 result = _byte_unpadding_check( 

178 self._buffer, 

179 self.block_size, 

180 check_ansix923_padding, 

181 ) 

182 self._buffer = None 

183 return result