Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py: 60%

135 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 07:26 +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. 

4 

5from __future__ import annotations 

6 

7import abc 

8import typing 

9 

10from cryptography.hazmat.bindings._rust import openssl as rust_openssl 

11from cryptography.hazmat.primitives import _serialization, hashes 

12from cryptography.hazmat.primitives.asymmetric import utils as asym_utils 

13 

14 

15class DSAParameters(metaclass=abc.ABCMeta): 

16 @abc.abstractmethod 

17 def generate_private_key(self) -> DSAPrivateKey: 

18 """ 

19 Generates and returns a DSAPrivateKey. 

20 """ 

21 

22 @abc.abstractmethod 

23 def parameter_numbers(self) -> DSAParameterNumbers: 

24 """ 

25 Returns a DSAParameterNumbers. 

26 """ 

27 

28 

29DSAParametersWithNumbers = DSAParameters 

30DSAParameters.register(rust_openssl.dsa.DSAParameters) 

31 

32 

33class DSAPrivateKey(metaclass=abc.ABCMeta): 

34 @property 

35 @abc.abstractmethod 

36 def key_size(self) -> int: 

37 """ 

38 The bit length of the prime modulus. 

39 """ 

40 

41 @abc.abstractmethod 

42 def public_key(self) -> DSAPublicKey: 

43 """ 

44 The DSAPublicKey associated with this private key. 

45 """ 

46 

47 @abc.abstractmethod 

48 def parameters(self) -> DSAParameters: 

49 """ 

50 The DSAParameters object associated with this private key. 

51 """ 

52 

53 @abc.abstractmethod 

54 def sign( 

55 self, 

56 data: bytes, 

57 algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, 

58 ) -> bytes: 

59 """ 

60 Signs the data 

61 """ 

62 

63 @abc.abstractmethod 

64 def private_numbers(self) -> DSAPrivateNumbers: 

65 """ 

66 Returns a DSAPrivateNumbers. 

67 """ 

68 

69 @abc.abstractmethod 

70 def private_bytes( 

71 self, 

72 encoding: _serialization.Encoding, 

73 format: _serialization.PrivateFormat, 

74 encryption_algorithm: _serialization.KeySerializationEncryption, 

75 ) -> bytes: 

76 """ 

77 Returns the key serialized as bytes. 

78 """ 

79 

80 

81DSAPrivateKeyWithSerialization = DSAPrivateKey 

82DSAPrivateKey.register(rust_openssl.dsa.DSAPrivateKey) 

83 

84 

85class DSAPublicKey(metaclass=abc.ABCMeta): 

86 @property 

87 @abc.abstractmethod 

88 def key_size(self) -> int: 

89 """ 

90 The bit length of the prime modulus. 

91 """ 

92 

93 @abc.abstractmethod 

94 def parameters(self) -> DSAParameters: 

95 """ 

96 The DSAParameters object associated with this public key. 

97 """ 

98 

99 @abc.abstractmethod 

100 def public_numbers(self) -> DSAPublicNumbers: 

101 """ 

102 Returns a DSAPublicNumbers. 

103 """ 

104 

105 @abc.abstractmethod 

106 def public_bytes( 

107 self, 

108 encoding: _serialization.Encoding, 

109 format: _serialization.PublicFormat, 

110 ) -> bytes: 

111 """ 

112 Returns the key serialized as bytes. 

113 """ 

114 

115 @abc.abstractmethod 

116 def verify( 

117 self, 

118 signature: bytes, 

119 data: bytes, 

120 algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, 

121 ) -> None: 

122 """ 

123 Verifies the signature of the data. 

124 """ 

125 

126 @abc.abstractmethod 

127 def __eq__(self, other: object) -> bool: 

128 """ 

129 Checks equality. 

130 """ 

131 

132 

133DSAPublicKeyWithSerialization = DSAPublicKey 

134DSAPublicKey.register(rust_openssl.dsa.DSAPublicKey) 

135 

136 

137class DSAParameterNumbers: 

138 def __init__(self, p: int, q: int, g: int): 

139 if ( 

140 not isinstance(p, int) 

141 or not isinstance(q, int) 

142 or not isinstance(g, int) 

143 ): 

144 raise TypeError( 

145 "DSAParameterNumbers p, q, and g arguments must be integers." 

146 ) 

147 

148 self._p = p 

149 self._q = q 

150 self._g = g 

151 

152 @property 

153 def p(self) -> int: 

154 return self._p 

155 

156 @property 

157 def q(self) -> int: 

158 return self._q 

159 

160 @property 

161 def g(self) -> int: 

162 return self._g 

163 

164 def parameters(self, backend: typing.Any = None) -> DSAParameters: 

165 _check_dsa_parameters(self) 

166 return rust_openssl.dsa.from_parameter_numbers(self) 

167 

168 def __eq__(self, other: object) -> bool: 

169 if not isinstance(other, DSAParameterNumbers): 

170 return NotImplemented 

171 

172 return self.p == other.p and self.q == other.q and self.g == other.g 

173 

174 def __repr__(self) -> str: 

175 return f"<DSAParameterNumbers(p={self.p}, q={self.q}, " f"g={self.g})>" 

176 

177 

178class DSAPublicNumbers: 

179 def __init__(self, y: int, parameter_numbers: DSAParameterNumbers): 

180 if not isinstance(y, int): 

181 raise TypeError("DSAPublicNumbers y argument must be an integer.") 

182 

183 if not isinstance(parameter_numbers, DSAParameterNumbers): 

184 raise TypeError( 

185 "parameter_numbers must be a DSAParameterNumbers instance." 

186 ) 

187 

188 self._y = y 

189 self._parameter_numbers = parameter_numbers 

190 

191 @property 

192 def y(self) -> int: 

193 return self._y 

194 

195 @property 

196 def parameter_numbers(self) -> DSAParameterNumbers: 

197 return self._parameter_numbers 

198 

199 def public_key(self, backend: typing.Any = None) -> DSAPublicKey: 

200 _check_dsa_parameters(self.parameter_numbers) 

201 return rust_openssl.dsa.from_public_numbers(self) 

202 

203 def __eq__(self, other: object) -> bool: 

204 if not isinstance(other, DSAPublicNumbers): 

205 return NotImplemented 

206 

207 return ( 

208 self.y == other.y 

209 and self.parameter_numbers == other.parameter_numbers 

210 ) 

211 

212 def __repr__(self) -> str: 

213 return ( 

214 f"<DSAPublicNumbers(y={self.y}, " 

215 f"parameter_numbers={self.parameter_numbers})>" 

216 ) 

217 

218 

219class DSAPrivateNumbers: 

220 def __init__(self, x: int, public_numbers: DSAPublicNumbers): 

221 if not isinstance(x, int): 

222 raise TypeError("DSAPrivateNumbers x argument must be an integer.") 

223 

224 if not isinstance(public_numbers, DSAPublicNumbers): 

225 raise TypeError( 

226 "public_numbers must be a DSAPublicNumbers instance." 

227 ) 

228 self._public_numbers = public_numbers 

229 self._x = x 

230 

231 @property 

232 def x(self) -> int: 

233 return self._x 

234 

235 @property 

236 def public_numbers(self) -> DSAPublicNumbers: 

237 return self._public_numbers 

238 

239 def private_key(self, backend: typing.Any = None) -> DSAPrivateKey: 

240 _check_dsa_private_numbers(self) 

241 return rust_openssl.dsa.from_private_numbers(self) 

242 

243 def __eq__(self, other: object) -> bool: 

244 if not isinstance(other, DSAPrivateNumbers): 

245 return NotImplemented 

246 

247 return ( 

248 self.x == other.x and self.public_numbers == other.public_numbers 

249 ) 

250 

251 

252def generate_parameters( 

253 key_size: int, backend: typing.Any = None 

254) -> DSAParameters: 

255 if key_size not in (1024, 2048, 3072, 4096): 

256 raise ValueError("Key size must be 1024, 2048, 3072, or 4096 bits.") 

257 

258 return rust_openssl.dsa.generate_parameters(key_size) 

259 

260 

261def generate_private_key( 

262 key_size: int, backend: typing.Any = None 

263) -> DSAPrivateKey: 

264 parameters = generate_parameters(key_size) 

265 return parameters.generate_private_key() 

266 

267 

268def _check_dsa_parameters(parameters: DSAParameterNumbers) -> None: 

269 if parameters.p.bit_length() not in [1024, 2048, 3072, 4096]: 

270 raise ValueError( 

271 "p must be exactly 1024, 2048, 3072, or 4096 bits long" 

272 ) 

273 if parameters.q.bit_length() not in [160, 224, 256]: 

274 raise ValueError("q must be exactly 160, 224, or 256 bits long") 

275 

276 if not (1 < parameters.g < parameters.p): 

277 raise ValueError("g, p don't satisfy 1 < g < p.") 

278 

279 

280def _check_dsa_private_numbers(numbers: DSAPrivateNumbers) -> None: 

281 parameters = numbers.public_numbers.parameter_numbers 

282 _check_dsa_parameters(parameters) 

283 if numbers.x <= 0 or numbers.x >= parameters.q: 

284 raise ValueError("x must be > 0 and < q.") 

285 

286 if numbers.public_numbers.y != pow(parameters.g, numbers.x, parameters.p): 

287 raise ValueError("y must be equal to (g ** x % p).")