aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2014-04-24 12:07:54 -0500
committerPaul Kehrer <paul.l.kehrer@gmail.com>2014-04-24 16:41:44 -0500
commit4e602f383aa7ee7e43b344e805d92f9626f4a8c7 (patch)
tree15356eb07291b80e92edd79ebe5da023306a0336 /cryptography
parentdcf63ab6bcee9d5a4ae837186db8f0804ddca62c (diff)
downloadcryptography-4e602f383aa7ee7e43b344e805d92f9626f4a8c7.tar.gz
cryptography-4e602f383aa7ee7e43b344e805d92f9626f4a8c7.tar.bz2
cryptography-4e602f383aa7ee7e43b344e805d92f9626f4a8c7.zip
RSA encryption support
Diffstat (limited to 'cryptography')
-rw-r--r--cryptography/hazmat/backends/interfaces.py6
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py83
-rw-r--r--cryptography/hazmat/primitives/asymmetric/rsa.py9
3 files changed, 68 insertions, 30 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 677f4c67..ca7122c2 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -123,6 +123,12 @@ class RSABackend(object):
Returns decrypted bytes.
"""
+ @abc.abstractmethod
+ def encrypt_rsa(self, public_key, plaintext, padding):
+ """
+ Returns encrypted bytes.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DSABackend(object):
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 16b963ae..7d48228a 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -475,6 +475,12 @@ class Backend(object):
)
def decrypt_rsa(self, private_key, ciphertext, padding):
+ return self._enc_dec_rsa(b"DECRYPT", private_key, ciphertext, padding)
+
+ def encrypt_rsa(self, public_key, plaintext, padding):
+ return self._enc_dec_rsa(b"ENCRYPT", public_key, plaintext, padding)
+
+ def _enc_dec_rsa(self, enc_dec, key, data, padding):
if isinstance(padding, PKCS1v15):
padding_enum = self._lib.RSA_PKCS1_PADDING
elif isinstance(padding, OAEP):
@@ -508,24 +514,31 @@ class Backend(object):
_Reasons.UNSUPPORTED_PADDING
)
- key_size_bytes = int(math.ceil(private_key.key_size / 8.0))
- if key_size_bytes < len(ciphertext):
- raise ValueError("Ciphertext too large for key size")
+ key_size_bytes = int(math.ceil(key.key_size / 8.0))
+ if key_size_bytes < len(data):
+ raise ValueError("Data too large for key size")
if self._lib.Cryptography_HAS_PKEY_CTX:
- return self._decrypt_rsa_pkey_ctx(private_key, ciphertext,
- padding_enum)
+ return self._enc_dec_rsa_pkey_ctx(enc_dec, key, data, padding_enum)
+ else:
+ return self._enc_dec_rsa_098(enc_dec, key, data, padding_enum)
+
+ def _enc_dec_rsa_pkey_ctx(self, enc_dec, key, data, padding_enum):
+ if enc_dec == b"ENCRYPT":
+ init = self._lib.EVP_PKEY_encrypt_init
+ crypt = self._lib.Cryptography_EVP_PKEY_encrypt
+ evp_pkey = self._rsa_public_key_to_evp_pkey(key)
else:
- return self._decrypt_rsa_098(private_key, ciphertext, padding_enum)
+ init = self._lib.EVP_PKEY_decrypt_init
+ crypt = self._lib.Cryptography_EVP_PKEY_decrypt
+ evp_pkey = self._rsa_private_key_to_evp_pkey(key)
- def _decrypt_rsa_pkey_ctx(self, private_key, ciphertext, padding_enum):
- evp_pkey = self._rsa_private_key_to_evp_pkey(private_key)
pkey_ctx = self._lib.EVP_PKEY_CTX_new(
evp_pkey, self._ffi.NULL
)
assert pkey_ctx != self._ffi.NULL
pkey_ctx = self._ffi.gc(pkey_ctx, self._lib.EVP_PKEY_CTX_free)
- res = self._lib.EVP_PKEY_decrypt_init(pkey_ctx)
+ res = init(pkey_ctx)
assert res == 1
res = self._lib.EVP_PKEY_CTX_set_rsa_padding(
pkey_ctx, padding_enum)
@@ -534,50 +547,60 @@ class Backend(object):
assert buf_size > 0
outlen = self._ffi.new("size_t *", buf_size)
buf = self._ffi.new("char[]", buf_size)
- res = self._lib.Cryptography_EVP_PKEY_decrypt(
+ res = crypt(
pkey_ctx,
buf,
outlen,
- ciphertext,
- len(ciphertext)
+ data,
+ len(data)
)
if res <= 0:
- errors = self._consume_errors()
- assert errors
- assert errors[0].lib == self._lib.ERR_LIB_RSA
- assert (
- errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
- errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
- )
- raise ValueError("Decryption failed")
+ self._handle_rsa_enc_dec_error(enc_dec)
return self._ffi.buffer(buf)[:outlen[0]]
- def _decrypt_rsa_098(self, private_key, ciphertext, padding_enum):
- rsa_cdata = self._rsa_cdata_from_private_key(private_key)
+ def _enc_dec_rsa_098(self, enc_dec, key, data, padding_enum):
+ if enc_dec == b"ENCRYPT":
+ crypt = self._lib.RSA_public_encrypt
+ rsa_cdata = self._rsa_cdata_from_public_key(key)
+ else:
+ crypt = self._lib.RSA_private_decrypt
+ rsa_cdata = self._rsa_cdata_from_private_key(key)
+
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
key_size = self._lib.RSA_size(rsa_cdata)
assert key_size > 0
buf = self._ffi.new("unsigned char[]", key_size)
- res = self._lib.RSA_private_decrypt(
- len(ciphertext),
- ciphertext,
+ res = crypt(
+ len(data),
+ data,
buf,
rsa_cdata,
padding_enum
)
if res < 0:
- errors = self._consume_errors()
- assert errors
- assert errors[0].lib == self._lib.ERR_LIB_RSA
+ self._handle_rsa_enc_dec_error(enc_dec)
+
+ return self._ffi.buffer(buf)[:res]
+
+ def _handle_rsa_enc_dec_error(self, enc_dec):
+ errors = self._consume_errors()
+ assert errors
+ assert errors[0].lib == self._lib.ERR_LIB_RSA
+ if enc_dec == b"ENCRYPT":
+ assert (errors[0].reason ==
+ self._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
+ raise ValueError(
+ "Data too long for key size. Encrypt less data or use a "
+ "larger key size"
+ )
+ else:
assert (
errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
)
raise ValueError("Decryption failed")
- return self._ffi.buffer(buf)[:res]
-
def cmac_algorithm_supported(self, algorithm):
return (
backend._lib.Cryptography_HAS_CMAC == 1
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index cffd4e98..5d3bb36c 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -52,6 +52,15 @@ class RSAPublicKey(object):
return backend.create_rsa_verification_ctx(self, signature, padding,
algorithm)
+ def encrypt(self, plaintext, padding, backend):
+ if not isinstance(backend, RSABackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement RSABackend",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ return backend.encrypt_rsa(self, plaintext, padding)
+
@property
def key_size(self):
return utils.bit_length(self.modulus)