From 0223438f384081c78960b9ac8fdba9c3e4b701d9 Mon Sep 17 00:00:00 2001 From: Donald Stufft <donald@stufft.io> Date: Sun, 6 Oct 2013 22:28:34 -0400 Subject: [PATCH] Port the crypto_secretbox implementation to the new layout --- src/nacl/_lib/crypto_secretbox.h | 28 ++++++++++++ src/nacl/c/__init__.py | 12 +++++ src/nacl/c/crypto_secretbox.py | 76 ++++++++++++++++++++++++++++++++ src/nacl/secret.py | 35 ++++----------- 4 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 src/nacl/_lib/crypto_secretbox.h create mode 100644 src/nacl/c/crypto_secretbox.py diff --git a/src/nacl/_lib/crypto_secretbox.h b/src/nacl/_lib/crypto_secretbox.h new file mode 100644 index 00000000..88da2a35 --- /dev/null +++ b/src/nacl/_lib/crypto_secretbox.h @@ -0,0 +1,28 @@ +/* Copyright 2013 Donald Stufft and individual contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +size_t crypto_secretbox_keybytes(); +size_t crypto_secretbox_noncebytes(); +size_t crypto_secretbox_zerobytes(); +size_t crypto_secretbox_boxzerobytes(); + + +int crypto_secretbox(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +int crypto_secretbox_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k); diff --git a/src/nacl/c/__init__.py b/src/nacl/c/__init__.py index e062935a..377192ae 100644 --- a/src/nacl/c/__init__.py +++ b/src/nacl/c/__init__.py @@ -23,6 +23,11 @@ from nacl.c.crypto_scalarmult import ( crypto_scalarmult_BYTES, crypto_scalarmult_SCALARBYTES, crypto_scalarmult_base, ) +from nacl.c.crypto_secretbox import ( + crypto_secretbox_KEYBYTES, crypto_secretbox_NONCEBYTES, + crypto_secretbox_ZEROBYTES, crypto_secretbox_BOXZEROBYTES, + crypto_secretbox, crypto_secretbox_open, +) from nacl.c.randombytes import randombytes @@ -44,5 +49,12 @@ __all__ = [ "crypto_scalarmult_SCALARBYTES", "crypto_scalarmult_base", + "crypto_secretbox_KEYBYTES", + "crypto_secretbox_NONCEBYTES", + "crypto_secretbox_ZEROBYTES", + "crypto_secretbox_BOXZEROBYTES", + "crypto_secretbox", + "crypto_secretbox_open", + "randombytes", ] diff --git a/src/nacl/c/crypto_secretbox.py b/src/nacl/c/crypto_secretbox.py new file mode 100644 index 00000000..bc867e59 --- /dev/null +++ b/src/nacl/c/crypto_secretbox.py @@ -0,0 +1,76 @@ +# Copyright 2013 Donald Stufft and individual contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +from nacl import _lib as lib +from nacl.exceptions import CryptoError + + +crypto_secretbox_KEYBYTES = lib.crypto_secretbox_keybytes() +crypto_secretbox_NONCEBYTES = lib.crypto_secretbox_noncebytes() +crypto_secretbox_ZEROBYTES = lib.crypto_secretbox_zerobytes() +crypto_secretbox_BOXZEROBYTES = lib.crypto_secretbox_boxzerobytes() + + +def crypto_secretbox(key, message, nonce): + """ + Encrypts and returns the message ``message`` with the secret ``key`` and + the nonce ``nonce``. + + :param key: bytes + :param message: bytes + :param nonce: bytes + :rtype: bytes + """ + if len(key) != crypto_secretbox_KEYBYTES: + raise ValueError("Invalid key") + + if len(nonce) != crypto_secretbox_NONCEBYTES: + raise ValueError("Invalid nonce") + + padded = b"\x00" * crypto_secretbox_ZEROBYTES + message + ciphertext = lib.ffi.new("unsigned char[]", len(padded)) + + if lib.crypto_secretbox(ciphertext, padded, len(padded), nonce, key) != 0: + raise CryptoError("Encryption failed") + + ciphertext = lib.ffi.buffer(ciphertext, len(padded)) + return ciphertext[crypto_secretbox_BOXZEROBYTES:] + + +def crypto_secretbox_open(key, ciphertext, nonce): + """ + Decrypt and returns the encrypted message ``ciphertext`` with the secret + ``key`` and the nonce ``nonce``. + + :param key: bytes + :param ciphertext: bytes + :param nonce: bytes + :rtype: bytes + """ + if len(key) != crypto_secretbox_KEYBYTES: + raise ValueError("Invalid key") + + if len(nonce) != crypto_secretbox_NONCEBYTES: + raise ValueError("Invalid nonce") + + padded = b"\x00" * crypto_secretbox_BOXZEROBYTES + ciphertext + plaintext = lib.ffi.new("unsigned char[]", len(padded)) + + if lib.crypto_secretbox_open( + plaintext, padded, len(padded), nonce, key) != 0: + raise CryptoError("Decryption failed. Ciphertext failed verification") + + plaintext = lib.ffi.buffer(plaintext, len(padded)) + return plaintext[crypto_secretbox_ZEROBYTES:] diff --git a/src/nacl/secret.py b/src/nacl/secret.py index c21f082b..31701f44 100644 --- a/src/nacl/secret.py +++ b/src/nacl/secret.py @@ -14,9 +14,9 @@ from __future__ import absolute_import from __future__ import division +import nacl.c + from . import encoding -from .c import _lib as nacl -from .exceptions import CryptoError from .utils import EncryptedMessage, StringFixer @@ -40,8 +40,8 @@ class SecretBox(encoding.Encodable, StringFixer, object): :cvar NONCE_SIZE: The size that the nonce is required to be. """ - KEY_SIZE = nacl.lib.crypto_secretbox_KEYBYTES - NONCE_SIZE = nacl.lib.crypto_secretbox_NONCEBYTES + KEY_SIZE = nacl.c.crypto_secretbox_KEYBYTES + NONCE_SIZE = nacl.c.crypto_secretbox_NONCEBYTES def __init__(self, key, encoder=encoding.RawEncoder): key = encoder.decode(key) @@ -73,18 +73,9 @@ class SecretBox(encoding.Encodable, StringFixer, object): """ if len(nonce) != self.NONCE_SIZE: raise ValueError("The nonce must be exactly %s bytes long" % - nacl.lib.crypto_secretbox_NONCEBYTES) - - padded = b"\x00" * nacl.lib.crypto_secretbox_ZEROBYTES + plaintext - ciphertext = nacl.ffi.new("unsigned char[]", len(padded)) - - if not nacl.lib.crypto_secretbox( - ciphertext, padded, len(padded), nonce, self._key, - ): - raise CryptoError("Encryption failed") + self.NONCE_SIZE) - box_zeros = nacl.lib.crypto_secretbox_BOXZEROBYTES - ciphertext = nacl.ffi.buffer(ciphertext, len(padded))[box_zeros:] + ciphertext = nacl.c.crypto_secretbox(self._key, plaintext, nonce) encoded_nonce = encoder.encode(nonce) encoded_ciphertext = encoder.encode(ciphertext) @@ -116,18 +107,8 @@ class SecretBox(encoding.Encodable, StringFixer, object): if len(nonce) != self.NONCE_SIZE: raise ValueError("The nonce must be exactly %s bytes long" % - nacl.lib.crypto_secretbox_NONCEBYTES) - - padded = b"\x00" * nacl.lib.crypto_secretbox_BOXZEROBYTES + ciphertext - plaintext = nacl.ffi.new("unsigned char[]", len(padded)) - - if not nacl.lib.crypto_secretbox_open( - plaintext, padded, len(padded), nonce, self._key, - ): - raise CryptoError( - "Decryption failed. Ciphertext failed verification") + self.NONCE_SIZE) - box_zeros = nacl.lib.crypto_secretbox_ZEROBYTES - plaintext = nacl.ffi.buffer(plaintext, len(padded))[box_zeros:] + plaintext = nacl.c.crypto_secretbox_open(self._key, ciphertext, nonce) return plaintext -- GitLab