aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/Makefile139
-rw-r--r--doc/_build/.keep0
-rw-r--r--doc/_static/.keep0
-rw-r--r--doc/_templates/.keep0
-rw-r--r--doc/cli.rst43
-rw-r--r--doc/compatibility.rst62
-rw-r--r--doc/conf.py222
-rw-r--r--doc/index.rst54
-rw-r--r--doc/installation.rst55
-rw-r--r--doc/intro.rst38
-rw-r--r--doc/licence.rst18
-rw-r--r--doc/make.bat170
-rw-r--r--doc/reference.rst112
-rw-r--r--doc/upgrading.rst73
-rw-r--r--doc/usage.rst353
15 files changed, 1339 insertions, 0 deletions
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..9495ae3
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,139 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+default: html
+
+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 " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @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 " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+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."
+
+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/Python-RSA.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Python-RSA.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/Python-RSA"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Python-RSA"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+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)."
+
+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."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+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."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+upload: html
+ @echo
+ @echo "UPLOADING to webserver"
+ @echo
+ rsync _build/html/* stuvel@stuvel.eu:site-stuvel.eu/htdocs/python-rsa-doc/ -va --delete
+
diff --git a/doc/_build/.keep b/doc/_build/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/doc/_build/.keep
diff --git a/doc/_static/.keep b/doc/_static/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/doc/_static/.keep
diff --git a/doc/_templates/.keep b/doc/_templates/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/doc/_templates/.keep
diff --git a/doc/cli.rst b/doc/cli.rst
new file mode 100644
index 0000000..af2b5f1
--- /dev/null
+++ b/doc/cli.rst
@@ -0,0 +1,43 @@
+Commandline interface
+==================================================
+
+A lot of the Python-RSA functionality is also available as commandline
+scripts. On Linux and other unix-like systems they are executable
+Python scripts, on Windows they are .exe files.
+
+All scripts accept a ``--help`` parameter that give you instructions
+on how to use them. Here is a short overview:
+
+.. index:: CLI interface
+.. index:: pyrsa-keygen, pyrsa-encrypt, pyrsa-decrypt, pyrsa-sign
+.. index:: pyrsa-verify, pyrsa-priv2pub, pyrsa-encrypt-bigfile
+.. index:: pyrsa-decrypt-bigfile, pyrsa-decrypt-bigfile
+
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| Command | Usage | Core function |
++=======================+==================================================+=========================================+
+| pyrsa-keygen | Generates a new RSA keypair in PEM or DER format | :py:func:`rsa.newkeys` |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| pyrsa-encrypt | Encrypts a file. The file must be shorter than | :py:func:`rsa.encrypt` |
+| | the key length in order to be encrypted. | |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| pyrsa-decrypt | Decrypts a file. | :py:func:`rsa.decrypt` |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| pyrsa-sign | Signs a file, outputs the signature. | :py:func:`rsa.sign` |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| pyrsa-verify | Verifies a signature. The result is written to | :py:func:`rsa.verify` |
+| | the console as well as returned in the exit | |
+| | status code. | |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| pyrsa-priv2pub | Reads a private key and outputs the | \- |
+| | corresponding public key. | |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| pyrsa-encrypt-bigfile | Encrypts a file to an encrypted VARBLOCK file. | :py:func:`rsa.bigfile.encrypt_bigfile` |
+| | The file can be larger than the key length, but | |
+| | the output file is only compatible with | |
+| | Python-RSA. | |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+| pyrsa-decrypt-bigfile | Decrypts an encrypted VARBLOCK file. | :py:func:`rsa.bigfile.encrypt_bigfile` |
++-----------------------+--------------------------------------------------+-----------------------------------------+
+
+
diff --git a/doc/compatibility.rst b/doc/compatibility.rst
new file mode 100644
index 0000000..aedfcb6
--- /dev/null
+++ b/doc/compatibility.rst
@@ -0,0 +1,62 @@
+Compatibility with standards
+============================
+
+.. index:: OpenSSL
+.. index:: compatibility
+
+Python-RSA implements encryption and signatures according to PKCS#1
+version 1.5. This makes it compatible with the OpenSSL RSA module.
+
+Keys are stored in PEM or DER format according to PKCS#1 v1.5. Private
+keys are compatible with OpenSSL. However, OpenSSL uses X.509 for its
+public keys, which are not supported.
+
+Encryption:
+ PKCS#1 v1.5 with at least 8 bytes of random padding
+
+Signatures:
+ PKCS#1 v1.5 using the following hash methods:
+ MD5, SHA-1, SHA-256, SHA-384, SHA-512
+
+Private keys:
+ PKCS#1 v1.5 in PEM and DER format, ASN.1 type RSAPrivateKey
+
+Public keys:
+ PKCS#1 v1.5 in PEM and DER format, ASN.1 type RSAPublicKey
+
+:ref:`VARBLOCK <bigfiles>` encryption:
+ Python-RSA only, not compatible with any other known application.
+
+.. _openssl:
+
+Interoperability with OpenSSL
+-----------------------------
+
+You can create a 512-bit RSA key in OpenSSL as follows::
+
+ openssl genrsa -out myprivatekey.pem 512
+
+To get a Python-RSA-compatible public key from OpenSSL, you need the
+private key first, then run it through the ``pyrsa-priv2pub``
+command::
+
+ pyrsa-priv2pub -i myprivatekey.pem -o mypublickey.pem
+
+Encryption and decryption is also compatible::
+
+ $ echo hello there > testfile.txt
+ $ pyrsa-encrypt -i testfile.txt -o testfile.rsa publickey.pem
+ $ openssl rsautl -in testfile.rsa -inkey privatekey.pem -decrypt
+ hello there
+
+Interoperability with PKCS#8
+----------------------------
+
+The standard PKCS#8 is widely used, and more complex than the PKCS#1
+v1.5 supported by Python-RSA. In order to extract a key from the
+PKCS#8 format you need an external tool such as OpenSSL::
+
+ openssl rsa -in privatekey-pkcs8.pem -out privatekey.pem
+
+You can then extract the corresponding public key as described above.
+
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 0000000..95317b2
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+#
+# Python-RSA documentation build configuration file, created by
+# sphinx-quickstart on Sat Jul 30 23:11:07 2011.
+#
+# 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 rsa
+
+# 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.todo',
+ 'sphinx.ext.coverage', 'sphinx.ext.pngmath']
+
+# I would like to add 'sphinx.ext.viewcode', but it causes a UnicodeDecodeError
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Python-RSA'
+copyright = u'2011-2016, Sybren A. Stüvel'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = rsa.__version__
+# The full version, including alpha/beta/rc tags.
+release = rsa.__version__
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+language = 'en'
+
+# 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.
+exclude_patterns = ['_build']
+
+# 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 = []
+
+
+# -- 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 = 'sphinxdoc'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+# html_title = None
+
+# 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 (within the static path) to use as 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']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+# html_last_updated_fmt = '%b %d, %Y'
+
+# 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
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Python-RSAdoc'
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+# latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+# latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Python-RSA.tex', u'Python-RSA Documentation',
+ u'Sybren A. Stüvel', '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
+
+# Additional stuff for the LaTeX preamble.
+# latex_preamble = ''
+
+# 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 = [
+ ('index', 'python-rsa', u'Python-RSA Documentation',
+ [u'Sybren A. Stüvel'], 1)
+]
+
+todo_include_todos = True
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..a0a1573
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,54 @@
+.. Python-RSA documentation master file, created by
+ sphinx-quickstart on Sat Jul 30 23:11:07 2011.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to Python-RSA's documentation!
+======================================
+
+Python-RSA is a pure-Python RSA implementation. It supports
+encryption and decryption, signing and verifying signatures, and key
+generation according to PKCS#1 version 1.5.
+
+If you have the time and skill to improve the implementation, by all
+means be my guest. The best way is to clone the `Git
+repository`_ and send me a merge request when you've got something
+worth merging.
+
+.. _`Git repository`: https://github.com/sybrenstuvel/python-rsa
+
+
+Security notice
+---------------
+
+This RSA implementation has seen the eyes of a security expert, and it
+uses an industry standard random padding method. However, there are
+still possible vectors of attack. Just to name one example, it doesn't
+compress the input stream to remove repetitions, and if you display
+the stack trace of a :py:class:`rsa.pkcs1.CryptoError` exception
+you'll leak information about the reason why decryption or
+verification failed.
+
+I'm sure that those aren't the only insecurities. Use your own
+judgement to decide whether this module is secure enough for your
+application.
+
+Contents
+--------
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ intro
+ installation
+ upgrading
+ licence
+ usage
+ cli
+ compatibility
+ reference
+
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/doc/installation.rst b/doc/installation.rst
new file mode 100644
index 0000000..578dc86
--- /dev/null
+++ b/doc/installation.rst
@@ -0,0 +1,55 @@
+Installation
+============
+
+Installation can be done in various ways. The simplest form uses pip
+or easy_install. Either one will work::
+
+ pip install rsa
+ easy_install rsa
+
+Depending on your system you may need to use ``sudo pip`` or ``sudo
+easy_install``.
+
+Installation from source is also quite easy. Download the source and
+then type::
+
+ python setup.py install
+
+or if that doesn't work::
+
+ sudo python setup.py install
+
+
+The sources are tracked in our `Git repository`_ at
+Github. It also hosts the `issue tracker`_.
+
+.. _`Git repository`: https://github.com/sybrenstuvel/python-rsa.git
+.. _`issue tracker`: https://github.com/sybrenstuvel/python-rsa/issues
+
+
+Dependencies
+------------
+
+Python-RSA has very few dependencies. As a matter of fact, to use it
+you only need Python itself. Loading and saving keys does require an
+extra module, though: pyasn1. If you used pip or easy_install like
+described above, you should be ready to go.
+
+
+Development dependencies
+------------------------
+
+In order to start developing on Python-RSA you need a bit more. Use
+pip to install the development requirements in a virtual environment::
+
+ virtualenv -p /path/to/your-python-version python-rsa-venv
+ . python-rsa-venv/bin/activate
+ pip install -r python-rsa/requirements.txt
+
+
+Once these are installed, use Git_ to get a copy of the source::
+
+ hg clone https://github.com/sybrenstuvel/python-rsa.git
+ python setup.py develop
+
+.. _Git: https://git-scm.com/
diff --git a/doc/intro.rst b/doc/intro.rst
new file mode 100644
index 0000000..e689bde
--- /dev/null
+++ b/doc/intro.rst
@@ -0,0 +1,38 @@
+Introduction & history
+======================
+
+Python-RSA's history starts in 2006. As a student assignment for the
+University of Amsterdam we wrote a RSA implementation. We chose Python
+for various reasons; one of the most important reasons was the
+`unlimited precision integer`_ support.
+
+.. _`unlimited precision integer`:
+ https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
+
+It started out as just a module for calculating large primes, and RSA
+encryption, decryption, signing and verification using those large
+numbers. It also included generating public and private keys. There
+was no functionality for working with byte sequences (such as files)
+yet.
+
+Version 1.0 did include support for byte sequences, but quite clunky,
+mostly because it didn't support 0-bytes and thus was unsuitable for
+binary messages.
+
+Version 2.0 introduced a lot of improvements by Barry Mead, but still
+wasn't compatible with other RSA implementations and used no random
+padding.
+
+Version 3.0 introduced PKCS#1 v1.5 functionality, which resulted in
+compatibility with OpenSSL and many others implementing the same
+standard. Random padding was introduced that considerably increased
+security, which also resulted in the ability to encrypt and decrypt
+binary messages.
+
+Key generation was also improved in version 3.0, ensuring that you
+really get the number of bits you asked for. At the same time key
+generation speed was greatly improved. The ability to save and load
+public and private keys in PEM and DER format as also added.
+
+
+
diff --git a/doc/licence.rst b/doc/licence.rst
new file mode 100644
index 0000000..bc07dbd
--- /dev/null
+++ b/doc/licence.rst
@@ -0,0 +1,18 @@
+Licence
+=======
+
+The source code and documentation are protected under copyright by
+Sybren A. Stüvel <sybren@stuvel.eu>
+
+The software is licensed under the Apache License, Version 2.0 (the
+"License"); you may not use the software except in compliance with the
+License. You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied. See the License for the specific language governing
+permissions and limitations under the License.
+
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644
index 0000000..9fb9761
--- /dev/null
+++ b/doc/make.bat
@@ -0,0 +1,170 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "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. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Python-RSA.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Python-RSA.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/doc/reference.rst b/doc/reference.rst
new file mode 100644
index 0000000..d1b0b6d
--- /dev/null
+++ b/doc/reference.rst
@@ -0,0 +1,112 @@
+Reference
+=========
+
+This is the class and function reference. For more usage information
+see the :ref:`usage` page.
+
+Functions
+---------
+
+.. autofunction:: rsa.encrypt
+
+.. autofunction:: rsa.decrypt
+
+.. autofunction:: rsa.sign
+
+.. autofunction:: rsa.verify
+
+.. autofunction:: rsa.newkeys(keysize)
+
+
+Classes
+-------
+
+.. note::
+
+ Storing public and private keys via the `pickle` module is possible.
+ However, it is insecure to load a key from an untrusted source.
+ The pickle module is not secure against erroneous or maliciously
+ constructed data. Never unpickle data received from an untrusted
+ or unauthenticated source.
+
+.. autoclass:: rsa.PublicKey
+ :members:
+ :inherited-members:
+
+.. autoclass:: rsa.PrivateKey
+ :members:
+ :inherited-members:
+
+Exceptions
+----------
+
+.. autoclass:: rsa.pkcs1.CryptoError(Exception)
+
+.. autoclass:: rsa.pkcs1.DecryptionError(CryptoError)
+
+.. autoclass:: rsa.pkcs1.VerificationError(CryptoError)
+
+
+.. index:: VARBLOCK (file format)
+
+Module: rsa.bigfile
+-------------------
+
+.. warning::
+
+ The :py:mod:`rsa.bigfile` module is NOT recommended for general use, has been
+ deprecated since Python-RSA 3.4, and will be removed in a future release. It's
+ vulnerable to a number of attacks. See :ref:`bigfiles` for more information.
+
+The :py:mod:`rsa.bigfile` module contains functions for encrypting and
+decrypting files that are larger than the RSA key. See
+:ref:`bigfiles` for more information.
+
+.. autofunction:: rsa.bigfile.encrypt_bigfile
+
+.. autofunction:: rsa.bigfile.decrypt_bigfile
+
+.. _VARBLOCK:
+
+The VARBLOCK file format
+++++++++++++++++++++++++
+
+.. warning::
+
+ The VARBLOCK format is NOT recommended for general use, has been deprecated since
+ Python-RSA 3.4, and will be removed in a future release. It's vulnerable to a
+ number of attacks. See :ref:`bigfiles` for more information.
+
+The VARBLOCK file format allows us to encrypt files that are larger
+than the RSA key. The format is as follows; || denotes byte string
+concatenation::
+
+ VARBLOCK := VERSION || BLOCK || BLOCK || ...
+
+ VERSION := 1
+
+ BLOCK := LENGTH || DATA
+
+ LENGTH := varint-encoded length of the following data, in bytes
+
+ DATA := the data to store in the block
+
+The varint-format was taken from Google's Protobuf_, and allows us to
+efficiently encode an arbitrarily long integer.
+
+.. _Protobuf:
+ https://code.google.com/apis/protocolbuffers/docs/encoding.html#varints
+
+
+Module: rsa.core
+----------------
+
+At the core of the RSA encryption method lie these functions. They
+both operate on (arbitrarily long) integers only. They probably aren't
+of much use to you, but I wanted to document them anyway as they are
+the core of the entire library.
+
+.. autofunction:: rsa.core.encrypt_int
+
+.. autofunction:: rsa.core.decrypt_int
+
diff --git a/doc/upgrading.rst b/doc/upgrading.rst
new file mode 100644
index 0000000..0ec18eb
--- /dev/null
+++ b/doc/upgrading.rst
@@ -0,0 +1,73 @@
+Upgrading from older versions
+=============================
+
+Previous versions of Python-RSA were less secure than the current
+version. In order to be able to gradually upgrade your software, those
+old versions will be available until Python-RSA 4.0.
+
+To use version 1.3.3, use this::
+
+ import rsa._version133 as rsa
+
+And to use version 2.0, use this::
+
+ import rsa._version200 as rsa
+
+You can import all three versions at the same time. This allows you to
+use an old version to decrypt your messages, and a new version to
+re-encrypt them::
+
+ import rsa._version200 as rsa200
+ import rsa # this imports version 3.0
+
+ decrypted = rsa200.decrypt(old_crypto, version_200_private_key)
+ new_crypto = rsa.encrypt(decrypted, version_3_public_key)
+
+Those import statements *will create warnings* as they import much
+less secure code into your project.
+
+.. warning::
+
+ These modules are included to allow upgrading to the latest version
+ of Python-RSA, and not as a way to keep using those old versions.
+ They will be removed in version 4.0.
+
+The random padding introduced in version 3.0 made things much more
+secure, but also requires a larger key to encrypt the same message.
+You can either generate a new key with :py:func:`rsa.newkeys`, or use
+:py:func:`rsa.bigfile.encrypt_bigfile` to encrypt your files.
+
+Converting keys
+---------------
+
+Version 3.0 introduced industrial standard RSA keys according to
+PKCS#1. The old keys were just dictionaries. To convert a key from an
+older version of Python-RSA, use the following::
+
+ import rsa
+
+ # Load the old key somehow.
+ old_pub_key = {
+ 'e': 65537,
+ 'n': 31698122414741849421263704398157795847591L
+ }
+
+ old_priv_key = {
+ 'd': 7506520894712811128876594754922157377793L,
+ 'p': 4169414332984308880603L,
+ 'q': 7602535963858869797L
+ }
+
+ # Create new key objects like this:
+ pub_key = rsa.PublicKey(n=old_pub_key['n'], e=old_pub_key['e'])
+
+ priv_key = rsa.PrivateKey(n=old_pub_key['n'], e=old_pub_key['e'],
+ d=old_priv_key['d'], p=old_priv_key['p'], q=old_priv_key['q'])
+
+
+ # Or use this shorter notation:
+ pub_key = rsa.PublicKey(**old_pub_key)
+
+ old_priv_key.update(old_pub_key)
+ priv_key = rsa.PrivateKey(**old_priv_key)
+
diff --git a/doc/usage.rst b/doc/usage.rst
new file mode 100644
index 0000000..a3d128d
--- /dev/null
+++ b/doc/usage.rst
@@ -0,0 +1,353 @@
+.. _usage:
+
+Usage
+=====
+
+This section describes the usage of the Python-RSA module.
+
+Before you can use RSA you need keys. You will receive a private key
+and a public key.
+
+.. important::
+
+ The private key is called *private* for a reason. Never share this
+ key with anyone.
+
+The public key is used for encypting a message such that it can only
+be read by the owner of the private key. As such it's also referred to
+as the *encryption key*. Decrypting a message can only be done using
+the private key, hence it's also called the *decryption key*.
+
+The private key is used for signing a message. With this signature and
+the public key, the receiver can verifying that a message was signed
+by the owner of the private key, and that the message was not modified
+after signing.
+
+
+Generating keys
+---------------
+
+You can use the :py:func:`rsa.newkeys` function to create a keypair:
+
+ >>> import rsa
+ >>> (pubkey, privkey) = rsa.newkeys(512)
+
+Alternatively you can use :py:meth:`rsa.PrivateKey.load_pkcs1` and
+:py:meth:`rsa.PublicKey.load_pkcs1` to load keys from a file:
+
+ >>> import rsa
+ >>> with open('private.pem', mode='rb') as privatefile:
+ ... keydata = privatefile.read()
+ >>> privkey = rsa.PrivateKey.load_pkcs1(keydata)
+
+
+Time to generate a key
+++++++++++++++++++++++
+
+Generating a keypair may take a long time, depending on the number of
+bits required. The number of bits determines the cryptographic
+strength of the key, as well as the size of the message you can
+encrypt. If you don't mind having a slightly smaller key than you
+requested, you can pass ``accurate=False`` to speed up the key
+generation process.
+
+Another way to speed up the key generation process is to use multiple
+processes in parallel to speed up the key generation. Use no more than
+the number of processes that your machine can run in parallel; a
+dual-core machine should use ``poolsize=2``; a quad-core
+hyperthreading machine can run two threads on each core, and thus can
+use ``poolsize=8``.
+
+ >>> (pubkey, privkey) = rsa.newkeys(512, poolsize=8)
+
+These are some average timings from my desktop machine (Linux 2.6,
+2.93 GHz quad-core Intel Core i7, 16 GB RAM) using 64-bit CPython 2.7.
+Since key generation is a random process, times may differ even on
+similar hardware. On all tests, we used the default ``accurate=True``.
+
++----------------+------------------+------------------+
+| Keysize (bits) | single process | eight processes |
++================+==================+==================+
+| 128 | 0.01 sec. | 0.01 sec. |
++----------------+------------------+------------------+
+| 256 | 0.03 sec. | 0.02 sec. |
++----------------+------------------+------------------+
+| 384 | 0.09 sec. | 0.04 sec. |
++----------------+------------------+------------------+
+| 512 | 0.11 sec. | 0.07 sec. |
++----------------+------------------+------------------+
+| 1024 | 0.79 sec. | 0.30 sec. |
++----------------+------------------+------------------+
+| 2048 | 6.55 sec. | 1.60 sec. |
++----------------+------------------+------------------+
+| 3072 | 23.4 sec. | 7.14 sec. |
++----------------+------------------+------------------+
+| 4096 | 72.0 sec. | 24.4 sec. |
++----------------+------------------+------------------+
+
+If key generation is too slow for you, you could use OpenSSL to
+generate them for you, then load them in your Python code. OpenSSL
+generates a 4096-bit key in 3.5 seconds on the same machine as used
+above. See :ref:`openssl` for more information.
+
+Key size requirements
+---------------------
+
+Python-RSA version 3.0 introduced PKCS#1-style random padding. This
+means that 11 bytes (88 bits) of your key are no longer usable for
+encryption, so keys smaller than this are unusable. The larger the
+key, the higher the security.
+
+Creating signatures also requires a key of a certain size, depending
+on the used hash method:
+
++-------------+-----------------------------------+
+| Hash method | Suggested minimum key size (bits) |
++=============+===================================+
+| MD5 | 360 |
++-------------+-----------------------------------+
+| SHA-1 | 368 |
++-------------+-----------------------------------+
+| SHA-256 | 496 |
++-------------+-----------------------------------+
+| SHA-384 | 624 |
++-------------+-----------------------------------+
+| SHA-512 | 752 |
++-------------+-----------------------------------+
+
+
+
+Encryption and decryption
+-------------------------
+
+To encrypt or decrypt a message, use :py:func:`rsa.encrypt` resp.
+:py:func:`rsa.decrypt`. Let's say that Alice wants to send a message
+that only Bob can read.
+
+#. Bob generates a keypair, and gives the public key to Alice. This is
+ done such that Alice knows for sure that the key is really Bob's
+ (for example by handing over a USB stick that contains the key).
+
+ >>> import rsa
+ >>> (bob_pub, bob_priv) = rsa.newkeys(512)
+
+#. Alice writes a message, and encodes it in UTF-8. The RSA module
+ only operates on bytes, and not on strings, so this step is
+ necessary.
+
+ >>> message = 'hello Bob!'.encode('utf8')
+
+#. Alice encrypts the message using Bob's public key, and sends the
+ encrypted message.
+
+ >>> import rsa
+ >>> crypto = rsa.encrypt(message, bob_pub)
+
+#. Bob receives the message, and decrypts it with his private key.
+
+ >>> message = rsa.decrypt(crypto, bob_priv)
+ >>> print(message.decode('utf8'))
+ hello Bob!
+
+Since Bob kept his private key *private*, Alice can be sure that he is
+the only one who can read the message. Bob does *not* know for sure
+that it was Alice that sent the message, since she didn't sign it.
+
+
+RSA can only encrypt messages that are smaller than the key. A couple
+of bytes are lost on random padding, and the rest is available for the
+message itself. For example, a 512-bit key can encode a 53-byte
+message (512 bit = 64 bytes, 11 bytes are used for random padding and
+other stuff). See :ref:`bigfiles` for information on how to work with
+larger files.
+
+Altering the encrypted information will *likely* cause a
+:py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use
+:py:func:`rsa.sign`.
+
+ >>> crypto = rsa.encrypt(b'hello', bob_pub)
+ >>> crypto = crypto[:-1] + b'X' # change the last byte
+ >>> rsa.decrypt(crypto, bob_priv)
+ Traceback (most recent call last):
+ ...
+ rsa.pkcs1.DecryptionError: Decryption failed
+
+
+.. warning::
+
+ Never display the stack trace of a
+ :py:class:`rsa.pkcs1.DecryptionError` exception. It shows where
+ in the code the exception occurred, and thus leaks information
+ about the key. It’s only a tiny bit of information, but every bit
+ makes cracking the keys easier.
+
+Low-level operations
+++++++++++++++++++++
+
+The core RSA algorithm operates on large integers. These operations
+are considered low-level and are supported by the
+:py:func:`rsa.core.encrypt_int` and :py:func:`rsa.core.decrypt_int`
+functions.
+
+Signing and verification
+------------------------
+
+You can create a detached signature for a message using the
+:py:func:`rsa.sign` function:
+
+ >>> (pubkey, privkey) = rsa.newkeys(512)
+ >>> message = 'Go left at the blue tree'
+ >>> signature = rsa.sign(message, privkey, 'SHA-1')
+
+This hashes the message using SHA-1. Other hash methods are also
+possible, check the :py:func:`rsa.sign` function documentation for
+details. The hash is then signed with the private key.
+
+In order to verify the signature, use the :py:func:`rsa.verify`
+function. This function returns True if the verification is successful:
+
+ >>> message = 'Go left at the blue tree'
+ >>> rsa.verify(message, signature, pubkey)
+ True
+
+Modify the message, and the signature is no longer valid and a
+:py:class:`rsa.pkcs1.VerificationError` is thrown:
+
+ >>> message = 'Go right at the blue tree'
+ >>> rsa.verify(message, signature, pubkey)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ File "/home/sybren/workspace/python-rsa/rsa/pkcs1.py", line 289, in verify
+ raise VerificationError('Verification failed')
+ rsa.pkcs1.VerificationError: Verification failed
+
+.. warning::
+
+ Never display the stack trace of a
+ :py:class:`rsa.pkcs1.VerificationError` exception. It shows where
+ in the code the exception occurred, and thus leaks information
+ about the key. It's only a tiny bit of information, but every bit
+ makes cracking the keys easier.
+
+Instead of a message you can also call :py:func:`rsa.sign` and
+:py:func:`rsa.verify` with a :py:class:`file`-like object. If the
+message object has a ``read(int)`` method it is assumed to be a file.
+In that case the file is hashed in 1024-byte blocks at the time.
+
+ >>> with open('somefile', 'rb') as msgfile:
+ ... signature = rsa.sign(msgfile, privkey, 'SHA-1')
+
+ >>> with open('somefile', 'rb') as msgfile:
+ ... rsa.verify(msgfile, signature, pubkey)
+
+
+.. _bigfiles:
+
+Working with big files
+----------------------
+
+RSA can only encrypt messages that are smaller than the key. A couple
+of bytes are lost on random padding, and the rest is available for the
+message itself. For example, a 512-bit key can encode a 53-byte
+message (512 bit = 64 bytes, 11 bytes are used for random padding and
+other stuff).
+
+How it usually works
+++++++++++++++++++++
+
+The most common way to use RSA with larger files uses a block cypher
+like AES or DES3 to encrypt the file with a random key, then encrypt
+the random key with RSA. You would send the encrypted file along with
+the encrypted key to the recipient. The complete flow is:
+
+#. Generate a random key
+
+ >>> import rsa.randnum
+ >>> aes_key = rsa.randnum.read_random_bits(128)
+
+#. Use that key to encrypt the file with AES.
+#. :py:func:`Encrypt <rsa.encrypt>` the AES key with RSA
+
+ >>> encrypted_aes_key = rsa.encrypt(aes_key, public_rsa_key)
+
+#. Send the encrypted file together with ``encrypted_aes_key``
+#. The recipient now reverses this process to obtain the encrypted
+ file.
+
+.. note::
+
+ The Python-RSA module does not contain functionality to do the AES
+ encryption for you.
+
+Only using Python-RSA: the VARBLOCK format
+++++++++++++++++++++++++++++++++++++++++++
+
+.. warning::
+
+ The VARBLOCK format is NOT recommended for general use, has been deprecated since
+ Python-RSA 3.4, and will be removed in a future release. It's vulnerable to a
+ number of attacks:
+
+ 1. decrypt/encrypt_bigfile() does not implement `Authenticated encryption`_ nor
+ uses MACs to verify messages before decrypting public key encrypted messages.
+
+ 2. decrypt/encrypt_bigfile() does not use hybrid encryption (it uses plain RSA)
+ and has no method for chaining, so block reordering is possible.
+
+ See `issue #19 on Github`_ for more information.
+
+.. _Authenticated encryption: https://en.wikipedia.org/wiki/Authenticated_encryption
+.. _issue #19 on Github: https://github.com/sybrenstuvel/python-rsa/issues/13
+
+
+As far as we know, there is no pure-Python AES encryption. Previous
+versions of Python-RSA included functionality to encrypt large files
+with just RSA, and so does this version. The format has been improved,
+though.
+
+Encrypting works as follows: the input file is split into blocks that
+are just large enough to encrypt with your RSA key. Every block is
+then encrypted using RSA, and the encrypted blocks are assembled into
+the output file. This file format is called the :ref:`VARBLOCK
+<VARBLOCK>` format.
+
+Decrypting works in reverse. The encrypted file is separated into
+encrypted blocks. Those are decrypted, and assembled into the original
+file.
+
+.. note::
+
+ The file will get larger after encryption, as each encrypted block
+ has 8 bytes of random padding and 3 more bytes of overhead.
+
+Since these encryption/decryption functions are potentially called on
+very large files, they use another approach. Where the regular
+functions store the message in memory in its entirety, these functions
+work on one block at the time. As a result, you should call them with
+:py:class:`file`-like objects as the parameters.
+
+Before using we of course need a keypair:
+
+>>> import rsa
+>>> (pub_key, priv_key) = rsa.newkeys(512)
+
+Encryption works on file handles using the
+:py:func:`rsa.bigfile.encrypt_bigfile` function:
+
+>>> from rsa.bigfile import *
+>>> with open('inputfile', 'rb') as infile, open('outputfile', 'wb') as outfile:
+... encrypt_bigfile(infile, outfile, pub_key)
+
+As does decryption using the :py:func:`rsa.bigfile.decrypt_bigfile`
+function:
+
+>>> from rsa.bigfile import *
+>>> with open('inputfile', 'rb') as infile, open('outputfile', 'wb') as outfile:
+... decrypt_bigfile(infile, outfile, priv_key)
+
+.. note::
+
+ :py:func:`rsa.sign` and :py:func:`rsa.verify` work on arbitrarily
+ long files, so they do not have a "bigfile" equivalent.
+
+