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