Merge pull request #404 from moisesguimaraes/wolfcrypt-py

wolfcrypt Python wrapper
This commit is contained in:
John Safranek 2016-06-03 08:24:12 -07:00
commit d05754f9db
31 changed files with 2604 additions and 6 deletions

12
Vagrantfile vendored
View File

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

View File

@ -28,3 +28,31 @@ 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/.gitignore
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/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/__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

View File

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

15
wrapper/python/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Distribution
build/
dist/
.eggs/
*.egg-info/
# Unit test
.tox/
# Sphinx documentation
docs/_build/

View File

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

View File

@ -0,0 +1,23 @@
Licensing
---------
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
~~~~~~~~~~~
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 @@
include LICENSING.rst

144
wrapper/python/README.rst Normal file
View File

@ -0,0 +1,144 @@
wolfcrypt: the wolfSSL Crypto Engine
====================================
**wolfCrypt Python**, a.k.a. ``wolfcrypt`` is a Python library that encapsulates
**wolfSSL's wolfCrypt API**.
`wolfCrypt <https://wolfssl.com/wolfSSL/Products-wolfcrypt.html>`_ 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 <https://wolfssl.com/wolfSSL/Products-wolfssl.html>`_.
Installation
------------
In order to use ``wolfcrypt``, first you'll need to install ``wolfssl`` C
embedded ssl library.
Installing ``wolfssl`` :
~~~~~~~~~~~~~~~~~~~~~~~~
**Mac OSX**
.. code-block:: console
brew install wolfssl
or
.. code-block:: console
git clone https://github.com/wolfssl/wolfssl.git
cd wolfssl/
./autogen.sh
./configure --enable-sha512
make
sudo make install
**Ubuntu**
.. code-block:: console
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 --enable-sha512
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 --enable-sha512
make
sudo make install
echo /usr/local/lib > wolfssl.conf
sudo mv wolfssl.conf /etc/ld.so.conf
sudo ldconfig
Installing ``wolfcrypt`` :
~~~~~~~~~~~~~~~~~~~~~~~~~~
**Mac OSX**
.. code-block:: console
sudo -H pip install wolfcrypt
**Ubuntu**
.. code-block:: console
sudo apt-get install -y python-dev python3-dev python-pip libffi-dev
sudo -H pip install wolfcrypt
**CentOS**
.. code-block:: console
sudo yum install -y python-devel python3-devel python-pip libffi-devel
sudo -H pip install wolfcrypt
Testing ``wolfcrypt`` :
~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: console
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: the test is performed using multiple versions of python. If you are
missing a version the test will be skipped with an **InterpreterNotFound
error**.

14
wrapper/python/Vagrantfile vendored Normal file
View File

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

View File

@ -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 <target>' where <target> 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."

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

299
wrapper/python/docs/conf.py Normal file
View File

@ -0,0 +1,299 @@
# -*- coding: utf-8 -*-
#
# 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.
#
# 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
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
# 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.doctest',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
'sphinx.ext.githubpages',
]
# 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 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.
#
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.
#
# 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 = '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
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#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
# 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 <link> 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 = 'wolfcrypt-pydoc'
# -- 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 Python 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 Python 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 Python 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
# 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

@ -0,0 +1,15 @@
.. include:: ../README.rst
Summary
-------
.. toctree::
:maxdepth: 1
symmetric
asymmetric
digest
mac
random
.. include:: ../LICENSING.rst

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

@ -0,0 +1,3 @@
pytest>=2.9.1
cffi>=1.6.0
tox>=2.3.1

55
wrapper/python/setup.py Executable file
View File

@ -0,0 +1,55 @@
#!/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
from wolfcrypt.__about__ import metadata
from setuptools import setup, find_packages
os.chdir(os.path.dirname(sys.argv[0]) or ".")
long_description = open("README.rst", "rt").read().replace(
".. include:: LICENSING.rst\n",
open("LICENSING.rst", "rt").read()
)
info = dict(
metadata = {k[2:-2]: metadata[k] for k in metadata},
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"],
"install_requires": ["cffi>=1.6.0"],
},
scripts = {},
plugins = {},
tests = {},
)
if __name__ == "__main__":
kwargs = {k:v for dct in info.values() for (k,v) in dct.items()}
setup(**kwargs)

View File

@ -0,0 +1,246 @@
# 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 *
from wolfcrypt.utils import t2b, h2b
class TestDes3(unittest.TestCase):
key = h2b("0123456789abcdeffedeba987654321089abcdef01234567")
IV = h2b("1234567890abcdef")
plain = t2b("Now is the time for all ")
cipher = h2b("43a0297ed184f80e8964843212d508981894157487127db0")
def setUp(self):
self.des3 = Des3.new(self.key, MODE_CBC, self.IV)
def test_raises(self):
# 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 = t2b("")
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 = t2b("")
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 = t2b("now is the time ")
cipher = h2b("959492575f4281532ccc9d4677a233cb")
def setUp(self):
self.aes = Aes.new(self.key, MODE_CBC, self.IV)
def test_raises(self):
# 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 = t2b("")
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 = t2b("")
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 = t2b("Everyone gets Friday off.")
def setUp(self):
self.rsa = RsaPrivate(h2b(self.key))
def test_raises(self):
# invalid key
self.assertRaises(WolfCryptError, 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 = t2b("Everyone gets Friday off.")
def setUp(self):
self.private = RsaPrivate(h2b(self.prv))
self.public = RsaPublic(h2b(self.pub))
def test_raises(self):
# invalid key
self.assertRaises(WolfCryptError, 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

View File

@ -0,0 +1,149 @@
# 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 *
from wolfcrypt.utils import t2b, h2b
class TestSha(unittest.TestCase):
_class = Sha
digest = t2b("1b6182d68ae91ce0853bd9c6b6edfedd4b6a510d")
def setUp(self):
self.hash = self._class()
def test_new(self):
# update inside constructor
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() == h2b(self.digest)
def test_hash_update_002(self):
self.hash.update("wolf")
self.hash.update("crypt")
assert self.hash.hexdigest() == self.digest
assert self.hash.digest() == h2b(self.digest)
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(TestSha):
_class = Sha256
digest = t2b("96e02e7b1cbcd6f104fe1fdb4652027a" \
+ "5505b68652b70095c6318f9dce0d1844")
class TestSha384(TestSha):
_class = Sha384
digest = t2b("4c79d80531203a16f91bee325f18c6aada47f9382fe44fc1" \
+ "1f92917837e9b7902f5dccb7d3656f667a1dce3460bc884b")
class TestSha512(TestSha):
_class = Sha512
digest = t2b("88fcf67ffd8558d713f9cedcd852db47" \
+ "9e6573f0bd9955610a993f609637553c" \
+ "e8fff55e644ee8a106aae19c07f91b3f" \
+ "2a2a6d40dfa7302c0fa6a1a9a5bfa03f")
_HMAC_KEY = "python"
class TestHmacSha(unittest.TestCase):
_class = HmacSha
digest = t2b("5dfabcfb3a25540824867cd21f065f52f73491e0")
def setUp(self):
self.hash = self._class(_HMAC_KEY)
def test_new(self):
# update inside constructor
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
def test_hash_update_002(self):
self.hash.update("wolf")
self.hash.update("crypt")
assert self.hash.hexdigest() == self.digest
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(TestHmacSha):
_class = HmacSha256
digest = t2b("4b641d721493d80f019d9447830ebfee" \
+ "89234a7d594378b89f8bb73873576bf6")
class TestHmacSha384(TestHmacSha):
_class = HmacSha384
digest = t2b("e72c72070c9c5c78e3286593068a510c1740cdf9dc34b512" \
+ "ccec97320295db1fe673216b46fe72e81f399a9ec04780ab")
class TestHmacSha512(TestHmacSha):
_class = HmacSha512
digest = t2b("c7f48db79314fc2b5be9a93fd58601a1" \
+ "bf42f397ec7f66dba034d44503890e6b" \
+ "5708242dcd71a248a78162d815c685f6" \
+ "038a4ac8cb34b8bf18986dbd300c9b41")

View File

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

7
wrapper/python/tox.ini Normal file
View File

@ -0,0 +1,7 @@
[tox]
envlist=py27,py34,py35
skip_missing_interpreters=true
[testenv]
deps=-rrequirements-testing.txt
commands=py.test test/

View File

@ -0,0 +1,45 @@
# __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.8",
__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, ssl, embedded, embedded ssl",
__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)
__all__ = list(metadata.keys())

View File

@ -0,0 +1,21 @@
# __init__.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 .__about__ import *

View File

@ -0,0 +1,133 @@
# build_ffi.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 <wolfssl/options.h>
#include <wolfssl/wolfcrypt/sha.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha512.h>
#include <wolfssl/wolfcrypt/hmac.h>
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/des3.h>
#include <wolfssl/wolfcrypt/asn.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/rsa.h>
""",
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)

View File

@ -0,0 +1,349 @@
# 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.utils import t2b
from wolfcrypt.random import Random
from wolfcrypt.exceptions import *
# 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):
"""
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:
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):
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 = t2b(key)
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)
ret = self._set_key(_ENCRYPTION)
if ret < 0:
raise WolfCryptError("Invalid key error (%d)" % ret)
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)
ret = self._set_key(_DECRYPTION)
if ret < 0:
raise WolfCryptError("Invalid key error (%d)" % ret)
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]
_native_type = "Aes *"
def _set_key(self, direction):
if direction == _ENCRYPTION:
return _lib.wc_AesSetKey(
self._enc, self._key, len(self._key), self._IV, _ENCRYPTION)
else:
return _lib.wc_AesSetKey(
self._dec, self._key, len(self._key), self._IV, _DECRYPTION)
def _encrypt(self, destination, source):
return _lib.wc_AesCbcEncrypt(self._enc, destination, source,len(source))
def _decrypt(self, destination, 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 *"
def _set_key(self, direction):
if direction == _ENCRYPTION:
return _lib.wc_Des3_SetKey(self._enc,self._key,self._IV,_ENCRYPTION)
else:
return _lib.wc_Des3_SetKey(self._dec,self._key,self._IV,_DECRYPTION)
def _encrypt(self, destination, source):
return _lib.wc_Des3_CbcEncrypt(self._enc,destination,source,len(source))
def _decrypt(self, destination, 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 *")
ret = _lib.wc_InitRsaKey(self.native_object, _ffi.NULL)
if ret < 0:
raise WolfCryptError("Invalid key error (%d)" % ret)
self._random = Random()
def __del__(self):
if self.native_object:
_lib.wc_FreeRsaKey(self.native_object)
class RsaPublic(_Rsa):
def __init__(self, key):
key = t2b(key)
_Rsa.__init__(self)
idx = _ffi.new("word32*")
idx[0] = 0
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 WolfCryptError("Invalid key error (%d)" % self.output_size)
def encrypt(self, plaintext):
"""
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),
self.native_object,
self._random.native_object)
if ret != self.output_size:
raise WolfCryptError("Encryption error (%d)" % ret)
return ciphertext
def verify(self, signature):
"""
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 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
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):
"""
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 WolfCryptError("Decryption error (%d)" % ret)
return plaintext[:ret]
def sign(self, plaintext):
"""
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),
self.native_object,
self._random.native_object)
if ret != self.output_size:
raise WolfCryptError("Signature error (%d)" % ret)
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

@ -0,0 +1,302 @@
# 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
from wolfcrypt.utils import t2b, b2h
from wolfcrypt.exceptions import *
class _Hash(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):
self.update(string)
@classmethod
def new(cls, string=None):
"""
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,
self._native_object,
self._native_size)
return copy
def update(self, 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):
"""
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)
ret = self._final(obj, result)
if ret < 0:
raise WolfCryptError("Hash finalize error (%d)" % ret)
return result
def hexdigest(self):
"""
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):
return _lib.wc_InitSha(self._native_object)
def _update(self, data):
return _lib.wc_ShaUpdate(self._native_object, data, len(data))
def _final(self, 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):
return _lib.wc_InitSha256(self._native_object)
def _update(self, data):
return _lib.wc_Sha256Update(self._native_object, data, len(data))
def _final(self, 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):
return _lib.wc_InitSha384(self._native_object)
def _update(self, data):
return _lib.wc_Sha384Update(self._native_object, data, len(data))
def _final(self, 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):
return _lib.wc_InitSha512(self._native_object)
def _update(self, data):
return _lib.wc_Sha512Update(self._native_object, data, len(data))
def _final(self, obj, ret):
return _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):
"""
A **PEP 247: Cryptographic Hash Functions** compliant
**Keyed Hash Function Interface**.
"""
digest_size = None
_native_type = "Hmac *"
_native_size = _ffi.sizeof("Hmac")
def __init__(self, key, string=None):
key = t2b(key)
self._native_object = _ffi.new(self._native_type)
ret = self._init(self._type, key)
if ret < 0:
raise WolfCryptError("Hmac init error (%d)" % ret)
if (string):
self.update(string)
@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):
return _lib.wc_HmacSetKey(self._native_object, type, key, len(key))
def _update(self, data):
return _lib.wc_HmacUpdate(self._native_object, data, len(data))
def _final(self, 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

View File

@ -0,0 +1,68 @@
# 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
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 *")
ret = _lib.wc_InitRng(self.native_object)
if ret < 0:
self.native_object = None
raise WolfCryptError("RNG init error (%d)" % ret)
def __del__(self):
if self.native_object:
_lib.wc_FreeRng(self.native_object)
def byte(self):
"""
Generate and return a random byte.
"""
result = t2b("\0")
ret = _lib.wc_RNG_GenerateByte(self.native_object, result)
if ret < 0:
raise WolfCryptError("RNG generate byte error (%d)" % ret)
return result
def bytes(self, length):
"""
Generate and return a random sequence of length bytes.
"""
result = t2b("\0" * length)
ret = _lib.wc_RNG_GenerateBlock(self.native_object, result, length)
if ret < 0:
raise WolfCryptError("RNG generate block error (%d)" % 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")