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

134 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:05 +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: typing.Union[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: typing.Union[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 from cryptography.hazmat.backends.openssl.backend import ( 

166 backend as ossl, 

167 ) 

168 

169 return ossl.load_dsa_parameter_numbers(self) 

170 

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

172 if not isinstance(other, DSAParameterNumbers): 

173 return NotImplemented 

174 

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

176 

177 def __repr__(self) -> str: 

178 return ( 

179 "<DSAParameterNumbers(p={self.p}, q={self.q}, " 

180 "g={self.g})>".format(self=self) 

181 ) 

182 

183 

184class DSAPublicNumbers: 

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

186 if not isinstance(y, int): 

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

188 

189 if not isinstance(parameter_numbers, DSAParameterNumbers): 

190 raise TypeError( 

191 "parameter_numbers must be a DSAParameterNumbers instance." 

192 ) 

193 

194 self._y = y 

195 self._parameter_numbers = parameter_numbers 

196 

197 @property 

198 def y(self) -> int: 

199 return self._y 

200 

201 @property 

202 def parameter_numbers(self) -> DSAParameterNumbers: 

203 return self._parameter_numbers 

204 

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

206 from cryptography.hazmat.backends.openssl.backend import ( 

207 backend as ossl, 

208 ) 

209 

210 return ossl.load_dsa_public_numbers(self) 

211 

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

213 if not isinstance(other, DSAPublicNumbers): 

214 return NotImplemented 

215 

216 return ( 

217 self.y == other.y 

218 and self.parameter_numbers == other.parameter_numbers 

219 ) 

220 

221 def __repr__(self) -> str: 

222 return ( 

223 "<DSAPublicNumbers(y={self.y}, " 

224 "parameter_numbers={self.parameter_numbers})>".format(self=self) 

225 ) 

226 

227 

228class DSAPrivateNumbers: 

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

230 if not isinstance(x, int): 

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

232 

233 if not isinstance(public_numbers, DSAPublicNumbers): 

234 raise TypeError( 

235 "public_numbers must be a DSAPublicNumbers instance." 

236 ) 

237 self._public_numbers = public_numbers 

238 self._x = x 

239 

240 @property 

241 def x(self) -> int: 

242 return self._x 

243 

244 @property 

245 def public_numbers(self) -> DSAPublicNumbers: 

246 return self._public_numbers 

247 

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

249 from cryptography.hazmat.backends.openssl.backend import ( 

250 backend as ossl, 

251 ) 

252 

253 return ossl.load_dsa_private_numbers(self) 

254 

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

256 if not isinstance(other, DSAPrivateNumbers): 

257 return NotImplemented 

258 

259 return ( 

260 self.x == other.x and self.public_numbers == other.public_numbers 

261 ) 

262 

263 

264def generate_parameters( 

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

266) -> DSAParameters: 

267 from cryptography.hazmat.backends.openssl.backend import backend as ossl 

268 

269 return ossl.generate_dsa_parameters(key_size) 

270 

271 

272def generate_private_key( 

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

274) -> DSAPrivateKey: 

275 from cryptography.hazmat.backends.openssl.backend import backend as ossl 

276 

277 return ossl.generate_dsa_private_key_and_parameters(key_size) 

278 

279 

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

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

282 raise ValueError( 

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

284 ) 

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

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

287 

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

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

290 

291 

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

293 parameters = numbers.public_numbers.parameter_numbers 

294 _check_dsa_parameters(parameters) 

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

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

297 

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

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