diff --git a/setup.py b/setup.py index db13f1b..0dd138f 100755 --- a/setup.py +++ b/setup.py @@ -26,9 +26,5 @@ setup( packages=find_packages(), setup_requires=["cffi>=1.5.2"], install_requires=["cffi>=1.5.2"], - cffi_modules=[ - "./wolfcrypt/build_hashes.py:ffi", - "./wolfcrypt/build_ciphers.py:ffi", - "./wolfcrypt/build_random.py:ffi" - ], + cffi_modules=["./wolfcrypt/build_ffi.py:ffi"] ) diff --git a/test/test_ciphers.py b/test/test_ciphers.py index 8dbb868..c034037 100644 --- a/test/test_ciphers.py +++ b/test/test_ciphers.py @@ -136,3 +136,33 @@ class TestAes(unittest.TestCase): result += self.aes.decrypt(segment) assert result == self.plain + + +class TestRsaPrivate(unittest.TestCase): + key = "3082025C02010002818100BC730EA849F374A2A9EF18A5DA559921F9C8ECB36D" \ + + "48E53535757737ECD161905F3ED9E4D5DF94CAC1A9D719DA86C9E84DC4613682" \ + + "FEABAD7E7725BB8D11A5BC623AA838CC39A20466B4F7F7F3AADA4D020EBB5E8D" \ + + "6948DC77C9280E22E96BA426BA4CE8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B" \ + + "3C67C8DC2700F6916865A902030100010281801397EAE8387825A25C04CE0D40" \ + + "7C31E5C470CD9B823B5809863B665FDC3190F14FD5DB15DDDED73B9593311831" \ + + "0E5EA3D6A21A716E81481C4BCFDB8E7A866132DCFB55C1166D279224458BF1B8" \ + + "48B14B1DACDEDADD8E2FC291FBA5A96EF83A6AF1FD5018EF9FE7C3CA78EA56D3" \ + + "D3725B96DD4E064E3AC3D9BE72B66507074C01024100FA47D47A7C923C55EF81" \ + + "F041302DA3CF8F1CE6872705700DDF9835D6F18B382F24B5D084B6794F712994" \ + + "5AF0646AACE772C6ED4D59983E673AF3742CF9611769024100C0C1820D0CEBC6" \ + + "2FDC92F99D821A31E9E9F74BF282871CEE166AD11D188270F3C0B62FF6F3F71D" \ + + "F18623C84EEB8F568E8FF5BFF1F72BB5CC3DC657390C1B54410241009D7E05DE" \ + + "EDF4B7B2FBFC304B551DE32F0147966905CD0E2E2CBD8363B6AB7CB76DCA5B64" \ + + "A7CEBE86DF3B53DE61D21EEBA5F637EDACAB78D94CE755FBD71199C102401898" \ + + "1829E61E2739702168AC0A2FA172C121869538C65890A0579CBAE3A7B115C8DE" \ + + "F61BC2612376EFB09D1C44BE1343396717C89DCAFBF545648B38822CF2810240" \ + + "3989E59C195530BAB7488C48140EF49F7E779743E1B419353123759C3B44AD69" \ + + "1256EE0061641666D37C742B15B4A2FEBF086B1A5D3F9012B105863129DBD9E2" + + def setUp(self): + self.rsa = RsaPrivate(self.key.decode("hex")) + + + def test_raises(self): + # invalid construction + self.assertRaises(KeyError, RsaPrivate, 'key') diff --git a/wolfcrypt/build_ciphers.py b/wolfcrypt/build_ciphers.py deleted file mode 100644 index a4fc21e..0000000 --- a/wolfcrypt/build_ciphers.py +++ /dev/null @@ -1,59 +0,0 @@ -# buidl_ciphers.py -# -# Copyright (C) 2006-2016 wolfSSL Inc. -# -# This file is part of wolfSSL. (formerly known as CyaSSL) -# -# wolfSSL is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# wolfSSL is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -import os - -from cffi import FFI - -ffi = FFI() - -ffi.set_source("wolfcrypt._ciphers", - """ - #include - #include - #include - """, - include_dirs=["/usr/local/include"], - library_dirs=["/usr/local/lib"], - libraries=["wolfssl"], -) - -ffi.cdef( -""" - - typedef unsigned char byte; - typedef unsigned int word32; - - typedef struct { ...; } Aes; - - int wc_AesSetKey(Aes*, const byte*, word32, const byte*, int); - int wc_AesCbcEncrypt(Aes*, byte*, const byte*, word32); - int wc_AesCbcDecrypt(Aes*, byte*, const byte*, word32); - - typedef struct { ...; } Des3; - - int wc_Des3_SetKey(Des3*, const byte*, const byte*, int); - int wc_Des3_CbcEncrypt(Des3*, byte*, const byte*, word32); - int wc_Des3_CbcDecrypt(Des3*, byte*, const byte*, word32); - -""" -) - -if __name__ == "__main__": - ffi.compile(verbose=1) diff --git a/wolfcrypt/build_hashes.py b/wolfcrypt/build_ffi.py similarity index 57% rename from wolfcrypt/build_hashes.py rename to wolfcrypt/build_ffi.py index 041da3d..7d87675 100644 --- a/wolfcrypt/build_hashes.py +++ b/wolfcrypt/build_ffi.py @@ -1,4 +1,4 @@ -# build_hashes.py +# build_random.py # # Copyright (C) 2006-2016 wolfSSL Inc. # @@ -23,13 +23,23 @@ from cffi import FFI ffi = FFI() -ffi.set_source("wolfcrypt._hashes", +ffi.set_source("wolfcrypt._ffi", """ #include + #include #include #include + #include + + #include + #include + #include + + #include + + #include """, include_dirs=["/usr/local/include"], library_dirs=["/usr/local/lib"], @@ -69,12 +79,53 @@ ffi.cdef( int wc_Sha512Update(Sha512*, const byte*, word32); int wc_Sha512Final(Sha512*, byte*); + typedef struct { ...; } Hmac; int wc_HmacSetKey(Hmac*, int, const byte*, word32); int wc_HmacUpdate(Hmac*, const byte*, word32); int wc_HmacFinal(Hmac*, byte*); + + typedef struct { ...; } Aes; + + int wc_AesSetKey(Aes*, const byte*, word32, const byte*, int); + int wc_AesCbcEncrypt(Aes*, byte*, const byte*, word32); + int wc_AesCbcDecrypt(Aes*, byte*, const byte*, word32); + + + typedef struct { ...; } Des3; + + int wc_Des3_SetKey(Des3*, const byte*, const byte*, int); + int wc_Des3_CbcEncrypt(Des3*, byte*, const byte*, word32); + int wc_Des3_CbcDecrypt(Des3*, byte*, const byte*, word32); + + + typedef struct { ...; } WC_RNG; + + int wc_InitRng(WC_RNG*); + int wc_RNG_GenerateBlock(WC_RNG*, byte*, word32); + int wc_RNG_GenerateByte(WC_RNG*, byte*); + int wc_FreeRng(WC_RNG*); + + + typedef struct {...; } RsaKey; + + int wc_InitRsaKey(RsaKey* key, void*); + int wc_FreeRsaKey(RsaKey* key); + + int wc_RsaPrivateKeyDecode(const byte*, word32*, RsaKey*, word32); + int wc_RsaPublicKeyDecode(const byte*, word32*, RsaKey*, word32); + int wc_RsaEncryptSize(RsaKey*); + + int wc_RsaPrivateDecrypt(const byte*, word32, byte*, word32, + RsaKey* key); + int wc_RsaPublicEncrypt(const byte*, word32, byte*, word32, + RsaKey*, WC_RNG*); + + int wc_RsaSSL_Sign(const byte*, word32, byte*, word32, RsaKey*, WC_RNG*); + int wc_RsaSSL_Verify(const byte*, word32, byte*, word32, RsaKey*); + """ ) diff --git a/wolfcrypt/build_random.py b/wolfcrypt/build_random.py deleted file mode 100644 index f6c3988..0000000 --- a/wolfcrypt/build_random.py +++ /dev/null @@ -1,53 +0,0 @@ -# build_random.py -# -# Copyright (C) 2006-2016 wolfSSL Inc. -# -# This file is part of wolfSSL. (formerly known as CyaSSL) -# -# wolfSSL is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# wolfSSL is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -import os - -from cffi import FFI - -ffi = FFI() - -ffi.set_source("wolfcrypt._random", - """ - #include - #include - """, - include_dirs=["/usr/local/include"], - library_dirs=["/usr/local/lib"], - libraries=["wolfssl"], -) - -ffi.cdef( -""" - - typedef unsigned char byte; - typedef unsigned int word32; - - typedef struct { ...; } WC_RNG; - - int wc_InitRng(WC_RNG*); - int wc_RNG_GenerateBlock(WC_RNG*, byte*, word32); - int wc_RNG_GenerateByte(WC_RNG*, byte*); - int wc_FreeRng(WC_RNG*); - -""" -) - -if __name__ == "__main__": - ffi.compile(verbose=1) diff --git a/wolfcrypt/ciphers.py b/wolfcrypt/ciphers.py index a062ee9..21f4ebd 100644 --- a/wolfcrypt/ciphers.py +++ b/wolfcrypt/ciphers.py @@ -17,8 +17,9 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -from wolfcrypt._ciphers import ffi as _ffi -from wolfcrypt._ciphers import lib as _lib +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib +from wolfcrypt.random import Random # key direction flags @@ -152,3 +153,75 @@ class Des3(_Cipher): def _decrypt(self, destination, source): _lib.wc_Des3_CbcDecrypt(self._dec, destination, source, len(source)) + + +class _Rsa(object): + def __init__(self): + self.native_object = _ffi.new("RsaKey *") + if _lib.wc_InitRsaKey(self.native_object, _ffi.NULL) != 0: + raise KeyError + + self._random = Random() + + + def __del__(self): + if self.native_object: + _lib.wc_FreeRsaKey(self.native_object) + + +class RsaPrivate(_Rsa): + def __init__(self, key): + _Rsa.__init__(self) + + idx = _ffi.new("word32*") + idx[0] = 0 + + if _lib.wc_RsaPrivateKeyDecode(key, idx, self.native_object, len(key)): + raise KeyError + + self.output_size = _lib.wc_RsaEncryptSize(self.native_object) + + + def decrypt(self, data): + ret = "\0" * self.output_size + + _lib.wc_RsaPrivateDecrypt(data, len(data), ret, len(ret), + self.native_object) + + return ret + + + def sign(self, data): + ret = "\0" * self.output_size + + _lib.wc_RsaSSL_Sign(data, len(data), ret, len(ret), + self.native_object, self._random.native_object) + + return ret + + +class RsaPublic(_Rsa): + def __init__(self, key): + _Rsa.__init__(self) + + idx = _ffi.new("word32*") + idx[0] = 0 + + if _lib.wc_RsaPublicKeyDecode(key, idx, self.native_object, len(key)): + raise KeyError + + self.output_size = _lib.wc_RsaEncryptSize(self.native_object) + + + def encrypt(self, data): + ret = "\0" * self.output_size + + _lib.wc_RsaPublicEncrypt(data, len(data), ret, len(ret), + self.native_object, self._random.native_object) + + return ret + + + def verify(self, data, signature): + return _lib.wc_RsaSSL_Verify(data, len(data), ret, len(ret), + self.native_object) diff --git a/wolfcrypt/hashes.py b/wolfcrypt/hashes.py index 4b2ae0a..18c0b54 100644 --- a/wolfcrypt/hashes.py +++ b/wolfcrypt/hashes.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -from wolfcrypt._hashes import ffi as _ffi -from wolfcrypt._hashes import lib as _lib +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib class _Hash(object): diff --git a/wolfcrypt/random.py b/wolfcrypt/random.py index 2cac804..047b758 100644 --- a/wolfcrypt/random.py +++ b/wolfcrypt/random.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -from wolfcrypt._random import ffi as _ffi -from wolfcrypt._random import lib as _lib +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib class Random(object):