Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PyNaCl-1.6.2-py3.11-linux-x86_64.egg/nacl/signing.py: 65%

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

88 statements  

1# Copyright 2013 Donald Stufft and individual contributors 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14from __future__ import annotations 

15 

16import nacl.bindings 

17from nacl import encoding 

18from nacl import exceptions as exc 

19from nacl.public import ( 

20 PrivateKey as _Curve25519_PrivateKey, 

21) 

22from nacl.public import ( 

23 PublicKey as _Curve25519_PublicKey, 

24) 

25from nacl.utils import StringFixer, random 

26 

27 

28class SignedMessage(bytes): 

29 """ 

30 A bytes subclass that holds a message that has been signed by a 

31 :class:`SigningKey`. 

32 """ 

33 

34 _signature: bytes 

35 _message: bytes 

36 

37 @classmethod 

38 def _from_parts( 

39 cls, signature: bytes, message: bytes, combined: bytes 

40 ) -> SignedMessage: 

41 obj = cls(combined) 

42 obj._signature = signature 

43 obj._message = message 

44 return obj 

45 

46 @property 

47 def signature(self) -> bytes: 

48 """ 

49 The signature contained within the :class:`SignedMessage`. 

50 """ 

51 return self._signature 

52 

53 @property 

54 def message(self) -> bytes: 

55 """ 

56 The message contained within the :class:`SignedMessage`. 

57 """ 

58 return self._message 

59 

60 

61class VerifyKey(encoding.Encodable, StringFixer): 

62 """ 

63 The public key counterpart to an Ed25519 SigningKey for producing digital 

64 signatures. 

65 

66 :param key: [:class:`bytes`] Serialized Ed25519 public key 

67 :param encoder: A class that is able to decode the `key` 

68 """ 

69 

70 def __init__( 

71 self, key: bytes, encoder: encoding.Encoder = encoding.RawEncoder 

72 ): 

73 # Decode the key 

74 key = encoder.decode(key) 

75 if not isinstance(key, bytes): 

76 raise exc.TypeError("VerifyKey must be created from 32 bytes") 

77 

78 if len(key) != nacl.bindings.crypto_sign_PUBLICKEYBYTES: 

79 raise exc.ValueError( 

80 f"The key must be exactly {nacl.bindings.crypto_sign_PUBLICKEYBYTES} bytes long", 

81 ) 

82 

83 self._key = key 

84 

85 def __bytes__(self) -> bytes: 

86 return self._key 

87 

88 def __hash__(self) -> int: 

89 return hash(bytes(self)) 

90 

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

92 if not isinstance(other, self.__class__): 

93 return False 

94 return nacl.bindings.sodium_memcmp(bytes(self), bytes(other)) 

95 

96 def __ne__(self, other: object) -> bool: 

97 return not (self == other) 

98 

99 def verify( 

100 self, 

101 smessage: bytes, 

102 signature: bytes | None = None, 

103 encoder: encoding.Encoder = encoding.RawEncoder, 

104 ) -> bytes: 

105 """ 

106 Verifies the signature of a signed message, returning the message 

107 if it has not been tampered with else raising 

108 :class:`~nacl.exceptions.BadSignatureError`. 

109 

110 :param smessage: [:class:`bytes`] Either the original messaged or a 

111 signature and message concated together. 

112 :param signature: [:class:`bytes`] If an unsigned message is given for 

113 smessage then the detached signature must be provided. 

114 :param encoder: A class that is able to decode the secret message and 

115 signature. 

116 :rtype: :class:`bytes` 

117 """ 

118 if signature is not None: 

119 # If we were given the message and signature separately, validate 

120 # signature size and combine them. 

121 if not isinstance(signature, bytes): 

122 raise exc.TypeError( 

123 "Verification signature must be created from " 

124 f"{nacl.bindings.crypto_sign_BYTES} bytes", 

125 ) 

126 

127 if len(signature) != nacl.bindings.crypto_sign_BYTES: 

128 raise exc.ValueError( 

129 "The signature must be exactly " 

130 f"{nacl.bindings.crypto_sign_BYTES} bytes long", 

131 ) 

132 

133 smessage = signature + encoder.decode(smessage) 

134 else: 

135 # Decode the signed message 

136 smessage = encoder.decode(smessage) 

137 

138 return nacl.bindings.crypto_sign_open(smessage, self._key) 

139 

140 def to_curve25519_public_key(self) -> _Curve25519_PublicKey: 

141 """ 

142 Converts a :class:`~nacl.signing.VerifyKey` to a 

143 :class:`~nacl.public.PublicKey` 

144 

145 :rtype: :class:`~nacl.public.PublicKey` 

146 """ 

147 raw_pk = nacl.bindings.crypto_sign_ed25519_pk_to_curve25519(self._key) 

148 return _Curve25519_PublicKey(raw_pk) 

149 

150 

151class SigningKey(encoding.Encodable, StringFixer): 

152 """ 

153 Private key for producing digital signatures using the Ed25519 algorithm. 

154 

155 Signing keys are produced from a 32-byte (256-bit) random seed value. This 

156 value can be passed into the :class:`~nacl.signing.SigningKey` as a 

157 :func:`bytes` whose length is 32. 

158 

159 .. warning:: This **must** be protected and remain secret. Anyone who knows 

160 the value of your :class:`~nacl.signing.SigningKey` or it's seed can 

161 masquerade as you. 

162 

163 :param seed: [:class:`bytes`] Random 32-byte value (i.e. private key) 

164 :param encoder: A class that is able to decode the seed 

165 

166 :ivar: verify_key: [:class:`~nacl.signing.VerifyKey`] The verify 

167 (i.e. public) key that corresponds with this signing key. 

168 """ 

169 

170 def __init__( 

171 self, 

172 seed: bytes, 

173 encoder: encoding.Encoder = encoding.RawEncoder, 

174 ): 

175 # Decode the seed 

176 seed = encoder.decode(seed) 

177 if not isinstance(seed, bytes): 

178 raise exc.TypeError( 

179 "SigningKey must be created from a 32 byte seed" 

180 ) 

181 

182 # Verify that our seed is the proper size 

183 if len(seed) != nacl.bindings.crypto_sign_SEEDBYTES: 

184 raise exc.ValueError( 

185 "The seed must be exactly " 

186 f"{nacl.bindings.crypto_sign_SEEDBYTES} bytes long" 

187 ) 

188 

189 public_key, secret_key = nacl.bindings.crypto_sign_seed_keypair(seed) 

190 

191 self._seed = seed 

192 self._signing_key = secret_key 

193 self.verify_key = VerifyKey(public_key) 

194 

195 def __bytes__(self) -> bytes: 

196 return self._seed 

197 

198 def __hash__(self) -> int: 

199 return hash(bytes(self)) 

200 

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

202 if not isinstance(other, self.__class__): 

203 return False 

204 return nacl.bindings.sodium_memcmp(bytes(self), bytes(other)) 

205 

206 def __ne__(self, other: object) -> bool: 

207 return not (self == other) 

208 

209 @classmethod 

210 def generate(cls) -> SigningKey: 

211 """ 

212 Generates a random :class:`~nacl.signing.SigningKey` object. 

213 

214 :rtype: :class:`~nacl.signing.SigningKey` 

215 """ 

216 return cls( 

217 random(nacl.bindings.crypto_sign_SEEDBYTES), 

218 encoder=encoding.RawEncoder, 

219 ) 

220 

221 def sign( 

222 self, 

223 message: bytes, 

224 encoder: encoding.Encoder = encoding.RawEncoder, 

225 ) -> SignedMessage: 

226 """ 

227 Sign a message using this key. 

228 

229 :param message: [:class:`bytes`] The data to be signed. 

230 :param encoder: A class that is used to encode the signed message. 

231 :rtype: :class:`~nacl.signing.SignedMessage` 

232 """ 

233 raw_signed = nacl.bindings.crypto_sign(message, self._signing_key) 

234 

235 crypto_sign_BYTES = nacl.bindings.crypto_sign_BYTES 

236 signature = encoder.encode(raw_signed[:crypto_sign_BYTES]) 

237 message = encoder.encode(raw_signed[crypto_sign_BYTES:]) 

238 signed = encoder.encode(raw_signed) 

239 

240 return SignedMessage._from_parts(signature, message, signed) 

241 

242 def to_curve25519_private_key(self) -> _Curve25519_PrivateKey: 

243 """ 

244 Converts a :class:`~nacl.signing.SigningKey` to a 

245 :class:`~nacl.public.PrivateKey` 

246 

247 :rtype: :class:`~nacl.public.PrivateKey` 

248 """ 

249 sk = self._signing_key 

250 raw_private = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(sk) 

251 return _Curve25519_PrivateKey(raw_private)