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

86 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-06 06:06 +0000

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 typing import Optional 

15 

16import nacl.bindings 

17from nacl import encoding 

18from nacl import exceptions as exc 

19from nacl.public import ( 

20 PrivateKey as _Curve25519_PrivateKey, 

21 PublicKey as _Curve25519_PublicKey, 

22) 

23from nacl.utils import StringFixer, random 

24 

25 

26class SignedMessage(bytes): 

27 """ 

28 A bytes subclass that holds a messaged that has been signed by a 

29 :class:`SigningKey`. 

30 """ 

31 

32 _signature: bytes 

33 _message: bytes 

34 

35 @classmethod 

36 def _from_parts( 

37 cls, signature: bytes, message: bytes, combined: bytes 

38 ) -> "SignedMessage": 

39 obj = cls(combined) 

40 obj._signature = signature 

41 obj._message = message 

42 return obj 

43 

44 @property 

45 def signature(self) -> bytes: 

46 """ 

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

48 """ 

49 return self._signature 

50 

51 @property 

52 def message(self) -> bytes: 

53 """ 

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

55 """ 

56 return self._message 

57 

58 

59class VerifyKey(encoding.Encodable, StringFixer): 

60 """ 

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

62 signatures. 

63 

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

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

66 """ 

67 

68 def __init__( 

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

70 ): 

71 # Decode the key 

72 key = encoder.decode(key) 

73 if not isinstance(key, bytes): 

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

75 

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

77 raise exc.ValueError( 

78 "The key must be exactly %s bytes long" 

79 % nacl.bindings.crypto_sign_PUBLICKEYBYTES, 

80 ) 

81 

82 self._key = key 

83 

84 def __bytes__(self) -> bytes: 

85 return self._key 

86 

87 def __hash__(self) -> int: 

88 return hash(bytes(self)) 

89 

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

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

92 return False 

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

94 

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

96 return not (self == other) 

97 

98 def verify( 

99 self, 

100 smessage: bytes, 

101 signature: Optional[bytes] = None, 

102 encoder: encoding.Encoder = encoding.RawEncoder, 

103 ) -> bytes: 

104 """ 

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

106 if it has not been tampered with else raising 

107 :class:`~nacl.signing.BadSignatureError`. 

108 

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

110 signature and message concated together. 

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

112 smessage then the detached signature must be provided. 

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

114 signature. 

115 :rtype: :class:`bytes` 

116 """ 

117 if signature is not None: 

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

119 # signature size and combine them. 

120 if not isinstance(signature, bytes): 

121 raise exc.TypeError( 

122 "Verification signature must be created from %d bytes" 

123 % nacl.bindings.crypto_sign_BYTES, 

124 ) 

125 

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

127 raise exc.ValueError( 

128 "The signature must be exactly %d bytes long" 

129 % nacl.bindings.crypto_sign_BYTES, 

130 ) 

131 

132 smessage = signature + encoder.decode(smessage) 

133 else: 

134 # Decode the signed message 

135 smessage = encoder.decode(smessage) 

136 

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

138 

139 def to_curve25519_public_key(self) -> _Curve25519_PublicKey: 

140 """ 

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

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

143 

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

145 """ 

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

147 return _Curve25519_PublicKey(raw_pk) 

148 

149 

150class SigningKey(encoding.Encodable, StringFixer): 

151 """ 

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

153 

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

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

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

157 

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

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

160 masquerade as you. 

161 

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

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

164 

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

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

167 """ 

168 

169 def __init__( 

170 self, 

171 seed: bytes, 

172 encoder: encoding.Encoder = encoding.RawEncoder, 

173 ): 

174 # Decode the seed 

175 seed = encoder.decode(seed) 

176 if not isinstance(seed, bytes): 

177 raise exc.TypeError( 

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

179 ) 

180 

181 # Verify that our seed is the proper size 

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

183 raise exc.ValueError( 

184 "The seed must be exactly %d bytes long" 

185 % nacl.bindings.crypto_sign_SEEDBYTES 

186 ) 

187 

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

189 

190 self._seed = seed 

191 self._signing_key = secret_key 

192 self.verify_key = VerifyKey(public_key) 

193 

194 def __bytes__(self) -> bytes: 

195 return self._seed 

196 

197 def __hash__(self) -> int: 

198 return hash(bytes(self)) 

199 

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

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

202 return False 

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

204 

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

206 return not (self == other) 

207 

208 @classmethod 

209 def generate(cls) -> "SigningKey": 

210 """ 

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

212 

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

214 """ 

215 return cls( 

216 random(nacl.bindings.crypto_sign_SEEDBYTES), 

217 encoder=encoding.RawEncoder, 

218 ) 

219 

220 def sign( 

221 self, 

222 message: bytes, 

223 encoder: encoding.Encoder = encoding.RawEncoder, 

224 ) -> SignedMessage: 

225 """ 

226 Sign a message using this key. 

227 

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

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

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

231 """ 

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

233 

234 crypto_sign_BYTES = nacl.bindings.crypto_sign_BYTES 

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

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

237 signed = encoder.encode(raw_signed) 

238 

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

240 

241 def to_curve25519_private_key(self) -> _Curve25519_PrivateKey: 

242 """ 

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

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

245 

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

247 """ 

248 sk = self._signing_key 

249 raw_private = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(sk) 

250 return _Curve25519_PrivateKey(raw_private)