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);