pynacl

Python wrapper for http://nacl.cace-project.eu/
git clone https://code.literati.org/pynacl.git
Log | Files | Refs | README

commit acc356f697111265b984d5b9d282aaf0f558a251
Author: Sean Lynch <seanl@literati.org>
Date:   Sat, 11 Jun 2011 23:04:54 -0700

Initial commit.

crypto_sign* and crypto_hash* are all implemented with tests.

Diffstat:
Anacl.i | 207+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asetup.py | 25+++++++++++++++++++++++++
Atest.py | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 299 insertions(+), 0 deletions(-)

diff --git a/nacl.i b/nacl.i @@ -0,0 +1,207 @@ +%module nacl + +%{ + #include "crypto_box.h" + #include "crypto_scalarmult_curve25519.h" + #include "crypto_sign.h" + #include "crypto_secretbox.h" + #include "crypto_stream.h" + #include "crypto_auth.h" + #include "crypto_onetimeauth.h" + #include "crypto_hash.h" + #include "crypto_hash_sha256.h" + + #include "crypto_uint32.h" + #include "randombytes.h" + + typedef struct { + crypto_uint32 v[32]; + } fe25519; + + typedef struct { + crypto_uint32 v[32]; + } sc25519; + + typedef struct { + fe25519 x; + fe25519 y; + fe25519 z; + fe25519 t; + } ge25519; + + #define sc25519_from32bytes crypto_sign_edwards25519sha512batch_sc25519_from32bytes + #define ge25519_pack crypto_sign_edwards25519sha512batch_ge25519_pack + #define ge25519_scalarmult_base crypto_sign_edwards25519sha512batch_ge25519_scalarmult_base + + void ge25519_pack(unsigned char r[32], const ge25519 *p); + void ge25519_scalarmult_base(ge25519 *r, const sc25519 *s); + void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]); + + void crypto_sign_keypair_fromseed(unsigned char *pk, + unsigned char *sk, + unsigned char *seed, + int seedlen) { + sc25519 scsk; + ge25519 gepk; + + crypto_hash_sha512(sk, seed, seedlen); + + sk[0] &= 248; + sk[31] &= 127; + sk[31] |= 64; + + sc25519_from32bytes(&scsk, sk); + + ge25519_scalarmult_base(&gepk, &scsk); + ge25519_pack(pk, &gepk); + } + +%} + +%include <typemaps.i> + +%typemap(in) (const unsigned char *m, unsigned long long mlen) { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } + $1 = (unsigned char *)PyString_AsString($input); + $2 = PyString_Size($input); +} + +%typemap(in, numinputs=0) unsigned char *sha256hash (unsigned char temp[32]) { + $1 = temp; +} + +%typemap(argout) unsigned char *sha256hash { + $result = PyString_FromStringAndSize((char *)$1, 32); +} + +int crypto_hash_sha256(unsigned char *sha256hash, const unsigned char *m, + unsigned long long mlen); + +%typemap(in, numinputs=0) unsigned char *sha512hash (unsigned char temp[64]) { + $1 = temp; +} + +%typemap(argout) unsigned char *sha512hash { + $result = PyString_FromStringAndSize((char *)$1, 64); +} + +int crypto_hash_sha512(unsigned char *sha512hash, const unsigned char *m, + unsigned long long mlen); + + +%constant int crypto_sign_PUBLICKEYBYTES; +%constant int crypto_sign_SECRETKEYBYTES; + +%typemap(in, numinputs=0) (unsigned char *pk, unsigned char *sk) + (unsigned char temp1[crypto_sign_PUBLICKEYBYTES], + unsigned char temp2[crypto_sign_SECRETKEYBYTES]) { + $1 = temp1; + $2 = temp2; +} + +%typemap(argout) (unsigned char *pk, unsigned char *sk) { + $result = PyList_New(2); + PyList_SetItem($result, 0, + PyString_FromStringAndSize((char *)$1, + crypto_sign_PUBLICKEYBYTES)); + PyList_SetItem($result, 1, + PyString_FromStringAndSize((char *)$2, + crypto_sign_SECRETKEYBYTES)); +} + +%typemap(in) (unsigned char *seed, int seedlen) { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } + $1 = (unsigned char *)PyString_AsString($input); + $2 = PyString_Size($input); +} + +void crypto_sign_keypair_fromseed(unsigned char *pk, unsigned char *sk, + unsigned char *seed, int seedlen); +int crypto_sign_keypair(unsigned char *pk, unsigned char *sk); + +%typemap(in) unsigned char *pk { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } + if (PyString_Size($input) != crypto_sign_PUBLICKEYBYTES) { + PyErr_Format(PyExc_ValueError, "Expecting a string of length %d", + crypto_sign_PUBLICKEYBYTES); + return NULL; + } + $1 = (unsigned char *)PyString_AsString($input); +} + +%typemap(in) unsigned char *sk { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } + if (PyString_Size($input) != crypto_sign_SECRETKEYBYTES) { + PyErr_Format(PyExc_ValueError, "Expecting a string of length %d", + crypto_sign_SECRETKEYBYTES); + return NULL; + } + $1 = (unsigned char *)PyString_AsString($input); +} + +%typemap(in) + (unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen) + (unsigned long long temp) { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } + $4 = PyString_Size($input); + $result = PyString_FromStringAndSize(NULL, $4 + crypto_sign_BYTES); + $1 = (unsigned char *)PyString_AsString($result); + $2 = &temp; + $3 = (unsigned char *)PyString_AsString($input); +} + +%typemap(in) + (unsigned char *m, unsigned long long *mlen, + const unsigned char *sm, unsigned long long smlen) + (unsigned long long temp) { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } + $4 = PyString_Size($input); + $result = PyString_FromStringAndSize(NULL, $4); + $1 = (unsigned char *)PyString_AsString($result); + $2 = &temp; + $3 = (unsigned char *)PyString_AsString($input); +} + +%typemap(argout) (unsigned char *sm, unsigned long long *smlen), + (unsigned char *m, unsigned long long *mlen) { + _PyString_Resize(&$result, *$2); +} + +%typemap(freearg) unsigned char *sm, unsigned char *m { + free($1); +} + +%typemap(out) int { + if ($1 != 0) { + PyErr_Format(PyExc_ValueError, "Operation failed with error %d", $1); + return NULL; + } +} + +int crypto_sign(unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen, + unsigned char *sk); +int crypto_sign_open(unsigned char *m, unsigned long long *mlen, + const unsigned char *sm, unsigned long long smlen, + unsigned char *pk); + + diff --git a/setup.py b/setup.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +""" +Documentation! +""" + +NACL_INCLUDE = '/Users/seanl/src/nacl-20110221/build/seanlMBP13/include/amd64' +NACL_LIB = '/Users/seanl/src/nacl-20110221/build/seanlMBP13/lib/amd64' + +from distutils.core import setup, Extension + + +nacl_module = Extension('_nacl', ['nacl.i'], + include_dirs=[NACL_INCLUDE], + library_dirs=[NACL_LIB], + libraries=['nacl'], + extra_objects=['{0}/randombytes.o'.format(NACL_LIB)], + swig_opts=['-I{0}'.format(NACL_INCLUDE)]) + +setup (name = 'nacl', + version = '0.1', + author = "Sean Lynch", + description = """Python wrapper for NaCl""", + ext_modules = [nacl_module], + py_modules = ["nacl", "test"]) diff --git a/test.py b/test.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +import binascii +import unittest + +import nacl + + + +class HashTestCase(unittest.TestCase): + fox = "The quick brown fox jumps over the lazy dog." + def check_hash(self, func, s, h): + f = getattr(nacl, func) + r = f(s) + self.assertEqual(binascii.b2a_hex(r), h) + + def test_sha256_empty(self): + self.check_hash("crypto_hash_sha256", "", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca4959" + "91b7852b855") + + def test_sha256_fox(self): + self.check_hash("crypto_hash_sha256", self.fox, + "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b7654" + "48c8635fb6c") + + def test_sha512_empty(self): + self.check_hash("crypto_hash_sha512", "", + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a" + "921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47" + "417a81a538327af927da3e") + + def test_sha512_fox(self): + self.check_hash("crypto_hash_sha512", self.fox, + "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d128" + "90cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3" + "c463d481c7e586c39ac1ed") + + +class SignTestCase(unittest.TestCase): + msg = "hello world" + + def setUp(self): + self.pk, self.sk = nacl.crypto_sign_keypair() + self.pk1, self.sk1 = nacl.crypto_sign_keypair() + self.assertNotEqual(self.pk, self.pk1) + self.assertNotEqual(self.sk, self.sk1) + self.assertNotEqual(self.pk, self.sk) + self.assertNotEqual(self.pk1, self.sk1) + + def test_pk_length(self): + self.assertEqual(len(self.pk), nacl.crypto_sign_PUBLICKEYBYTES) + + def test_sk_length(self): + self.assertEqual(len(self.sk), nacl.crypto_sign_SECRETKEYBYTES) + + def test_signature(self): + sm = nacl.crypto_sign(self.msg, self.sk) + r = nacl.crypto_sign_open(sm, self.pk) + self.assertEqual(r, self.msg) + + def test_failed_signature(self): + sm = nacl.crypto_sign(self.msg, self.sk) + self.assertRaises(ValueError, nacl.crypto_sign_open, sm, self.pk1) + + +if __name__ == '__main__': + unittest.main()