docs, tests, general huge improvements to RSA decryption
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index c5c5a16..677f4c6 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -118,7 +118,7 @@
         """
 
     @abc.abstractmethod
-    def rsa_decrypt(self, private_key, ciphertext, padding):
+    def decrypt_rsa(self, private_key, ciphertext, padding):
         """
         Returns decrypted bytes.
         """
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 2965c78..ca898df 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -473,14 +473,15 @@
             y=self._bn_to_int(ctx.pub_key)
         )
 
-    def rsa_decrypt(self, private_key, ciphertext, padding):
+    def decrypt_rsa(self, private_key, ciphertext, padding):
         if isinstance(padding, PKCS1v15):
             padding_enum = self._lib.RSA_PKCS1_PADDING
         elif isinstance(padding, OAEP):
             padding_enum = self._lib.RSA_PKCS1_OAEP_PADDING
             if not isinstance(padding._mgf, MGF1):
                 raise UnsupportedAlgorithm(
-                    "Only MGF1 is supported by this backend"
+                    "Only MGF1 is supported by this backend",
+                    _Reasons.UNSUPPORTED_MGF
                 )
 
             if not isinstance(padding._mgf._algorithm, hashes.SHA1):
@@ -489,6 +490,16 @@
                     "using OAEP",
                     _Reasons.UNSUPPORTED_HASH
                 )
+
+            if padding._label is not None and padding._label != b"":
+                raise ValueError("This backend does not support OAEP labels")
+
+            if not isinstance(padding._algorithm, hashes.SHA1):
+                raise UnsupportedAlgorithm(
+                    "This backend only supports SHA1 when using OAEP",
+                    _Reasons.UNSUPPORTED_HASH
+                )
+
         else:
             raise UnsupportedAlgorithm(
                 "{0} is not supported by this backend".format(
@@ -519,16 +530,17 @@
                 ciphertext,
                 len(ciphertext)
             )
-            assert res >= 0
-            if res == 0:
+            if res <= 0:
                 errors = self._consume_errors()
                 assert errors
-                raise SystemError  # TODO
+                raise self._unknown_error(errors[0])  # TODO
 
             return self._ffi.buffer(buf)[:outlen[0]]
         else:
             rsa_cdata = self._rsa_cdata_from_private_key(private_key)
             rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+            res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL)
+            assert res == 1
             key_size = self._lib.RSA_size(rsa_cdata)
             assert key_size > 0
             buf = self._ffi.new("unsigned char[]", key_size)
@@ -542,7 +554,7 @@
             if res < 0:
                 errors = self._consume_errors()
                 assert errors
-                raise SystemError  # TODO
+                raise self._unknown_error(errors[0])  # TODO
 
             return self._ffi.buffer(buf)[:res]
 
diff --git a/cryptography/hazmat/primitives/asymmetric/padding.py b/cryptography/hazmat/primitives/asymmetric/padding.py
index 899fed1..9755dbc 100644
--- a/cryptography/hazmat/primitives/asymmetric/padding.py
+++ b/cryptography/hazmat/primitives/asymmetric/padding.py
@@ -58,8 +58,13 @@
 class OAEP(object):
     name = "EME-OAEP"
 
-    def __init__(self, mgf):
+    def __init__(self, mgf, algorithm, label):
         self._mgf = mgf
+        if not isinstance(algorithm, interfaces.HashAlgorithm):
+            raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+
+        self._algorithm = algorithm
+        self._label = label
 
 
 class MGF1(object):
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index 5b15350..cffd4e9 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -189,6 +189,15 @@
 
         return backend.create_rsa_signature_ctx(self, padding, algorithm)
 
+    def decrypt(self, ciphertext, padding, backend):
+        if not isinstance(backend, RSABackend):
+            raise UnsupportedAlgorithm(
+                "Backend object does not implement RSABackend",
+                _Reasons.BACKEND_MISSING_INTERFACE
+            )
+
+        return backend.decrypt_rsa(self, ciphertext, padding)
+
     @property
     def key_size(self):
         return utils.bit_length(self.modulus)
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index 394d060..71cd456 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -263,6 +263,18 @@
         :returns: ``True`` if the specified ``algorithm`` is supported by this
             backend, otherwise ``False``.
 
+    .. method:: decrypt_rsa(private_key, ciphertext, padding)
+
+        :param private_key: An instance of an
+            :class:`~cryptography.hazmat.primitives.interfaces.RSAPrivateKey`
+            provider.
+
+        :param bytes ciphertext: The ciphertext to decrypt.
+
+        :param padding: An instance of an
+            :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
+            provider.
+
 
 .. class:: OpenSSLSerializationBackend
 
diff --git a/docs/hazmat/primitives/asymmetric/padding.rst b/docs/hazmat/primitives/asymmetric/padding.rst
index 89af7ea..0c2f7ce 100644
--- a/docs/hazmat/primitives/asymmetric/padding.rst
+++ b/docs/hazmat/primitives/asymmetric/padding.rst
@@ -10,6 +10,21 @@
     correct padding signatures can be forged, messages decrypted, and private
     keys compromised.
 
+.. class:: OAEP(mgf, label)
+
+    .. versionadded:: 0.4
+
+    OAEP (Optimal Asymmetric Encryption Padding) is a padding scheme defined in
+    :rfc:`3447`. It provides probabilistic encryption and is `proven secure`_
+    against several attack types. This is the `recommended padding algorithm`_
+    for RSA encryption. It cannot be used with RSA signing.
+
+    :param mgf: A mask generation function object. At this time the only
+        supported MGF is :class:`MGF1`.
+
+    :param bytes label: A label to apply. This is a rarely used field and many
+        backends do not support it.
+
 .. class:: PSS(mgf, salt_length)
 
     .. versionadded:: 0.3
@@ -19,7 +34,8 @@
 
     PSS (Probabilistic Signature Scheme) is a signature scheme defined in
     :rfc:`3447`. It is more complex than PKCS1 but possesses a `security proof`_.
-    This is the `recommended padding algorithm`_ for RSA signatures.
+    This is the `recommended padding algorithm`_ for RSA signatures. It cannot
+    be used with RSA encryption.
 
     :param mgf: A mask generation function object. At this time the only
         supported MGF is :class:`MGF1`.
@@ -37,7 +53,8 @@
     .. versionadded:: 0.3
 
     PKCS1 v1.5 (also known as simply PKCS1) is a simple padding scheme
-    developed for use with RSA keys. It is defined in :rfc:`3447`.
+    developed for use with RSA keys. It is defined in :rfc:`3447`. This padding
+    can be used for signing and encryption.
 
 Mask generation functions
 ~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -58,5 +75,6 @@
 
 
 .. _`Padding is critical`: http://rdist.root.org/2009/10/06/why-rsa-encryption-padding-is-critical/
+.. _`proven secure`: http://cseweb.ucsd.edu/users/mihir/papers/oae.pdf
 .. _`security proof`: http://eprint.iacr.org/2001/062.pdf
 .. _`recommended padding algorithm`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 43d28c3..46feae4 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -143,8 +143,8 @@
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH):
             backend.derive_pbkdf2_hmac(hashes.SHA256(), 10, b"", 1000, b"")
 
-    # This test is not in the next class because to check if it's really
-    # default we don't want to run the setup_method before it
+    # This test is not in the TestOpenSSLRandomEngine class because to check
+    # if it's really default we don't want to run the setup_method before it
     def test_osrandom_engine_is_default(self):
         e = backend._lib.ENGINE_get_default_RAND()
         name = backend._lib.ENGINE_get_name(e)
@@ -291,3 +291,54 @@
 
     def test_unsupported_mgf1_hash_algorithm(self):
         assert backend.mgf1_hash_supported(DummyHash()) is False
+
+    def test_unsupported_mgf1_hash_algorithm_decrypt(self):
+        private_key = rsa.RSAPrivateKey.generate(
+            public_exponent=65537,
+            key_size=512,
+            backend=backend
+        )
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH):
+            private_key.decrypt(
+                b"ciphertext",
+                padding.OAEP(
+                    mgf=padding.MGF1(algorithm=hashes.SHA256()),
+                    algorithm=hashes.SHA1(),
+                    label=None
+                ),
+                backend
+            )
+
+    def test_unsupported_oaep_hash_algorithm_decrypt(self):
+        private_key = rsa.RSAPrivateKey.generate(
+            public_exponent=65537,
+            key_size=512,
+            backend=backend
+        )
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH):
+            private_key.decrypt(
+                b"ciphertext",
+                padding.OAEP(
+                    mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                    algorithm=hashes.SHA256(),
+                    label=None
+                ),
+                backend
+            )
+
+    def test_unsupported_oaep_label_decrypt(self):
+        private_key = rsa.RSAPrivateKey.generate(
+            public_exponent=65537,
+            key_size=512,
+            backend=backend
+        )
+        with pytest.raises(ValueError):
+            private_key.decrypt(
+                b"ciphertext",
+                padding.OAEP(
+                    mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                    algorithm=hashes.SHA1(),
+                    label=b"label"
+                ),
+                backend
+            )
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index 70ae20d..7b658b6 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -1227,6 +1227,17 @@
         assert mgf._salt_length == padding.MGF1.MAX_LENGTH
 
 
+class TestOAEP(object):
+    def test_invalid_algorithm(self):
+        mgf = padding.MGF1(hashes.SHA1())
+        with pytest.raises(TypeError):
+            padding.OAEP(
+                mgf=mgf,
+                algorithm=b"",
+                label=None
+            )
+
+
 @pytest.mark.rsa
 class TestRSADecryption(object):
     @pytest.mark.parametrize(
@@ -1249,16 +1260,14 @@
             public_exponent=private["public_exponent"],
             modulus=private["modulus"]
         )
-        message = backend.rsa_decrypt(
-            skey,
+        message = skey.decrypt(
             binascii.unhexlify(example["encryption"]),
-            # TODO: handle MGF1 here
             padding.OAEP(
-                padding.MGF1(
-                    algorithm=hashes.SHA1(),
-                    salt_length=padding.MGF1.MAX_LENGTH
-                )
-            )
+                mgf=padding.MGF1(algorithm=hashes.SHA1()),
+                algorithm=hashes.SHA1(),
+                label=None
+            ),
+            backend
         )
         assert message == binascii.unhexlify(example["message"])
 
@@ -1282,9 +1291,48 @@
             public_exponent=private["public_exponent"],
             modulus=private["modulus"]
         )
-        message = backend.rsa_decrypt(
-            skey,
+        message = skey.decrypt(
             binascii.unhexlify(example["encryption"]),
-            padding.PKCS1v15()
+            padding.PKCS1v15(),
+            backend
         )
         assert message == binascii.unhexlify(example["message"])
+
+    def test_unsupported_padding(self, backend):
+        private_key = rsa.RSAPrivateKey.generate(
+            public_exponent=65537,
+            key_size=512,
+            backend=backend
+        )
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
+            private_key.decrypt(b"somedata", DummyPadding(), backend)
+
+    def test_unsupported_oaep_mgf(self, backend):
+        private_key = rsa.RSAPrivateKey.generate(
+            public_exponent=65537,
+            key_size=512,
+            backend=backend
+        )
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF):
+            private_key.decrypt(
+                b"ciphertext",
+                padding.OAEP(
+                    mgf=DummyMGF(),
+                    algorithm=hashes.SHA1(),
+                    label=None
+                ),
+                backend
+            )
+
+    def test_decrypt_invalid_decrypt(self, backend):
+        private_key = rsa.RSAPrivateKey.generate(
+            public_exponent=65537,
+            key_size=512,
+            backend=backend
+        )
+        with pytest.raises(exceptions.InternalError):
+            private_key.decrypt(
+                b"\x00" * 64,
+                padding.PKCS1v15(),
+                backend
+            )