From 7e661ab86616a23b901a3fe14d29211c855bb545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Thu, 28 Apr 2016 13:20:10 -0300 Subject: [PATCH 01/24] importing wolfcrypt-py repo --- wrapper/python/README.rst | 38 +++ wrapper/python/requirements-testing.txt | 3 + wrapper/python/setup.py | 30 ++ wrapper/python/test/test_ciphers.py | 251 +++++++++++++++ wrapper/python/test/test_hashes.py | 388 ++++++++++++++++++++++++ wrapper/python/test/test_random.py | 38 +++ wrapper/python/tox.ini | 6 + wrapper/python/wolfcrypt/__init__.py | 21 ++ wrapper/python/wolfcrypt/build_ffi.py | 133 ++++++++ wrapper/python/wolfcrypt/ciphers.py | 252 +++++++++++++++ wrapper/python/wolfcrypt/hashes.py | 210 +++++++++++++ wrapper/python/wolfcrypt/random.py | 49 +++ 12 files changed, 1419 insertions(+) create mode 100644 wrapper/python/README.rst create mode 100644 wrapper/python/requirements-testing.txt create mode 100755 wrapper/python/setup.py create mode 100644 wrapper/python/test/test_ciphers.py create mode 100644 wrapper/python/test/test_hashes.py create mode 100644 wrapper/python/test/test_random.py create mode 100644 wrapper/python/tox.ini create mode 100644 wrapper/python/wolfcrypt/__init__.py create mode 100644 wrapper/python/wolfcrypt/build_ffi.py create mode 100644 wrapper/python/wolfcrypt/ciphers.py create mode 100644 wrapper/python/wolfcrypt/hashes.py create mode 100644 wrapper/python/wolfcrypt/random.py diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst new file mode 100644 index 000000000..e2ebe1fad --- /dev/null +++ b/wrapper/python/README.rst @@ -0,0 +1,38 @@ +wolfcrypt: the wolfSSL Crypto Engine +==================================== + + +A Python wrapper which encapsulates the wolfCrypt API inside wolfSSL library + + +**REQUIRES** [wolfSSL](https://github.com/wolfSSL/wolfssl) + + +1. Clone the repository:: + + + $ git clone git@github.com:wolfssl/wolfcrypt-py.git + + +2. Make sure that ``cffi``, ``py.test``, and ``tox`` are installed:: + + + $ pip install -r requirements-testing.txt + + +3. Run ``python setup.py install`` to build and install wolfcrypt-py:: + + + $ python setup.py install + ... + Finished processing dependencies for wolfcrypt==0.1 + + +4. Test locally with ``tox``:: + + + $ tox + ... + _________________________________ summary _________________________________ + py27: commands succeeded + congratulations :) \ No newline at end of file diff --git a/wrapper/python/requirements-testing.txt b/wrapper/python/requirements-testing.txt new file mode 100644 index 000000000..e8f289c1f --- /dev/null +++ b/wrapper/python/requirements-testing.txt @@ -0,0 +1,3 @@ +pytest>=2.9.1 +cffi>=1.5.2 +tox>=2.3.1 diff --git a/wrapper/python/setup.py b/wrapper/python/setup.py new file mode 100755 index 000000000..0dd138fff --- /dev/null +++ b/wrapper/python/setup.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import sys + +from setuptools import setup, find_packages + +os.chdir(os.path.dirname(sys.argv[0]) or ".") + +setup( + name="wolfcrypt", + version="0.1", + description="A python wrapper for the wolfCrypt API", + long_description=open("README.rst", "rt").read(), + url="https://github.com/wolfssl/wolfcrypt-py", + author="Moisés Guimarães", + author_email="moises@wolfssl.com", + classifiers=[ + "Development Status :: 0 - Alpha", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: Implementation :: PyPy", + "License :: GPLv2 License :: Commercial License", + ], + packages=find_packages(), + setup_requires=["cffi>=1.5.2"], + install_requires=["cffi>=1.5.2"], + cffi_modules=["./wolfcrypt/build_ffi.py:ffi"] +) diff --git a/wrapper/python/test/test_ciphers.py b/wrapper/python/test/test_ciphers.py new file mode 100644 index 000000000..57dd2c6f2 --- /dev/null +++ b/wrapper/python/test/test_ciphers.py @@ -0,0 +1,251 @@ +# test_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 unittest +from wolfcrypt.ciphers import * + +class TestDes3(unittest.TestCase): + key = "0123456789abcdeffedeba987654321089abcdef01234567".decode("hex") + IV = "1234567890abcdef".decode("hex") + plain = "Now is the time for all " + cipher = "43a0297ed184f80e8964843212d508981894157487127db0".decode("hex") + + + def setUp(self): + self.des3 = Des3.new(self.key, MODE_CBC, self.IV) + + + def test_raises(self): + # invalid construction + self.assertRaises(ValueError, Des3) + + # invalid key length + self.assertRaises(ValueError, Des3.new, "key", MODE_CBC, self.IV) + + # invalid mode + self.assertRaises(ValueError, Des3.new, self.key, MODE_ECB, self.IV) + + # invalid iv length + self.assertRaises(ValueError, Des3.new, self.key, MODE_CBC, "IV") + + # invalid data length + self.assertRaises(ValueError, self.des3.encrypt, "foo") + self.assertRaises(ValueError, self.des3.decrypt, "bar") + + + def test_single_encryption(self): + assert self.des3.encrypt(self.plain) == self.cipher + + + def test_multi_encryption(self): + result = "" + segments = tuple(self.plain[i:i + Des3.block_size] \ + for i in range(0, len(self.plain), Des3.block_size)) + + for segment in segments: + result += self.des3.encrypt(segment) + + assert result == self.cipher + + + def test_single_decryption(self): + assert self.des3.decrypt(self.cipher) == self.plain + + + def test_multi_decryption(self): + result = "" + segments = tuple(self.cipher[i:i + Des3.block_size] \ + for i in range(0, len(self.cipher), Des3.block_size)) + + for segment in segments: + result += self.des3.decrypt(segment) + + assert result == self.plain + + +class TestAes(unittest.TestCase): + key = "0123456789abcdef" + IV = "1234567890abcdef" + plain = "now is the time " + cipher = "959492575f4281532ccc9d4677a233cb".decode("hex") + + + def setUp(self): + self.aes = Aes.new(self.key, MODE_CBC, self.IV) + + + def test_raises(self): + # invalid construction + self.assertRaises(ValueError, Aes) + + # invalid key length + self.assertRaises(ValueError, Aes.new, "key", MODE_CBC, self.IV) + + # invalid mode + self.assertRaises(ValueError, Aes.new, self.key, MODE_ECB, self.IV) + + # invalid iv length + self.assertRaises(ValueError, Aes.new, self.key, MODE_CBC, "IV") + + # invalid data length + self.assertRaises(ValueError, self.aes.encrypt, "foo") + self.assertRaises(ValueError, self.aes.decrypt, "bar") + + + def test_single_encryption(self): + assert self.aes.encrypt(self.plain) == self.cipher + + + def test_multi_encryption(self): + result = "" + segments = tuple(self.plain[i:i + self.aes.block_size] \ + for i in range(0, len(self.plain), self.aes.block_size)) + + for segment in segments: + result += self.aes.encrypt(segment) + + assert result == self.cipher + + + def test_single_decryption(self): + assert self.aes.decrypt(self.cipher) == self.plain + + + def test_multi_decryption(self): + result = "" + segments = tuple(self.cipher[i:i + self.aes.block_size] \ + for i in range(0, len(self.cipher), self.aes.block_size)) + + for segment in segments: + 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" + + plain = "Everyone gets Friday off." + + + def setUp(self): + self.rsa = RsaPrivate(self.key.decode("hex")) + + + def test_raises(self): + # invalid key + self.assertRaises(KeyError, RsaPrivate, 'key') + + + def test_output_size(self): + assert self.rsa.output_size == 1024 / 8 + + + def test_encrypt_decrypt(self): + cipher = self.rsa.encrypt(self.plain) + result = self.rsa.decrypt(cipher) + + assert len(cipher) == self.rsa.output_size == 1024 / 8 + assert self.plain == result + + + def test_sign_verify(self): + signature = self.rsa.sign(self.plain) + result = self.rsa.verify(signature) + + assert len(signature) == self.rsa.output_size == 1024 / 8 + assert self.plain == result + + +class TestRsaPublic(unittest.TestCase): + prv = "3082025C02010002818100BC730EA849F374A2A9EF18A5DA559921F9C8ECB36D" \ + + "48E53535757737ECD161905F3ED9E4D5DF94CAC1A9D719DA86C9E84DC4613682" \ + + "FEABAD7E7725BB8D11A5BC623AA838CC39A20466B4F7F7F3AADA4D020EBB5E8D" \ + + "6948DC77C9280E22E96BA426BA4CE8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B" \ + + "3C67C8DC2700F6916865A902030100010281801397EAE8387825A25C04CE0D40" \ + + "7C31E5C470CD9B823B5809863B665FDC3190F14FD5DB15DDDED73B9593311831" \ + + "0E5EA3D6A21A716E81481C4BCFDB8E7A866132DCFB55C1166D279224458BF1B8" \ + + "48B14B1DACDEDADD8E2FC291FBA5A96EF83A6AF1FD5018EF9FE7C3CA78EA56D3" \ + + "D3725B96DD4E064E3AC3D9BE72B66507074C01024100FA47D47A7C923C55EF81" \ + + "F041302DA3CF8F1CE6872705700DDF9835D6F18B382F24B5D084B6794F712994" \ + + "5AF0646AACE772C6ED4D59983E673AF3742CF9611769024100C0C1820D0CEBC6" \ + + "2FDC92F99D821A31E9E9F74BF282871CEE166AD11D188270F3C0B62FF6F3F71D" \ + + "F18623C84EEB8F568E8FF5BFF1F72BB5CC3DC657390C1B54410241009D7E05DE" \ + + "EDF4B7B2FBFC304B551DE32F0147966905CD0E2E2CBD8363B6AB7CB76DCA5B64" \ + + "A7CEBE86DF3B53DE61D21EEBA5F637EDACAB78D94CE755FBD71199C102401898" \ + + "1829E61E2739702168AC0A2FA172C121869538C65890A0579CBAE3A7B115C8DE" \ + + "F61BC2612376EFB09D1C44BE1343396717C89DCAFBF545648B38822CF2810240" \ + + "3989E59C195530BAB7488C48140EF49F7E779743E1B419353123759C3B44AD69" \ + + "1256EE0061641666D37C742B15B4A2FEBF086B1A5D3F9012B105863129DBD9E2" + + pub = "30819F300D06092A864886F70D010101050003818D0030818902818100BC730E" \ + + "A849F374A2A9EF18A5DA559921F9C8ECB36D48E53535757737ECD161905F3ED9" \ + + "E4D5DF94CAC1A9D719DA86C9E84DC4613682FEABAD7E7725BB8D11A5BC623AA8" \ + + "38CC39A20466B4F7F7F3AADA4D020EBB5E8D6948DC77C9280E22E96BA426BA4C" \ + + "E8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B3C67C8DC2700F6916865A90203010001" + + plain = "Everyone gets Friday off." + + + def setUp(self): + self.private = RsaPrivate(self.prv.decode("hex")) + self.public = RsaPublic(self.pub.decode("hex")) + + + def test_raises(self): + # invalid key + self.assertRaises(KeyError, RsaPublic, 'key') + + + def test_output_size(self): + assert self.public.output_size == 1024 / 8 + + + def test_encrypt_decrypt(self): + cipher = self.public.encrypt(self.plain) + result = self.private.decrypt(cipher) + + assert len(cipher) == self.public.output_size == 1024 / 8 + assert self.plain == result + + + def test_sign_verify(self): + signature = self.private.sign(self.plain) + result = self.public.verify(signature) + + assert len(signature) == self.public.output_size == 1024 / 8 + assert self.plain == result diff --git a/wrapper/python/test/test_hashes.py b/wrapper/python/test/test_hashes.py new file mode 100644 index 000000000..5ed245462 --- /dev/null +++ b/wrapper/python/test/test_hashes.py @@ -0,0 +1,388 @@ +# test_hashes.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 unittest +from wolfcrypt.hashes import * + + +class TestSha(unittest.TestCase): + digest = "1b6182d68ae91ce0853bd9c6b6edfedd4b6a510d" + + + def setUp(self): + self.hash = Sha.new() + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, Sha) + + # update inside constructor + assert Sha.new("wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest + + +class TestSha256(unittest.TestCase): + digest = "96e02e7b1cbcd6f104fe1fdb4652027a5505b68652b70095c6318f9dce0d1844" + + + def setUp(self): + self.hash = Sha256.new() + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, Sha256) + + # update inside constructor + assert Sha256.new("wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest + + +class TestSha384(unittest.TestCase): + digest = "4c79d80531203a16f91bee325f18c6aada47f9382fe44fc1" \ + + "1f92917837e9b7902f5dccb7d3656f667a1dce3460bc884b" + + + def setUp(self): + self.hash = Sha384.new() + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, Sha384) + + # update inside constructor + assert Sha384.new("wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest + + +class TestSha512(unittest.TestCase): + digest = "88fcf67ffd8558d713f9cedcd852db479e6573f0bd9955610a993f609637553c"\ + + "e8fff55e644ee8a106aae19c07f91b3f2a2a6d40dfa7302c0fa6a1a9a5bfa03f" + + + def setUp(self): + self.hash = Sha512.new() + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, Sha512) + + # update inside constructor + assert Sha512.new("wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest + + +_HMAC_KEY = "python" + + +class TestHmacSha(unittest.TestCase): + digest = "5dfabcfb3a25540824867cd21f065f52f73491e0" + + + def setUp(self): + self.hash = HmacSha.new(_HMAC_KEY) + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, HmacSha) + + # update inside constructor + assert HmacSha.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest + + +class TestHmacSha256(unittest.TestCase): + digest = "4b641d721493d80f019d9447830ebfee89234a7d594378b89f8bb73873576bf6" + + + def setUp(self): + self.hash = HmacSha256.new(_HMAC_KEY) + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, HmacSha256) + + # update inside constructor + assert HmacSha256.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest + + +class TestHmacSha384(unittest.TestCase): + digest = "e72c72070c9c5c78e3286593068a510c1740cdf9dc34b512" \ + + "ccec97320295db1fe673216b46fe72e81f399a9ec04780ab" + + + def setUp(self): + self.hash = HmacSha384.new(_HMAC_KEY) + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, HmacSha384) + + # update inside constructor + assert HmacSha384.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest + + +class TestHmacSha512(unittest.TestCase): + digest = "c7f48db79314fc2b5be9a93fd58601a1bf42f397ec7f66dba034d44503890e6b"\ + + "5708242dcd71a248a78162d815c685f6038a4ac8cb34b8bf18986dbd300c9b41" + + + def setUp(self): + self.hash = HmacSha512.new(_HMAC_KEY) + + + def test_new(self): + # invalid construction + self.assertRaises(ValueError, HmacSha512) + + # update inside constructor + assert HmacSha512.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest + + + def test_hash_update_001(self): + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_update_002(self): + self.hash.update("wolf") + self.hash.update("crypt") + + assert self.hash.hexdigest() == self.digest + assert self.hash.digest() == self.digest.decode("hex") + + + def test_hash_copy(self): + copy = self.hash.copy() + + assert self.hash.hexdigest() == copy.hexdigest() + + self.hash.update("wolfcrypt") + + assert self.hash.hexdigest() != copy.hexdigest() + + copy.update("wolfcrypt") + + assert self.hash.hexdigest() == copy.hexdigest() == self.digest diff --git a/wrapper/python/test/test_random.py b/wrapper/python/test/test_random.py new file mode 100644 index 000000000..7c5456480 --- /dev/null +++ b/wrapper/python/test/test_random.py @@ -0,0 +1,38 @@ +# test_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 unittest +from wolfcrypt.random import * + + +class TestRandom(unittest.TestCase): + + + def setUp(self): + self.random = Random() + + + def test_byte(self): + assert len(self.random.byte()) == 1 + + + def test_bytes(self): + assert len(self.random.bytes(1)) == 1 + assert len(self.random.bytes(10)) == 10 + assert len(self.random.bytes(100)) == 100 diff --git a/wrapper/python/tox.ini b/wrapper/python/tox.ini new file mode 100644 index 000000000..c8778e414 --- /dev/null +++ b/wrapper/python/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist=py27 + +[testenv] +deps=-rrequirements-testing.txt +commands=py.test test/ diff --git a/wrapper/python/wolfcrypt/__init__.py b/wrapper/python/wolfcrypt/__init__.py new file mode 100644 index 000000000..498cd8902 --- /dev/null +++ b/wrapper/python/wolfcrypt/__init__.py @@ -0,0 +1,21 @@ +# WolfCrypt +# +# 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 + +# dummy file diff --git a/wrapper/python/wolfcrypt/build_ffi.py b/wrapper/python/wolfcrypt/build_ffi.py new file mode 100644 index 000000000..7d876751d --- /dev/null +++ b/wrapper/python/wolfcrypt/build_ffi.py @@ -0,0 +1,133 @@ +# 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._ffi", + """ + #include + + #include + #include + #include + + #include + + #include + #include + #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 { ...; } Sha; + + int wc_InitSha(Sha*); + int wc_ShaUpdate(Sha*, const byte*, word32); + int wc_ShaFinal(Sha*, byte*); + + + typedef struct { ...; } Sha256; + + int wc_InitSha256(Sha256*); + int wc_Sha256Update(Sha256*, const byte*, word32); + int wc_Sha256Final(Sha256*, byte*); + + + typedef struct { ...; } Sha384; + + int wc_InitSha384(Sha384*); + int wc_Sha384Update(Sha384*, const byte*, word32); + int wc_Sha384Final(Sha384*, byte*); + + + typedef struct { ...; } Sha512; + + int wc_InitSha512(Sha512*); + 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*); + +""" +) + +if __name__ == "__main__": + ffi.compile(verbose=1) diff --git a/wrapper/python/wolfcrypt/ciphers.py b/wrapper/python/wolfcrypt/ciphers.py new file mode 100644 index 000000000..2aa69728c --- /dev/null +++ b/wrapper/python/wolfcrypt/ciphers.py @@ -0,0 +1,252 @@ +# 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 +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib +from wolfcrypt.random import Random + + +# key direction flags +_ENCRYPTION = 0 +_DECRYPTION = 1 + + +# feedback modes +MODE_ECB = 1 # Electronic Code Book +MODE_CBC = 2 # Cipher Block Chaining +MODE_CFB = 3 # Cipher Feedback +MODE_OFB = 5 # Output Feedback +MODE_CTR = 6 # Counter + +_FEEDBACK_MODES = [MODE_ECB, MODE_CBC, MODE_CFB, MODE_OFB, MODE_CTR] + + +class _Cipher(object): + # Magic object that protects against constructors. + _JAPANESE_CYBER_SWORD = object() + + + def __init__(self, token=""): + if token is not self._JAPANESE_CYBER_SWORD: + # PEP 272 -- API for Block Encryption Algorithms v1.0 + raise ValueError("don't construct directly, use new([string])") + + + @classmethod + def new(cls, key, mode, IV=None, **kwargs): + if mode not in _FEEDBACK_MODES: + raise ValueError("this mode is not supported") + if mode != MODE_CBC: + raise ValueError("this mode is not supported by this cipher") + + self = cls(_Cipher._JAPANESE_CYBER_SWORD) + + if self.key_size: + if self.key_size != len(key): + raise ValueError("key must be %d in length" % self.key_size) + elif self._key_sizes: + if len(key) not in self._key_sizes: + raise ValueError("key must be %s in length" % self._key_sizes) + else: + if not len(key): + raise ValueError("key must not be 0 in length") + + if IV is not None and len(IV) != self.block_size: + raise ValueError("IV must be %d in length" % self.block_size) + + self._native_object = _ffi.new(self._native_type) + + self._enc = None + self._dec = None + self._key = key + self._IV = IV if IV else "\0" * self.block_size + + return self + + + def encrypt(self, string): + if not string or len(string) % self.block_size: + raise ValueError( + "string must be a multiple of %d in length" % self.block_size) + + if self._enc is None: + self._enc = _ffi.new(self._native_type) + self._set_key(_ENCRYPTION) + + result = "\0" * len(string) + self._encrypt(result, string) + + return result + + + def decrypt(self, string): + if not string or len(string) % self.block_size: + raise ValueError( + "string must be a multiple of %d in length" % self.block_size) + + if self._dec is None: + self._dec = _ffi.new(self._native_type) + self._set_key(_DECRYPTION) + + result = "\0" * len(string) + self._decrypt(result, string) + + return result + + +class Aes(_Cipher): + block_size = 16 + key_size = None # 16, 24, 32 + _key_sizes = [16, 24, 32] + _native_type = "Aes *" + + + def _set_key(self, direction): + if direction == _ENCRYPTION: + _lib.wc_AesSetKey( + self._enc, self._key, len(self._key), self._IV, _ENCRYPTION) + else: + _lib.wc_AesSetKey( + self._dec, self._key, len(self._key), self._IV, _DECRYPTION) + + + def _encrypt(self, destination, source): + _lib.wc_AesCbcEncrypt(self._enc, destination, source, len(source)) + + + def _decrypt(self, destination, source): + _lib.wc_AesCbcDecrypt(self._dec, destination, source, len(source)) + + +class Des3(_Cipher): + block_size = 8 + key_size = 24 + _native_type = "Des3 *" + + + def _set_key(self, direction): + if direction == _ENCRYPTION: + _lib.wc_Des3_SetKey(self._enc, self._key, self._IV, _ENCRYPTION) + else: + _lib.wc_Des3_SetKey(self._dec, self._key, self._IV, _DECRYPTION) + + + def _encrypt(self, destination, source): + _lib.wc_Des3_CbcEncrypt(self._enc, destination, source, len(source)) + + + 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 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) + + if self.output_size <= 0: + raise KeyError + + + def encrypt(self, plaintext): + ciphertext = "\0" * self.output_size + + ret = _lib.wc_RsaPublicEncrypt(plaintext, len(plaintext), + ciphertext, len(ciphertext), + self.native_object, + self._random.native_object) + + if ret != self.output_size: + raise KeyError + + return ciphertext + + + def verify(self, signature): + plaintext = "\0" * self.output_size + + ret = _lib.wc_RsaSSL_Verify(signature, len(signature), + plaintext, len(plaintext), + self.native_object) + + if ret < 0: + raise KeyError + + return plaintext[:ret] + + +class RsaPrivate(RsaPublic): + 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, ciphertext): + plaintext = "\0" * self.output_size + + ret = _lib.wc_RsaPrivateDecrypt(ciphertext, len(ciphertext), + plaintext, len(plaintext), + self.native_object) + + if ret < 0: + raise KeyError + + return plaintext[:ret] + + + def sign(self, plaintext): + signature = "\0" * self.output_size + + ret = _lib.wc_RsaSSL_Sign(plaintext, len(plaintext), + signature, len(signature), + self.native_object, + self._random.native_object) + + if ret != self.output_size: + raise KeyError + + return signature diff --git a/wrapper/python/wolfcrypt/hashes.py b/wrapper/python/wolfcrypt/hashes.py new file mode 100644 index 000000000..18c0b54b3 --- /dev/null +++ b/wrapper/python/wolfcrypt/hashes.py @@ -0,0 +1,210 @@ +# hashes.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 +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib + + +class _Hash(object): + # Magic object that protects against constructors. + _JAPANESE_CYBER_SWORD = object() + + + def __init__(self, token=""): + if token is not self._JAPANESE_CYBER_SWORD: + # PEP 247 -- API for Cryptographic Hash Functions + raise ValueError("don't construct directly, use new([string])") + + + @classmethod + def new(cls, string=None): + self = cls(cls._JAPANESE_CYBER_SWORD) + + self._native_object = _ffi.new(self._native_type) + + self._init() + + if (string): + self._update(string) + + return self + + + def copy(self): + copy = self.new("") + + _ffi.memmove(copy._native_object, + self._native_object, + self._native_size) + + return copy + + + def update(self, string): + self._update(string) + + + def digest(self): + ret = "\0" * self.digest_size + + if self._native_object: + obj = _ffi.new(self._native_type) + + _ffi.memmove(obj, self._native_object, self._native_size) + + self._final(obj, ret) + + return ret + + + def hexdigest(self): + return self.digest().encode("hex") + + +class Sha(_Hash): + digest_size = 20 + _native_type = "Sha *" + _native_size = _ffi.sizeof("Sha") + + + def _init(self): + _lib.wc_InitSha(self._native_object) + + + def _update(self, data): + _lib.wc_ShaUpdate(self._native_object, data, len(data)) + + + def _final(self, obj, ret): + _lib.wc_ShaFinal(obj, ret) + + +class Sha256(_Hash): + digest_size = 32 + _native_type = "Sha256 *" + _native_size = _ffi.sizeof("Sha256") + + + def _init(self): + _lib.wc_InitSha256(self._native_object) + + + def _update(self, data): + _lib.wc_Sha256Update(self._native_object, data, len(data)) + + + def _final(self, obj, ret): + _lib.wc_Sha256Final(obj, ret) + + +class Sha384(_Hash): + digest_size = 48 + _native_type = "Sha384 *" + _native_size = _ffi.sizeof("Sha384") + + + def _init(self): + _lib.wc_InitSha384(self._native_object) + + + def _update(self, data): + _lib.wc_Sha384Update(self._native_object, data, len(data)) + + + def _final(self, obj, ret): + _lib.wc_Sha384Final(obj, ret) + + +class Sha512(_Hash): + digest_size = 64 + _native_type = "Sha512 *" + _native_size = _ffi.sizeof("Sha512") + + + def _init(self): + _lib.wc_InitSha512(self._native_object) + + + def _update(self, data): + _lib.wc_Sha512Update(self._native_object, data, len(data)) + + + def _final(self, obj, ret): + _lib.wc_Sha512Final(obj, ret) + + +# Hmac types + +_TYPE_SHA = 1 +_TYPE_SHA256 = 2 +_TYPE_SHA384 = 5 +_TYPE_SHA512 = 4 +_HMAC_TYPES = [_TYPE_SHA, _TYPE_SHA256, _TYPE_SHA384, _TYPE_SHA512] + + +class _Hmac(_Hash): + digest_size = None + _native_type = "Hmac *" + _native_size = _ffi.sizeof("Hmac") + + + @classmethod + def new(cls, key, string=None): + self = cls(cls._JAPANESE_CYBER_SWORD) + + self._native_object = _ffi.new(self._native_type) + + self._init(self._type, key) + + if (string): + self._update(string) + + return self + + + def _init(self, type, key): + _lib.wc_HmacSetKey(self._native_object, type, key, len(key)) + + + def _update(self, data): + _lib.wc_HmacUpdate(self._native_object, data, len(data)) + + + def _final(self, obj, ret): + _lib.wc_HmacFinal(obj, ret) + + +class HmacSha(_Hmac): + _type = _TYPE_SHA + digest_size = Sha.digest_size + + +class HmacSha256(_Hmac): + _type = _TYPE_SHA256 + digest_size = Sha256.digest_size + + +class HmacSha384(_Hmac): + _type = _TYPE_SHA384 + digest_size = Sha384.digest_size + + +class HmacSha512(_Hmac): + _type = _TYPE_SHA512 + digest_size = Sha512.digest_size diff --git a/wrapper/python/wolfcrypt/random.py b/wrapper/python/wolfcrypt/random.py new file mode 100644 index 000000000..047b75856 --- /dev/null +++ b/wrapper/python/wolfcrypt/random.py @@ -0,0 +1,49 @@ +# 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 +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib + + +class Random(object): + def __init__(self): + self.native_object = _ffi.new("WC_RNG *") + if _lib.wc_InitRng(self.native_object) != 0: + self.native_object = None + + + def __del__(self): + if self.native_object: + _lib.wc_FreeRng(self.native_object) + + + def byte(self): + ret = "\0" + + _lib.wc_RNG_GenerateByte(self.native_object, ret) + + return ret + + + def bytes(self, length): + ret = "\0" * length + + _lib.wc_RNG_GenerateBlock(self.native_object, ret, length) + + return ret From d8309ab624f53e8027234c969556b6a315b6d13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Thu, 28 Apr 2016 13:26:59 -0300 Subject: [PATCH 02/24] adds python ignored files --- wrapper/python/.gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 wrapper/python/.gitignore diff --git a/wrapper/python/.gitignore b/wrapper/python/.gitignore new file mode 100644 index 000000000..8cb79fe5b --- /dev/null +++ b/wrapper/python/.gitignore @@ -0,0 +1,11 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Distribution +build/ +*.egg-info/ + +# Unit test +.tox/ From 66d41eee36204bd640a810b1012342d45000aa56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Thu, 28 Apr 2016 13:36:41 -0300 Subject: [PATCH 03/24] updates python README --- wrapper/python/README.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index e2ebe1fad..82bf1352f 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -2,21 +2,24 @@ wolfcrypt: the wolfSSL Crypto Engine ==================================== -A Python wrapper which encapsulates the wolfCrypt API inside wolfSSL library +A Python wrapper which encapsulates the wolfCrypt API from wolfSSL library -**REQUIRES** [wolfSSL](https://github.com/wolfSSL/wolfssl) +1. Clone the repository and install wolfssl:: -1. Clone the repository:: - - - $ git clone git@github.com:wolfssl/wolfcrypt-py.git + $ git clone git@github.com:wolfssl/wolfssl.git + $ cd wolfssl + $ ./autogen.sh + $ ./configure + $ make + $ sudo make install 2. Make sure that ``cffi``, ``py.test``, and ``tox`` are installed:: + $ cd wrappers/python $ pip install -r requirements-testing.txt @@ -35,4 +38,4 @@ A Python wrapper which encapsulates the wolfCrypt API inside wolfSSL library ... _________________________________ summary _________________________________ py27: commands succeeded - congratulations :) \ No newline at end of file + congratulations :) From 1efd1343eed0a229ba2ac459843f571625ab5a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Fri, 29 Apr 2016 16:13:38 -0300 Subject: [PATCH 04/24] initial docs --- wrapper/python/docs/Makefile | 230 +++++++++++++++++++++++++++ wrapper/python/docs/conf.py | 290 ++++++++++++++++++++++++++++++++++ wrapper/python/docs/index.rst | 22 +++ 3 files changed, 542 insertions(+) create mode 100644 wrapper/python/docs/Makefile create mode 100644 wrapper/python/docs/conf.py create mode 100644 wrapper/python/docs/index.rst diff --git a/wrapper/python/docs/Makefile b/wrapper/python/docs/Makefile new file mode 100644 index 000000000..805fe1fdc --- /dev/null +++ b/wrapper/python/docs/Makefile @@ -0,0 +1,230 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wolfCrypt.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wolfCrypt.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/wolfCrypt" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wolfCrypt" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/wrapper/python/docs/conf.py b/wrapper/python/docs/conf.py new file mode 100644 index 000000000..c5fd47be0 --- /dev/null +++ b/wrapper/python/docs/conf.py @@ -0,0 +1,290 @@ +# -*- coding: utf-8 -*- +# +# wolfCrypt documentation build configuration file, created by +# sphinx-quickstart on Fri Apr 29 16:04:23 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'wolfCrypt' +copyright = u'2016, wolfSSL' +author = u'wolfSSL' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'0.0' +# The full version, including alpha/beta/rc tags. +release = u'0.0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +#html_title = u'wolfCrypt v0.0.1' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +#html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'wolfCryptdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'wolfCrypt.tex', u'wolfCrypt Documentation', + u'wolfSSL', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'wolfcrypt', u'wolfCrypt Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'wolfCrypt', u'wolfCrypt Documentation', + author, 'wolfCrypt', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/wrapper/python/docs/index.rst b/wrapper/python/docs/index.rst new file mode 100644 index 000000000..35b4525b2 --- /dev/null +++ b/wrapper/python/docs/index.rst @@ -0,0 +1,22 @@ +.. wolfCrypt documentation master file, created by + sphinx-quickstart on Fri Apr 29 16:04:23 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to wolfCrypt's documentation! +===================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + From 69ac477976335d05283df1a6a3f4507790337fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Fri, 29 Apr 2016 16:25:53 -0300 Subject: [PATCH 05/24] updates docs template --- wrapper/python/docs/conf.py | 5 +++-- wrapper/python/requirements-testing.txt | 1 + wrapper/python/setup.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/wrapper/python/docs/conf.py b/wrapper/python/docs/conf.py index c5fd47be0..fe64bbb29 100644 --- a/wrapper/python/docs/conf.py +++ b/wrapper/python/docs/conf.py @@ -14,6 +14,7 @@ import sys import os +import sphinx_rtd_theme # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -112,7 +113,7 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -120,7 +121,7 @@ html_theme = 'alabaster' #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. # " v documentation" by default. diff --git a/wrapper/python/requirements-testing.txt b/wrapper/python/requirements-testing.txt index e8f289c1f..0d3256e5b 100644 --- a/wrapper/python/requirements-testing.txt +++ b/wrapper/python/requirements-testing.txt @@ -1,3 +1,4 @@ pytest>=2.9.1 cffi>=1.5.2 tox>=2.3.1 +sphinx_rtd_theme>=0.1.9 diff --git a/wrapper/python/setup.py b/wrapper/python/setup.py index 0dd138fff..9c6b3f64a 100755 --- a/wrapper/python/setup.py +++ b/wrapper/python/setup.py @@ -10,7 +10,7 @@ os.chdir(os.path.dirname(sys.argv[0]) or ".") setup( name="wolfcrypt", - version="0.1", + version="0.0.1", description="A python wrapper for the wolfCrypt API", long_description=open("README.rst", "rt").read(), url="https://github.com/wolfssl/wolfcrypt-py", From 31817314047d3ac059a676cc9f6aa82efa812194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Tue, 3 May 2016 00:41:54 -0300 Subject: [PATCH 06/24] adds docs --- wrapper/python/.gitignore | 4 + wrapper/python/README.rst | 24 +- wrapper/python/docs/Makefile | 8 +- wrapper/python/docs/asymmetric.rst | 74 ++++++ wrapper/python/docs/conf.py | 36 +-- wrapper/python/docs/digest.rst | 71 ++++++ wrapper/python/docs/index.rst | 50 +++- wrapper/python/docs/mac.rst | 74 ++++++ wrapper/python/docs/random.rst | 30 +++ wrapper/python/docs/symmetric.rst | 44 ++++ wrapper/python/requirements-testing.txt | 3 +- wrapper/python/setup.py | 14 +- wrapper/python/test/test_ciphers.py | 41 ++- wrapper/python/test/test_hashes.py | 317 +++--------------------- wrapper/python/tox.ini | 2 +- wrapper/python/wolfcrypt/__init__.py | 2 +- wrapper/python/wolfcrypt/about.py | 58 +++++ wrapper/python/wolfcrypt/build_ffi.py | 2 +- wrapper/python/wolfcrypt/ciphers.py | 199 +++++++++++---- wrapper/python/wolfcrypt/exceptions.py | 23 ++ wrapper/python/wolfcrypt/hashes.py | 184 ++++++++++---- wrapper/python/wolfcrypt/random.py | 37 ++- wrapper/python/wolfcrypt/utils.py | 38 +++ 23 files changed, 882 insertions(+), 453 deletions(-) create mode 100644 wrapper/python/docs/asymmetric.rst create mode 100644 wrapper/python/docs/digest.rst create mode 100644 wrapper/python/docs/mac.rst create mode 100644 wrapper/python/docs/random.rst create mode 100644 wrapper/python/docs/symmetric.rst create mode 100644 wrapper/python/wolfcrypt/about.py create mode 100644 wrapper/python/wolfcrypt/exceptions.py create mode 100644 wrapper/python/wolfcrypt/utils.py diff --git a/wrapper/python/.gitignore b/wrapper/python/.gitignore index 8cb79fe5b..421703396 100644 --- a/wrapper/python/.gitignore +++ b/wrapper/python/.gitignore @@ -5,7 +5,11 @@ __pycache__/ # Distribution build/ +dist/ +.eggs/ *.egg-info/ # Unit test .tox/ +# Sphinx documentation +docs/_build/ diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 82bf1352f..23e9d1f78 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -1,8 +1,10 @@ + + wolfcrypt: the wolfSSL Crypto Engine ==================================== -A Python wrapper which encapsulates the wolfCrypt API from wolfSSL library +A Python library that encapsulates wolfSSL's wolfCrypt API 1. Clone the repository and install wolfssl:: @@ -23,12 +25,12 @@ A Python wrapper which encapsulates the wolfCrypt API from wolfSSL library $ pip install -r requirements-testing.txt -3. Run ``python setup.py install`` to build and install wolfcrypt-py:: +3. Run ``python setup.py install`` to build and install wolfcrypt:: $ python setup.py install ... - Finished processing dependencies for wolfcrypt==0.1 + Finished processing dependencies for wolfcrypt==0.1.0 4. Test locally with ``tox``:: @@ -37,5 +39,21 @@ A Python wrapper which encapsulates the wolfCrypt API from wolfSSL library $ tox ... _________________________________ summary _________________________________ + py26: commands succeeded py27: commands succeeded + py35: commands succeeded congratulations :) + +Licensing +========= + + +wolfSSL (formerly known as CyaSSL) and wolfCrypt are either licensed for use +under the GPLv2 or a standard commercial license. For our users who cannot use +wolfSSL under GPLv2, a commercial license to wolfSSL and wolfCrypt is available. +Please contact wolfSSL Inc. directly at: + +Email: licensing@wolfssl.com +Phone: +1 425 245-8247 + +More information can be found on the `wolfSSL website `_. diff --git a/wrapper/python/docs/Makefile b/wrapper/python/docs/Makefile index 805fe1fdc..c552bc9b3 100644 --- a/wrapper/python/docs/Makefile +++ b/wrapper/python/docs/Makefile @@ -96,9 +96,9 @@ qthelp: @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wolfCrypt.qhcp" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wolfcrypt.qhcp" @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wolfCrypt.qhc" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wolfcrypt.qhc" .PHONY: applehelp applehelp: @@ -115,8 +115,8 @@ devhelp: @echo @echo "Build finished." @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/wolfCrypt" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wolfCrypt" + @echo "# mkdir -p $$HOME/.local/share/devhelp/wolfcrypt" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wolfcrypt" @echo "# devhelp" .PHONY: epub diff --git a/wrapper/python/docs/asymmetric.rst b/wrapper/python/docs/asymmetric.rst new file mode 100644 index 000000000..970078dee --- /dev/null +++ b/wrapper/python/docs/asymmetric.rst @@ -0,0 +1,74 @@ +Asymmetric Key Algorithms +========================= + +.. module:: wolfcrypt.ciphers + +**Asymmetric key algorithms** are encryption algorithms that use **a pair +of cryptographic keys**, one for data encryption and signing and the other +one for data decryption and signature verification. + +``wolfcrypt`` provides access to the following **Asymmetric Key Ciphers**: + +Asymmetric Key Encryption Classes +--------------------------------- + +.. autoclass:: RsaPublic + :members: + :inherited-members: + +.. autoclass:: RsaPrivate + :members: + :inherited-members: + + +Example +------- + + >>> from wolfcrypt.ciphers import RsaPrivate, RsaPublic + >>> from wolfcrypt.utils import h2b + >>> + >>> private = "3082025C02010002818100BC730EA849F374A2A9EF18A5DA559921F9C8ECB36D" \ + ... + "48E53535757737ECD161905F3ED9E4D5DF94CAC1A9D719DA86C9E84DC4613682" \ + ... + "FEABAD7E7725BB8D11A5BC623AA838CC39A20466B4F7F7F3AADA4D020EBB5E8D" \ + ... + "6948DC77C9280E22E96BA426BA4CE8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B" \ + ... + "3C67C8DC2700F6916865A902030100010281801397EAE8387825A25C04CE0D40" \ + ... + "7C31E5C470CD9B823B5809863B665FDC3190F14FD5DB15DDDED73B9593311831" \ + ... + "0E5EA3D6A21A716E81481C4BCFDB8E7A866132DCFB55C1166D279224458BF1B8" \ + ... + "48B14B1DACDEDADD8E2FC291FBA5A96EF83A6AF1FD5018EF9FE7C3CA78EA56D3" \ + ... + "D3725B96DD4E064E3AC3D9BE72B66507074C01024100FA47D47A7C923C55EF81" \ + ... + "F041302DA3CF8F1CE6872705700DDF9835D6F18B382F24B5D084B6794F712994" \ + ... + "5AF0646AACE772C6ED4D59983E673AF3742CF9611769024100C0C1820D0CEBC6" \ + ... + "2FDC92F99D821A31E9E9F74BF282871CEE166AD11D188270F3C0B62FF6F3F71D" \ + ... + "F18623C84EEB8F568E8FF5BFF1F72BB5CC3DC657390C1B54410241009D7E05DE" \ + ... + "EDF4B7B2FBFC304B551DE32F0147966905CD0E2E2CBD8363B6AB7CB76DCA5B64" \ + ... + "A7CEBE86DF3B53DE61D21EEBA5F637EDACAB78D94CE755FBD71199C102401898" \ + ... + "1829E61E2739702168AC0A2FA172C121869538C65890A0579CBAE3A7B115C8DE" \ + ... + "F61BC2612376EFB09D1C44BE1343396717C89DCAFBF545648B38822CF2810240" \ + ... + "3989E59C195530BAB7488C48140EF49F7E779743E1B419353123759C3B44AD69" \ + ... + "1256EE0061641666D37C742B15B4A2FEBF086B1A5D3F9012B105863129DBD9E2" + >>> + >>> prv = RsaPrivate(h2b(private)) + >>> + >>> public = "30819F300D06092A864886F70D010101050003818D0030818902818100BC730E" \ + ... + "A849F374A2A9EF18A5DA559921F9C8ECB36D48E53535757737ECD161905F3ED9" \ + ... + "E4D5DF94CAC1A9D719DA86C9E84DC4613682FEABAD7E7725BB8D11A5BC623AA8" \ + ... + "38CC39A20466B4F7F7F3AADA4D020EBB5E8D6948DC77C9280E22E96BA426BA4C" \ + ... + "E8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B3C67C8DC2700F6916865A90203010001" + >>> + >>> pub = RsaPublic(h2b(public)) + >>> + >>> plaintext = b"Everyone gets Friday off." + >>> + >>> ciphertext = pub.encrypt(plaintext) + >>> ciphertext # doctest: +SKIP + b'e\xb7\xc2\xad\x0c\x04.\xefU8\x17QB\x852\x03\x01\xef\xbe=\xb4\xaf\xaf\x97\x9e4\x96\x9f\xc3\x8e\x87\x9a8o$.|_e\x1d\xa2yi?\x83\x18\xf9Yr|\x1fQ\x1a\x18\x1e\xab\xd17\xc5\x8c\xae\x08c)\xbc\nIr\x8d\xc3\x88\x7f\xde\x1f\x1a^lB\r\xf1\xc0\xfd0\xdeA\xf3\xd2\xe5q\x9a0\xee\xb4,\x97\x80\xa4|U;\xe6\x11\xf0\xc2Q\x987\xe1>F\xf5\x14\x186@G~(Q\xf2;\xcb\x05\xee\x88\x0b\xd8\xa7' + >>> + >>> prv.decrypt(ciphertext) + b'Everyone gets Friday off.' + >>> + >>> signature = prv.sign(plaintext) + >>> signature # doctest: +SKIP + b'~\xc4\xe65\x15\xb17\x7fX\xaf,\xc2lw\xbd\x8f\t\x9d\xbf\xac\xdez\x90\xb4\x9f\x1aM\x88#Z\xea\xcb\xa6\xdb\x99\xf55\xd0\xfe|Mu\xb6\xb79(t\x81+h\xf2\xcd\x88v\xa8\xbaM\x86\xcfk\xe8\xf3\x0b\xb8\x8ew\xda>\xf8\xd5[H\xeaAh\xc6\xdaQlo]\xdd\xf8w\xe7#M-\x12f\xae,\xdd\xa6d FP<;R\xa2\x96hJ\xee_\x1fh\xaa\xc8\xdfAJ\xa5\xdd\x05\xc4\x89\x0c\xd7\xa0C\xb7u"U\x03' + >>> + >>> pub.verify(signature) + b'Everyone gets Friday off.' diff --git a/wrapper/python/docs/conf.py b/wrapper/python/docs/conf.py index fe64bbb29..b9d4b4a8c 100644 --- a/wrapper/python/docs/conf.py +++ b/wrapper/python/docs/conf.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # -# wolfCrypt documentation build configuration file, created by -# sphinx-quickstart on Fri Apr 29 16:04:23 2016. +# wolfcrypt documentation build configuration file, created by +# sphinx-quickstart on Fri Apr 29 16:47:53 2016. # # This file is execfile()d with the current directory set to its # containing dir. @@ -31,8 +31,10 @@ import sphinx_rtd_theme # ones. extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages', ] # Add any paths that contain templates here, relative to this directory. @@ -50,18 +52,21 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'wolfCrypt' -copyright = u'2016, wolfSSL' +project = u'wolfcrypt' +copyright = u'2016, wolfSSL Inc. All rights reserved' author = u'wolfSSL' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # -# The short X.Y version. -version = u'0.0' -# The full version, including alpha/beta/rc tags. -release = u'0.0.1' + +base_dir = os.path.join(os.path.dirname(__file__), os.pardir) +about = {} +with open(os.path.join(base_dir, "wolfcrypt", "about.py")) as f: + exec(f.read(), about) + +version = release = about["__version__"] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -125,7 +130,7 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. # " v documentation" by default. -#html_title = u'wolfCrypt v0.0.1' +#html_title = u'%s v%s' % (project, release) # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None @@ -207,7 +212,7 @@ html_static_path = ['_static'] #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'wolfCryptdoc' +htmlhelp_basename = 'wolfcrypt-pydoc' # -- Options for LaTeX output --------------------------------------------- @@ -229,7 +234,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'wolfCrypt.tex', u'wolfCrypt Documentation', + (master_doc, 'wolfcrypt.tex', u'wolfcrypt Python Documentation', u'wolfSSL', 'manual'), ] @@ -259,7 +264,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'wolfcrypt', u'wolfCrypt Documentation', + (master_doc, 'wolfcrypt', u'wolfcrypt Python Documentation', [author], 1) ] @@ -273,8 +278,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'wolfCrypt', u'wolfCrypt Documentation', - author, 'wolfCrypt', 'One line description of project.', + (master_doc, 'wolfcrypt', u'wolfcrypt Python Documentation', + author, 'wolfcrypt', 'One line description of project.', 'Miscellaneous'), ] @@ -289,3 +294,6 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +# Preserves the order of the members, doesn't sorts them alphabetically. +autodoc_member_order = 'bysource' diff --git a/wrapper/python/docs/digest.rst b/wrapper/python/docs/digest.rst new file mode 100644 index 000000000..0d79f8ef0 --- /dev/null +++ b/wrapper/python/docs/digest.rst @@ -0,0 +1,71 @@ +Message Digests +=============== + +.. module:: wolfcrypt.hashes + +A **message digest** is the output of a **cryptographic hash function** +containing a string of bytes created by a **one-way formula** using the +original message as input. + +Message digests are designed to protect the integrity of a piece of data or +media to detect changes and alterations to any part of a message. + + +Hashing Classes +--------------- + +Interface +~~~~~~~~~ + +All Hashing Functions available in this module implements the following +interface: + +.. autoclass:: _Hash + :members: + +SHA-1 +~~~~~ + +.. attention:: + + NIST has deprecated SHA-1 in favor of the SHA-2 variants. New applications + are strongly suggested to use SHA-2 over SHA-1. + +.. autoclass:: Sha + +SHA-2 family +~~~~~~~~~~~~ + +.. autoclass:: Sha256 + + +.. autoclass:: Sha384 + + +.. autoclass:: Sha512 + + +Example +------- + +.. doctest:: + + >>> from wolfcrypt.hashes import Sha256 + >>> + >>> s = Sha256() + >>> s.update(b'wolf') + >>> s.update(b'crypt') + >>> s.digest() + b'\x96\xe0.{\x1c\xbc\xd6\xf1\x04\xfe\x1f\xdbFR\x02zU\x05\xb6\x86R\xb7\x00\x95\xc61\x8f\x9d\xce\r\x18D' + >>> s.hexdigest() + b'96e02e7b1cbcd6f104fe1fdb4652027a5505b68652b70095c6318f9dce0d1844' + >>> + >>> s.update(b'rocks') + >>> s.hexdigest() + b'e1a50df419d65715c48316bdc6a6f7f0485f4b26c1b107228faf17988b61c83f' + >>> + >>> Sha256(b'wolfcryptrocks').hexdigest() + b'e1a50df419d65715c48316bdc6a6f7f0485f4b26c1b107228faf17988b61c83f' + >>> + >>> Sha256.new(b'wolfcryptrocks').hexdigest() + b'e1a50df419d65715c48316bdc6a6f7f0485f4b26c1b107228faf17988b61c83f' diff --git a/wrapper/python/docs/index.rst b/wrapper/python/docs/index.rst index 35b4525b2..9b796b186 100644 --- a/wrapper/python/docs/index.rst +++ b/wrapper/python/docs/index.rst @@ -1,22 +1,46 @@ -.. wolfCrypt documentation master file, created by - sphinx-quickstart on Fri Apr 29 16:04:23 2016. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +wolfCrypt Python Documentation +================================== -Welcome to wolfCrypt's documentation! -===================================== +**wolfCrypt Python**, a.k.a. ``wolfcrypt`` is a Python library that encapsulates +**wolfSSL's wolfCrypt API**. -Contents: +**wolfCrypt** is a lightweight, portable, C-language-based crypto library +targeted at IoT, embedded, and RTOS environments primarily because of its size, +speed, and feature set. It works seamlessly in desktop, enterprise, and cloud +environments as well. + +Summary +------- .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + symmetric + asymmetric + digest + mac + random +Licensing +--------- -Indices and tables -================== +wolfSSL’s software is available under two distinct licensing models: +open source and standard commercial licensing. Please see the relevant +section below for information on each type of license. -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +Open Source +~~~~~~~~~~~ +wolfCrypt and wolfSSL software are free software downloads and may be modified +to the needs of the user as long as the user adheres to version two of the GPL +License. The GPLv2 license can be found on the `gnu.org website +`_. + +Commercial Licensing +~~~~~~~~~~~~~~~~~~~~ + +Businesses and enterprises who wish to incorporate wolfSSL products into +proprietary appliances or other commercial software products for +re-distribution must license commercial versions. Licenses are generally issued +for one product and include unlimited royalty-free distribution. Custom +licensing terms are also available at licensing@wolfssl.com. diff --git a/wrapper/python/docs/mac.rst b/wrapper/python/docs/mac.rst new file mode 100644 index 000000000..14b39cd78 --- /dev/null +++ b/wrapper/python/docs/mac.rst @@ -0,0 +1,74 @@ +Message Authentication Codes +============================ + +.. module:: wolfcrypt.hashes + +A **message authentication code** (MAC) is a short piece of information used +to authenticate a message — in other words, to confirm that the message came +from the stated sender (its authenticity) and has not been changed in transit +(its integrity). + +``wolfcrypt`` implements the **Hash-based message authentication code** (HMAC), +which uses a cryptographic hash function coupled with a secret key to produce +**message authentication codes**. + + +Hmac Classes +------------ + +Interface +~~~~~~~~~ + +All Hmac classes available in this module implements the following +interface: + +.. autoclass:: _Hmac + :members: + :inherited-members: + +SHA-1 +~~~~~ + +.. attention:: + + NIST has deprecated SHA-1 in favor of the SHA-2 variants. New applications + are strongly suggested to use SHA-2 over SHA-1. + +.. autoclass:: HmacSha + +SHA-2 family +~~~~~~~~~~~~ + +.. autoclass:: HmacSha256 + + +.. autoclass:: HmacSha384 + + +.. autoclass:: HmacSha512 + + +Example +------- + +.. doctest:: + + >>> from wolfcrypt.hashes import HmacSha256 + >>> + >>> h = HmacSha256('secret') + >>> h.update("wolf") + >>> h.update("crypt") + >>> h.digest() + b'\x18\xbf*\t9\xa2o\xdf\\\xc8\xe0\xc2U\x94,\x8dY\x02;\x1c>> h.hexdigest() + b'18bf2a0939a26fdf5cc8e0c255942c8d59023b1c3c51df8ddb8633fbc166236f' + >>> + >>> h.update("rocks") + >>> h.hexdigest() + b'85dc8c1995d20b17942d52773d8a597d028ad958e5736beafb59a4742f63889e' + >>> + >>> HmacSha256('secret', 'wolfcryptrocks').hexdigest() + b'85dc8c1995d20b17942d52773d8a597d028ad958e5736beafb59a4742f63889e' + >>> + >>> HmacSha256.new('secret', 'wolfcryptrocks').hexdigest() + b'85dc8c1995d20b17942d52773d8a597d028ad958e5736beafb59a4742f63889e' diff --git a/wrapper/python/docs/random.rst b/wrapper/python/docs/random.rst new file mode 100644 index 000000000..ba8e33bda --- /dev/null +++ b/wrapper/python/docs/random.rst @@ -0,0 +1,30 @@ +Random Number Generation +======================== + +A **cryptographically secure pseudo-random number generator** (CSPRNG) is a +**pseudo-random number generator** (PRNG) with properties that make it suitable +for use in cryptography. + +Using the standard random module APIs for cryptographic keys or initialization +vectors can result in major security issues depending on the algorithms in use. + +``wolfcrypt`` provides the following CSPRNG implementation: + +.. module:: wolfcrypt.random + +.. autoclass:: Random + :members: + + +Example +------- + + >>> from wolfcrypt.random import Random + >>> + >>> r = Random() + >>> b = r.byte() + >>> b # doctest: +SKIP + b'\x8c' + >>> b16 = r.bytes(16) + >>> b16 # doctest: +SKIP + b']\x93nk\x95\xbc@\xffX\xab\xdcB\xda\x11\xf7\x03' diff --git a/wrapper/python/docs/symmetric.rst b/wrapper/python/docs/symmetric.rst new file mode 100644 index 000000000..0535080b0 --- /dev/null +++ b/wrapper/python/docs/symmetric.rst @@ -0,0 +1,44 @@ +Symmetric Key Algorithms +======================== + +.. module:: wolfcrypt.ciphers + +**Symmetric key algorithms** are encryption algorithms that use the **same +cryptographic keys** for both encryption and decryption of data. +This operation is also known as **Symmetric Key Encryption**. + +``wolfcrypt`` provides access to the following **Symmetric Key Ciphers**: + +Symmetric Key Encryption Classes +-------------------------------- + +Interface +~~~~~~~~~ + +All **Symmetric Key Ciphers** available in this module implements the following +interface: + +.. autoclass:: _Cipher + :members: + +Classes +~~~~~~~ + +.. autoclass:: Aes + +.. autoclass:: Des3 + + +Example +------- + +.. doctest:: + + >>> from wolfcrypt.ciphers import Aes, MODE_CBC + >>> + >>> cipher = Aes(b'0123456789abcdef', MODE_CBC, b'1234567890abcdef') + >>> ciphertext = cipher.encrypt('now is the time ') + >>> ciphertext + b'\x95\x94\x92W_B\x81S,\xcc\x9dFw\xa23\xcb' + >>> cipher.decrypt(ciphertext) + b'now is the time ' diff --git a/wrapper/python/requirements-testing.txt b/wrapper/python/requirements-testing.txt index 0d3256e5b..61def5278 100644 --- a/wrapper/python/requirements-testing.txt +++ b/wrapper/python/requirements-testing.txt @@ -1,4 +1,3 @@ pytest>=2.9.1 -cffi>=1.5.2 +cffi>=1.6.0 tox>=2.3.1 -sphinx_rtd_theme>=0.1.9 diff --git a/wrapper/python/setup.py b/wrapper/python/setup.py index 9c6b3f64a..35260d529 100755 --- a/wrapper/python/setup.py +++ b/wrapper/python/setup.py @@ -10,12 +10,12 @@ os.chdir(os.path.dirname(sys.argv[0]) or ".") setup( name="wolfcrypt", - version="0.0.1", - description="A python wrapper for the wolfCrypt API", + version="0.1.0", + description="A Python wrapper that encapsulates wolfSSL's wolfCrypt API", long_description=open("README.rst", "rt").read(), - url="https://github.com/wolfssl/wolfcrypt-py", - author="Moisés Guimarães", - author_email="moises@wolfssl.com", + url="https://wolfssl.github.io/wolfcrypt-py", + author="wolfSSL", + author_email="info@wolfssl.com", classifiers=[ "Development Status :: 0 - Alpha", "Programming Language :: Python :: 2", @@ -24,7 +24,7 @@ setup( "License :: GPLv2 License :: Commercial License", ], packages=find_packages(), - setup_requires=["cffi>=1.5.2"], - install_requires=["cffi>=1.5.2"], + setup_requires=["cffi>=1.6.0"], + install_requires=["cffi>=1.6.0"], cffi_modules=["./wolfcrypt/build_ffi.py:ffi"] ) diff --git a/wrapper/python/test/test_ciphers.py b/wrapper/python/test/test_ciphers.py index 57dd2c6f2..c1929c89e 100644 --- a/wrapper/python/test/test_ciphers.py +++ b/wrapper/python/test/test_ciphers.py @@ -19,12 +19,13 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import unittest from wolfcrypt.ciphers import * +from wolfcrypt.utils import t2b, h2b class TestDes3(unittest.TestCase): - key = "0123456789abcdeffedeba987654321089abcdef01234567".decode("hex") - IV = "1234567890abcdef".decode("hex") - plain = "Now is the time for all " - cipher = "43a0297ed184f80e8964843212d508981894157487127db0".decode("hex") + key = h2b("0123456789abcdeffedeba987654321089abcdef01234567") + IV = h2b("1234567890abcdef") + plain = t2b("Now is the time for all ") + cipher = h2b("43a0297ed184f80e8964843212d508981894157487127db0") def setUp(self): @@ -32,9 +33,6 @@ class TestDes3(unittest.TestCase): def test_raises(self): - # invalid construction - self.assertRaises(ValueError, Des3) - # invalid key length self.assertRaises(ValueError, Des3.new, "key", MODE_CBC, self.IV) @@ -54,7 +52,7 @@ class TestDes3(unittest.TestCase): def test_multi_encryption(self): - result = "" + result = t2b("") segments = tuple(self.plain[i:i + Des3.block_size] \ for i in range(0, len(self.plain), Des3.block_size)) @@ -69,7 +67,7 @@ class TestDes3(unittest.TestCase): def test_multi_decryption(self): - result = "" + result = t2b("") segments = tuple(self.cipher[i:i + Des3.block_size] \ for i in range(0, len(self.cipher), Des3.block_size)) @@ -82,8 +80,8 @@ class TestDes3(unittest.TestCase): class TestAes(unittest.TestCase): key = "0123456789abcdef" IV = "1234567890abcdef" - plain = "now is the time " - cipher = "959492575f4281532ccc9d4677a233cb".decode("hex") + plain = t2b("now is the time ") + cipher = h2b("959492575f4281532ccc9d4677a233cb") def setUp(self): @@ -91,9 +89,6 @@ class TestAes(unittest.TestCase): def test_raises(self): - # invalid construction - self.assertRaises(ValueError, Aes) - # invalid key length self.assertRaises(ValueError, Aes.new, "key", MODE_CBC, self.IV) @@ -113,7 +108,7 @@ class TestAes(unittest.TestCase): def test_multi_encryption(self): - result = "" + result = t2b("") segments = tuple(self.plain[i:i + self.aes.block_size] \ for i in range(0, len(self.plain), self.aes.block_size)) @@ -128,7 +123,7 @@ class TestAes(unittest.TestCase): def test_multi_decryption(self): - result = "" + result = t2b("") segments = tuple(self.cipher[i:i + self.aes.block_size] \ for i in range(0, len(self.cipher), self.aes.block_size)) @@ -159,16 +154,16 @@ class TestRsaPrivate(unittest.TestCase): + "3989E59C195530BAB7488C48140EF49F7E779743E1B419353123759C3B44AD69" \ + "1256EE0061641666D37C742B15B4A2FEBF086B1A5D3F9012B105863129DBD9E2" - plain = "Everyone gets Friday off." + plain = t2b("Everyone gets Friday off.") def setUp(self): - self.rsa = RsaPrivate(self.key.decode("hex")) + self.rsa = RsaPrivate(h2b(self.key)) def test_raises(self): # invalid key - self.assertRaises(KeyError, RsaPrivate, 'key') + self.assertRaises(WolfCryptError, RsaPrivate, 'key') def test_output_size(self): @@ -218,17 +213,17 @@ class TestRsaPublic(unittest.TestCase): + "38CC39A20466B4F7F7F3AADA4D020EBB5E8D6948DC77C9280E22E96BA426BA4C" \ + "E8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B3C67C8DC2700F6916865A90203010001" - plain = "Everyone gets Friday off." + plain = t2b("Everyone gets Friday off.") def setUp(self): - self.private = RsaPrivate(self.prv.decode("hex")) - self.public = RsaPublic(self.pub.decode("hex")) + self.private = RsaPrivate(h2b(self.prv)) + self.public = RsaPublic(h2b(self.pub)) def test_raises(self): # invalid key - self.assertRaises(KeyError, RsaPublic, 'key') + self.assertRaises(WolfCryptError, RsaPublic, 'key') def test_output_size(self): diff --git a/wrapper/python/test/test_hashes.py b/wrapper/python/test/test_hashes.py index 5ed245462..79e953e9c 100644 --- a/wrapper/python/test/test_hashes.py +++ b/wrapper/python/test/test_hashes.py @@ -19,29 +19,28 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import unittest from wolfcrypt.hashes import * +from wolfcrypt.utils import t2b, h2b class TestSha(unittest.TestCase): - digest = "1b6182d68ae91ce0853bd9c6b6edfedd4b6a510d" + _class = Sha + digest = t2b("1b6182d68ae91ce0853bd9c6b6edfedd4b6a510d") def setUp(self): - self.hash = Sha.new() + self.hash = self._class() def test_new(self): - # invalid construction - self.assertRaises(ValueError, Sha) - # update inside constructor - assert Sha.new("wolfcrypt").hexdigest() == self.digest + assert self._class.new("wolfcrypt").hexdigest() == self.digest def test_hash_update_001(self): self.hash.update("wolfcrypt") assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") + assert self.hash.digest() == h2b(self.digest) def test_hash_update_002(self): @@ -49,7 +48,7 @@ class TestSha(unittest.TestCase): self.hash.update("crypt") assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") + assert self.hash.digest() == h2b(self.digest) def test_hash_copy(self): @@ -66,167 +65,47 @@ class TestSha(unittest.TestCase): assert self.hash.hexdigest() == copy.hexdigest() == self.digest -class TestSha256(unittest.TestCase): - digest = "96e02e7b1cbcd6f104fe1fdb4652027a5505b68652b70095c6318f9dce0d1844" +class TestSha256(TestSha): + _class = Sha256 + digest = t2b("96e02e7b1cbcd6f104fe1fdb4652027a" \ + + "5505b68652b70095c6318f9dce0d1844") - def setUp(self): - self.hash = Sha256.new() +class TestSha384(TestSha): + _class = Sha384 + digest = t2b("4c79d80531203a16f91bee325f18c6aada47f9382fe44fc1" \ + + "1f92917837e9b7902f5dccb7d3656f667a1dce3460bc884b") - def test_new(self): - # invalid construction - self.assertRaises(ValueError, Sha256) - - # update inside constructor - assert Sha256.new("wolfcrypt").hexdigest() == self.digest - - - def test_hash_update_001(self): - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_update_002(self): - self.hash.update("wolf") - self.hash.update("crypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_copy(self): - copy = self.hash.copy() - - assert self.hash.hexdigest() == copy.hexdigest() - - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() != copy.hexdigest() - - copy.update("wolfcrypt") - - assert self.hash.hexdigest() == copy.hexdigest() == self.digest - - -class TestSha384(unittest.TestCase): - digest = "4c79d80531203a16f91bee325f18c6aada47f9382fe44fc1" \ - + "1f92917837e9b7902f5dccb7d3656f667a1dce3460bc884b" - - - def setUp(self): - self.hash = Sha384.new() - - - def test_new(self): - # invalid construction - self.assertRaises(ValueError, Sha384) - - # update inside constructor - assert Sha384.new("wolfcrypt").hexdigest() == self.digest - - - def test_hash_update_001(self): - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_update_002(self): - self.hash.update("wolf") - self.hash.update("crypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_copy(self): - copy = self.hash.copy() - - assert self.hash.hexdigest() == copy.hexdigest() - - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() != copy.hexdigest() - - copy.update("wolfcrypt") - - assert self.hash.hexdigest() == copy.hexdigest() == self.digest - - -class TestSha512(unittest.TestCase): - digest = "88fcf67ffd8558d713f9cedcd852db479e6573f0bd9955610a993f609637553c"\ - + "e8fff55e644ee8a106aae19c07f91b3f2a2a6d40dfa7302c0fa6a1a9a5bfa03f" - - - def setUp(self): - self.hash = Sha512.new() - - - def test_new(self): - # invalid construction - self.assertRaises(ValueError, Sha512) - - # update inside constructor - assert Sha512.new("wolfcrypt").hexdigest() == self.digest - - - def test_hash_update_001(self): - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_update_002(self): - self.hash.update("wolf") - self.hash.update("crypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_copy(self): - copy = self.hash.copy() - - assert self.hash.hexdigest() == copy.hexdigest() - - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() != copy.hexdigest() - - copy.update("wolfcrypt") - - assert self.hash.hexdigest() == copy.hexdigest() == self.digest +class TestSha512(TestSha): + _class = Sha512 + digest = t2b("88fcf67ffd8558d713f9cedcd852db47" \ + + "9e6573f0bd9955610a993f609637553c" \ + + "e8fff55e644ee8a106aae19c07f91b3f" \ + + "2a2a6d40dfa7302c0fa6a1a9a5bfa03f") _HMAC_KEY = "python" class TestHmacSha(unittest.TestCase): - digest = "5dfabcfb3a25540824867cd21f065f52f73491e0" + _class = HmacSha + digest = t2b("5dfabcfb3a25540824867cd21f065f52f73491e0") def setUp(self): - self.hash = HmacSha.new(_HMAC_KEY) + self.hash = self._class(_HMAC_KEY) def test_new(self): - # invalid construction - self.assertRaises(ValueError, HmacSha) - # update inside constructor - assert HmacSha.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest + assert self._class.new(_HMAC_KEY,"wolfcrypt").hexdigest() == self.digest def test_hash_update_001(self): self.hash.update("wolfcrypt") assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") def test_hash_update_002(self): @@ -234,7 +113,6 @@ class TestHmacSha(unittest.TestCase): self.hash.update("crypt") assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") def test_hash_copy(self): @@ -251,138 +129,21 @@ class TestHmacSha(unittest.TestCase): assert self.hash.hexdigest() == copy.hexdigest() == self.digest -class TestHmacSha256(unittest.TestCase): - digest = "4b641d721493d80f019d9447830ebfee89234a7d594378b89f8bb73873576bf6" +class TestHmacSha256(TestHmacSha): + _class = HmacSha256 + digest = t2b("4b641d721493d80f019d9447830ebfee" \ + + "89234a7d594378b89f8bb73873576bf6") - def setUp(self): - self.hash = HmacSha256.new(_HMAC_KEY) +class TestHmacSha384(TestHmacSha): + _class = HmacSha384 + digest = t2b("e72c72070c9c5c78e3286593068a510c1740cdf9dc34b512" \ + + "ccec97320295db1fe673216b46fe72e81f399a9ec04780ab") - def test_new(self): - # invalid construction - self.assertRaises(ValueError, HmacSha256) - - # update inside constructor - assert HmacSha256.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest - - - def test_hash_update_001(self): - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_update_002(self): - self.hash.update("wolf") - self.hash.update("crypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_copy(self): - copy = self.hash.copy() - - assert self.hash.hexdigest() == copy.hexdigest() - - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() != copy.hexdigest() - - copy.update("wolfcrypt") - - assert self.hash.hexdigest() == copy.hexdigest() == self.digest - - -class TestHmacSha384(unittest.TestCase): - digest = "e72c72070c9c5c78e3286593068a510c1740cdf9dc34b512" \ - + "ccec97320295db1fe673216b46fe72e81f399a9ec04780ab" - - - def setUp(self): - self.hash = HmacSha384.new(_HMAC_KEY) - - - def test_new(self): - # invalid construction - self.assertRaises(ValueError, HmacSha384) - - # update inside constructor - assert HmacSha384.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest - - - def test_hash_update_001(self): - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_update_002(self): - self.hash.update("wolf") - self.hash.update("crypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_copy(self): - copy = self.hash.copy() - - assert self.hash.hexdigest() == copy.hexdigest() - - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() != copy.hexdigest() - - copy.update("wolfcrypt") - - assert self.hash.hexdigest() == copy.hexdigest() == self.digest - - -class TestHmacSha512(unittest.TestCase): - digest = "c7f48db79314fc2b5be9a93fd58601a1bf42f397ec7f66dba034d44503890e6b"\ - + "5708242dcd71a248a78162d815c685f6038a4ac8cb34b8bf18986dbd300c9b41" - - - def setUp(self): - self.hash = HmacSha512.new(_HMAC_KEY) - - - def test_new(self): - # invalid construction - self.assertRaises(ValueError, HmacSha512) - - # update inside constructor - assert HmacSha512.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest - - - def test_hash_update_001(self): - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_update_002(self): - self.hash.update("wolf") - self.hash.update("crypt") - - assert self.hash.hexdigest() == self.digest - assert self.hash.digest() == self.digest.decode("hex") - - - def test_hash_copy(self): - copy = self.hash.copy() - - assert self.hash.hexdigest() == copy.hexdigest() - - self.hash.update("wolfcrypt") - - assert self.hash.hexdigest() != copy.hexdigest() - - copy.update("wolfcrypt") - - assert self.hash.hexdigest() == copy.hexdigest() == self.digest +class TestHmacSha512(TestHmacSha): + _class = HmacSha512 + digest = t2b("c7f48db79314fc2b5be9a93fd58601a1" \ + + "bf42f397ec7f66dba034d44503890e6b" \ + + "5708242dcd71a248a78162d815c685f6" \ + + "038a4ac8cb34b8bf18986dbd300c9b41") diff --git a/wrapper/python/tox.ini b/wrapper/python/tox.ini index c8778e414..20d93e22f 100644 --- a/wrapper/python/tox.ini +++ b/wrapper/python/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27 +envlist=py26,py27,py35 [testenv] deps=-rrequirements-testing.txt diff --git a/wrapper/python/wolfcrypt/__init__.py b/wrapper/python/wolfcrypt/__init__.py index 498cd8902..907791ff7 100644 --- a/wrapper/python/wolfcrypt/__init__.py +++ b/wrapper/python/wolfcrypt/__init__.py @@ -1,4 +1,4 @@ -# WolfCrypt +# __init__.py # # Copyright (C) 2006-2016 wolfSSL Inc. # diff --git a/wrapper/python/wolfcrypt/about.py b/wrapper/python/wolfcrypt/about.py new file mode 100644 index 000000000..2d8017e91 --- /dev/null +++ b/wrapper/python/wolfcrypt/about.py @@ -0,0 +1,58 @@ +# __about__.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 + +metadata = dict( + __name__ = "wolfcrypt", + __version__ = "0.1.0", + __author__ = "wolfSSL Inc.", + __email__ = "info@wolfssl.com", + __url__ = "https://wolfssl.github.io/wolfcrypt-py", + __summary__ = "A Python library that encapsulates wolfSSL's wolfCrypt API", + __keywords__ = """ + cryptography, aes, des3, rsa, sha, sha256, sha384, sha512, hmac, random + """, + __license__ = """ + wolfSSL’s software is available under two distinct licensing models: + open source and standard commercial licensing. Please see the relevant + section below for information on each type of license. + + Open Source + + wolfSSL (formerly CyaSSL), yaSSL, wolfCrypt, yaSSH and TaoCrypt software + are free software downloads and may be modified to the needs of the user + as long as the user adheres to version two of the GPL License. The GPLv2 + license can be found on the gnu.org website: + http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + + Commercial Licensing + + Businesses and enterprises who wish to incorporate wolfSSL products into + proprietary appliances or other commercial software products for + re-distribution must license commercial versions. Commercial licenses for + wolfSSL, yaSSL, and wolfCrypt are available for $5,000 USD per end product + or SKU. Licenses are generally issued for one product and include unlimited + royalty-free distribution. Custom licensing terms are also available. + """, + __copyright__ = "Copyright 2016 wolfSSL Inc. All rights reserved" +) + +globals().update(metadata) + +__all__ = metadata.keys() diff --git a/wrapper/python/wolfcrypt/build_ffi.py b/wrapper/python/wolfcrypt/build_ffi.py index 7d876751d..720e96cfc 100644 --- a/wrapper/python/wolfcrypt/build_ffi.py +++ b/wrapper/python/wolfcrypt/build_ffi.py @@ -1,4 +1,4 @@ -# build_random.py +# build_ffi.py # # Copyright (C) 2006-2016 wolfSSL Inc. # diff --git a/wrapper/python/wolfcrypt/ciphers.py b/wrapper/python/wolfcrypt/ciphers.py index 2aa69728c..4084e6bf7 100644 --- a/wrapper/python/wolfcrypt/ciphers.py +++ b/wrapper/python/wolfcrypt/ciphers.py @@ -17,10 +17,13 @@ # 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._ffi import ffi as _ffi -from wolfcrypt._ffi import lib as _lib +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib +from wolfcrypt.utils import t2b from wolfcrypt.random import Random +from wolfcrypt.exceptions import * + # key direction flags _ENCRYPTION = 0 @@ -38,24 +41,19 @@ _FEEDBACK_MODES = [MODE_ECB, MODE_CBC, MODE_CFB, MODE_OFB, MODE_CTR] class _Cipher(object): - # Magic object that protects against constructors. - _JAPANESE_CYBER_SWORD = object() - - - def __init__(self, token=""): - if token is not self._JAPANESE_CYBER_SWORD: - # PEP 272 -- API for Block Encryption Algorithms v1.0 - raise ValueError("don't construct directly, use new([string])") - - - @classmethod - def new(cls, key, mode, IV=None, **kwargs): + """ + A **PEP 272: Block Encryption Algorithms** compliant + **Symmetric Key Cipher**. + """ + def __init__(self, key, mode, IV=None): if mode not in _FEEDBACK_MODES: raise ValueError("this mode is not supported") - if mode != MODE_CBC: - raise ValueError("this mode is not supported by this cipher") - self = cls(_Cipher._JAPANESE_CYBER_SWORD) + if mode == MODE_CBC: + if IV is None: + raise ValueError("this mode requires an 'IV' string") + else: + raise ValueError("this mode is not supported by this cipher") if self.key_size: if self.key_size != len(key): @@ -71,46 +69,92 @@ class _Cipher(object): raise ValueError("IV must be %d in length" % self.block_size) self._native_object = _ffi.new(self._native_type) - self._enc = None self._dec = None - self._key = key - self._IV = IV if IV else "\0" * self.block_size + self._key = t2b(key) - return self + if IV: + self._IV = t2b(IV) + else: + self._IV = t2b("\0" * self.block_size) + + + @classmethod + def new(cls, key, mode, IV=None, **kwargs): + """ + Returns a ciphering object, using the secret key contained in + the string **key**, and using the feedback mode **mode**, which + must be one of MODE_* defined in this module. + + If **mode** is MODE_CBC or MODE_CFB, **IV** must be provided and + must be a string of the same length as the block size. Not + providing a value of **IV** will result in a ValueError exception + being raised. + """ + return cls(key, mode, IV) def encrypt(self, string): + """ + Encrypts a non-empty string, using the key-dependent data in + the object, and with the appropriate feedback mode. The + string's length must be an exact multiple of the algorithm's + block size or, in CFB mode, of the segment size. Returns a + string containing the ciphertext. + """ + string = t2b(string) + if not string or len(string) % self.block_size: raise ValueError( "string must be a multiple of %d in length" % self.block_size) if self._enc is None: self._enc = _ffi.new(self._native_type) - self._set_key(_ENCRYPTION) + ret = self._set_key(_ENCRYPTION) + if ret < 0: + raise WolfCryptError("Invalid key error (%d)" % ret) - result = "\0" * len(string) - self._encrypt(result, string) + result = t2b("\0" * len(string)) + ret = self._encrypt(result, string) + if ret < 0: + raise WolfCryptError("Encryption error (%d)" % ret) return result def decrypt(self, string): + """ + Decrypts **string**, using the key-dependent data in the + object and with the appropriate feedback mode. The string's + length must be an exact multiple of the algorithm's block + size or, in CFB mode, of the segment size. Returns a string + containing the plaintext. + """ + string = t2b(string) + if not string or len(string) % self.block_size: raise ValueError( "string must be a multiple of %d in length" % self.block_size) if self._dec is None: self._dec = _ffi.new(self._native_type) - self._set_key(_DECRYPTION) + ret = self._set_key(_DECRYPTION) + if ret < 0: + raise WolfCryptError("Invalid key error (%d)" % ret) - result = "\0" * len(string) - self._decrypt(result, string) + result = t2b("\0" * len(string)) + ret = self._decrypt(result, string) + if ret < 0: + raise WolfCryptError("Decryption error (%d)" % ret) return result class Aes(_Cipher): + """ + The **Advanced Encryption Standard** (AES), a.k.a. Rijndael, is + a symmetric-key cipher standardized by **NIST**. + """ block_size = 16 key_size = None # 16, 24, 32 _key_sizes = [16, 24, 32] @@ -119,22 +163,28 @@ class Aes(_Cipher): def _set_key(self, direction): if direction == _ENCRYPTION: - _lib.wc_AesSetKey( + return _lib.wc_AesSetKey( self._enc, self._key, len(self._key), self._IV, _ENCRYPTION) else: - _lib.wc_AesSetKey( + return _lib.wc_AesSetKey( self._dec, self._key, len(self._key), self._IV, _DECRYPTION) def _encrypt(self, destination, source): - _lib.wc_AesCbcEncrypt(self._enc, destination, source, len(source)) + return _lib.wc_AesCbcEncrypt(self._enc, destination, source,len(source)) def _decrypt(self, destination, source): - _lib.wc_AesCbcDecrypt(self._dec, destination, source, len(source)) + return _lib.wc_AesCbcDecrypt(self._dec, destination, source,len(source)) class Des3(_Cipher): + """ + **Triple DES** (3DES) is the common name for the **Triple Data + Encryption Algorithm** (TDEA or Triple DEA) symmetric-key block + cipher, which applies the **Data Encryption Standard** (DES) + cipher algorithm three times to each data block. + """ block_size = 8 key_size = 24 _native_type = "Des3 *" @@ -142,24 +192,27 @@ class Des3(_Cipher): def _set_key(self, direction): if direction == _ENCRYPTION: - _lib.wc_Des3_SetKey(self._enc, self._key, self._IV, _ENCRYPTION) + return _lib.wc_Des3_SetKey(self._enc,self._key,self._IV,_ENCRYPTION) else: - _lib.wc_Des3_SetKey(self._dec, self._key, self._IV, _DECRYPTION) + return _lib.wc_Des3_SetKey(self._dec,self._key,self._IV,_DECRYPTION) def _encrypt(self, destination, source): - _lib.wc_Des3_CbcEncrypt(self._enc, destination, source, len(source)) + return _lib.wc_Des3_CbcEncrypt(self._enc,destination,source,len(source)) def _decrypt(self, destination, source): - _lib.wc_Des3_CbcDecrypt(self._dec, destination, source, len(source)) + return _lib.wc_Des3_CbcDecrypt(self._dec,destination,source,len(source)) class _Rsa(object): + RSA_MIN_PAD_SIZE = 11 + def __init__(self): self.native_object = _ffi.new("RsaKey *") - if _lib.wc_InitRsaKey(self.native_object, _ffi.NULL) != 0: - raise KeyError + ret = _lib.wc_InitRsaKey(self.native_object, _ffi.NULL) + if ret < 0: + raise WolfCryptError("Invalid key error (%d)" % ret) self._random = Random() @@ -171,22 +224,34 @@ class _Rsa(object): class RsaPublic(_Rsa): def __init__(self, key): + key = t2b(key) + _Rsa.__init__(self) idx = _ffi.new("word32*") idx[0] = 0 - if _lib.wc_RsaPublicKeyDecode(key, idx, self.native_object, len(key)): - raise KeyError + ret = _lib.wc_RsaPublicKeyDecode(key, idx, self.native_object, len(key)) + if ret < 0: + raise WolfCryptError("Invalid key error (%d)" % ret) self.output_size = _lib.wc_RsaEncryptSize(self.native_object) - if self.output_size <= 0: - raise KeyError + raise WolfCryptError("Invalid key error (%d)" % self.output_size) def encrypt(self, plaintext): - ciphertext = "\0" * self.output_size + """ + Encrypts **plaintext**, using the public key data in the + object. The plaintext's length must not be greater than: + + **self.output_size - self.RSA_MIN_PAD_SIZE** + + Returns a string containing the ciphertext. + """ + + plaintext = t2b(plaintext) + ciphertext = t2b("\0" * self.output_size) ret = _lib.wc_RsaPublicEncrypt(plaintext, len(plaintext), ciphertext, len(ciphertext), @@ -194,52 +259,84 @@ class RsaPublic(_Rsa): self._random.native_object) if ret != self.output_size: - raise KeyError + raise WolfCryptError("Encryption error (%d)" % ret) return ciphertext def verify(self, signature): - plaintext = "\0" * self.output_size + """ + Verifies **signature**, using the public key data in the + object. The signature's length must be equal to: + + **self.output_size** + + Returns a string containing the plaintext. + """ + signature = t2b(signature) + plaintext = t2b("\0" * self.output_size) ret = _lib.wc_RsaSSL_Verify(signature, len(signature), plaintext, len(plaintext), self.native_object) if ret < 0: - raise KeyError + raise WolfCryptError("Verify error (%d)" % ret) return plaintext[:ret] class RsaPrivate(RsaPublic): def __init__(self, key): + key = t2b(key) + _Rsa.__init__(self) idx = _ffi.new("word32*") idx[0] = 0 - if _lib.wc_RsaPrivateKeyDecode(key, idx, self.native_object, len(key)): - raise KeyError + ret = _lib.wc_RsaPrivateKeyDecode(key, idx, self.native_object,len(key)) + if ret < 0: + raise WolfCryptError("Invalid key error (%d)" % ret) self.output_size = _lib.wc_RsaEncryptSize(self.native_object) + if self.output_size <= 0: + raise WolfCryptError("Invalid key error (%d)" % self.output_size) def decrypt(self, ciphertext): - plaintext = "\0" * self.output_size + """ + Decrypts **ciphertext**, using the private key data in the + object. The ciphertext's length must be equal to: + + **self.output_size** + + Returns a string containing the plaintext. + """ + ciphertext = t2b(ciphertext) + plaintext = t2b("\0" * self.output_size) ret = _lib.wc_RsaPrivateDecrypt(ciphertext, len(ciphertext), plaintext, len(plaintext), self.native_object) if ret < 0: - raise KeyError + raise WolfCryptError("Decryption error (%d)" % ret) return plaintext[:ret] def sign(self, plaintext): - signature = "\0" * self.output_size + """ + Signs **plaintext**, using the private key data in the object. + The plaintext's length must not be greater than: + + **self.output_size - self.RSA_MIN_PAD_SIZE** + + Returns a string containing the signature. + """ + plaintext = t2b(plaintext) + signature = t2b("\0" * self.output_size) ret = _lib.wc_RsaSSL_Sign(plaintext, len(plaintext), signature, len(signature), @@ -247,6 +344,6 @@ class RsaPrivate(RsaPublic): self._random.native_object) if ret != self.output_size: - raise KeyError + raise WolfCryptError("Signature error (%d)" % ret) return signature diff --git a/wrapper/python/wolfcrypt/exceptions.py b/wrapper/python/wolfcrypt/exceptions.py new file mode 100644 index 000000000..838a2b2b0 --- /dev/null +++ b/wrapper/python/wolfcrypt/exceptions.py @@ -0,0 +1,23 @@ +# exceptions.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 + + +class WolfCryptError(Exception): + pass diff --git a/wrapper/python/wolfcrypt/hashes.py b/wrapper/python/wolfcrypt/hashes.py index 18c0b54b3..816f205cc 100644 --- a/wrapper/python/wolfcrypt/hashes.py +++ b/wrapper/python/wolfcrypt/hashes.py @@ -17,36 +17,43 @@ # 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._ffi import ffi as _ffi -from wolfcrypt._ffi import lib as _lib +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib +from wolfcrypt.utils import t2b, b2h +from wolfcrypt.exceptions import * class _Hash(object): - # Magic object that protects against constructors. - _JAPANESE_CYBER_SWORD = object() + """ + A **PEP 247: Cryptographic Hash Functions** compliant + **Hash Function Interface**. + """ + def __init__(self, string=None): + self._native_object = _ffi.new(self._native_type) + ret = self._init() + if ret < 0: + raise WolfCryptError("Hash init error (%d)" % ret) - - def __init__(self, token=""): - if token is not self._JAPANESE_CYBER_SWORD: - # PEP 247 -- API for Cryptographic Hash Functions - raise ValueError("don't construct directly, use new([string])") + if (string): + self.update(string) @classmethod def new(cls, string=None): - self = cls(cls._JAPANESE_CYBER_SWORD) - - self._native_object = _ffi.new(self._native_type) - - self._init() - - if (string): - self._update(string) - - return self + """ + Creates a new hashing object and returns it. The optional + **string** parameter, if supplied, will be immediately + hashed into the object's starting state, as if + obj.update(string) was called. + """ + return cls(string) def copy(self): + """ + Returns a separate copy of this hashing object. An update + to this copy won't affect the original object. + """ copy = self.new("") _ffi.memmove(copy._native_object, @@ -57,96 +64,142 @@ class _Hash(object): def update(self, string): - self._update(string) + """ + Hashes **string** into the current state of the hashing + object. update() can be called any number of times during + a hashing object's lifetime. + """ + string = t2b(string) + + ret = self._update(string) + if ret < 0: + raise WolfCryptError("Hash update error (%d)" % ret) def digest(self): - ret = "\0" * self.digest_size + """ + Returns the hash value of this hashing object as a string + containing 8-bit data. The object is not altered in any + way by this function; you can continue updating the object + after calling this function. + """ + result = t2b("\0" * self.digest_size) if self._native_object: obj = _ffi.new(self._native_type) _ffi.memmove(obj, self._native_object, self._native_size) - self._final(obj, ret) + ret = self._final(obj, result) + if ret < 0: + raise WolfCryptError("Hash finalize error (%d)" % ret) - return ret + return result def hexdigest(self): - return self.digest().encode("hex") + """ + Returns the hash value of this hashing object as a string + containing hexadecimal digits. Lowercase letters are used + for the digits 'a' through 'f'. Like the .digest() method, + this method doesn't alter the object. + """ + return b2h(self.digest()) class Sha(_Hash): + """ + **SHA-1** is a cryptographic hash function standardized by **NIST**. + + It produces an [ **160-bit | 20 bytes** ] message digest. + """ digest_size = 20 _native_type = "Sha *" _native_size = _ffi.sizeof("Sha") def _init(self): - _lib.wc_InitSha(self._native_object) + return _lib.wc_InitSha(self._native_object) def _update(self, data): - _lib.wc_ShaUpdate(self._native_object, data, len(data)) + return _lib.wc_ShaUpdate(self._native_object, data, len(data)) def _final(self, obj, ret): - _lib.wc_ShaFinal(obj, ret) + return _lib.wc_ShaFinal(obj, ret) class Sha256(_Hash): + """ + **SHA-256** is a cryptographic hash function from the + **SHA-2 family** and is standardized by **NIST**. + + It produces a [ **256-bit | 32 bytes** ] message digest. + """ digest_size = 32 _native_type = "Sha256 *" _native_size = _ffi.sizeof("Sha256") def _init(self): - _lib.wc_InitSha256(self._native_object) + return _lib.wc_InitSha256(self._native_object) def _update(self, data): - _lib.wc_Sha256Update(self._native_object, data, len(data)) + return _lib.wc_Sha256Update(self._native_object, data, len(data)) def _final(self, obj, ret): - _lib.wc_Sha256Final(obj, ret) + return _lib.wc_Sha256Final(obj, ret) class Sha384(_Hash): + """ + **SHA-384** is a cryptographic hash function from the + **SHA-2 family** and is standardized by **NIST**. + + It produces a [ **384-bit | 48 bytes** ] message digest. + """ digest_size = 48 _native_type = "Sha384 *" _native_size = _ffi.sizeof("Sha384") def _init(self): - _lib.wc_InitSha384(self._native_object) + return _lib.wc_InitSha384(self._native_object) def _update(self, data): - _lib.wc_Sha384Update(self._native_object, data, len(data)) + return _lib.wc_Sha384Update(self._native_object, data, len(data)) def _final(self, obj, ret): - _lib.wc_Sha384Final(obj, ret) + return _lib.wc_Sha384Final(obj, ret) class Sha512(_Hash): + """ + **SHA-512** is a cryptographic hash function from the + **SHA-2 family** and is standardized by **NIST**. + + It produces a [ **512-bit | 64 bytes** ] message digest. + """ digest_size = 64 _native_type = "Sha512 *" _native_size = _ffi.sizeof("Sha512") def _init(self): - _lib.wc_InitSha512(self._native_object) + return _lib.wc_InitSha512(self._native_object) def _update(self, data): - _lib.wc_Sha512Update(self._native_object, data, len(data)) + return _lib.wc_Sha512Update(self._native_object, data, len(data)) def _final(self, obj, ret): - _lib.wc_Sha512Final(obj, ret) + return _lib.wc_Sha512Final(obj, ret) # Hmac types @@ -159,52 +212,91 @@ _HMAC_TYPES = [_TYPE_SHA, _TYPE_SHA256, _TYPE_SHA384, _TYPE_SHA512] class _Hmac(_Hash): + """ + A **PEP 247: Cryptographic Hash Functions** compliant + **Keyed Hash Function Interface**. + """ digest_size = None _native_type = "Hmac *" _native_size = _ffi.sizeof("Hmac") - @classmethod - def new(cls, key, string=None): - self = cls(cls._JAPANESE_CYBER_SWORD) + def __init__(self, key, string=None): + key = t2b(key) self._native_object = _ffi.new(self._native_type) - - self._init(self._type, key) + ret = self._init(self._type, key) + if ret < 0: + raise WolfCryptError("Hmac init error (%d)" % ret) if (string): - self._update(string) + self.update(string) - return self + + + @classmethod + def new(cls, key, string=None): + """ + Creates a new hashing object and returns it. **key** is + a required parameter containing a string giving the key + to use. The optional **string** parameter, if supplied, + will be immediately hashed into the object's starting + state, as if obj.update(string) was called. + """ + return cls(key, string) def _init(self, type, key): - _lib.wc_HmacSetKey(self._native_object, type, key, len(key)) + return _lib.wc_HmacSetKey(self._native_object, type, key, len(key)) def _update(self, data): - _lib.wc_HmacUpdate(self._native_object, data, len(data)) + return _lib.wc_HmacUpdate(self._native_object, data, len(data)) def _final(self, obj, ret): - _lib.wc_HmacFinal(obj, ret) + return _lib.wc_HmacFinal(obj, ret) class HmacSha(_Hmac): + """ + A HMAC function using **SHA-1** as it's cryptographic + hash function. + + It produces a [ **512-bit | 64 bytes** ] message digest. + """ _type = _TYPE_SHA digest_size = Sha.digest_size class HmacSha256(_Hmac): + """ + A HMAC function using **SHA-256** as it's cryptographic + hash function. + + It produces a [ **512-bit | 64 bytes** ] message digest. + """ _type = _TYPE_SHA256 digest_size = Sha256.digest_size class HmacSha384(_Hmac): + """ + A HMAC function using **SHA-384** as it's cryptographic + hash function. + + It produces a [ **512-bit | 64 bytes** ] message digest. + """ _type = _TYPE_SHA384 digest_size = Sha384.digest_size class HmacSha512(_Hmac): + """ + A HMAC function using **SHA-512** as it's cryptographic + hash function. + + It produces a [ **512-bit | 64 bytes** ] message digest. + """ _type = _TYPE_SHA512 digest_size = Sha512.digest_size diff --git a/wrapper/python/wolfcrypt/random.py b/wrapper/python/wolfcrypt/random.py index 047b75856..f819f51d8 100644 --- a/wrapper/python/wolfcrypt/random.py +++ b/wrapper/python/wolfcrypt/random.py @@ -17,15 +17,24 @@ # 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._ffi import ffi as _ffi -from wolfcrypt._ffi import lib as _lib +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib +from wolfcrypt.utils import t2b + +from wolfcrypt.exceptions import * class Random(object): + """ + A Cryptographically Secure Pseudo Random Number Generator - CSPRNG + """ def __init__(self): self.native_object = _ffi.new("WC_RNG *") - if _lib.wc_InitRng(self.native_object) != 0: + + ret = _lib.wc_InitRng(self.native_object) + if ret < 0: self.native_object = None + raise WolfCryptError("RNG init error (%d)" % ret) def __del__(self): @@ -34,16 +43,26 @@ class Random(object): def byte(self): - ret = "\0" + """ + Generate and return a random byte. + """ + result = t2b("\0") - _lib.wc_RNG_GenerateByte(self.native_object, ret) + ret = _lib.wc_RNG_GenerateByte(self.native_object, result) + if ret < 0: + raise WolfCryptError("RNG generate byte error (%d)" % ret) - return ret + return result def bytes(self, length): - ret = "\0" * length + """ + Generate and return a random sequence of length bytes. + """ + result = t2b("\0" * length) - _lib.wc_RNG_GenerateBlock(self.native_object, ret, length) + ret = _lib.wc_RNG_GenerateBlock(self.native_object, result, length) + if ret < 0: + raise WolfCryptError("RNG generate block error (%d)" % ret) - return ret + return result diff --git a/wrapper/python/wolfcrypt/utils.py b/wrapper/python/wolfcrypt/utils.py new file mode 100644 index 000000000..34646ff8a --- /dev/null +++ b/wrapper/python/wolfcrypt/utils.py @@ -0,0 +1,38 @@ +# utils.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 sys +from binascii import hexlify as b2h, unhexlify as h2b + + +if sys.version_info[0] == 3: + _text_type = str + _binary_type = bytes +else: + _text_type = unicode + _binary_type = str + + +def t2b(s): + """ + Converts text to bynary. + """ + if isinstance(s, _binary_type): + return s + return _text_type(s).encode("utf-8") From 9e9fd24d68edf0db668112599e40280a0bab8e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Wed, 4 May 2016 21:38:27 -0300 Subject: [PATCH 07/24] updates metadata; drops py26 tests --- wrapper/python/LICENSING.rst | 30 ++++++++++++++++++++++++++++++ wrapper/python/MANIFEST.in | 1 + wrapper/python/README.rst | 14 +++----------- wrapper/python/tox.ini | 2 +- 4 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 wrapper/python/LICENSING.rst create mode 100644 wrapper/python/MANIFEST.in diff --git a/wrapper/python/LICENSING.rst b/wrapper/python/LICENSING.rst new file mode 100644 index 000000000..d04a7880f --- /dev/null +++ b/wrapper/python/LICENSING.rst @@ -0,0 +1,30 @@ +Licensing +========= + +wolfSSL’s software is available under two distinct licensing models: +open source and standard commercial licensing. Please see the relevant +section below for information on each type of license. + +Open Source +----------- + +wolfSSL (formerly CyaSSL), yaSSL, wolfCrypt, yaSSH and TaoCrypt software +are free software downloads and may be modified to the needs of the user +as long as the user adheres to version two of the GPL License. The GPLv2 +license can be found on the gnu.org website: + + http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + +Commercial Licensing +-------------------- + +Businesses and enterprises who wish to incorporate wolfSSL products into +proprietary appliances or other commercial software products for +re-distribution must license commercial versions. Commercial licenses for +wolfSSL, yaSSL, and wolfCrypt are available for $5,000 USD per end product +or SKU. Licenses are generally issued for one product and include unlimited +royalty-free distribution. Custom licensing terms are also available. + + Email: licensing@wolfssl.com + + Phone: +1 425 245-8247 diff --git a/wrapper/python/MANIFEST.in b/wrapper/python/MANIFEST.in new file mode 100644 index 000000000..3c56fcf44 --- /dev/null +++ b/wrapper/python/MANIFEST.in @@ -0,0 +1 @@ +include LICENSING.rst diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 23e9d1f78..5b9a16dc6 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -44,16 +44,8 @@ A Python library that encapsulates wolfSSL's wolfCrypt API py35: commands succeeded congratulations :) -Licensing -========= + +.. include:: LICENSING.rst -wolfSSL (formerly known as CyaSSL) and wolfCrypt are either licensed for use -under the GPLv2 or a standard commercial license. For our users who cannot use -wolfSSL under GPLv2, a commercial license to wolfSSL and wolfCrypt is available. -Please contact wolfSSL Inc. directly at: - -Email: licensing@wolfssl.com -Phone: +1 425 245-8247 - -More information can be found on the `wolfSSL website `_. +Copyright 2016 wolfSSL Inc. All rights reserved. diff --git a/wrapper/python/tox.ini b/wrapper/python/tox.ini index 20d93e22f..9cb8be548 100644 --- a/wrapper/python/tox.ini +++ b/wrapper/python/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py26,py27,py35 +envlist=py27,py35 [testenv] deps=-rrequirements-testing.txt From b0c23ceafa56fe4a4c309e0048601613a4fda734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Thu, 5 May 2016 12:48:47 -0300 Subject: [PATCH 08/24] fixes about --- wrapper/python/docs/conf.py | 2 +- wrapper/python/requirements-testing.txt | 1 + wrapper/python/setup.py | 71 ++++++++++++++++++------- wrapper/python/wolfcrypt/__about__.py | 36 +++++++++++++ wrapper/python/wolfcrypt/__init__.py | 2 +- wrapper/python/wolfcrypt/about.py | 58 -------------------- 6 files changed, 90 insertions(+), 80 deletions(-) create mode 100644 wrapper/python/wolfcrypt/__about__.py delete mode 100644 wrapper/python/wolfcrypt/about.py diff --git a/wrapper/python/docs/conf.py b/wrapper/python/docs/conf.py index b9d4b4a8c..3e9de701c 100644 --- a/wrapper/python/docs/conf.py +++ b/wrapper/python/docs/conf.py @@ -63,7 +63,7 @@ author = u'wolfSSL' base_dir = os.path.join(os.path.dirname(__file__), os.pardir) about = {} -with open(os.path.join(base_dir, "wolfcrypt", "about.py")) as f: +with open(os.path.join(base_dir, "wolfcrypt", "__about__.py")) as f: exec(f.read(), about) version = release = about["__version__"] diff --git a/wrapper/python/requirements-testing.txt b/wrapper/python/requirements-testing.txt index 61def5278..31b7985c1 100644 --- a/wrapper/python/requirements-testing.txt +++ b/wrapper/python/requirements-testing.txt @@ -1,3 +1,4 @@ pytest>=2.9.1 cffi>=1.6.0 tox>=2.3.1 +about>=5.2 diff --git a/wrapper/python/setup.py b/wrapper/python/setup.py index 35260d529..0794a2020 100755 --- a/wrapper/python/setup.py +++ b/wrapper/python/setup.py @@ -1,30 +1,61 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# +# 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 +# Python 2.7 Standard Library +from __future__ import absolute_import import os import sys - +import wolfcrypt from setuptools import setup, find_packages +try: + import about +except ImportError: + error = "about is not installed, refer to <{url}> for instructions." + raise ImportError(error.format(url="https://pypi.io/project/about/")) + os.chdir(os.path.dirname(sys.argv[0]) or ".") -setup( - name="wolfcrypt", - version="0.1.0", - description="A Python wrapper that encapsulates wolfSSL's wolfCrypt API", - long_description=open("README.rst", "rt").read(), - url="https://wolfssl.github.io/wolfcrypt-py", - author="wolfSSL", - author_email="info@wolfssl.com", - classifiers=[ - "Development Status :: 0 - Alpha", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: Implementation :: PyPy", - "License :: GPLv2 License :: Commercial License", - ], - packages=find_packages(), - setup_requires=["cffi>=1.6.0"], - install_requires=["cffi>=1.6.0"], - cffi_modules=["./wolfcrypt/build_ffi.py:ffi"] +long_description = open("README.rst", "rt").read().replace( + ".. include:: LICENSING.rst\n", + open("LICENSING.rst", "rt").read() ) + +info = dict( + metadata = about.get_metadata(wolfcrypt), + contents = { + "long_description": long_description, + "package_data": {"": ["*.txt"]}, + "packages": find_packages(), + "cffi_modules": ["./wolfcrypt/build_ffi.py:ffi"], + }, + requirements = { + "setup_requires": ["cffi>=1.6.0", "about>=5.2"], + "install_requires": ["cffi>=1.6.0", "about>=5.2"], + }, + scripts = {}, + plugins = {}, + tests = {}, +) + +if __name__ == "__main__": + kwargs = {k:v for dct in info.values() for (k,v) in dct.items()} + setup(**kwargs) diff --git a/wrapper/python/wolfcrypt/__about__.py b/wrapper/python/wolfcrypt/__about__.py new file mode 100644 index 000000000..68590bf28 --- /dev/null +++ b/wrapper/python/wolfcrypt/__about__.py @@ -0,0 +1,36 @@ +# __about__.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 + +metadata = dict( + __name__ = "wolfcrypt", + __version__ = "0.1.5", + __license__ = """GPLv2 or Commercial License""", + __author__ = "wolfSSL Inc. ", + __url__ = "https://wolfssl.github.io/wolfcrypt-py", + __summary__ = "A Python library that encapsulates wolfSSL's wolfCrypt API.", + __keywords__ = """ + OS independent, Python / 2.7, Python / 3.5, software development, + security, cryptography, Proprietary, GPLv2 + """, +) + +globals().update(metadata) + +__all__ = list(metadata.keys()) diff --git a/wrapper/python/wolfcrypt/__init__.py b/wrapper/python/wolfcrypt/__init__.py index 907791ff7..562fb1275 100644 --- a/wrapper/python/wolfcrypt/__init__.py +++ b/wrapper/python/wolfcrypt/__init__.py @@ -18,4 +18,4 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -# dummy file +from .__about__ import * diff --git a/wrapper/python/wolfcrypt/about.py b/wrapper/python/wolfcrypt/about.py deleted file mode 100644 index 2d8017e91..000000000 --- a/wrapper/python/wolfcrypt/about.py +++ /dev/null @@ -1,58 +0,0 @@ -# __about__.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 - -metadata = dict( - __name__ = "wolfcrypt", - __version__ = "0.1.0", - __author__ = "wolfSSL Inc.", - __email__ = "info@wolfssl.com", - __url__ = "https://wolfssl.github.io/wolfcrypt-py", - __summary__ = "A Python library that encapsulates wolfSSL's wolfCrypt API", - __keywords__ = """ - cryptography, aes, des3, rsa, sha, sha256, sha384, sha512, hmac, random - """, - __license__ = """ - wolfSSL’s software is available under two distinct licensing models: - open source and standard commercial licensing. Please see the relevant - section below for information on each type of license. - - Open Source - - wolfSSL (formerly CyaSSL), yaSSL, wolfCrypt, yaSSH and TaoCrypt software - are free software downloads and may be modified to the needs of the user - as long as the user adheres to version two of the GPL License. The GPLv2 - license can be found on the gnu.org website: - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Commercial Licensing - - Businesses and enterprises who wish to incorporate wolfSSL products into - proprietary appliances or other commercial software products for - re-distribution must license commercial versions. Commercial licenses for - wolfSSL, yaSSL, and wolfCrypt are available for $5,000 USD per end product - or SKU. Licenses are generally issued for one product and include unlimited - royalty-free distribution. Custom licensing terms are also available. - """, - __copyright__ = "Copyright 2016 wolfSSL Inc. All rights reserved" -) - -globals().update(metadata) - -__all__ = metadata.keys() From 412141198e2962708379fa7d6053734a57b60628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 9 May 2016 15:18:35 -0300 Subject: [PATCH 09/24] drops 'import about' requirement --- wrapper/python/setup.py | 14 ++++--------- wrapper/python/wolfcrypt/__about__.py | 29 ++++++++++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/wrapper/python/setup.py b/wrapper/python/setup.py index 0794a2020..1eeaed17e 100755 --- a/wrapper/python/setup.py +++ b/wrapper/python/setup.py @@ -23,15 +23,9 @@ from __future__ import absolute_import import os import sys -import wolfcrypt +from wolfcrypt.__about__ import metadata from setuptools import setup, find_packages -try: - import about -except ImportError: - error = "about is not installed, refer to <{url}> for instructions." - raise ImportError(error.format(url="https://pypi.io/project/about/")) - os.chdir(os.path.dirname(sys.argv[0]) or ".") long_description = open("README.rst", "rt").read().replace( @@ -40,7 +34,7 @@ long_description = open("README.rst", "rt").read().replace( ) info = dict( - metadata = about.get_metadata(wolfcrypt), + metadata = {k[2:-2]: metadata[k] for k in metadata}, contents = { "long_description": long_description, "package_data": {"": ["*.txt"]}, @@ -48,8 +42,8 @@ info = dict( "cffi_modules": ["./wolfcrypt/build_ffi.py:ffi"], }, requirements = { - "setup_requires": ["cffi>=1.6.0", "about>=5.2"], - "install_requires": ["cffi>=1.6.0", "about>=5.2"], + "setup_requires": ["cffi>=1.6.0"], + "install_requires": ["cffi>=1.6.0"], }, scripts = {}, plugins = {}, diff --git a/wrapper/python/wolfcrypt/__about__.py b/wrapper/python/wolfcrypt/__about__.py index 68590bf28..d94ce1926 100644 --- a/wrapper/python/wolfcrypt/__about__.py +++ b/wrapper/python/wolfcrypt/__about__.py @@ -19,16 +19,25 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA metadata = dict( - __name__ = "wolfcrypt", - __version__ = "0.1.5", - __license__ = """GPLv2 or Commercial License""", - __author__ = "wolfSSL Inc. ", - __url__ = "https://wolfssl.github.io/wolfcrypt-py", - __summary__ = "A Python library that encapsulates wolfSSL's wolfCrypt API.", - __keywords__ = """ - OS independent, Python / 2.7, Python / 3.5, software development, - security, cryptography, Proprietary, GPLv2 - """, + __name__ = "wolfcrypt", + __version__ = "0.1.6", + __license__ = "GPLv2 or Commercial License", + __author__ = "wolfSSL Inc.", + __author_email__ = "info@wolfssl.com", + __url__ = "https://wolfssl.github.io/wolfcrypt-py", + __description__ = \ + u"A Python library that encapsulates wolfSSL's wolfCrypt API.", + __keywords__ = "security, cryptography", + __classifiers__ = [ + u"License :: OSI Approved :: GNU General Public License v2 (GPLv2)", + u"License :: Other/Proprietary License", + u"Operating System :: OS Independent", + u"Programming Language :: Python :: 2.7", + u"Programming Language :: Python :: 3.5", + u"Topic :: Security", + u"Topic :: Security :: Cryptography", + u"Topic :: Software Development" + ] ) globals().update(metadata) From 9659505260e1d69c66bafccc17bbf8be205d8687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 9 May 2016 18:46:01 -0300 Subject: [PATCH 10/24] updates python docs --- wrapper/python/LICENSING.rst | 27 +++++------- wrapper/python/README.rst | 77 ++++++++++++++++++++++++++++------- wrapper/python/docs/index.rst | 35 +--------------- 3 files changed, 74 insertions(+), 65 deletions(-) diff --git a/wrapper/python/LICENSING.rst b/wrapper/python/LICENSING.rst index d04a7880f..a7f0f3727 100644 --- a/wrapper/python/LICENSING.rst +++ b/wrapper/python/LICENSING.rst @@ -1,30 +1,23 @@ Licensing -========= +--------- wolfSSL’s software is available under two distinct licensing models: open source and standard commercial licensing. Please see the relevant section below for information on each type of license. Open Source ------------ +~~~~~~~~~~~ -wolfSSL (formerly CyaSSL), yaSSL, wolfCrypt, yaSSH and TaoCrypt software -are free software downloads and may be modified to the needs of the user -as long as the user adheres to version two of the GPL License. The GPLv2 -license can be found on the gnu.org website: - - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +wolfCrypt and wolfSSL software are free software downloads and may be modified +to the needs of the user as long as the user adheres to version two of the GPL +License. The GPLv2 license can be found on the `gnu.org website +`_. Commercial Licensing --------------------- +~~~~~~~~~~~~~~~~~~~~ Businesses and enterprises who wish to incorporate wolfSSL products into proprietary appliances or other commercial software products for -re-distribution must license commercial versions. Commercial licenses for -wolfSSL, yaSSL, and wolfCrypt are available for $5,000 USD per end product -or SKU. Licenses are generally issued for one product and include unlimited -royalty-free distribution. Custom licensing terms are also available. - - Email: licensing@wolfssl.com - - Phone: +1 425 245-8247 +re-distribution must license commercial versions. Licenses are generally issued +for one product and include unlimited royalty-free distribution. Custom +licensing terms are also available at licensing@wolfssl.com. diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 5b9a16dc6..ea7cbfd1a 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -3,12 +3,25 @@ wolfcrypt: the wolfSSL Crypto Engine ==================================== +**wolfCrypt Python**, a.k.a. ``wolfcrypt`` is a Python library that encapsulates +**wolfSSL's wolfCrypt API**. -A Python library that encapsulates wolfSSL's wolfCrypt API +**wolfCrypt** is a lightweight, portable, C-language-based crypto library +targeted at IoT, embedded, and RTOS environments primarily because of its size, +speed, and feature set. It works seamlessly in desktop, enterprise, and cloud +environments as well. -1. Clone the repository and install wolfssl:: +Installation +------------ +You can install ``wolfcrypt`` via ``pip`` or ``source code``, but before +installing it, make sure you have ``wolfssl`` C library installed in your +machine. + +To install wolfssl do: + +.. code-block:: console $ git clone git@github.com:wolfssl/wolfssl.git $ cd wolfssl @@ -18,34 +31,68 @@ A Python library that encapsulates wolfSSL's wolfCrypt API $ sudo make install -2. Make sure that ``cffi``, ``py.test``, and ``tox`` are installed:: +wolfcrypt pip installation +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To install ``wolfcrypt`` with ``pip``: + +.. code-block:: console + + $ pip install wolfcrypt + +or if you need admin privileges to use ``pip``: + +.. code-block:: console + + $ sudo -H pip install wolfcrypt - $ cd wrappers/python - $ pip install -r requirements-testing.txt +wolfcrypt source installation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +To install ``wolfcrypt`` from sources: -3. Run ``python setup.py install`` to build and install wolfcrypt:: +1. Get the sources: +.. code-block:: console + + $ git clone git@github.com:wolfssl/wolfssl.git + $ cd wolfssl/wrappers/python + +2. Build and install ``wolfcrypt`` + +.. code-block:: console $ python setup.py install ... - Finished processing dependencies for wolfcrypt==0.1.0 + Finished processing dependencies for wolfcrypt... + +or if you need admin privileges to use the install command: + +.. code-block:: console + + $ sudo python setup.py install -4. Test locally with ``tox``:: +Testing +------- +Test ``wolfcrypt`` locally with ``tox``: + +1. Make sure that the testing requirements are installed: + +.. code-block:: console + + $ pip install -r requirements-testing.txt + + +2. Call ``tox``: + +.. code-block:: console $ tox ... _________________________________ summary _________________________________ - py26: commands succeeded py27: commands succeeded py35: commands succeeded congratulations :) - - -.. include:: LICENSING.rst - - -Copyright 2016 wolfSSL Inc. All rights reserved. diff --git a/wrapper/python/docs/index.rst b/wrapper/python/docs/index.rst index 9b796b186..efd3431a8 100644 --- a/wrapper/python/docs/index.rst +++ b/wrapper/python/docs/index.rst @@ -1,13 +1,4 @@ -wolfCrypt Python Documentation -================================== - -**wolfCrypt Python**, a.k.a. ``wolfcrypt`` is a Python library that encapsulates -**wolfSSL's wolfCrypt API**. - -**wolfCrypt** is a lightweight, portable, C-language-based crypto library -targeted at IoT, embedded, and RTOS environments primarily because of its size, -speed, and feature set. It works seamlessly in desktop, enterprise, and cloud -environments as well. +.. include:: ../README.rst Summary ------- @@ -21,26 +12,4 @@ Summary mac random -Licensing ---------- - -wolfSSL’s software is available under two distinct licensing models: -open source and standard commercial licensing. Please see the relevant -section below for information on each type of license. - -Open Source -~~~~~~~~~~~ - -wolfCrypt and wolfSSL software are free software downloads and may be modified -to the needs of the user as long as the user adheres to version two of the GPL -License. The GPLv2 license can be found on the `gnu.org website -`_. - -Commercial Licensing -~~~~~~~~~~~~~~~~~~~~ - -Businesses and enterprises who wish to incorporate wolfSSL products into -proprietary appliances or other commercial software products for -re-distribution must license commercial versions. Licenses are generally issued -for one product and include unlimited royalty-free distribution. Custom -licensing terms are also available at licensing@wolfssl.com. +.. include:: ../LICENSING.rst From d76d74d6c56f5ca033d7e5dd2bb863b76ab6619a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Sun, 15 May 2016 15:03:07 -0300 Subject: [PATCH 11/24] updates Linux deps on README --- Vagrantfile | 12 ++++++------ wrapper/include.am | 32 ++++++++++++++++++++++++++++++++ wrapper/python/README.rst | 18 ++++++++++++++++++ wrapper/python/tox.ini | 3 ++- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index ddf37ce83..ee7b4c49f 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -8,13 +8,13 @@ apt-get update apt-get install -y git autoconf libtool make valgrind libpq-dev -URL=https://sourceforge.net/projects/levent/files/libevent -LIB=libevent-2.0 -VER=22-stable +URL=https://github.com/libevent/libevent/releases/download/release +LIB=libevent +VER=2.0.22-stable -wget -q $URL/$LIB/$LIB.$VER.tar.gz && tar -zxf $LIB.$VER.tar.gz -cd $LIB.$VER/ && ./autogen.sh && ./configure -q && make -s -sudo make install && cd .. && rm -rf $LIB.$VER* +wget -q $URL-$VER/$LIB-$VER.tar.gz && tar -zxf $LIB-$VER.tar.gz +cd $LIB-$VER/ && ./autogen.sh && ./configure -q && make -s +sudo make install && cd .. && rm -rf $LIB-$VER* DST=wolfssl diff --git a/wrapper/include.am b/wrapper/include.am index bb61de307..6da65d42b 100644 --- a/wrapper/include.am +++ b/wrapper/include.am @@ -28,3 +28,35 @@ EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/Properties/Resources.Designer.cs EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/Properties/Resources.resx EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/wolfSSL.cs EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/wolfSSL_CSharp.csproj + +# wolfcrypt python wrapper files +EXTRA_DIST+= wrapper/python/docs +EXTRA_DIST+= wrapper/python/docs/_static +EXTRA_DIST+= wrapper/python/docs/_templates +EXTRA_DIST+= wrapper/python/docs/asymmetric.rst +EXTRA_DIST+= wrapper/python/docs/conf.py +EXTRA_DIST+= wrapper/python/docs/digest.rst +EXTRA_DIST+= wrapper/python/docs/index.rst +EXTRA_DIST+= wrapper/python/docs/mac.rst +EXTRA_DIST+= wrapper/python/docs/Makefile +EXTRA_DIST+= wrapper/python/docs/random.rst +EXTRA_DIST+= wrapper/python/docs/symmetric.rst +EXTRA_DIST+= wrapper/python/LICENSING.rst +EXTRA_DIST+= wrapper/python/MANIFEST.in +EXTRA_DIST+= wrapper/python/README.rst +EXTRA_DIST+= wrapper/python/requirements-testing.txt +EXTRA_DIST+= wrapper/python/setup.py +EXTRA_DIST+= wrapper/python/test +EXTRA_DIST+= wrapper/python/test/test_ciphers.py +EXTRA_DIST+= wrapper/python/test/test_hashes.py +EXTRA_DIST+= wrapper/python/test/test_random.py +EXTRA_DIST+= wrapper/python/tox.ini +EXTRA_DIST+= wrapper/python/wolfcrypt +EXTRA_DIST+= wrapper/python/wolfcrypt/__about__.py +EXTRA_DIST+= wrapper/python/wolfcrypt/__init__.py +EXTRA_DIST+= wrapper/python/wolfcrypt/build_ffi.py +EXTRA_DIST+= wrapper/python/wolfcrypt/ciphers.py +EXTRA_DIST+= wrapper/python/wolfcrypt/exceptions.py +EXTRA_DIST+= wrapper/python/wolfcrypt/hashes.py +EXTRA_DIST+= wrapper/python/wolfcrypt/random.py +EXTRA_DIST+= wrapper/python/wolfcrypt/utils.py diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index ea7cbfd1a..8e81382cc 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -19,6 +19,15 @@ You can install ``wolfcrypt`` via ``pip`` or ``source code``, but before installing it, make sure you have ``wolfssl`` C library installed in your machine. +**Linux ONLY:** Make sure you have ``python-dev``, ``python3-dev``, +``python-pip`` and ``libffi-dev`` installed: + +.. code-block:: console + + $ sudo apt-get update + $ sudo apt-get install python-dev python3-dev python-pip libffi-dev + + To install wolfssl do: .. code-block:: console @@ -30,6 +39,12 @@ To install wolfssl do: $ make $ sudo make install +**Linux ONLY:** Update your dynamic linker bindings with: + +.. code-block:: console + + $ sudo ldconfig + wolfcrypt pip installation ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -94,5 +109,8 @@ Test ``wolfcrypt`` locally with ``tox``: ... _________________________________ summary _________________________________ py27: commands succeeded + SKIPPED: py34: InterpreterNotFound: python3.4 py35: commands succeeded congratulations :) + +Note that some tests might be skipped if you don't have the proper interpreter. diff --git a/wrapper/python/tox.ini b/wrapper/python/tox.ini index 9cb8be548..98ec7f995 100644 --- a/wrapper/python/tox.ini +++ b/wrapper/python/tox.ini @@ -1,5 +1,6 @@ [tox] -envlist=py27,py35 +envlist=py27,py34,py35 +skip_missing_interpreters=true [testenv] deps=-rrequirements-testing.txt From 40cf30a13dc82115d616c2d49473819d4e7d8829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 16 May 2016 15:31:51 -0300 Subject: [PATCH 12/24] adds .gitignore to include.am --- wrapper/include.am | 1 + 1 file changed, 1 insertion(+) diff --git a/wrapper/include.am b/wrapper/include.am index 6da65d42b..30507fa66 100644 --- a/wrapper/include.am +++ b/wrapper/include.am @@ -30,6 +30,7 @@ EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/wolfSSL.cs EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/wolfSSL_CSharp.csproj # wolfcrypt python wrapper files +EXTRA_DIST+= wrapper/python/.gitignore EXTRA_DIST+= wrapper/python/docs EXTRA_DIST+= wrapper/python/docs/_static EXTRA_DIST+= wrapper/python/docs/_templates From 347d80e87901ad9f5bb099e6f1fb11c53da006d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 16 May 2016 15:49:32 -0300 Subject: [PATCH 13/24] removes folders from include.am --- wrapper/include.am | 3 --- 1 file changed, 3 deletions(-) diff --git a/wrapper/include.am b/wrapper/include.am index 30507fa66..ac9e3bba0 100644 --- a/wrapper/include.am +++ b/wrapper/include.am @@ -31,7 +31,6 @@ EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/wolfSSL_CSharp.csproj # wolfcrypt python wrapper files EXTRA_DIST+= wrapper/python/.gitignore -EXTRA_DIST+= wrapper/python/docs EXTRA_DIST+= wrapper/python/docs/_static EXTRA_DIST+= wrapper/python/docs/_templates EXTRA_DIST+= wrapper/python/docs/asymmetric.rst @@ -47,12 +46,10 @@ EXTRA_DIST+= wrapper/python/MANIFEST.in EXTRA_DIST+= wrapper/python/README.rst EXTRA_DIST+= wrapper/python/requirements-testing.txt EXTRA_DIST+= wrapper/python/setup.py -EXTRA_DIST+= wrapper/python/test EXTRA_DIST+= wrapper/python/test/test_ciphers.py EXTRA_DIST+= wrapper/python/test/test_hashes.py EXTRA_DIST+= wrapper/python/test/test_random.py EXTRA_DIST+= wrapper/python/tox.ini -EXTRA_DIST+= wrapper/python/wolfcrypt EXTRA_DIST+= wrapper/python/wolfcrypt/__about__.py EXTRA_DIST+= wrapper/python/wolfcrypt/__init__.py EXTRA_DIST+= wrapper/python/wolfcrypt/build_ffi.py From 2a0adc74a061faf69e4a690f035128e73d5ce17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 16 May 2016 20:13:26 -0300 Subject: [PATCH 14/24] fixes wrapper path --- wrapper/python/README.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 8e81382cc..491750131 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -45,6 +45,10 @@ To install wolfssl do: $ sudo ldconfig + # or + + $ export LD_LIBRARY_PATH=/usr/local/lib + wolfcrypt pip installation ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -72,7 +76,7 @@ To install ``wolfcrypt`` from sources: .. code-block:: console $ git clone git@github.com:wolfssl/wolfssl.git - $ cd wolfssl/wrappers/python + $ cd wolfssl/wrapper/python 2. Build and install ``wolfcrypt`` @@ -100,6 +104,12 @@ Test ``wolfcrypt`` locally with ``tox``: $ pip install -r requirements-testing.txt +or if you need admin privileges to use the install command: + +.. code-block:: console + + $ sudo -H pip install -r requirements-testing.txt + 2. Call ``tox``: From 2851f7d6a1731b9b06e90aaa7aeeff00855b1714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 16 May 2016 20:37:42 -0300 Subject: [PATCH 15/24] remove unnecessary dependency --- wrapper/python/requirements-testing.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/wrapper/python/requirements-testing.txt b/wrapper/python/requirements-testing.txt index 31b7985c1..61def5278 100644 --- a/wrapper/python/requirements-testing.txt +++ b/wrapper/python/requirements-testing.txt @@ -1,4 +1,3 @@ pytest>=2.9.1 cffi>=1.6.0 tox>=2.3.1 -about>=5.2 From dc080694b42ebd64521b5f380f8a5a2a40185241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 16 May 2016 21:55:31 -0300 Subject: [PATCH 16/24] reorder installation steps --- wrapper/python/README.rst | 94 +++++++++++++++------------------------ 1 file changed, 37 insertions(+), 57 deletions(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 491750131..0644487ed 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -15,20 +15,11 @@ environments as well. Installation ------------ -You can install ``wolfcrypt`` via ``pip`` or ``source code``, but before -installing it, make sure you have ``wolfssl`` C library installed in your -machine. +Dependencies +~~~~~~~~~~~~ -**Linux ONLY:** Make sure you have ``python-dev``, ``python3-dev``, -``python-pip`` and ``libffi-dev`` installed: - -.. code-block:: console - - $ sudo apt-get update - $ sudo apt-get install python-dev python3-dev python-pip libffi-dev - - -To install wolfssl do: +Before installing ``wolfcrypt``, make sure you have ``wolfssl`` C library +installed in your machine: .. code-block:: console @@ -39,28 +30,31 @@ To install wolfssl do: $ make $ sudo make install -**Linux ONLY:** Update your dynamic linker bindings with: +**Linux ONLY:** Update your dynamic linker: .. code-block:: console $ sudo ldconfig - # or - $ export LD_LIBRARY_PATH=/usr/local/lib +**Linux ONLY:** Make sure you have ``python-dev``, ``python3-dev``, +``python-pip`` and ``libffi-dev`` installed: + +.. code-block:: console + + $ sudo apt-get update + $ sudo apt-get install python-dev python3-dev python-pip libffi-dev + + +Now, you can install ``wolfcrypt`` via ``pip`` or ``source code``: + wolfcrypt pip installation ~~~~~~~~~~~~~~~~~~~~~~~~~~ To install ``wolfcrypt`` with ``pip``: -.. code-block:: console - - $ pip install wolfcrypt - -or if you need admin privileges to use ``pip``: - .. code-block:: console $ sudo -H pip install wolfcrypt @@ -69,49 +63,17 @@ or if you need admin privileges to use ``pip``: wolfcrypt source installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To install ``wolfcrypt`` from sources: - -1. Get the sources: - -.. code-block:: console - - $ git clone git@github.com:wolfssl/wolfssl.git - $ cd wolfssl/wrapper/python - -2. Build and install ``wolfcrypt`` - -.. code-block:: console - - $ python setup.py install - ... - Finished processing dependencies for wolfcrypt... - -or if you need admin privileges to use the install command: - -.. code-block:: console - - $ sudo python setup.py install - - -Testing -------- - -Test ``wolfcrypt`` locally with ``tox``: +**Before** proceeding with installation, you can test ``wolfcrypt`` locally with +``tox``: 1. Make sure that the testing requirements are installed: -.. code-block:: console - - $ pip install -r requirements-testing.txt - -or if you need admin privileges to use the install command: - .. code-block:: console $ sudo -H pip install -r requirements-testing.txt -2. Call ``tox``: +2. Run ``tox``: .. code-block:: console @@ -124,3 +86,21 @@ or if you need admin privileges to use the install command: congratulations :) Note that some tests might be skipped if you don't have the proper interpreter. + + +**Now**, to install ``wolfcrypt`` from sources: + +1. Get the sources: + +.. code-block:: console + + $ git clone git@github.com:wolfssl/wolfssl.git + $ cd wolfssl/wrapper/python + +2. Build and install ``wolfcrypt`` + +.. code-block:: console + + $ sudo python setup.py install + ... + Finished processing dependencies for wolfcrypt... From a000ee4db3b61b9aae814eab8a8ad714ab07b2ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 16 May 2016 22:17:09 -0300 Subject: [PATCH 17/24] remove empty dirs --- wrapper/include.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/wrapper/include.am b/wrapper/include.am index ac9e3bba0..56b63fec4 100644 --- a/wrapper/include.am +++ b/wrapper/include.am @@ -31,8 +31,6 @@ EXTRA_DIST+= wrapper/CSharp/wolfSSL_CSharp/wolfSSL_CSharp.csproj # wolfcrypt python wrapper files EXTRA_DIST+= wrapper/python/.gitignore -EXTRA_DIST+= wrapper/python/docs/_static -EXTRA_DIST+= wrapper/python/docs/_templates EXTRA_DIST+= wrapper/python/docs/asymmetric.rst EXTRA_DIST+= wrapper/python/docs/conf.py EXTRA_DIST+= wrapper/python/docs/digest.rst From 47a1dd8cc49118e5e2c756ee57eb7db098917afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Tue, 17 May 2016 14:15:17 -0300 Subject: [PATCH 18/24] fixes install steps --- wrapper/python/README.rst | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 0644487ed..0b7852a21 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -63,17 +63,26 @@ To install ``wolfcrypt`` with ``pip``: wolfcrypt source installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**Before** proceeding with installation, you can test ``wolfcrypt`` locally with -``tox``: +1. Get the sources: -1. Make sure that the testing requirements are installed: +.. code-block:: console + + $ git clone git@github.com:wolfssl/wolfssl.git + $ cd wolfssl/wrapper/python + + +**Before** proceeding with installation, you can test ``wolfcrypt`` locally with +``tox``. If you don't want to run the tests, jump to step 4 instead. + + +2. Make sure that the testing requirements are installed: .. code-block:: console $ sudo -H pip install -r requirements-testing.txt -2. Run ``tox``: +3. Run ``tox``: .. code-block:: console @@ -90,14 +99,8 @@ Note that some tests might be skipped if you don't have the proper interpreter. **Now**, to install ``wolfcrypt`` from sources: -1. Get the sources: -.. code-block:: console - - $ git clone git@github.com:wolfssl/wolfssl.git - $ cd wolfssl/wrapper/python - -2. Build and install ``wolfcrypt`` +4. Build and install ``wolfcrypt`` .. code-block:: console From fcc0eb7a6a2970d7a05e9f61be7ca01cd90828b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Fri, 20 May 2016 03:55:57 -0300 Subject: [PATCH 19/24] fixes install instructions --- wrapper/python/README.rst | 117 +++++++++++++------------- wrapper/python/wolfcrypt/__about__.py | 4 +- 2 files changed, 62 insertions(+), 59 deletions(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 0b7852a21..53c9f5158 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -9,101 +9,104 @@ wolfcrypt: the wolfSSL Crypto Engine **wolfCrypt** is a lightweight, portable, C-language-based crypto library targeted at IoT, embedded, and RTOS environments primarily because of its size, speed, and feature set. It works seamlessly in desktop, enterprise, and cloud -environments as well. +environments as well. It is the crypto engine behind wolfSSl's embedded ssl +library. Installation ------------ -Dependencies -~~~~~~~~~~~~ +In order to use ``wolfcrypt``, first you'll need to install ``wolfssl`` C +embedded ssl library. -Before installing ``wolfcrypt``, make sure you have ``wolfssl`` C library -installed in your machine: +Installing ``wolfssl`` : +~~~~~~~~~~~~~~~~~~~~~~~~ + +**Mac OSX** .. code-block:: console - $ git clone git@github.com:wolfssl/wolfssl.git - $ cd wolfssl - $ ./autogen.sh - $ ./configure - $ make - $ sudo make install + brew install wolfssl -**Linux ONLY:** Update your dynamic linker: +or .. code-block:: console - $ sudo ldconfig - # or - $ export LD_LIBRARY_PATH=/usr/local/lib + git clone https://github.com/wolfssl/wolfssl.git + cd wolfssl/ + ./autogen.sh + ./configure + make + sudo make install -**Linux ONLY:** Make sure you have ``python-dev``, ``python3-dev``, -``python-pip`` and ``libffi-dev`` installed: +**Ubuntu** .. code-block:: console - $ sudo apt-get update - $ sudo apt-get install python-dev python3-dev python-pip libffi-dev + sudo apt-get update + sudo apt-get install -y git autoconf libtool + + git clone https://github.com/wolfssl/wolfssl.git + cd wolfssl/ + ./autogen.sh + ./configure + make + sudo make install + + sudo ldconfig + +**CentOS** + +.. code-block:: console + + sudo rpm -ivh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-6.noarch.rpm + sudo yum update + sudo yum install -y git autoconf libtool + + git clone git@github.com:wolfssl/wolfssl.git + cd wolfssl + ./autogen.sh + ./configure + make + sudo make install + + echo /usr/local/lib > wolfssl.conf + sudo mv wolfssl.conf /etc/ld.so.conf + sudo ldconfig -Now, you can install ``wolfcrypt`` via ``pip`` or ``source code``: - -wolfcrypt pip installation +Installing ``wolfcrypt`` : ~~~~~~~~~~~~~~~~~~~~~~~~~~ -To install ``wolfcrypt`` with ``pip``: +**Mac OSX** .. code-block:: console - $ sudo -H pip install wolfcrypt + sudo -H pip install wolfcrypt -wolfcrypt source installation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Get the sources: +**Ubuntu** .. code-block:: console - $ git clone git@github.com:wolfssl/wolfssl.git - $ cd wolfssl/wrapper/python + sudo apt-get install -y python-dev python-pip libffi-dev + sudo -H pip install wolfcrypt -**Before** proceeding with installation, you can test ``wolfcrypt`` locally with -``tox``. If you don't want to run the tests, jump to step 4 instead. - - -2. Make sure that the testing requirements are installed: +**CentOS** .. code-block:: console - $ sudo -H pip install -r requirements-testing.txt + sudo yum install -y python-devel python-pip libffi-devel + sudo -H pip install wolfcrypt -3. Run ``tox``: +Testing ``wolfcrypt`` : +~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: console - $ tox - ... - _________________________________ summary _________________________________ - py27: commands succeeded - SKIPPED: py34: InterpreterNotFound: python3.4 - py35: commands succeeded - congratulations :) + python -c "from wolfcrypt.hashes import Sha; print Sha().hexdigest()" -Note that some tests might be skipped if you don't have the proper interpreter. - - -**Now**, to install ``wolfcrypt`` from sources: - - -4. Build and install ``wolfcrypt`` - -.. code-block:: console - - $ sudo python setup.py install - ... - Finished processing dependencies for wolfcrypt... +expected output: **da39a3ee5e6b4b0d3255bfef95601890afd80709** diff --git a/wrapper/python/wolfcrypt/__about__.py b/wrapper/python/wolfcrypt/__about__.py index d94ce1926..b5c1697d0 100644 --- a/wrapper/python/wolfcrypt/__about__.py +++ b/wrapper/python/wolfcrypt/__about__.py @@ -20,14 +20,14 @@ metadata = dict( __name__ = "wolfcrypt", - __version__ = "0.1.6", + __version__ = "0.1.7", __license__ = "GPLv2 or Commercial License", __author__ = "wolfSSL Inc.", __author_email__ = "info@wolfssl.com", __url__ = "https://wolfssl.github.io/wolfcrypt-py", __description__ = \ u"A Python library that encapsulates wolfSSL's wolfCrypt API.", - __keywords__ = "security, cryptography", + __keywords__ = "security, cryptography, ssl, embedded, embedded ssl", __classifiers__ = [ u"License :: OSI Approved :: GNU General Public License v2 (GPLv2)", u"License :: Other/Proprietary License", From 04d5ca41df499ff203428b89a2a9eb8dd0ac32a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 23 May 2016 20:33:11 -0300 Subject: [PATCH 20/24] adds --enable-Sha512 to make sure it is always present --- wrapper/python/README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 53c9f5158..494be1e02 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -35,7 +35,7 @@ or git clone https://github.com/wolfssl/wolfssl.git cd wolfssl/ ./autogen.sh - ./configure + ./configure --enable-sha512 make sudo make install @@ -50,7 +50,7 @@ or git clone https://github.com/wolfssl/wolfssl.git cd wolfssl/ ./autogen.sh - ./configure + ./configure --enable-sha512 make sudo make install @@ -67,7 +67,7 @@ or git clone git@github.com:wolfssl/wolfssl.git cd wolfssl ./autogen.sh - ./configure + ./configure --enable-sha512 make sudo make install From 07ce928bf356e8288a3e1fce32c91632e61adbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 23 May 2016 21:10:44 -0300 Subject: [PATCH 21/24] adds installation testing with vagrant --- wrapper/python/.centos-provisioner.sh | 31 +++++++++++++++++++++++++++ wrapper/python/.ubuntu-provisioner.sh | 28 ++++++++++++++++++++++++ wrapper/python/Vagrantfile | 14 ++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 wrapper/python/.centos-provisioner.sh create mode 100644 wrapper/python/.ubuntu-provisioner.sh create mode 100644 wrapper/python/Vagrantfile diff --git a/wrapper/python/.centos-provisioner.sh b/wrapper/python/.centos-provisioner.sh new file mode 100644 index 000000000..8f74110d2 --- /dev/null +++ b/wrapper/python/.centos-provisioner.sh @@ -0,0 +1,31 @@ +[ "$(whoami)" != "root" ] && echo "Sorry, you are not root." && exit 1 + +rpm -ivh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-6.noarch.rpm +yum update +yum install -y git autoconf libtool + +git clone https://github.com/wolfssl/wolfssl.git +[ $? -ne 0 ] && echo "\n\nCouldn't download wolfssl.\n\n" && exit 1 + +pushd wolfssl + +./autogen.sh +./configure +make +make install +echo /usr/local/lib > wolfssl.conf +mv wolfssl.conf /etc/ld.so.conf +ldconfig + +popd +rm -rf wolfssl + +yum install -y libffi-devel python-devel python-pip + +pip install wolfcrypt +[ $? -ne 0 ] && echo "\n\nCouldn't install wolfcrypt.\n\n" && exit 1 + +echo "Test should print:" +echo "da39a3ee5e6b4b0d3255bfef95601890afd80709" +echo "Running test:" +python -c "from wolfcrypt.hashes import Sha; print(Sha().hexdigest())" diff --git a/wrapper/python/.ubuntu-provisioner.sh b/wrapper/python/.ubuntu-provisioner.sh new file mode 100644 index 000000000..ab9e54cb3 --- /dev/null +++ b/wrapper/python/.ubuntu-provisioner.sh @@ -0,0 +1,28 @@ +[ "$(whoami)" != "root" ] && echo "Sorry, you are not root." && exit 1 + +apt-get update +apt-get install -y git autoconf libtool + +git clone https://github.com/wolfssl/wolfssl.git +[ $? -ne 0 ] && echo "\n\nCouldn't download wolfssl.\n\n" && exit 1 + +pushd wolfssl + +./autogen.sh +./configure +make +make install +ldconfig + +popd +rm -rf wolfssl + +apt-get install -y libffi-dev python-dev python-pip + +pip install wolfcrypt +[ $? -ne 0 ] && echo "\n\nCouldn't install wolfcrypt.\n\n" && exit 1 + +echo "Test should print:" +echo "da39a3ee5e6b4b0d3255bfef95601890afd80709" +echo "Running test:" +python -c "from wolfcrypt.hashes import Sha; print(Sha().hexdigest())" diff --git a/wrapper/python/Vagrantfile b/wrapper/python/Vagrantfile new file mode 100644 index 000000000..e164331df --- /dev/null +++ b/wrapper/python/Vagrantfile @@ -0,0 +1,14 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : +BOX = "ubuntu" +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + if BOX == "ubuntu" + config.vm.box = "ubuntu/trusty64" + config.vm.provision "shell", path: ".ubuntu-provisioner.sh" + else + config.vm.box = "moisesguimaraes/centos72-64" + config.vm.provision "shell", path: ".centos-provisioner.sh" + end +end From a76291c2e2e6c049682d98fc622a41be6d7e7334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Thu, 2 Jun 2016 21:38:34 -0300 Subject: [PATCH 22/24] adds tox instructions --- wrapper/python/README.rst | 29 +++++++++++++++++++++++++++ wrapper/python/wolfcrypt/__about__.py | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index 494be1e02..d5fde45a1 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -110,3 +110,32 @@ Testing ``wolfcrypt`` : python -c "from wolfcrypt.hashes import Sha; print Sha().hexdigest()" expected output: **da39a3ee5e6b4b0d3255bfef95601890afd80709** + + +Testing ``wolfcrypt``'s source code with ``tox`` : +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To run the unit tests in the source code, you'll need ``tox`` and a few other +requirements. The source code relies at 'WOLFSSL_DIR/wrapper/python' where +WOLFSSL_DIR is the path of ``wolfssl``'s source code. + +1. Make sure that the testing requirements are installed: + +.. code-block:: console + + $ sudo -H pip install -r requirements-testing.txt + + +2. Run ``tox``: + +.. code-block:: console + + $ tox + ... + _________________________________ summary _________________________________ + py27: commands succeeded + SKIPPED: py34: InterpreterNotFound: python3.4 + py35: commands succeeded + congratulations :) + +Note that some tests might be skipped if you don't have the proper interpreter. diff --git a/wrapper/python/wolfcrypt/__about__.py b/wrapper/python/wolfcrypt/__about__.py index b5c1697d0..b5c05386a 100644 --- a/wrapper/python/wolfcrypt/__about__.py +++ b/wrapper/python/wolfcrypt/__about__.py @@ -20,7 +20,7 @@ metadata = dict( __name__ = "wolfcrypt", - __version__ = "0.1.7", + __version__ = "0.1.8", __license__ = "GPLv2 or Commercial License", __author__ = "wolfSSL Inc.", __author_email__ = "info@wolfssl.com", From 6736ffe10ed616c2fd93f0dd61182166e4d177b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Thu, 2 Jun 2016 22:08:57 -0300 Subject: [PATCH 23/24] adds links to wolfssl.com --- wrapper/python/README.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index d5fde45a1..a6dc59ab4 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -6,11 +6,12 @@ wolfcrypt: the wolfSSL Crypto Engine **wolfCrypt Python**, a.k.a. ``wolfcrypt`` is a Python library that encapsulates **wolfSSL's wolfCrypt API**. -**wolfCrypt** is a lightweight, portable, C-language-based crypto library +`wolfCrypt `_ is a +lightweight, portable, C-language-based crypto library targeted at IoT, embedded, and RTOS environments primarily because of its size, speed, and feature set. It works seamlessly in desktop, enterprise, and cloud -environments as well. It is the crypto engine behind wolfSSl's embedded ssl -library. +environments as well. It is the crypto engine behind `wolfSSl's embedded ssl +library `_. Installation From 7f71c526f68dd3ca42cc212b680c65621806d068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Fri, 3 Jun 2016 10:36:00 -0300 Subject: [PATCH 24/24] adds python3 support --- wrapper/python/README.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/wrapper/python/README.rst b/wrapper/python/README.rst index a6dc59ab4..87121192b 100644 --- a/wrapper/python/README.rst +++ b/wrapper/python/README.rst @@ -91,7 +91,7 @@ Installing ``wolfcrypt`` : .. code-block:: console - sudo apt-get install -y python-dev python-pip libffi-dev + sudo apt-get install -y python-dev python3-dev python-pip libffi-dev sudo -H pip install wolfcrypt @@ -99,7 +99,7 @@ Installing ``wolfcrypt`` : .. code-block:: console - sudo yum install -y python-devel python-pip libffi-devel + sudo yum install -y python-devel python3-devel python-pip libffi-devel sudo -H pip install wolfcrypt @@ -139,4 +139,6 @@ WOLFSSL_DIR is the path of ``wolfssl``'s source code. py35: commands succeeded congratulations :) -Note that some tests might be skipped if you don't have the proper interpreter. +Note: the test is performed using multiple versions of python. If you are +missing a version the test will be skipped with an **InterpreterNotFound +error**.