adds docs

This commit is contained in:
Moisés Guimarães
2016-05-03 00:41:54 -03:00
parent 69ac477976
commit 3181731404
23 changed files with 882 additions and 453 deletions

View File

@@ -5,7 +5,11 @@ __pycache__/
# Distribution # Distribution
build/ build/
dist/
.eggs/
*.egg-info/ *.egg-info/
# Unit test # Unit test
.tox/ .tox/
# Sphinx documentation
docs/_build/

View File

@@ -1,8 +1,10 @@
wolfcrypt: the wolfSSL Crypto Engine 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:: 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 $ 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 $ python setup.py install
... ...
Finished processing dependencies for wolfcrypt==0.1 Finished processing dependencies for wolfcrypt==0.1.0
4. Test locally with ``tox``:: 4. Test locally with ``tox``::
@@ -37,5 +39,21 @@ A Python wrapper which encapsulates the wolfCrypt API from wolfSSL library
$ tox $ tox
... ...
_________________________________ summary _________________________________ _________________________________ summary _________________________________
py26: commands succeeded
py27: commands succeeded py27: commands succeeded
py35: commands succeeded
congratulations :) 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 <https://www.wolfssl.com>`_.

View File

@@ -96,9 +96,9 @@ qthelp:
@echo @echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:" ".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 "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wolfCrypt.qhc" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wolfcrypt.qhc"
.PHONY: applehelp .PHONY: applehelp
applehelp: applehelp:
@@ -115,8 +115,8 @@ devhelp:
@echo @echo
@echo "Build finished." @echo "Build finished."
@echo "To view the help file:" @echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/wolfCrypt" @echo "# mkdir -p $$HOME/.local/share/devhelp/wolfcrypt"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wolfCrypt" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wolfcrypt"
@echo "# devhelp" @echo "# devhelp"
.PHONY: epub .PHONY: epub

View File

@@ -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.'

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# wolfCrypt documentation build configuration file, created by # wolfcrypt documentation build configuration file, created by
# sphinx-quickstart on Fri Apr 29 16:04:23 2016. # sphinx-quickstart on Fri Apr 29 16:47:53 2016.
# #
# This file is execfile()d with the current directory set to its # This file is execfile()d with the current directory set to its
# containing dir. # containing dir.
@@ -31,8 +31,10 @@ import sphinx_rtd_theme
# ones. # ones.
extensions = [ extensions = [
'sphinx.ext.autodoc', 'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.coverage', 'sphinx.ext.coverage',
'sphinx.ext.viewcode', 'sphinx.ext.viewcode',
'sphinx.ext.githubpages',
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
@@ -50,18 +52,21 @@ source_suffix = '.rst'
master_doc = 'index' master_doc = 'index'
# General information about the project. # General information about the project.
project = u'wolfCrypt' project = u'wolfcrypt'
copyright = u'2016, wolfSSL' copyright = u'2016, wolfSSL Inc. All rights reserved'
author = u'wolfSSL' author = u'wolfSSL'
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
# built documents. # built documents.
# #
# The short X.Y version.
version = u'0.0' base_dir = os.path.join(os.path.dirname(__file__), os.pardir)
# The full version, including alpha/beta/rc tags. about = {}
release = u'0.0.1' 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 # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # 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. # The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default. # "<project> v<release> 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. # A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None #html_short_title = None
@@ -207,7 +212,7 @@ html_static_path = ['_static']
#html_search_scorer = 'scorer.js' #html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'wolfCryptdoc' htmlhelp_basename = 'wolfcrypt-pydoc'
# -- Options for LaTeX output --------------------------------------------- # -- Options for LaTeX output ---------------------------------------------
@@ -229,7 +234,7 @@ latex_elements = {
# (source start file, target name, title, # (source start file, target name, title,
# author, documentclass [howto, manual, or own class]). # author, documentclass [howto, manual, or own class]).
latex_documents = [ latex_documents = [
(master_doc, 'wolfCrypt.tex', u'wolfCrypt Documentation', (master_doc, 'wolfcrypt.tex', u'wolfcrypt Python Documentation',
u'wolfSSL', 'manual'), u'wolfSSL', 'manual'),
] ]
@@ -259,7 +264,7 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [
(master_doc, 'wolfcrypt', u'wolfCrypt Documentation', (master_doc, 'wolfcrypt', u'wolfcrypt Python Documentation',
[author], 1) [author], 1)
] ]
@@ -273,8 +278,8 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
(master_doc, 'wolfCrypt', u'wolfCrypt Documentation', (master_doc, 'wolfcrypt', u'wolfcrypt Python Documentation',
author, 'wolfCrypt', 'One line description of project.', author, 'wolfcrypt', 'One line description of project.',
'Miscellaneous'), 'Miscellaneous'),
] ]
@@ -289,3 +294,6 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu. # If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False #texinfo_no_detailmenu = False
# Preserves the order of the members, doesn't sorts them alphabetically.
autodoc_member_order = 'bysource'

View File

@@ -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'

View File

@@ -1,22 +1,46 @@
.. wolfCrypt documentation master file, created by wolfCrypt Python Documentation
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! **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:: .. toctree::
:maxdepth: 2 :maxdepth: 1
symmetric
asymmetric
digest
mac
random
Licensing
---------
Indices and tables wolfSSLs 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` Open Source
* :ref:`modindex` ~~~~~~~~~~~
* :ref:`search`
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
<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. Licenses are generally issued
for one product and include unlimited royalty-free distribution. Custom
licensing terms are also available at licensing@wolfssl.com.

View File

@@ -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<Q\xdf\x8d\xdb\x863\xfb\xc1f#o'
>>> h.hexdigest()
b'18bf2a0939a26fdf5cc8e0c255942c8d59023b1c3c51df8ddb8633fbc166236f'
>>>
>>> h.update("rocks")
>>> h.hexdigest()
b'85dc8c1995d20b17942d52773d8a597d028ad958e5736beafb59a4742f63889e'
>>>
>>> HmacSha256('secret', 'wolfcryptrocks').hexdigest()
b'85dc8c1995d20b17942d52773d8a597d028ad958e5736beafb59a4742f63889e'
>>>
>>> HmacSha256.new('secret', 'wolfcryptrocks').hexdigest()
b'85dc8c1995d20b17942d52773d8a597d028ad958e5736beafb59a4742f63889e'

View File

@@ -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'

View File

@@ -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 '

View File

@@ -1,4 +1,3 @@
pytest>=2.9.1 pytest>=2.9.1
cffi>=1.5.2 cffi>=1.6.0
tox>=2.3.1 tox>=2.3.1
sphinx_rtd_theme>=0.1.9

View File

@@ -10,12 +10,12 @@ os.chdir(os.path.dirname(sys.argv[0]) or ".")
setup( setup(
name="wolfcrypt", name="wolfcrypt",
version="0.0.1", version="0.1.0",
description="A python wrapper for the wolfCrypt API", description="A Python wrapper that encapsulates wolfSSL's wolfCrypt API",
long_description=open("README.rst", "rt").read(), long_description=open("README.rst", "rt").read(),
url="https://github.com/wolfssl/wolfcrypt-py", url="https://wolfssl.github.io/wolfcrypt-py",
author="Moisés Guimarães", author="wolfSSL",
author_email="moises@wolfssl.com", author_email="info@wolfssl.com",
classifiers=[ classifiers=[
"Development Status :: 0 - Alpha", "Development Status :: 0 - Alpha",
"Programming Language :: Python :: 2", "Programming Language :: Python :: 2",
@@ -24,7 +24,7 @@ setup(
"License :: GPLv2 License :: Commercial License", "License :: GPLv2 License :: Commercial License",
], ],
packages=find_packages(), packages=find_packages(),
setup_requires=["cffi>=1.5.2"], setup_requires=["cffi>=1.6.0"],
install_requires=["cffi>=1.5.2"], install_requires=["cffi>=1.6.0"],
cffi_modules=["./wolfcrypt/build_ffi.py:ffi"] cffi_modules=["./wolfcrypt/build_ffi.py:ffi"]
) )

View File

@@ -19,12 +19,13 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import unittest import unittest
from wolfcrypt.ciphers import * from wolfcrypt.ciphers import *
from wolfcrypt.utils import t2b, h2b
class TestDes3(unittest.TestCase): class TestDes3(unittest.TestCase):
key = "0123456789abcdeffedeba987654321089abcdef01234567".decode("hex") key = h2b("0123456789abcdeffedeba987654321089abcdef01234567")
IV = "1234567890abcdef".decode("hex") IV = h2b("1234567890abcdef")
plain = "Now is the time for all " plain = t2b("Now is the time for all ")
cipher = "43a0297ed184f80e8964843212d508981894157487127db0".decode("hex") cipher = h2b("43a0297ed184f80e8964843212d508981894157487127db0")
def setUp(self): def setUp(self):
@@ -32,9 +33,6 @@ class TestDes3(unittest.TestCase):
def test_raises(self): def test_raises(self):
# invalid construction
self.assertRaises(ValueError, Des3)
# invalid key length # invalid key length
self.assertRaises(ValueError, Des3.new, "key", MODE_CBC, self.IV) self.assertRaises(ValueError, Des3.new, "key", MODE_CBC, self.IV)
@@ -54,7 +52,7 @@ class TestDes3(unittest.TestCase):
def test_multi_encryption(self): def test_multi_encryption(self):
result = "" result = t2b("")
segments = tuple(self.plain[i:i + Des3.block_size] \ segments = tuple(self.plain[i:i + Des3.block_size] \
for i in range(0, len(self.plain), 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): def test_multi_decryption(self):
result = "" result = t2b("")
segments = tuple(self.cipher[i:i + Des3.block_size] \ segments = tuple(self.cipher[i:i + Des3.block_size] \
for i in range(0, len(self.cipher), 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): class TestAes(unittest.TestCase):
key = "0123456789abcdef" key = "0123456789abcdef"
IV = "1234567890abcdef" IV = "1234567890abcdef"
plain = "now is the time " plain = t2b("now is the time ")
cipher = "959492575f4281532ccc9d4677a233cb".decode("hex") cipher = h2b("959492575f4281532ccc9d4677a233cb")
def setUp(self): def setUp(self):
@@ -91,9 +89,6 @@ class TestAes(unittest.TestCase):
def test_raises(self): def test_raises(self):
# invalid construction
self.assertRaises(ValueError, Aes)
# invalid key length # invalid key length
self.assertRaises(ValueError, Aes.new, "key", MODE_CBC, self.IV) self.assertRaises(ValueError, Aes.new, "key", MODE_CBC, self.IV)
@@ -113,7 +108,7 @@ class TestAes(unittest.TestCase):
def test_multi_encryption(self): def test_multi_encryption(self):
result = "" result = t2b("")
segments = tuple(self.plain[i:i + self.aes.block_size] \ segments = tuple(self.plain[i:i + self.aes.block_size] \
for i in range(0, len(self.plain), 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): def test_multi_decryption(self):
result = "" result = t2b("")
segments = tuple(self.cipher[i:i + self.aes.block_size] \ segments = tuple(self.cipher[i:i + self.aes.block_size] \
for i in range(0, len(self.cipher), 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" \ + "3989E59C195530BAB7488C48140EF49F7E779743E1B419353123759C3B44AD69" \
+ "1256EE0061641666D37C742B15B4A2FEBF086B1A5D3F9012B105863129DBD9E2" + "1256EE0061641666D37C742B15B4A2FEBF086B1A5D3F9012B105863129DBD9E2"
plain = "Everyone gets Friday off." plain = t2b("Everyone gets Friday off.")
def setUp(self): def setUp(self):
self.rsa = RsaPrivate(self.key.decode("hex")) self.rsa = RsaPrivate(h2b(self.key))
def test_raises(self): def test_raises(self):
# invalid key # invalid key
self.assertRaises(KeyError, RsaPrivate, 'key') self.assertRaises(WolfCryptError, RsaPrivate, 'key')
def test_output_size(self): def test_output_size(self):
@@ -218,17 +213,17 @@ class TestRsaPublic(unittest.TestCase):
+ "38CC39A20466B4F7F7F3AADA4D020EBB5E8D6948DC77C9280E22E96BA426BA4C" \ + "38CC39A20466B4F7F7F3AADA4D020EBB5E8D6948DC77C9280E22E96BA426BA4C" \
+ "E8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B3C67C8DC2700F6916865A90203010001" + "E8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B3C67C8DC2700F6916865A90203010001"
plain = "Everyone gets Friday off." plain = t2b("Everyone gets Friday off.")
def setUp(self): def setUp(self):
self.private = RsaPrivate(self.prv.decode("hex")) self.private = RsaPrivate(h2b(self.prv))
self.public = RsaPublic(self.pub.decode("hex")) self.public = RsaPublic(h2b(self.pub))
def test_raises(self): def test_raises(self):
# invalid key # invalid key
self.assertRaises(KeyError, RsaPublic, 'key') self.assertRaises(WolfCryptError, RsaPublic, 'key')
def test_output_size(self): def test_output_size(self):

View File

@@ -19,29 +19,28 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import unittest import unittest
from wolfcrypt.hashes import * from wolfcrypt.hashes import *
from wolfcrypt.utils import t2b, h2b
class TestSha(unittest.TestCase): class TestSha(unittest.TestCase):
digest = "1b6182d68ae91ce0853bd9c6b6edfedd4b6a510d" _class = Sha
digest = t2b("1b6182d68ae91ce0853bd9c6b6edfedd4b6a510d")
def setUp(self): def setUp(self):
self.hash = Sha.new() self.hash = self._class()
def test_new(self): def test_new(self):
# invalid construction
self.assertRaises(ValueError, Sha)
# update inside constructor # update inside constructor
assert Sha.new("wolfcrypt").hexdigest() == self.digest assert self._class.new("wolfcrypt").hexdigest() == self.digest
def test_hash_update_001(self): def test_hash_update_001(self):
self.hash.update("wolfcrypt") self.hash.update("wolfcrypt")
assert self.hash.hexdigest() == self.digest 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): def test_hash_update_002(self):
@@ -49,7 +48,7 @@ class TestSha(unittest.TestCase):
self.hash.update("crypt") self.hash.update("crypt")
assert self.hash.hexdigest() == self.digest 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): def test_hash_copy(self):
@@ -66,167 +65,47 @@ class TestSha(unittest.TestCase):
assert self.hash.hexdigest() == copy.hexdigest() == self.digest assert self.hash.hexdigest() == copy.hexdigest() == self.digest
class TestSha256(unittest.TestCase): class TestSha256(TestSha):
digest = "96e02e7b1cbcd6f104fe1fdb4652027a5505b68652b70095c6318f9dce0d1844" _class = Sha256
digest = t2b("96e02e7b1cbcd6f104fe1fdb4652027a" \
+ "5505b68652b70095c6318f9dce0d1844")
def setUp(self): class TestSha384(TestSha):
self.hash = Sha256.new() _class = Sha384
digest = t2b("4c79d80531203a16f91bee325f18c6aada47f9382fe44fc1" \
+ "1f92917837e9b7902f5dccb7d3656f667a1dce3460bc884b")
def test_new(self): class TestSha512(TestSha):
# invalid construction _class = Sha512
self.assertRaises(ValueError, Sha256) digest = t2b("88fcf67ffd8558d713f9cedcd852db47" \
+ "9e6573f0bd9955610a993f609637553c" \
# update inside constructor + "e8fff55e644ee8a106aae19c07f91b3f" \
assert Sha256.new("wolfcrypt").hexdigest() == self.digest + "2a2a6d40dfa7302c0fa6a1a9a5bfa03f")
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" _HMAC_KEY = "python"
class TestHmacSha(unittest.TestCase): class TestHmacSha(unittest.TestCase):
digest = "5dfabcfb3a25540824867cd21f065f52f73491e0" _class = HmacSha
digest = t2b("5dfabcfb3a25540824867cd21f065f52f73491e0")
def setUp(self): def setUp(self):
self.hash = HmacSha.new(_HMAC_KEY) self.hash = self._class(_HMAC_KEY)
def test_new(self): def test_new(self):
# invalid construction
self.assertRaises(ValueError, HmacSha)
# update inside constructor # 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): def test_hash_update_001(self):
self.hash.update("wolfcrypt") self.hash.update("wolfcrypt")
assert self.hash.hexdigest() == self.digest assert self.hash.hexdigest() == self.digest
assert self.hash.digest() == self.digest.decode("hex")
def test_hash_update_002(self): def test_hash_update_002(self):
@@ -234,7 +113,6 @@ class TestHmacSha(unittest.TestCase):
self.hash.update("crypt") self.hash.update("crypt")
assert self.hash.hexdigest() == self.digest assert self.hash.hexdigest() == self.digest
assert self.hash.digest() == self.digest.decode("hex")
def test_hash_copy(self): def test_hash_copy(self):
@@ -251,138 +129,21 @@ class TestHmacSha(unittest.TestCase):
assert self.hash.hexdigest() == copy.hexdigest() == self.digest assert self.hash.hexdigest() == copy.hexdigest() == self.digest
class TestHmacSha256(unittest.TestCase): class TestHmacSha256(TestHmacSha):
digest = "4b641d721493d80f019d9447830ebfee89234a7d594378b89f8bb73873576bf6" _class = HmacSha256
digest = t2b("4b641d721493d80f019d9447830ebfee" \
+ "89234a7d594378b89f8bb73873576bf6")
def setUp(self): class TestHmacSha384(TestHmacSha):
self.hash = HmacSha256.new(_HMAC_KEY) _class = HmacSha384
digest = t2b("e72c72070c9c5c78e3286593068a510c1740cdf9dc34b512" \
+ "ccec97320295db1fe673216b46fe72e81f399a9ec04780ab")
def test_new(self): class TestHmacSha512(TestHmacSha):
# invalid construction _class = HmacSha512
self.assertRaises(ValueError, HmacSha256) digest = t2b("c7f48db79314fc2b5be9a93fd58601a1" \
+ "bf42f397ec7f66dba034d44503890e6b" \
# update inside constructor + "5708242dcd71a248a78162d815c685f6" \
assert HmacSha256.new(_HMAC_KEY, "wolfcrypt").hexdigest() == self.digest + "038a4ac8cb34b8bf18986dbd300c9b41")
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

View File

@@ -1,5 +1,5 @@
[tox] [tox]
envlist=py27 envlist=py26,py27,py35
[testenv] [testenv]
deps=-rrequirements-testing.txt deps=-rrequirements-testing.txt

View File

@@ -1,4 +1,4 @@
# WolfCrypt # __init__.py
# #
# Copyright (C) 2006-2016 wolfSSL Inc. # Copyright (C) 2006-2016 wolfSSL Inc.
# #

View File

@@ -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__ = """
wolfSSLs 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()

View File

@@ -1,4 +1,4 @@
# build_random.py # build_ffi.py
# #
# Copyright (C) 2006-2016 wolfSSL Inc. # Copyright (C) 2006-2016 wolfSSL Inc.
# #

View File

@@ -19,8 +19,11 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from wolfcrypt._ffi import ffi as _ffi from wolfcrypt._ffi import ffi as _ffi
from wolfcrypt._ffi import lib as _lib from wolfcrypt._ffi import lib as _lib
from wolfcrypt.utils import t2b
from wolfcrypt.random import Random from wolfcrypt.random import Random
from wolfcrypt.exceptions import *
# key direction flags # key direction flags
_ENCRYPTION = 0 _ENCRYPTION = 0
@@ -38,24 +41,19 @@ _FEEDBACK_MODES = [MODE_ECB, MODE_CBC, MODE_CFB, MODE_OFB, MODE_CTR]
class _Cipher(object): class _Cipher(object):
# Magic object that protects against constructors. """
_JAPANESE_CYBER_SWORD = object() A **PEP 272: Block Encryption Algorithms** compliant
**Symmetric Key Cipher**.
"""
def __init__(self, token=""): def __init__(self, key, mode, IV=None):
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: if mode not in _FEEDBACK_MODES:
raise ValueError("this mode is not supported") 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:
if self.key_size != len(key): if self.key_size != len(key):
@@ -71,46 +69,92 @@ class _Cipher(object):
raise ValueError("IV must be %d in length" % self.block_size) raise ValueError("IV must be %d in length" % self.block_size)
self._native_object = _ffi.new(self._native_type) self._native_object = _ffi.new(self._native_type)
self._enc = None self._enc = None
self._dec = None self._dec = None
self._key = key self._key = t2b(key)
self._IV = IV if IV else "\0" * self.block_size
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): 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: if not string or len(string) % self.block_size:
raise ValueError( raise ValueError(
"string must be a multiple of %d in length" % self.block_size) "string must be a multiple of %d in length" % self.block_size)
if self._enc is None: if self._enc is None:
self._enc = _ffi.new(self._native_type) 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) result = t2b("\0" * len(string))
self._encrypt(result, string) ret = self._encrypt(result, string)
if ret < 0:
raise WolfCryptError("Encryption error (%d)" % ret)
return result return result
def decrypt(self, string): 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: if not string or len(string) % self.block_size:
raise ValueError( raise ValueError(
"string must be a multiple of %d in length" % self.block_size) "string must be a multiple of %d in length" % self.block_size)
if self._dec is None: if self._dec is None:
self._dec = _ffi.new(self._native_type) 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) result = t2b("\0" * len(string))
self._decrypt(result, string) ret = self._decrypt(result, string)
if ret < 0:
raise WolfCryptError("Decryption error (%d)" % ret)
return result return result
class Aes(_Cipher): class Aes(_Cipher):
"""
The **Advanced Encryption Standard** (AES), a.k.a. Rijndael, is
a symmetric-key cipher standardized by **NIST**.
"""
block_size = 16 block_size = 16
key_size = None # 16, 24, 32 key_size = None # 16, 24, 32
_key_sizes = [16, 24, 32] _key_sizes = [16, 24, 32]
@@ -119,22 +163,28 @@ class Aes(_Cipher):
def _set_key(self, direction): def _set_key(self, direction):
if direction == _ENCRYPTION: if direction == _ENCRYPTION:
_lib.wc_AesSetKey( return _lib.wc_AesSetKey(
self._enc, self._key, len(self._key), self._IV, _ENCRYPTION) self._enc, self._key, len(self._key), self._IV, _ENCRYPTION)
else: else:
_lib.wc_AesSetKey( return _lib.wc_AesSetKey(
self._dec, self._key, len(self._key), self._IV, _DECRYPTION) self._dec, self._key, len(self._key), self._IV, _DECRYPTION)
def _encrypt(self, destination, source): 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): 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): 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 block_size = 8
key_size = 24 key_size = 24
_native_type = "Des3 *" _native_type = "Des3 *"
@@ -142,24 +192,27 @@ class Des3(_Cipher):
def _set_key(self, direction): def _set_key(self, direction):
if direction == _ENCRYPTION: 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: 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): 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): 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): class _Rsa(object):
RSA_MIN_PAD_SIZE = 11
def __init__(self): def __init__(self):
self.native_object = _ffi.new("RsaKey *") self.native_object = _ffi.new("RsaKey *")
if _lib.wc_InitRsaKey(self.native_object, _ffi.NULL) != 0: ret = _lib.wc_InitRsaKey(self.native_object, _ffi.NULL)
raise KeyError if ret < 0:
raise WolfCryptError("Invalid key error (%d)" % ret)
self._random = Random() self._random = Random()
@@ -171,22 +224,34 @@ class _Rsa(object):
class RsaPublic(_Rsa): class RsaPublic(_Rsa):
def __init__(self, key): def __init__(self, key):
key = t2b(key)
_Rsa.__init__(self) _Rsa.__init__(self)
idx = _ffi.new("word32*") idx = _ffi.new("word32*")
idx[0] = 0 idx[0] = 0
if _lib.wc_RsaPublicKeyDecode(key, idx, self.native_object, len(key)): ret = _lib.wc_RsaPublicKeyDecode(key, idx, self.native_object, len(key))
raise KeyError if ret < 0:
raise WolfCryptError("Invalid key error (%d)" % ret)
self.output_size = _lib.wc_RsaEncryptSize(self.native_object) self.output_size = _lib.wc_RsaEncryptSize(self.native_object)
if self.output_size <= 0: if self.output_size <= 0:
raise KeyError raise WolfCryptError("Invalid key error (%d)" % self.output_size)
def encrypt(self, plaintext): 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), ret = _lib.wc_RsaPublicEncrypt(plaintext, len(plaintext),
ciphertext, len(ciphertext), ciphertext, len(ciphertext),
@@ -194,52 +259,84 @@ class RsaPublic(_Rsa):
self._random.native_object) self._random.native_object)
if ret != self.output_size: if ret != self.output_size:
raise KeyError raise WolfCryptError("Encryption error (%d)" % ret)
return ciphertext return ciphertext
def verify(self, signature): 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), ret = _lib.wc_RsaSSL_Verify(signature, len(signature),
plaintext, len(plaintext), plaintext, len(plaintext),
self.native_object) self.native_object)
if ret < 0: if ret < 0:
raise KeyError raise WolfCryptError("Verify error (%d)" % ret)
return plaintext[:ret] return plaintext[:ret]
class RsaPrivate(RsaPublic): class RsaPrivate(RsaPublic):
def __init__(self, key): def __init__(self, key):
key = t2b(key)
_Rsa.__init__(self) _Rsa.__init__(self)
idx = _ffi.new("word32*") idx = _ffi.new("word32*")
idx[0] = 0 idx[0] = 0
if _lib.wc_RsaPrivateKeyDecode(key, idx, self.native_object, len(key)): ret = _lib.wc_RsaPrivateKeyDecode(key, idx, self.native_object,len(key))
raise KeyError if ret < 0:
raise WolfCryptError("Invalid key error (%d)" % ret)
self.output_size = _lib.wc_RsaEncryptSize(self.native_object) 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): 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), ret = _lib.wc_RsaPrivateDecrypt(ciphertext, len(ciphertext),
plaintext, len(plaintext), plaintext, len(plaintext),
self.native_object) self.native_object)
if ret < 0: if ret < 0:
raise KeyError raise WolfCryptError("Decryption error (%d)" % ret)
return plaintext[:ret] return plaintext[:ret]
def sign(self, plaintext): 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), ret = _lib.wc_RsaSSL_Sign(plaintext, len(plaintext),
signature, len(signature), signature, len(signature),
@@ -247,6 +344,6 @@ class RsaPrivate(RsaPublic):
self._random.native_object) self._random.native_object)
if ret != self.output_size: if ret != self.output_size:
raise KeyError raise WolfCryptError("Signature error (%d)" % ret)
return signature return signature

View File

@@ -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

View File

@@ -19,34 +19,41 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from wolfcrypt._ffi import ffi as _ffi from wolfcrypt._ffi import ffi as _ffi
from wolfcrypt._ffi import lib as _lib from wolfcrypt._ffi import lib as _lib
from wolfcrypt.utils import t2b, b2h
from wolfcrypt.exceptions import *
class _Hash(object): 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)
if (string):
def __init__(self, token=""): self.update(string)
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 @classmethod
def new(cls, string=None): def new(cls, string=None):
self = cls(cls._JAPANESE_CYBER_SWORD) """
Creates a new hashing object and returns it. The optional
self._native_object = _ffi.new(self._native_type) **string** parameter, if supplied, will be immediately
hashed into the object's starting state, as if
self._init() obj.update(string) was called.
"""
if (string): return cls(string)
self._update(string)
return self
def copy(self): 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("") copy = self.new("")
_ffi.memmove(copy._native_object, _ffi.memmove(copy._native_object,
@@ -57,96 +64,142 @@ class _Hash(object):
def update(self, string): 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): 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: if self._native_object:
obj = _ffi.new(self._native_type) obj = _ffi.new(self._native_type)
_ffi.memmove(obj, self._native_object, self._native_size) _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): 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): 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 digest_size = 20
_native_type = "Sha *" _native_type = "Sha *"
_native_size = _ffi.sizeof("Sha") _native_size = _ffi.sizeof("Sha")
def _init(self): def _init(self):
_lib.wc_InitSha(self._native_object) return _lib.wc_InitSha(self._native_object)
def _update(self, data): 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): def _final(self, obj, ret):
_lib.wc_ShaFinal(obj, ret) return _lib.wc_ShaFinal(obj, ret)
class Sha256(_Hash): 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 digest_size = 32
_native_type = "Sha256 *" _native_type = "Sha256 *"
_native_size = _ffi.sizeof("Sha256") _native_size = _ffi.sizeof("Sha256")
def _init(self): def _init(self):
_lib.wc_InitSha256(self._native_object) return _lib.wc_InitSha256(self._native_object)
def _update(self, data): 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): def _final(self, obj, ret):
_lib.wc_Sha256Final(obj, ret) return _lib.wc_Sha256Final(obj, ret)
class Sha384(_Hash): 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 digest_size = 48
_native_type = "Sha384 *" _native_type = "Sha384 *"
_native_size = _ffi.sizeof("Sha384") _native_size = _ffi.sizeof("Sha384")
def _init(self): def _init(self):
_lib.wc_InitSha384(self._native_object) return _lib.wc_InitSha384(self._native_object)
def _update(self, data): 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): def _final(self, obj, ret):
_lib.wc_Sha384Final(obj, ret) return _lib.wc_Sha384Final(obj, ret)
class Sha512(_Hash): 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 digest_size = 64
_native_type = "Sha512 *" _native_type = "Sha512 *"
_native_size = _ffi.sizeof("Sha512") _native_size = _ffi.sizeof("Sha512")
def _init(self): def _init(self):
_lib.wc_InitSha512(self._native_object) return _lib.wc_InitSha512(self._native_object)
def _update(self, data): 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): def _final(self, obj, ret):
_lib.wc_Sha512Final(obj, ret) return _lib.wc_Sha512Final(obj, ret)
# Hmac types # Hmac types
@@ -159,52 +212,91 @@ _HMAC_TYPES = [_TYPE_SHA, _TYPE_SHA256, _TYPE_SHA384, _TYPE_SHA512]
class _Hmac(_Hash): class _Hmac(_Hash):
"""
A **PEP 247: Cryptographic Hash Functions** compliant
**Keyed Hash Function Interface**.
"""
digest_size = None digest_size = None
_native_type = "Hmac *" _native_type = "Hmac *"
_native_size = _ffi.sizeof("Hmac") _native_size = _ffi.sizeof("Hmac")
@classmethod def __init__(self, key, string=None):
def new(cls, key, string=None): key = t2b(key)
self = cls(cls._JAPANESE_CYBER_SWORD)
self._native_object = _ffi.new(self._native_type) self._native_object = _ffi.new(self._native_type)
ret = self._init(self._type, key)
self._init(self._type, key) if ret < 0:
raise WolfCryptError("Hmac init error (%d)" % ret)
if (string): 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): 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): 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): def _final(self, obj, ret):
_lib.wc_HmacFinal(obj, ret) return _lib.wc_HmacFinal(obj, ret)
class HmacSha(_Hmac): 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 _type = _TYPE_SHA
digest_size = Sha.digest_size digest_size = Sha.digest_size
class HmacSha256(_Hmac): 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 _type = _TYPE_SHA256
digest_size = Sha256.digest_size digest_size = Sha256.digest_size
class HmacSha384(_Hmac): 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 _type = _TYPE_SHA384
digest_size = Sha384.digest_size digest_size = Sha384.digest_size
class HmacSha512(_Hmac): 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 _type = _TYPE_SHA512
digest_size = Sha512.digest_size digest_size = Sha512.digest_size

View File

@@ -19,13 +19,22 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from wolfcrypt._ffi import ffi as _ffi from wolfcrypt._ffi import ffi as _ffi
from wolfcrypt._ffi import lib as _lib from wolfcrypt._ffi import lib as _lib
from wolfcrypt.utils import t2b
from wolfcrypt.exceptions import *
class Random(object): class Random(object):
"""
A Cryptographically Secure Pseudo Random Number Generator - CSPRNG
"""
def __init__(self): def __init__(self):
self.native_object = _ffi.new("WC_RNG *") 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 self.native_object = None
raise WolfCryptError("RNG init error (%d)" % ret)
def __del__(self): def __del__(self):
@@ -34,16 +43,26 @@ class Random(object):
def byte(self): 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): 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

View File

@@ -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")