Merge pull request #962 from reaperhulk/rsa-enc

RSA encryption support
diff --git a/.travis/install.sh b/.travis/install.sh
index 58d7404..7979005 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -32,12 +32,12 @@
     if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi
     case "${TOX_ENV}" in
         py26)
-            curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
+            curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
             sudo python get-pip.py
             sudo pip install virtualenv
             ;;
         py27)
-            curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
+            curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
             sudo python get-pip.py
             sudo pip install virtualenv
             ;;
@@ -62,7 +62,7 @@
             pip install virtualenv
             ;;
         docs)
-            curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
+            curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
             sudo python get-pip.py
             sudo pip install virtualenv
             ;;
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 2fa5e3e..e09fa5d 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -10,7 +10,7 @@
   :class:`~cryptography.hazmat.primitives.asymmetric.padding.MGF1` and added it
   to :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`. It will be
   removed from ``MGF1`` in two releases per our :doc:`/api-stability` policy.
-
+* Added :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SEED` support.
 * Added :class:`~cryptography.hazmat.primitives.cmac.CMAC`.
 * Added decryption support to :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`
   and encryption support to :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`.
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index ca7122c..aaaca5e 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -147,9 +147,9 @@
 
 
 @six.add_metaclass(abc.ABCMeta)
-class OpenSSLSerializationBackend(object):
+class TraditionalOpenSSLSerializationBackend(object):
     @abc.abstractmethod
-    def load_openssl_pem_private_key(self, data, password):
+    def load_traditional_openssl_pem_private_key(self, data, password):
         """
         Load a private key from PEM encoded data, using password if the data
         is encrypted.
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 2114cd8..f9154f3 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -351,7 +351,7 @@
     def _new_evp_pkey(self):
         evp_pkey = self._lib.EVP_PKEY_new()
         assert evp_pkey != self._ffi.NULL
-        return self._ffi.gc(evp_pkey, backend._lib.EVP_PKEY_free)
+        return self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
 
     def _rsa_private_key_to_evp_pkey(self, private_key):
         evp_pkey = self._new_evp_pkey()
@@ -603,8 +603,8 @@
 
     def cmac_algorithm_supported(self, algorithm):
         return (
-            backend._lib.Cryptography_HAS_CMAC == 1
-            and backend.cipher_supported(algorithm, CBC(
+            self._lib.Cryptography_HAS_CMAC == 1
+            and self.cipher_supported(algorithm, CBC(
                 b"\x00" * algorithm.block_size))
         )
 
diff --git a/cryptography/hazmat/bindings/commoncrypto/binding.py b/cryptography/hazmat/bindings/commoncrypto/binding.py
index 3673ea3..144bb09 100644
--- a/cryptography/hazmat/bindings/commoncrypto/binding.py
+++ b/cryptography/hazmat/bindings/commoncrypto/binding.py
@@ -42,8 +42,10 @@
         if cls.ffi is not None and cls.lib is not None:
             return
 
-        cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
-                                     "", "", [])
+        cls.ffi, cls.lib = build_ffi(
+            module_prefix=cls._module_prefix,
+            modules=cls._modules,
+        )
 
     @classmethod
     def is_available(cls):
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index cc40a10..f0ff327 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -97,9 +97,13 @@
         else:  # pragma: no cover
             libraries = ["libeay32", "ssleay32", "advapi32"]
 
-        cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules,
-                                     _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE,
-                                     libraries)
+        cls.ffi, cls.lib = build_ffi(
+            module_prefix=cls._module_prefix,
+            modules=cls._modules,
+            pre_include=_OSX_PRE_INCLUDE,
+            post_include=_OSX_POST_INCLUDE,
+            libraries=libraries,
+        )
         res = cls.lib.Cryptography_add_osrandom_engine()
         assert res != 0
 
diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py
index a530589..7db0332 100644
--- a/cryptography/hazmat/bindings/openssl/dsa.py
+++ b/cryptography/hazmat/bindings/openssl/dsa.py
@@ -48,6 +48,10 @@
 int i2d_DSA_SIG(const DSA_SIG *, unsigned char **);
 DSA_SIG *d2i_DSA_SIG(DSA_SIG **, const unsigned char **, long);
 int DSA_size(const DSA *);
+int DSA_sign(int, const unsigned char *, int, unsigned char *, unsigned int *,
+             DSA *);
+int DSA_verify(int, const unsigned char *, int, const unsigned char *, int,
+               DSA *);
 """
 
 MACROS = """
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index c08c880..f6456d6 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -138,6 +138,7 @@
 static const int EVP_R_AES_KEY_SETUP_FAILED;
 static const int EVP_R_ASN1_LIB;
 static const int EVP_R_BAD_BLOCK_LENGTH;
+static const int EVP_R_BAD_DECRYPT;
 static const int EVP_R_BAD_KEY_LENGTH;
 static const int EVP_R_BN_DECODE_ERROR;
 static const int EVP_R_BN_PUBKEY_ERROR;
diff --git a/cryptography/hazmat/bindings/openssl/x509.py b/cryptography/hazmat/bindings/openssl/x509.py
index 9287036..36a15e4 100644
--- a/cryptography/hazmat/bindings/openssl/x509.py
+++ b/cryptography/hazmat/bindings/openssl/x509.py
@@ -183,8 +183,13 @@
 
 int i2d_RSA_PUBKEY(RSA *, unsigned char **);
 RSA *d2i_RSA_PUBKEY(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPublicKey(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPrivateKey(RSA **, const unsigned char **, long);
 int i2d_DSA_PUBKEY(DSA *, unsigned char **);
 DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long);
+
 
 RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **);
 int i2d_RSAPrivateKey_bio(BIO *, RSA *);
@@ -223,6 +228,11 @@
 int sk_X509_REVOKED_num(Cryptography_STACK_OF_X509_REVOKED *);
 X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int);
 
+int i2d_RSAPublicKey(RSA *, unsigned char **);
+int i2d_RSAPrivateKey(RSA *, unsigned char **);
+int i2d_DSAPublicKey(DSA *, unsigned char **);
+int i2d_DSAPrivateKey(DSA *, unsigned char **);
+
 /* These aren't macros these arguments are all const X on openssl > 1.0.x */
 int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *);
 int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py
index 318b82b..1c48116 100644
--- a/cryptography/hazmat/bindings/utils.py
+++ b/cryptography/hazmat/bindings/utils.py
@@ -20,7 +20,8 @@
 import cffi
 
 
-def build_ffi(module_prefix, modules, pre_include, post_include, libraries):
+def build_ffi(module_prefix, modules, pre_include="", post_include="",
+              libraries=[], extra_compile_args=[], extra_link_args=[]):
     """
     Modules listed in ``modules`` should have the following attributes:
 
@@ -75,6 +76,8 @@
         modulename=_create_modulename(cdef_sources, source, sys.version),
         libraries=libraries,
         ext_package="cryptography",
+        extra_compile_args=extra_compile_args,
+        extra_link_args=extra_link_args,
     )
 
     for name in modules:
diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py
index d78c6a5..c1a763b 100644
--- a/cryptography/hazmat/primitives/padding.py
+++ b/cryptography/hazmat/primitives/padding.py
@@ -20,6 +20,7 @@
 import six
 
 from cryptography import utils
+from cryptography.exceptions import AlreadyFinalized
 from cryptography.hazmat.bindings.utils import _create_modulename
 from cryptography.hazmat.primitives import interfaces
 
@@ -101,7 +102,7 @@
 
     def update(self, data):
         if self._buffer is None:
-            raise ValueError("Context was already finalized")
+            raise AlreadyFinalized("Context was already finalized")
 
         if isinstance(data, six.text_type):
             raise TypeError("Unicode-objects must be encoded before padding")
@@ -117,7 +118,7 @@
 
     def finalize(self):
         if self._buffer is None:
-            raise ValueError("Context was already finalized")
+            raise AlreadyFinalized("Context was already finalized")
 
         pad_size = self.block_size // 8 - len(self._buffer)
         result = self._buffer + six.int2byte(pad_size) * pad_size
@@ -134,7 +135,7 @@
 
     def update(self, data):
         if self._buffer is None:
-            raise ValueError("Context was already finalized")
+            raise AlreadyFinalized("Context was already finalized")
 
         if isinstance(data, six.text_type):
             raise TypeError("Unicode-objects must be encoded before unpadding")
@@ -153,7 +154,7 @@
 
     def finalize(self):
         if self._buffer is None:
-            raise ValueError("Context was already finalized")
+            raise AlreadyFinalized("Context was already finalized")
 
         if len(self._buffer) != self.block_size // 8:
             raise ValueError("Invalid padding bytes")
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index ef7c084..2f63f3e 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -288,7 +288,7 @@
             provider.
 
 
-.. class:: OpenSSLSerializationBackend
+.. class:: TraditionalOpenSSLSerializationBackend
 
     .. versionadded:: 0.3
 
@@ -302,8 +302,8 @@
         :param bytes password: The password to use if this data is encrypted.
             Should be None if the data is not encrypted.
 
-        :return: A new instance of
-            :class:`~cryptography.hazmat.primitives.serialization.OpenSSLPrivateKey`
+        :return: A new instance of the appropriate private key or public key
+            that the serialized data contains.
 
         :raises ValueError: If the data could not be deserialized correctly.
 
diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst
index 83154c0..3056eb9 100644
--- a/docs/hazmat/primitives/padding.rst
+++ b/docs/hazmat/primitives/padding.rst
@@ -5,7 +5,7 @@
 
 .. currentmodule:: cryptography.hazmat.primitives.padding
 
-Padding is a way to take data that may or may not be be a multiple of the block
+Padding is a way to take data that may or may not be a multiple of the block
 size for a cipher and extend it out so that it is. This is required for many
 block cipher modes as they require the data to be encrypted to be an exact
 multiple of the block size.
@@ -66,7 +66,16 @@
 
         :param bytes data: The data you wish to pass into the context.
         :return bytes: Returns the data that was padded or unpadded.
+        :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`.
 
     .. method:: finalize()
 
+        Finalize the current context and return the rest of the data.
+
+        After ``finalize`` has been called this object can no longer be used;
+        :meth:`update` and :meth:`finalize` will raise an
+        :class:`~cryptography.exceptions.AlreadyFinalized` exception.
+
         :return bytes: Returns the remainder of the data.
+        :raises ValueError: When trying to remove padding from incorrectly
+                            padded data.
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 02b9f9e..aae52ae 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -25,6 +25,7 @@
 introspectability
 invariants
 iOS
+metadata
 pickleable
 plaintext
 pseudorandom
diff --git a/pytest.ini b/pytest.ini
index cb6a80a..f717693 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -8,4 +8,5 @@
     hmac: this test requires a backend providing HMACBackend
     pbkdf2hmac: this test requires a backend providing PBKDF2HMACBackend
     rsa: this test requires a backend providing RSABackend
+    traditional_openssl_serialization: this test requires a backend providing TraditionalOpenSSLSerializationBackend
     supported: parametrized test requiring only_if and skip_message
diff --git a/tests/conftest.py b/tests/conftest.py
index d55e6cf..86d5a03 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -18,7 +18,7 @@
 from cryptography.hazmat.backends import _available_backends
 from cryptography.hazmat.backends.interfaces import (
     CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
-    PBKDF2HMACBackend, RSABackend
+    PBKDF2HMACBackend, RSABackend, TraditionalOpenSSLSerializationBackend
 )
 from .utils import check_backend_support, check_for_iface, select_backends
 
@@ -40,6 +40,11 @@
     check_for_iface("pbkdf2hmac", PBKDF2HMACBackend, item)
     check_for_iface("dsa", DSABackend, item)
     check_for_iface("rsa", RSABackend, item)
+    check_for_iface(
+        "traditional_openssl_serialization",
+        TraditionalOpenSSLSerializationBackend,
+        item
+    )
     check_backend_support(item)
 
 
diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py
index 1dbd23b..58d7602 100644
--- a/tests/hazmat/bindings/test_openssl.py
+++ b/tests/hazmat/bindings/test_openssl.py
@@ -84,7 +84,7 @@
         with pytest.raises(RuntimeError):
             b._lock_cb(0, b.lib.CRYPTO_LOCK_SSL, "<test>", 1)
 
-        # errors shouldnt cause locking
+        # errors shouldn't cause locking
         assert lock.acquire(False)
         lock.release()
 
diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py
index 932cef1..cac54f2 100644
--- a/tests/hazmat/primitives/test_padding.py
+++ b/tests/hazmat/primitives/test_padding.py
@@ -17,6 +17,7 @@
 
 import six
 
+from cryptography.exceptions import AlreadyFinalized
 from cryptography.hazmat.primitives import padding
 
 
@@ -97,15 +98,15 @@
     def test_use_after_finalize(self):
         padder = padding.PKCS7(128).padder()
         b = padder.finalize()
-        with pytest.raises(ValueError):
+        with pytest.raises(AlreadyFinalized):
             padder.update(b"")
-        with pytest.raises(ValueError):
+        with pytest.raises(AlreadyFinalized):
             padder.finalize()
 
         unpadder = padding.PKCS7(128).unpadder()
         unpadder.update(b)
         unpadder.finalize()
-        with pytest.raises(ValueError):
+        with pytest.raises(AlreadyFinalized):
             unpadder.update(b"")
-        with pytest.raises(ValueError):
+        with pytest.raises(AlreadyFinalized):
             unpadder.finalize()
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index 602f524..38a5d0a 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -26,7 +26,9 @@
 from cryptography.hazmat.primitives import hashes, interfaces
 from cryptography.hazmat.primitives.asymmetric import padding, rsa
 
-from .utils import generate_rsa_verification_test
+from .utils import (
+    _check_rsa_private_key, generate_rsa_verification_test
+)
 from ...utils import (
     load_pkcs1_vectors, load_rsa_nist_vectors, load_vectors_from_file,
     raises_unsupported_algorithm
@@ -42,24 +44,6 @@
     _salt_length = 0
 
 
-def _check_rsa_private_key(skey):
-    assert skey
-    assert skey.modulus
-    assert skey.public_exponent
-    assert skey.private_exponent
-    assert skey.p * skey.q == skey.modulus
-    assert skey.key_size
-    assert skey.dmp1 == rsa.rsa_crt_dmp1(skey.d, skey.p)
-    assert skey.dmq1 == rsa.rsa_crt_dmq1(skey.d, skey.q)
-    assert skey.iqmp == rsa.rsa_crt_iqmp(skey.p, skey.q)
-
-    pkey = skey.public_key()
-    assert pkey
-    assert skey.modulus == pkey.modulus
-    assert skey.public_exponent == pkey.public_exponent
-    assert skey.key_size == pkey.key_size
-
-
 def _flatten_pkcs1_examples(vectors):
     flattened_vectors = []
     for vector in vectors:
@@ -95,7 +79,7 @@
 @pytest.mark.rsa
 class TestRSA(object):
     @pytest.mark.parametrize(
-        "public_exponent,key_size",
+        ("public_exponent", "key_size"),
         itertools.product(
             (3, 5, 65537),
             (1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1536, 2048)
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index 2e83847..6c3f4c9 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -406,3 +406,21 @@
             verifier.verify()
     else:
         verifier.verify()
+
+
+def _check_rsa_private_key(skey):
+    assert skey
+    assert skey.modulus
+    assert skey.public_exponent
+    assert skey.private_exponent
+    assert skey.p * skey.q == skey.modulus
+    assert skey.key_size
+    assert skey.dmp1 == rsa.rsa_crt_dmp1(skey.d, skey.p)
+    assert skey.dmq1 == rsa.rsa_crt_dmq1(skey.d, skey.q)
+    assert skey.iqmp == rsa.rsa_crt_iqmp(skey.p, skey.q)
+
+    pkey = skey.public_key()
+    assert pkey
+    assert skey.modulus == pkey.modulus
+    assert skey.public_exponent == pkey.public_exponent
+    assert skey.key_size == pkey.key_size
diff --git a/tests/test_utils.py b/tests/test_utils.py
index b50c21f..7a0b9e7 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -2638,7 +2638,7 @@
 
 
 def test_raises_unsupported_algorithm():
-    # Check that it doesnt assert if the right things are raised.
+    # Check that it doesn't assert if the right things are raised.
     with raises_unsupported_algorithm(
         _Reasons.BACKEND_MISSING_INTERFACE
     ) as exc_info: