~davide-cst00/uftp/0.2

« back to all changes in this revision

Viewing changes to nacl/public.py

  • Committer: Davide Costa
  • Date: 2018-09-14 12:21:37 UTC
  • Revision ID: davide.cst00@gmail.com-20180914122137-j0ycqb4tk9z2r1k5
Xenial release 0.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
15
from __future__ import absolute_import, division, print_function
 
16
 
 
17
from nacl import encoding
 
18
import nacl.bindings
 
19
from nacl.utils import EncryptedMessage, StringFixer, random
 
20
 
 
21
 
 
22
class PublicKey(encoding.Encodable, StringFixer, object):
 
23
    """
 
24
    The public key counterpart to an Curve25519 :class:`nacl.public.PrivateKey`
 
25
    for encrypting messages.
 
26
 
 
27
    :param public_key: [:class:`bytes`] Encoded Curve25519 public key
 
28
    :param encoder: A class that is able to decode the `public_key`
 
29
 
 
30
    :cvar SIZE: The size that the public key is required to be
 
31
    """
 
32
 
 
33
    SIZE = nacl.bindings.crypto_box_PUBLICKEYBYTES
 
34
 
 
35
    def __init__(self, public_key, encoder=encoding.RawEncoder):
 
36
        self._public_key = encoder.decode(public_key)
 
37
        if not isinstance(self._public_key, bytes):
 
38
            raise TypeError("PublicKey must be created from 32 bytes")
 
39
 
 
40
        if len(self._public_key) != self.SIZE:
 
41
            raise ValueError("The public key must be exactly %s bytes long" %
 
42
                             self.SIZE)
 
43
 
 
44
    def __bytes__(self):
 
45
        return self._public_key
 
46
 
 
47
 
 
48
class PrivateKey(encoding.Encodable, StringFixer, object):
 
49
    """
 
50
    Private key for decrypting messages using the Curve25519 algorithm.
 
51
 
 
52
    .. warning:: This **must** be protected and remain secret. Anyone who
 
53
        knows the value of your :class:`~nacl.public.PrivateKey` can decrypt
 
54
        any message encrypted by the corresponding
 
55
        :class:`~nacl.public.PublicKey`
 
56
 
 
57
    :param private_key: The private key used to decrypt messages
 
58
    :param encoder: The encoder class used to decode the given keys
 
59
 
 
60
    :cvar SIZE: The size that the private key is required to be
 
61
    """
 
62
 
 
63
    SIZE = nacl.bindings.crypto_box_SECRETKEYBYTES
 
64
 
 
65
    def __init__(self, private_key, encoder=encoding.RawEncoder):
 
66
        # Decode the secret_key
 
67
        private_key = encoder.decode(private_key)
 
68
        if not isinstance(private_key, bytes):
 
69
            raise TypeError("PrivateKey must be created from a 32 byte seed")
 
70
 
 
71
        # Verify that our seed is the proper size
 
72
        if len(private_key) != self.SIZE:
 
73
            raise ValueError(
 
74
                "The secret key must be exactly %d bytes long" % self.SIZE)
 
75
 
 
76
        raw_public_key = nacl.bindings.crypto_scalarmult_base(private_key)
 
77
 
 
78
        self._private_key = private_key
 
79
        self.public_key = PublicKey(raw_public_key)
 
80
 
 
81
    def __bytes__(self):
 
82
        return self._private_key
 
83
 
 
84
    @classmethod
 
85
    def generate(cls):
 
86
        """
 
87
        Generates a random :class:`~nacl.public.PrivateKey` object
 
88
 
 
89
        :rtype: :class:`~nacl.public.PrivateKey`
 
90
        """
 
91
        return cls(random(PrivateKey.SIZE), encoder=encoding.RawEncoder)
 
92
 
 
93
 
 
94
class Box(encoding.Encodable, StringFixer, object):
 
95
    """
 
96
    The Box class boxes and unboxes messages between a pair of keys
 
97
 
 
98
    The ciphertexts generated by :class:`~nacl.public.Box` include a 16
 
99
    byte authenticator which is checked as part of the decryption. An invalid
 
100
    authenticator will cause the decrypt function to raise an exception. The
 
101
    authenticator is not a signature. Once you've decrypted the message you've
 
102
    demonstrated the ability to create arbitrary valid message, so messages you
 
103
    send are repudiable. For non-repudiable messages, sign them after
 
104
    encryption.
 
105
 
 
106
    :param private_key: :class:`~nacl.public.PrivateKey` used to encrypt and
 
107
        decrypt messages
 
108
    :param public_key: :class:`~nacl.public.PublicKey` used to encrypt and
 
109
        decrypt messages
 
110
 
 
111
    :cvar NONCE_SIZE: The size that the nonce is required to be.
 
112
    """
 
113
 
 
114
    NONCE_SIZE = nacl.bindings.crypto_box_NONCEBYTES
 
115
 
 
116
    def __init__(self, private_key, public_key):
 
117
        if private_key and public_key:
 
118
            if ((not isinstance(private_key, PrivateKey) or
 
119
                 not isinstance(public_key, PublicKey))):
 
120
                raise TypeError("Box must be created from "
 
121
                                "a PrivateKey and a PublicKey")
 
122
            self._shared_key = nacl.bindings.crypto_box_beforenm(
 
123
                public_key.encode(encoder=encoding.RawEncoder),
 
124
                private_key.encode(encoder=encoding.RawEncoder),
 
125
            )
 
126
        else:
 
127
            self._shared_key = None
 
128
 
 
129
    def __bytes__(self):
 
130
        return self._shared_key
 
131
 
 
132
    @classmethod
 
133
    def decode(cls, encoded, encoder=encoding.RawEncoder):
 
134
        # Create an empty box
 
135
        box = cls(None, None)
 
136
 
 
137
        # Assign our decoded value to the shared key of the box
 
138
        box._shared_key = encoder.decode(encoded)
 
139
 
 
140
        return box
 
141
 
 
142
    def encrypt(self, plaintext, nonce, encoder=encoding.RawEncoder):
 
143
        """
 
144
        Encrypts the plaintext message using the given `nonce` and returns
 
145
        the ciphertext encoded with the encoder.
 
146
 
 
147
        .. warning:: It is **VITALLY** important that the nonce is a nonce,
 
148
            i.e. it is a number used only once for any given key. If you fail
 
149
            to do this, you compromise the privacy of the messages encrypted.
 
150
 
 
151
        :param plaintext: [:class:`bytes`] The plaintext message to encrypt
 
152
        :param nonce: [:class:`bytes`] The nonce to use in the encryption
 
153
        :param encoder: The encoder to use to encode the ciphertext
 
154
        :rtype: [:class:`nacl.utils.EncryptedMessage`]
 
155
        """
 
156
        if len(nonce) != self.NONCE_SIZE:
 
157
            raise ValueError("The nonce must be exactly %s bytes long" %
 
158
                             self.NONCE_SIZE)
 
159
 
 
160
        ciphertext = nacl.bindings.crypto_box_afternm(
 
161
            plaintext,
 
162
            nonce,
 
163
            self._shared_key,
 
164
        )
 
165
 
 
166
        encoded_nonce = encoder.encode(nonce)
 
167
        encoded_ciphertext = encoder.encode(ciphertext)
 
168
 
 
169
        return EncryptedMessage._from_parts(
 
170
            encoded_nonce,
 
171
            encoded_ciphertext,
 
172
            encoder.encode(nonce + ciphertext),
 
173
        )
 
174
 
 
175
    def decrypt(self, ciphertext, nonce=None, encoder=encoding.RawEncoder):
 
176
        """
 
177
        Decrypts the ciphertext using the given nonce and returns the
 
178
        plaintext message.
 
179
 
 
180
        :param ciphertext: [:class:`bytes`] The encrypted message to decrypt
 
181
        :param nonce: [:class:`bytes`] The nonce used when encrypting the
 
182
            ciphertext
 
183
        :param encoder: The encoder used to decode the ciphertext.
 
184
        :rtype: [:class:`bytes`]
 
185
        """
 
186
        # Decode our ciphertext
 
187
        ciphertext = encoder.decode(ciphertext)
 
188
 
 
189
        if nonce is None:
 
190
            # If we were given the nonce and ciphertext combined, split them.
 
191
            nonce = ciphertext[:self.NONCE_SIZE]
 
192
            ciphertext = ciphertext[self.NONCE_SIZE:]
 
193
 
 
194
        if len(nonce) != self.NONCE_SIZE:
 
195
            raise ValueError("The nonce must be exactly %s bytes long" %
 
196
                             self.NONCE_SIZE)
 
197
 
 
198
        plaintext = nacl.bindings.crypto_box_open_afternm(
 
199
            ciphertext,
 
200
            nonce,
 
201
            self._shared_key,
 
202
        )
 
203
 
 
204
        return plaintext