Skip to content
Snippets Groups Projects
Commit 7eb6123e authored by Donald Stufft's avatar Donald Stufft
Browse files

Document nacl.secret.SecretBox

parent c2ffa1c9
No related branches found
No related tags found
No related merge requests found
...@@ -6,6 +6,7 @@ Contents: ...@@ -6,6 +6,7 @@ Contents:
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
secret
signing signing
......
Secret Key Encryption
=====================
Secret key encryption is analogous to a safe. You can store something secret
through it and anyone who has the key can open it and view the contents.
:class:`~nacl.secret.SecretBox` functions as just such a safe, and like any
good safe any attempts to tamper with the contents is easily detected.
Secret Key Encryption allows you to store or transmit data over insecure
channels without leaking the contents of that message, nor anything about it
other than the length.
Example
-------
.. code:: python
import nacl
import nacl.secret
# This must be kept secret, this is the combination to your safe
key = nacl.random(nacl.secret.SecretBox.KEY_SIZE)
# This is your safe, you can use it to encrypt or decrypt messages
box = nacl.secret.SecretBox(key)
# This is our message to send, it must be a bytestring as SecretBox will
# treat is as just a binary blob of data.
message = b"The president will be exiting through the lower levels"
# This is a nonce, it *MUST* only be used once, but it is not considered
# secret and can be transmitted or stored alongside the ciphertext. A
# good source of nonce is just 24 random bytes.
nonce = nacl.random(24)
# Encrypt our message, it will be exactly 16 bytes longer than the original
# message as it stores authentication information alongside it.
ciphertext = box.encrypt(message, nonce)
# Decrypt our message, an exception will be raised if the encryption was
# tampered with or there was otherwise an error.
plaintext = box.decrypt(ciphertext, nonce)
Usage Information
-----------------
* :class:`~nacl.secret.SecretBox` requires a 32 byte key that must be kept
secret. It is the combination to your "safe" and anyone with this key will
be able to decrypt the data.
* :class:`~nacl.secret.SecretBox` requires a new 24 bytes nonce with every
encrypted message. This nonce is *not* secret and be freely transfered or
stored in plaintext alongside the ciphertext. However it is absolutely
imperative that you **NEVER** reuse a nonce with the same key. Reusing the
nonce with the same key provides enough information for an attacker
to decrypt any and all messages made with your key.
Reference
---------
.. autoclass:: nacl.secret.SecretBox
:members:
Algorithm details
-----------------
:Encryption: `Salsa20 steam cipher <https://en.wikipedia.org/wiki/Salsa20>`_
:Authentication: `Poly1305 MAC <https://en.wikipedia.org/wiki/Poly1305-AES>`_
...@@ -8,8 +8,27 @@ from .exceptions import CryptoError ...@@ -8,8 +8,27 @@ from .exceptions import CryptoError
class SecretBox(encoding.Encodable, six.StringFixer, object): class SecretBox(encoding.Encodable, six.StringFixer, object):
"""
The SecretBox class encrypted and decrypts messages using the given secret
key.
The ciphertexts generated by :class:`~nacl.secret.Secretbox` include a 16
byte authenticator which is checked as part of the decryption. An invalid
authenticator will cause the decrypt function to raise an exception. The
authenticator is not a signature. Once you've decrypted the message you've
demonstrated the ability to create arbitrary valid message, so messages you
send are repudiable. For non-repudiable messages, sign them after
encryption.
:param key: The secret key used to encrypt and decrypt messages
:param encoder: The encoder class used to decode the given key
:cvar KEY_SIZE: The size that the key is required to be.
:cvar NONCE_SIZE: The size that the nonce is required to be.
"""
KEY_SIZE = nacl.lib.crypto_secretbox_KEYBYTES KEY_SIZE = nacl.lib.crypto_secretbox_KEYBYTES
NONCE_SIZE = nacl.lib.crypto_secretbox_NONCEBYTES
def __init__(self, key, encoder=encoding.RawEncoder): def __init__(self, key, encoder=encoding.RawEncoder):
key = encoder.decode(key) key = encoder.decode(key)
...@@ -24,7 +43,22 @@ class SecretBox(encoding.Encodable, six.StringFixer, object): ...@@ -24,7 +43,22 @@ class SecretBox(encoding.Encodable, six.StringFixer, object):
return self._key return self._key
def encrypt(self, plaintext, nonce, encoder=encoding.RawEncoder): def encrypt(self, plaintext, nonce, encoder=encoding.RawEncoder):
if len(nonce) != nacl.lib.crypto_secretbox_NONCEBYTES: """
Encrypts the plaintext message using the given nonce and returns the
ciphertext encoded with the encoder.
.. warning:: It is **VITALLY** important that the nonce is a nonce,
i.e. itis a number used only once for any given key. If you fail to
do this, you compromise the privacy of the messages encrypted. Give
your nonces a different prefix, or have one side use an odd counter
and one an even counter. Just make sure they are different.
:param plaintext: [:class:`bytes`] The plaintext message to encrypt
:param nonce: [:class:`bytes`] The nonce to use in the encryption
:param encoder: The encoder to use to encode the ciphertext
:rtype: [:class:`bytes`]
"""
if len(nonce) != self.NONCE_SIZE:
raise ValueError("The nonce must be exactly %s bytes long" % raise ValueError("The nonce must be exactly %s bytes long" %
nacl.lib.crypto_secretbox_NONCEBYTES) nacl.lib.crypto_secretbox_NONCEBYTES)
...@@ -42,7 +76,17 @@ class SecretBox(encoding.Encodable, six.StringFixer, object): ...@@ -42,7 +76,17 @@ class SecretBox(encoding.Encodable, six.StringFixer, object):
return encoder.encode(ciphertext) return encoder.encode(ciphertext)
def decrypt(self, ciphertext, nonce, encoder=encoding.RawEncoder): def decrypt(self, ciphertext, nonce, encoder=encoding.RawEncoder):
if len(nonce) != nacl.lib.crypto_secretbox_NONCEBYTES: """
Decrypts the ciphertext using the given nonce and returns the plaintext
message.
:param ciphertext: [:class:`bytes`] The encrypted message to decrypt
:param nonce: [:class:`bytes`] The nonce used when encrypting the
ciphertext
:param encoder: The encoder used to decode the ciphertext.
:rtype: [:class:`bytes`]
"""
if len(nonce) != self.NONCE_SIZE:
raise ValueError("The nonce must be exactly %s bytes long" % raise ValueError("The nonce must be exactly %s bytes long" %
nacl.lib.crypto_secretbox_NONCEBYTES) nacl.lib.crypto_secretbox_NONCEBYTES)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment