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. 14 15from __future__ import absolute_import, division, print_function 16 17import nacl.bindings 18from nacl import encoding 19from nacl import exceptions as exc 20from nacl.utils import EncryptedMessage, StringFixer, random 21 22 23class PublicKey(encoding.Encodable, StringFixer, object): 24 """ 25 The public key counterpart to an Curve25519 :class:`nacl.public.PrivateKey` 26 for encrypting messages. 27 28 :param public_key: [:class:`bytes`] Encoded Curve25519 public key 29 :param encoder: A class that is able to decode the `public_key` 30 31 :cvar SIZE: The size that the public key is required to be 32 """ 33 34 SIZE = nacl.bindings.crypto_box_PUBLICKEYBYTES 35 36 def __init__(self, public_key, encoder=encoding.RawEncoder): 37 self._public_key = encoder.decode(public_key) 38 if not isinstance(self._public_key, bytes): 39 raise exc.TypeError("PublicKey must be created from 32 bytes") 40 41 if len(self._public_key) != self.SIZE: 42 raise exc.ValueError( 43 "The public key must be exactly {0} bytes long".format( 44 self.SIZE 45 ) 46 ) 47 48 def __bytes__(self): 49 return self._public_key 50 51 def __hash__(self): 52 return hash(bytes(self)) 53 54 def __eq__(self, other): 55 if not isinstance(other, self.__class__): 56 return False 57 return nacl.bindings.sodium_memcmp(bytes(self), bytes(other)) 58 59 def __ne__(self, other): 60 return not (self == other) 61 62 63class PrivateKey(encoding.Encodable, StringFixer, object): 64 """ 65 Private key for decrypting messages using the Curve25519 algorithm. 66 67 .. warning:: This **must** be protected and remain secret. Anyone who 68 knows the value of your :class:`~nacl.public.PrivateKey` can decrypt 69 any message encrypted by the corresponding 70 :class:`~nacl.public.PublicKey` 71 72 :param private_key: The private key used to decrypt messages 73 :param encoder: The encoder class used to decode the given keys 74 75 :cvar SIZE: The size that the private key is required to be 76 :cvar SEED_SIZE: The size that the seed used to generate the 77 private key is required to be 78 """ 79 80 SIZE = nacl.bindings.crypto_box_SECRETKEYBYTES 81 SEED_SIZE = nacl.bindings.crypto_box_SEEDBYTES 82 83 def __init__(self, private_key, encoder=encoding.RawEncoder): 84 # Decode the secret_key 85 private_key = encoder.decode(private_key) 86 # verify the given secret key type and size are correct 87 if not (isinstance(private_key, bytes) and 88 len(private_key) == self.SIZE): 89 raise exc.TypeError(("PrivateKey must be created from a {0} " 90 "bytes long raw secret key").format(self.SIZE) 91 ) 92 93 raw_public_key = nacl.bindings.crypto_scalarmult_base(private_key) 94 95 self._private_key = private_key 96 self.public_key = PublicKey(raw_public_key) 97 98 @classmethod 99 def from_seed(cls, seed, encoder=encoding.RawEncoder): 100 """ 101 Generate a PrivateKey using a deterministic construction 102 starting from a caller-provided seed 103 104 .. warning:: The seed **must** be high-entropy; therefore, 105 its generator **must** be a cryptographic quality 106 random function like, for example, :func:`~nacl.utils.random`. 107 108 .. warning:: The seed **must** be protected and remain secret. 109 Anyone who knows the seed is really in possession of 110 the corresponding PrivateKey. 111 112 :param seed: The seed used to generate the private key 113 :rtype: :class:`~nacl.public.PrivateKey` 114 """ 115 # decode the seed 116 seed = encoder.decode(seed) 117 # Verify the given seed type and size are correct 118 if not (isinstance(seed, bytes) and len(seed) == cls.SEED_SIZE): 119 raise exc.TypeError(("PrivateKey seed must be a {0} bytes long " 120 "binary sequence").format(cls.SEED_SIZE) 121 ) 122 # generate a raw keypair from the given seed 123 raw_pk, raw_sk = nacl.bindings.crypto_box_seed_keypair(seed) 124 # construct a instance from the raw secret key 125 return cls(raw_sk) 126 127 def __bytes__(self): 128 return self._private_key 129 130 def __hash__(self): 131 return hash((type(self), bytes(self.public_key))) 132 133 def __eq__(self, other): 134 if not isinstance(other, self.__class__): 135 return False 136 return self.public_key == other.public_key 137 138 def __ne__(self, other): 139 return not (self == other) 140 141 @classmethod 142 def generate(cls): 143 """ 144 Generates a random :class:`~nacl.public.PrivateKey` object 145 146 :rtype: :class:`~nacl.public.PrivateKey` 147 """ 148 return cls(random(PrivateKey.SIZE), encoder=encoding.RawEncoder) 149 150 151class Box(encoding.Encodable, StringFixer, object): 152 """ 153 The Box class boxes and unboxes messages between a pair of keys 154 155 The ciphertexts generated by :class:`~nacl.public.Box` include a 16 156 byte authenticator which is checked as part of the decryption. An invalid 157 authenticator will cause the decrypt function to raise an exception. The 158 authenticator is not a signature. Once you've decrypted the message you've 159 demonstrated the ability to create arbitrary valid message, so messages you 160 send are repudiable. For non-repudiable messages, sign them after 161 encryption. 162 163 :param private_key: :class:`~nacl.public.PrivateKey` used to encrypt and 164 decrypt messages 165 :param public_key: :class:`~nacl.public.PublicKey` used to encrypt and 166 decrypt messages 167 168 :cvar NONCE_SIZE: The size that the nonce is required to be. 169 """ 170 171 NONCE_SIZE = nacl.bindings.crypto_box_NONCEBYTES 172 173 def __init__(self, private_key, public_key): 174 if private_key and public_key: 175 if ((not isinstance(private_key, PrivateKey) or 176 not isinstance(public_key, PublicKey))): 177 raise exc.TypeError("Box must be created from " 178 "a PrivateKey and a PublicKey") 179 self._shared_key = nacl.bindings.crypto_box_beforenm( 180 public_key.encode(encoder=encoding.RawEncoder), 181 private_key.encode(encoder=encoding.RawEncoder), 182 ) 183 else: 184 self._shared_key = None 185 186 def __bytes__(self): 187 return self._shared_key 188 189 @classmethod 190 def decode(cls, encoded, encoder=encoding.RawEncoder): 191 # Create an empty box 192 box = cls(None, None) 193 194 # Assign our decoded value to the shared key of the box 195 box._shared_key = encoder.decode(encoded) 196 197 return box 198 199 def encrypt(self, plaintext, nonce=None, encoder=encoding.RawEncoder): 200 """ 201 Encrypts the plaintext message using the given `nonce` (or generates 202 one randomly if omitted) and returns the ciphertext encoded with the 203 encoder. 204 205 .. warning:: It is **VITALLY** important that the nonce is a nonce, 206 i.e. it is a number used only once for any given key. If you fail 207 to do this, you compromise the privacy of the messages encrypted. 208 209 :param plaintext: [:class:`bytes`] The plaintext message to encrypt 210 :param nonce: [:class:`bytes`] The nonce to use in the encryption 211 :param encoder: The encoder to use to encode the ciphertext 212 :rtype: [:class:`nacl.utils.EncryptedMessage`] 213 """ 214 if nonce is None: 215 nonce = random(self.NONCE_SIZE) 216 217 if len(nonce) != self.NONCE_SIZE: 218 raise exc.ValueError("The nonce must be exactly %s bytes long" % 219 self.NONCE_SIZE) 220 221 ciphertext = nacl.bindings.crypto_box_afternm( 222 plaintext, 223 nonce, 224 self._shared_key, 225 ) 226 227 encoded_nonce = encoder.encode(nonce) 228 encoded_ciphertext = encoder.encode(ciphertext) 229 230 return EncryptedMessage._from_parts( 231 encoded_nonce, 232 encoded_ciphertext, 233 encoder.encode(nonce + ciphertext), 234 ) 235 236 def decrypt(self, ciphertext, nonce=None, encoder=encoding.RawEncoder): 237 """ 238 Decrypts the ciphertext using the `nonce` (explicitly, when passed as a 239 parameter or implicitly, when omitted, as part of the ciphertext) and 240 returns the plaintext message. 241 242 :param ciphertext: [:class:`bytes`] The encrypted message to decrypt 243 :param nonce: [:class:`bytes`] The nonce used when encrypting the 244 ciphertext 245 :param encoder: The encoder used to decode the ciphertext. 246 :rtype: [:class:`bytes`] 247 """ 248 # Decode our ciphertext 249 ciphertext = encoder.decode(ciphertext) 250 251 if nonce is None: 252 # If we were given the nonce and ciphertext combined, split them. 253 nonce = ciphertext[:self.NONCE_SIZE] 254 ciphertext = ciphertext[self.NONCE_SIZE:] 255 256 if len(nonce) != self.NONCE_SIZE: 257 raise exc.ValueError("The nonce must be exactly %s bytes long" % 258 self.NONCE_SIZE) 259 260 plaintext = nacl.bindings.crypto_box_open_afternm( 261 ciphertext, 262 nonce, 263 self._shared_key, 264 ) 265 266 return plaintext 267 268 def shared_key(self): 269 """ 270 Returns the Curve25519 shared secret, that can then be used as a key in 271 other symmetric ciphers. 272 273 .. warning:: It is **VITALLY** important that you use a nonce with your 274 symmetric cipher. If you fail to do this, you compromise the 275 privacy of the messages encrypted. Ensure that the key length of 276 your cipher is 32 bytes. 277 :rtype: [:class:`bytes`] 278 """ 279 280 return self._shared_key 281 282 283class SealedBox(encoding.Encodable, StringFixer, object): 284 """ 285 The SealedBox class boxes and unboxes messages addressed to 286 a specified key-pair by using ephemeral sender's keypairs, 287 whose private part will be discarded just after encrypting 288 a single plaintext message. 289 290 The ciphertexts generated by :class:`~nacl.public.SecretBox` include 291 the public part of the ephemeral key before the :class:`~nacl.public.Box` 292 ciphertext. 293 294 :param public_key: :class:`~nacl.public.PublicKey` used to encrypt 295 messages and derive nonces 296 :param private_key: :class:`~nacl.public.PrivateKey` used to decrypt 297 messages 298 299 .. versionadded:: 1.2 300 """ 301 302 def __init__(self, recipient_key): 303 304 if isinstance(recipient_key, PublicKey): 305 self._public_key = recipient_key.encode( 306 encoder=encoding.RawEncoder) 307 self._private_key = None 308 elif isinstance(recipient_key, PrivateKey): 309 self._private_key = recipient_key.encode( 310 encoder=encoding.RawEncoder) 311 self._public_key = recipient_key.public_key.encode( 312 encoder=encoding.RawEncoder) 313 else: 314 raise exc.TypeError("SealedBox must be created from " 315 "a PublicKey or a PrivateKey") 316 317 def __bytes__(self): 318 return self._public_key 319 320 def encrypt(self, plaintext, encoder=encoding.RawEncoder): 321 """ 322 Encrypts the plaintext message using a random-generated ephemeral 323 keypair and returns a "composed ciphertext", containing both 324 the public part of the keypair and the ciphertext proper, 325 encoded with the encoder. 326 327 The private part of the ephemeral key-pair will be scrubbed before 328 returning the ciphertext, therefore, the sender will not be able to 329 decrypt the generated ciphertext. 330 331 :param plaintext: [:class:`bytes`] The plaintext message to encrypt 332 :param encoder: The encoder to use to encode the ciphertext 333 :return bytes: encoded ciphertext 334 """ 335 336 ciphertext = nacl.bindings.crypto_box_seal( 337 plaintext, 338 self._public_key 339 ) 340 341 encoded_ciphertext = encoder.encode(ciphertext) 342 343 return encoded_ciphertext 344 345 def decrypt(self, ciphertext, encoder=encoding.RawEncoder): 346 """ 347 Decrypts the ciphertext using the ephemeral public key enclosed 348 in the ciphertext and the SealedBox private key, returning 349 the plaintext message. 350 351 :param ciphertext: [:class:`bytes`] The encrypted message to decrypt 352 :param encoder: The encoder used to decode the ciphertext. 353 :return bytes: The original plaintext 354 """ 355 # Decode our ciphertext 356 ciphertext = encoder.decode(ciphertext) 357 358 plaintext = nacl.bindings.crypto_box_seal_open( 359 ciphertext, 360 self._public_key, 361 self._private_key, 362 ) 363 364 return plaintext 365