diff --git a/src/nacl/c/__init__.py b/src/nacl/c/__init__.py
index e19b2509ee6bdcfe1b93054892a9404217d3ccf9..09b02c6189107402d5c19123b7fbddcb0e7d48ee 100644
--- a/src/nacl/c/__init__.py
+++ b/src/nacl/c/__init__.py
@@ -12,3 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 from __future__ import absolute_import, division, print_function
+
+from nacl.c.crypto_box import crypto_box_keypair
+
+
+__all__ = [
+    "crypto_box_keypair",
+]
diff --git a/src/nacl/c/crypto_box.py b/src/nacl/c/crypto_box.py
new file mode 100644
index 0000000000000000000000000000000000000000..3a47a0dc40cb51ff6af689237796e95532becfec
--- /dev/null
+++ b/src/nacl/c/crypto_box.py
@@ -0,0 +1,109 @@
+# 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.c import lib
+from nacl.exceptions import CryptoError
+
+
+__all__ = ["crypto_box_keypair", "crypto_box"]
+
+
+def crypto_box_keypair():
+    """
+    Returns a randomly generated secret and public key.
+
+    :rtype: (bytes(secret_key), bytes(public_key))
+    """
+    sk_size = lib.crypto_box_secretkeybytes()
+    pk_size = lib.crypto_box_publickeybytes()
+
+    sk = lib.ffi.new("unsigned char[]", sk_size)
+    pk = lib.ffi.new("unsigned char[]", pk_size)
+
+    if lib.crypto_box_keypair(pk, sk) != 0:
+        raise CryptoError("An error occurred trying to generate the keypair")
+
+    return (lib.ffi.buffer(sk, sk_size)[:], lib.ffi.buffer(pk, pk_size)[:])
+
+
+def crypto_box(sk, pk, message, nonce):
+    """
+    Encrypts and returns a message ``message`` using the secret key ``sk``,
+    public key ``pk``, and the nonce ``nonce``.
+
+    :param sk: bytes
+    :param pk: bytes
+    :param message: bytes
+    :param nonce: bytes
+    :rtype: bytes
+    """
+    sk_size = lib.crypto_box_secretkeybytes()
+    pk_size = lib.crypto_box_publickeybytes()
+    n_size = lib.crypto_box_noncebytes()
+    zero_bytes = lib.crypto_box_zerobytes()
+    box_zeros = lib.crypto_box_boxzerobytes()
+
+    if len(sk) != sk_size:
+        raise ValueError("Invalid secret key")
+
+    if len(pk) != pk_size:
+        raise ValueError("Invalid public key")
+
+    if len(nonce) != n_size:
+        raise ValueError("Invalid nonce size")
+
+    padded = (b"\x00" * zero_bytes) + message
+    ciphertext = lib.ffi.new("unsigned char[]", len(padded))
+
+    if lib.crypto_box(ciphertext, message, len(message), nonce, pk, sk) != 0:
+        raise CryptoError("An error occurred trying to encrypt the message")
+
+    return lib.ffi.buffer(ciphertext, len(padded))[box_zeros:]
+
+
+def crypto_box_open(sk, pk, ciphertext, nonce):
+    """
+    Decrypts and returns an encrypted message ``ciphertext``, using the secret
+    key ``sk``, public key ``pk``, and the nonce ``nonce``.
+
+    :param sk: bytes
+    :param pk: bytes
+    :param ciphertext: bytes
+    :param nonce: bytes
+    :rtype: bytes
+    """
+    sk_size = lib.crypto_box_secretkeybytes()
+    pk_size = lib.crypto_box_publickeybytes()
+    n_size = lib.crypto_box_noncebytes()
+    box_zeros = lib.crypto_box_boxzerobytes()
+    zero_bytes = lib.crypto_box_zerobytes()
+
+    if len(sk) != sk_size:
+        raise ValueError("Invalid secret key")
+
+    if len(pk) != pk_size:
+        raise ValueError("Invalid public key")
+
+    if len(nonce) != n_size:
+        raise ValueError("Invalid nonce size")
+
+    padded = (b"\x00" * box_zeros) + ciphertext
+    plaintext = lib.ffi.new("unsigned char[]", len(padded))
+
+    if lib.crypto_box_open(
+            plaintext, ciphertext, len(ciphertext), nonce, pk, sk):
+        raise CryptoError("An error occurred trying to decrypt the message")
+
+    return lib.ffi.buffer(plaintext, len(padded))[zero_bytes:]
diff --git a/src/nacl/c/lib/__init__.py b/src/nacl/c/lib/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c5454c4a1ca98b87767f2180555e351f9f44fb38
--- /dev/null
+++ b/src/nacl/c/lib/__init__.py
@@ -0,0 +1,62 @@
+# 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
+
+import glob
+import os.path
+
+import six
+
+from cffi import FFI
+
+
+__all__ = ["ffi"]
+
+
+HEADERS = glob.glob(
+    os.path.join(os.path.abspath(os.path.dirname(__file__)), "*.h")
+)
+
+
+# Build our FFI instance
+ffi = FFI()
+
+
+# Add all of our header files
+for header in HEADERS:
+    with open(header, "r") as hfile:
+        ffi.cdef(hfile.read())
+
+
+# Compile our module
+# TODO: Can we use the ABI of libsodium for this instead?
+lib = ffi.verify(
+    "#include <sodium.h>",
+
+    # We need to link to the sodium library
+    libraries=["sodium"],
+
+    # Our ext_package is nacl so look for it
+    ext_package="nacl.c.lib",
+)
+
+
+# Put all of the exposed functions onto the module
+g = globals()
+for name, function in six.iteritems(lib.__dict__):
+    # Add this function to the __all__ namespace
+    __all__.append(name)
+
+    # Add this function to the globals
+    g[name] = function
diff --git a/src/nacl/c/lib/crypto_box.h b/src/nacl/c/lib/crypto_box.h
new file mode 100644
index 0000000000000000000000000000000000000000..271bb7dbac123b32a1813c67f09bac741c898b71
--- /dev/null
+++ b/src/nacl/c/lib/crypto_box.h
@@ -0,0 +1,32 @@
+/* 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_box_secretkeybytes();
+size_t crypto_box_publickeybytes();
+
+size_t crypto_box_zerobytes();
+size_t crypto_box_boxzerobytes();
+size_t crypto_box_noncebytes();
+
+
+int crypto_box_keypair(unsigned char *pk, unsigned char *sk);
+
+int crypto_box(unsigned char *c,        const unsigned char *m,
+               unsigned long long mlen, const unsigned char *n,
+         const unsigned char *pk,       const unsigned char *sk);
+
+int crypto_box_open(unsigned char *m,        const unsigned char *c,
+                    unsigned long long clen, const unsigned char *n,
+              const unsigned char *pk,       const unsigned char *sk);