aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2013-11-19 07:38:19 -0800
committerAlex Gaynor <alex.gaynor@gmail.com>2013-11-19 07:38:19 -0800
commitb29a6b2e4623fa87fecaccc05551b996f684cd53 (patch)
treef3579a5536862a304eaba25612f07f0c2515c8bd /cryptography
parent867acfa0300ca75f2c11c15490e04b556d8bfe99 (diff)
parent62e96cbb0698d8f7d65d8dd2d301ef975a829d9e (diff)
downloadcryptography-b29a6b2e4623fa87fecaccc05551b996f684cd53.tar.gz
cryptography-b29a6b2e4623fa87fecaccc05551b996f684cd53.tar.bz2
cryptography-b29a6b2e4623fa87fecaccc05551b996f684cd53.zip
Merge branch 'master' into fernet
Diffstat (limited to 'cryptography')
-rw-r--r--cryptography/exceptions.py4
-rw-r--r--cryptography/hazmat/bindings/openssl/backend.py274
-rw-r--r--cryptography/hazmat/bindings/openssl/evp.py5
-rw-r--r--cryptography/hazmat/bindings/openssl/ssl.py189
-rw-r--r--cryptography/hazmat/primitives/ciphers/algorithms.py33
-rw-r--r--cryptography/hazmat/primitives/ciphers/base.py25
-rw-r--r--cryptography/hazmat/primitives/ciphers/modes.py23
-rw-r--r--cryptography/hazmat/primitives/hashes.py42
-rw-r--r--cryptography/hazmat/primitives/hmac.py28
-rw-r--r--cryptography/hazmat/primitives/interfaces.py17
-rw-r--r--cryptography/hazmat/primitives/padding.py12
-rw-r--r--cryptography/utils.py21
12 files changed, 477 insertions, 196 deletions
diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py
index 391bed82..c2e71493 100644
--- a/cryptography/exceptions.py
+++ b/cryptography/exceptions.py
@@ -14,3 +14,7 @@
class UnsupportedAlgorithm(Exception):
pass
+
+
+class AlreadyFinalized(Exception):
+ pass
diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py
index 0c3d22d5..92cd3868 100644
--- a/cryptography/hazmat/bindings/openssl/backend.py
+++ b/cryptography/hazmat/bindings/openssl/backend.py
@@ -18,10 +18,11 @@ import sys
import cffi
+from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives import interfaces
from cryptography.hazmat.primitives.ciphers.algorithms import (
- AES, Blowfish, Camellia, CAST5, TripleDES,
+ AES, Blowfish, Camellia, CAST5, TripleDES, ARC4,
)
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CTR, ECB, OFB, CFB
@@ -63,9 +64,8 @@ class Backend(object):
def __init__(self):
self._ensure_ffi_initialized()
- self.ciphers = Ciphers(self)
- self.hashes = Hashes(self)
- self.hmacs = HMACs(self)
+ self._cipher_registry = {}
+ self._register_default_ciphers()
@classmethod
def _ensure_ffi_initialized(cls):
@@ -123,6 +123,70 @@ class Backend(object):
"""
return self.ffi.string(self.lib.OPENSSL_VERSION_TEXT).decode("ascii")
+ def create_hmac_ctx(self, key, algorithm):
+ return _HMACContext(self, key, algorithm)
+
+ def hash_supported(self, algorithm):
+ digest = self.lib.EVP_get_digestbyname(algorithm.name.encode("ascii"))
+ return digest != self.ffi.NULL
+
+ def create_hash_ctx(self, algorithm):
+ return _HashContext(self, algorithm)
+
+ def cipher_supported(self, cipher, mode):
+ try:
+ adapter = self._cipher_registry[type(cipher), type(mode)]
+ except KeyError:
+ return False
+ evp_cipher = adapter(self, cipher, mode)
+ return self.ffi.NULL != evp_cipher
+
+ def register_cipher_adapter(self, cipher_cls, mode_cls, adapter):
+ if (cipher_cls, mode_cls) in self._cipher_registry:
+ raise ValueError("Duplicate registration for: {0} {1}".format(
+ cipher_cls, mode_cls)
+ )
+ self._cipher_registry[cipher_cls, mode_cls] = adapter
+
+ def _register_default_ciphers(self):
+ for cipher_cls, mode_cls in itertools.product(
+ [AES, Camellia],
+ [CBC, CTR, ECB, OFB, CFB],
+ ):
+ self.register_cipher_adapter(
+ cipher_cls,
+ mode_cls,
+ GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ )
+ for mode_cls in [CBC, CFB, OFB]:
+ self.register_cipher_adapter(
+ TripleDES,
+ mode_cls,
+ GetCipherByName("des-ede3-{mode.name}")
+ )
+ for mode_cls in [CBC, CFB, OFB, ECB]:
+ self.register_cipher_adapter(
+ Blowfish,
+ mode_cls,
+ GetCipherByName("bf-{mode.name}")
+ )
+ self.register_cipher_adapter(
+ CAST5,
+ ECB,
+ GetCipherByName("cast5-ecb")
+ )
+ self.register_cipher_adapter(
+ ARC4,
+ type(None),
+ GetCipherByName("rc4")
+ )
+
+ def create_symmetric_encryption_ctx(self, cipher, mode):
+ return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT)
+
+ def create_symmetric_decryption_ctx(self, cipher, mode):
+ return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
+
class GetCipherByName(object):
def __init__(self, fmt):
@@ -133,18 +197,19 @@ class GetCipherByName(object):
return backend.lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
-@interfaces.register(interfaces.CipherContext)
+@utils.register_interface(interfaces.CipherContext)
class _CipherContext(object):
_ENCRYPT = 1
_DECRYPT = 0
def __init__(self, backend, cipher, mode, operation):
self._backend = backend
+ self._cipher = cipher
ctx = self._backend.lib.EVP_CIPHER_CTX_new()
ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free)
- registry = self._backend.ciphers._cipher_registry
+ registry = self._backend._cipher_registry
try:
adapter = registry[type(cipher), type(mode)]
except KeyError:
@@ -185,9 +250,8 @@ class _CipherContext(object):
self._ctx = ctx
def update(self, data):
- block_size = self._backend.lib.EVP_CIPHER_CTX_block_size(self._ctx)
buf = self._backend.ffi.new("unsigned char[]",
- len(data) + block_size - 1)
+ len(data) + self._cipher.block_size - 1)
outlen = self._backend.ffi.new("int *")
res = self._backend.lib.EVP_CipherUpdate(self._ctx, buf, outlen, data,
len(data))
@@ -195,8 +259,7 @@ class _CipherContext(object):
return self._backend.ffi.buffer(buf)[:outlen[0]]
def finalize(self):
- block_size = self._backend.lib.EVP_CIPHER_CTX_block_size(self._ctx)
- buf = self._backend.ffi.new("unsigned char[]", block_size)
+ buf = self._backend.ffi.new("unsigned char[]", self._cipher.block_size)
outlen = self._backend.ffi.new("int *")
res = self._backend.lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
assert res != 0
@@ -205,146 +268,99 @@ class _CipherContext(object):
return self._backend.ffi.buffer(buf)[:outlen[0]]
-class Ciphers(object):
- def __init__(self, backend):
- super(Ciphers, self).__init__()
- self._backend = backend
- self._cipher_registry = {}
- self._register_default_ciphers()
+@utils.register_interface(interfaces.HashContext)
+class _HashContext(object):
+ def __init__(self, backend, algorithm, ctx=None):
+ self.algorithm = algorithm
- def supported(self, cipher, mode):
- try:
- adapter = self._cipher_registry[type(cipher), type(mode)]
- except KeyError:
- return False
- evp_cipher = adapter(self._backend, cipher, mode)
- return self._backend.ffi.NULL != evp_cipher
-
- def register_cipher_adapter(self, cipher_cls, mode_cls, adapter):
- if (cipher_cls, mode_cls) in self._cipher_registry:
- raise ValueError("Duplicate registration for: {0} {1}".format(
- cipher_cls, mode_cls)
- )
- self._cipher_registry[cipher_cls, mode_cls] = adapter
-
- def _register_default_ciphers(self):
- for cipher_cls, mode_cls in itertools.product(
- [AES, Camellia],
- [CBC, CTR, ECB, OFB, CFB],
- ):
- self.register_cipher_adapter(
- cipher_cls,
- mode_cls,
- GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
- )
- for mode_cls in [CBC, CFB, OFB]:
- self.register_cipher_adapter(
- TripleDES,
- mode_cls,
- GetCipherByName("des-ede3-{mode.name}")
- )
- for mode_cls in [CBC, CFB, OFB, ECB]:
- self.register_cipher_adapter(
- Blowfish,
- mode_cls,
- GetCipherByName("bf-{mode.name}")
- )
- self.register_cipher_adapter(
- CAST5,
- ECB,
- GetCipherByName("cast5-ecb")
- )
-
- def create_encrypt_ctx(self, cipher, mode):
- return _CipherContext(self._backend, cipher, mode,
- _CipherContext._ENCRYPT)
-
- def create_decrypt_ctx(self, cipher, mode):
- return _CipherContext(self._backend, cipher, mode,
- _CipherContext._DECRYPT)
+ self._backend = backend
+ if ctx is None:
+ ctx = self._backend.lib.EVP_MD_CTX_create()
+ ctx = self._backend.ffi.gc(ctx,
+ self._backend.lib.EVP_MD_CTX_destroy)
+ evp_md = self._backend.lib.EVP_get_digestbyname(
+ algorithm.name.encode("ascii"))
+ assert evp_md != self._backend.ffi.NULL
+ res = self._backend.lib.EVP_DigestInit_ex(ctx, evp_md,
+ self._backend.ffi.NULL)
+ assert res != 0
-class Hashes(object):
- def __init__(self, backend):
- super(Hashes, self).__init__()
- self._backend = backend
+ self._ctx = ctx
- def supported(self, hash_cls):
- return (self._backend.ffi.NULL !=
- self._backend.lib.EVP_get_digestbyname(
- hash_cls.name.encode("ascii")))
-
- def create_ctx(self, hashobject):
- ctx = self._backend.lib.EVP_MD_CTX_create()
- ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_MD_CTX_destroy)
- evp_md = self._backend.lib.EVP_get_digestbyname(
- hashobject.name.encode("ascii"))
- assert evp_md != self._backend.ffi.NULL
- res = self._backend.lib.EVP_DigestInit_ex(ctx, evp_md,
- self._backend.ffi.NULL)
+ def copy(self):
+ copied_ctx = self._backend.lib.EVP_MD_CTX_create()
+ copied_ctx = self._backend.ffi.gc(copied_ctx,
+ self._backend.lib.EVP_MD_CTX_destroy)
+ res = self._backend.lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
assert res != 0
- return ctx
+ return _HashContext(self._backend, self.algorithm, ctx=copied_ctx)
- def update_ctx(self, ctx, data):
- res = self._backend.lib.EVP_DigestUpdate(ctx, data, len(data))
+ def update(self, data):
+ res = self._backend.lib.EVP_DigestUpdate(self._ctx, data, len(data))
assert res != 0
- def finalize_ctx(self, ctx, digest_size):
- buf = self._backend.ffi.new("unsigned char[]", digest_size)
- res = self._backend.lib.EVP_DigestFinal_ex(ctx, buf,
+ def finalize(self):
+ buf = self._backend.ffi.new("unsigned char[]",
+ self.algorithm.digest_size)
+ res = self._backend.lib.EVP_DigestFinal_ex(self._ctx, buf,
self._backend.ffi.NULL)
assert res != 0
- res = self._backend.lib.EVP_MD_CTX_cleanup(ctx)
+ res = self._backend.lib.EVP_MD_CTX_cleanup(self._ctx)
assert res == 1
- return self._backend.ffi.buffer(buf)[:digest_size]
-
- def copy_ctx(self, ctx):
- copied_ctx = self._backend.lib.EVP_MD_CTX_create()
- copied_ctx = self._backend.ffi.gc(copied_ctx,
- self._backend.lib.EVP_MD_CTX_destroy)
- res = self._backend.lib.EVP_MD_CTX_copy_ex(copied_ctx, ctx)
- assert res != 0
- return copied_ctx
+ return self._backend.ffi.buffer(buf)[:]
-class HMACs(object):
- def __init__(self, backend):
- super(HMACs, self).__init__()
+@utils.register_interface(interfaces.HashContext)
+class _HMACContext(object):
+ def __init__(self, backend, key, algorithm, ctx=None):
+ self.algorithm = algorithm
self._backend = backend
- def create_ctx(self, key, hash_cls):
- ctx = self._backend.ffi.new("HMAC_CTX *")
- self._backend.lib.HMAC_CTX_init(ctx)
- ctx = self._backend.ffi.gc(ctx, self._backend.lib.HMAC_CTX_cleanup)
- evp_md = self._backend.lib.EVP_get_digestbyname(
- hash_cls.name.encode('ascii'))
- assert evp_md != self._backend.ffi.NULL
- res = self._backend.lib.Cryptography_HMAC_Init_ex(
- ctx, key, len(key), evp_md, self._backend.ffi.NULL
- )
- assert res != 0
- return ctx
+ if ctx is None:
+ ctx = self._backend.ffi.new("HMAC_CTX *")
+ self._backend.lib.HMAC_CTX_init(ctx)
+ ctx = self._backend.ffi.gc(ctx, self._backend.lib.HMAC_CTX_cleanup)
+ evp_md = self._backend.lib.EVP_get_digestbyname(
+ algorithm.name.encode('ascii'))
+ assert evp_md != self._backend.ffi.NULL
+ res = self._backend.lib.Cryptography_HMAC_Init_ex(
+ ctx, key, len(key), evp_md, self._backend.ffi.NULL
+ )
+ assert res != 0
+
+ self._ctx = ctx
+ self._key = key
- def update_ctx(self, ctx, data):
- res = self._backend.lib.Cryptography_HMAC_Update(ctx, data, len(data))
+ def copy(self):
+ copied_ctx = self._backend.ffi.new("HMAC_CTX *")
+ self._backend.lib.HMAC_CTX_init(copied_ctx)
+ copied_ctx = self._backend.ffi.gc(
+ copied_ctx, self._backend.lib.HMAC_CTX_cleanup
+ )
+ res = self._backend.lib.Cryptography_HMAC_CTX_copy(
+ copied_ctx, self._ctx
+ )
assert res != 0
+ return _HMACContext(
+ self._backend, self._key, self.algorithm, ctx=copied_ctx
+ )
- def finalize_ctx(self, ctx, digest_size):
- buf = self._backend.ffi.new("unsigned char[]", digest_size)
- buflen = self._backend.ffi.new("unsigned int *", digest_size)
- res = self._backend.lib.Cryptography_HMAC_Final(ctx, buf, buflen)
+ def update(self, data):
+ res = self._backend.lib.Cryptography_HMAC_Update(
+ self._ctx, data, len(data)
+ )
assert res != 0
- self._backend.lib.HMAC_CTX_cleanup(ctx)
- return self._backend.ffi.buffer(buf)[:digest_size]
- def copy_ctx(self, ctx):
- copied_ctx = self._backend.ffi.new("HMAC_CTX *")
- self._backend.lib.HMAC_CTX_init(copied_ctx)
- copied_ctx = self._backend.ffi.gc(copied_ctx,
- self._backend.lib.HMAC_CTX_cleanup)
- res = self._backend.lib.Cryptography_HMAC_CTX_copy(copied_ctx, ctx)
+ def finalize(self):
+ buf = self._backend.ffi.new("unsigned char[]",
+ self.algorithm.digest_size)
+ buflen = self._backend.ffi.new("unsigned int *",
+ self.algorithm.digest_size)
+ res = self._backend.lib.Cryptography_HMAC_Final(self._ctx, buf, buflen)
assert res != 0
- return copied_ctx
+ self._backend.lib.HMAC_CTX_cleanup(self._ctx)
+ return self._backend.ffi.buffer(buf)[:]
backend = Backend()
diff --git a/cryptography/hazmat/bindings/openssl/evp.py b/cryptography/hazmat/bindings/openssl/evp.py
index da54f89d..8cb44610 100644
--- a/cryptography/hazmat/bindings/openssl/evp.py
+++ b/cryptography/hazmat/bindings/openssl/evp.py
@@ -16,10 +16,13 @@ INCLUDES = """
"""
TYPES = """
+typedef ... EVP_CIPHER;
typedef struct {
+ const EVP_CIPHER *cipher;
+ ENGINE *engine;
+ int encrypt;
...;
} EVP_CIPHER_CTX;
-typedef ... EVP_CIPHER;
typedef ... EVP_MD;
typedef struct env_md_ctx_st EVP_MD_CTX;
diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py
index 58a64f0b..04611309 100644
--- a/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/cryptography/hazmat/bindings/openssl/ssl.py
@@ -16,13 +16,200 @@ INCLUDES = """
"""
TYPES = """
+static const int SSL_FILETYPE_PEM;
+static const int SSL_FILETYPE_ASN1;
+static const int SSL_ERROR_NONE;
+static const int SSL_ERROR_ZERO_RETURN;
+static const int SSL_ERROR_WANT_READ;
+static const int SSL_ERROR_WANT_WRITE;
+static const int SSL_ERROR_WANT_X509_LOOKUP;
+static const int SSL_ERROR_SYSCALL;
+static const int SSL_ERROR_SSL;
+static const int SSL_SENT_SHUTDOWN;
+static const int SSL_RECEIVED_SHUTDOWN;
+static const int SSL_OP_NO_SSLv2;
+static const int SSL_OP_NO_SSLv3;
+static const int SSL_OP_NO_TLSv1;
+static const int SSL_OP_SINGLE_DH_USE;
+static const int SSL_OP_EPHEMERAL_RSA;
+static const int SSL_OP_MICROSOFT_SESS_ID_BUG;
+static const int SSL_OP_NETSCAPE_CHALLENGE_BUG;
+static const int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+static const int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG;
+static const int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER;
+static const int SSL_OP_MSIE_SSLV2_RSA_PADDING;
+static const int SSL_OP_SSLEAY_080_CLIENT_DH_BUG;
+static const int SSL_OP_TLS_D5_BUG;
+static const int SSL_OP_TLS_BLOCK_PADDING_BUG;
+static const int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+static const int SSL_OP_CIPHER_SERVER_PREFERENCE;
+static const int SSL_OP_TLS_ROLLBACK_BUG;
+static const int SSL_OP_PKCS1_CHECK_1;
+static const int SSL_OP_PKCS1_CHECK_2;
+static const int SSL_OP_NETSCAPE_CA_DN_BUG;
+static const int SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG;
+static const int SSL_OP_NO_QUERY_MTU;
+static const int SSL_OP_COOKIE_EXCHANGE;
+static const int SSL_OP_NO_TICKET;
+static const int SSL_OP_ALL;
+static const int SSL_VERIFY_PEER;
+static const int SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+static const int SSL_VERIFY_CLIENT_ONCE;
+static const int SSL_VERIFY_NONE;
+static const int SSL_SESS_CACHE_OFF;
+static const int SSL_SESS_CACHE_CLIENT;
+static const int SSL_SESS_CACHE_SERVER;
+static const int SSL_SESS_CACHE_BOTH;
+static const int SSL_SESS_CACHE_NO_AUTO_CLEAR;
+static const int SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
+static const int SSL_SESS_CACHE_NO_INTERNAL_STORE;
+static const int SSL_SESS_CACHE_NO_INTERNAL;
+static const int SSL_ST_CONNECT;
+static const int SSL_ST_ACCEPT;
+static const int SSL_ST_MASK;
+static const int SSL_ST_INIT;
+static const int SSL_ST_BEFORE;
+static const int SSL_ST_OK;
+static const int SSL_ST_RENEGOTIATE;
+static const int SSL_CB_LOOP;
+static const int SSL_CB_EXIT;
+static const int SSL_CB_READ;
+static const int SSL_CB_WRITE;
+static const int SSL_CB_ALERT;
+static const int SSL_CB_READ_ALERT;
+static const int SSL_CB_WRITE_ALERT;
+static const int SSL_CB_ACCEPT_LOOP;
+static const int SSL_CB_ACCEPT_EXIT;
+static const int SSL_CB_CONNECT_LOOP;
+static const int SSL_CB_CONNECT_EXIT;
+static const int SSL_CB_HANDSHAKE_START;
+static const int SSL_CB_HANDSHAKE_DONE;
+static const int SSL_MODE_ENABLE_PARTIAL_WRITE;
+static const int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
+static const int SSL_MODE_AUTO_RETRY;
+static const int SSL3_RANDOM_SIZE;
+typedef ... X509_STORE_CTX;
+static const int X509_V_OK;
+typedef ... SSL_METHOD;
+typedef ... SSL_CTX;
+
+typedef struct {
+ int master_key_length;
+ unsigned char master_key[...];
+ ...;
+} SSL_SESSION;
+
+typedef struct {
+ unsigned char server_random[...];
+ unsigned char client_random[...];
+ ...;
+} SSL3_STATE;
+
+typedef struct {
+ SSL3_STATE *s3;
+ SSL_SESSION *session;
+ ...;
+} SSL;
+
+static const int TLSEXT_NAMETYPE_host_name;
"""
FUNCTIONS = """
void SSL_load_error_strings();
+
+int SSL_library_init();
+
+/* SSL */
+SSL_CTX *SSL_set_SSL_CTX(SSL *, SSL_CTX *);
+SSL_SESSION *SSL_get1_session(SSL *);
+int SSL_set_session(SSL *, SSL_SESSION *);
+int SSL_get_verify_mode(const SSL *);
+void SSL_set_verify_depth(SSL *, int);
+int SSL_get_verify_depth(const SSL *);
+SSL *SSL_new(SSL_CTX *);
+void SSL_free(SSL *);
+int SSL_set_fd(SSL *, int);
+void SSL_set_bio(SSL *, BIO *, BIO *);
+void SSL_set_connect_state(SSL *);
+void SSL_set_accept_state(SSL *);
+void SSL_set_shutdown(SSL *, int);
+int SSL_get_shutdown(const SSL *);
+int SSL_pending(const SSL *);
+int SSL_write(SSL *, const void *, int);
+int SSL_read(SSL *, void *, int);
+X509 *SSL_get_peer_certificate(const SSL *);
+int SSL_get_error(const SSL *, int);
+int SSL_do_handshake(SSL *);
+int SSL_shutdown(SSL *);
+const char *SSL_get_cipher_list(const SSL *, int);
+
+/* context */
+void SSL_CTX_free(SSL_CTX *);
+long SSL_CTX_set_timeout(SSL_CTX *, long);
+int SSL_CTX_set_default_verify_paths(SSL_CTX *);
+void SSL_CTX_set_verify_depth(SSL_CTX *, int);
+int SSL_CTX_get_verify_mode(const SSL_CTX *);
+int SSL_CTX_get_verify_depth(const SSL_CTX *);
+int SSL_CTX_set_cipher_list(SSL_CTX *, const char *);
+int SSL_CTX_load_verify_locations(SSL_CTX *, const char *, const char *);
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *, pem_password_cb *);
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *, void *);
+int SSL_CTX_use_certificate(SSL_CTX *, X509 *);
+int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
+int SSL_CTX_use_PrivateKey(SSL_CTX *, EVP_PKEY *);
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
+void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *);
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
+int SSL_CTX_add_client_CA(SSL_CTX *, X509 *);
+
+/* X509_STORE_CTX */
+int X509_STORE_CTX_get_error(X509_STORE_CTX *);
+void X509_STORE_CTX_set_error(X509_STORE_CTX *, int);
+int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *);
+X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *);
+
+/* SSL_SESSION */
+void SSL_SESSION_free(SSL_SESSION *);
"""
-MACROS = """
+MACROS = MACROS = """
+long SSL_set_mode(SSL *, long);
+long SSL_get_mode(SSL *);
+
+long SSL_set_options(SSL *, long);
+long SSL_get_options(SSL *);
+
+int SSL_want_read(const SSL *);
+int SSL_want_write(const SSL *);
+
+int SSL_total_renegotiations(const SSL *);
+
+long SSL_CTX_set_options(SSL_CTX *, long);
+long SSL_CTX_get_options(SSL_CTX *);
+long SSL_CTX_set_mode(SSL_CTX *, long);
+long SSL_CTX_get_mode(SSL_CTX *);
+long SSL_CTX_set_session_cache_mode(SSL_CTX *, long);
+long SSL_CTX_get_session_cache_mode(SSL_CTX *);
+long SSL_CTX_set_tmp_dh(SSL_CTX *, DH *);
+long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
+
+/*- These aren't macros these functions are all const X on openssl > 1.0.x -*/
+
+/* methods */
+const SSL_METHOD *SSLv3_method();
+const SSL_METHOD *SSLv3_server_method();
+const SSL_METHOD *SSLv3_client_method();
+const SSL_METHOD *TLSv1_method();
+const SSL_METHOD *TLSv1_server_method();
+const SSL_METHOD *TLSv1_client_method();
+const SSL_METHOD *SSLv23_method();
+const SSL_METHOD *SSLv23_server_method();
+const SSL_METHOD *SSLv23_client_method();
+
+/*- These aren't macros these arguments are all const X on openssl > 1.0.x -*/
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *);
+long SSL_CTX_get_timeout(const SSL_CTX *);
"""
CUSTOMIZATIONS = """
diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py
index 8046bd26..75a87265 100644
--- a/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -13,14 +13,17 @@
from __future__ import absolute_import, division, print_function
+from cryptography import utils
+from cryptography.hazmat.primitives import interfaces
+
+@utils.register_interface(interfaces.CipherAlgorithm)
class AES(object):
name = "AES"
block_size = 128
key_sizes = frozenset([128, 192, 256])
def __init__(self, key):
- super(AES, self).__init__()
self.key = key
# Verify that the key size matches the expected key size
@@ -34,13 +37,13 @@ class AES(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.CipherAlgorithm)
class Camellia(object):
name = "camellia"
block_size = 128
key_sizes = frozenset([128, 192, 256])
def __init__(self, key):
- super(Camellia, self).__init__()
self.key = key
# Verify that the key size matches the expected key size
@@ -54,13 +57,13 @@ class Camellia(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.CipherAlgorithm)
class TripleDES(object):
name = "3DES"
block_size = 64
key_sizes = frozenset([64, 128, 192])
def __init__(self, key):
- super(TripleDES, self).__init__()
if len(key) == 8:
key += key + key
elif len(key) == 16:
@@ -78,13 +81,13 @@ class TripleDES(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.CipherAlgorithm)
class Blowfish(object):
name = "Blowfish"
block_size = 64
key_sizes = frozenset(range(32, 449, 8))
def __init__(self, key):
- super(Blowfish, self).__init__()
self.key = key
# Verify that the key size matches the expected key size
@@ -98,13 +101,33 @@ class Blowfish(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.CipherAlgorithm)
class CAST5(object):
name = "CAST5"
block_size = 64
key_sizes = frozenset([40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128])
def __init__(self, key):
- super(CAST5, self).__init__()
+ self.key = key
+
+ # Verify that the key size matches the expected key size
+ if self.key_size not in self.key_sizes:
+ raise ValueError("Invalid key size ({0}) for {1}".format(
+ self.key_size, self.name
+ ))
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.CipherAlgorithm)
+class ARC4(object):
+ name = "RC4"
+ block_size = 1
+ key_sizes = frozenset([40, 56, 64, 80, 128, 192, 256])
+
+ def __init__(self, key):
self.key = key
# Verify that the key size matches the expected key size
diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py
index 1599308c..3d733afc 100644
--- a/cryptography/hazmat/primitives/ciphers/base.py
+++ b/cryptography/hazmat/primitives/ciphers/base.py
@@ -13,46 +13,49 @@
from __future__ import absolute_import, division, print_function
+from cryptography import utils
+from cryptography.exceptions import AlreadyFinalized
from cryptography.hazmat.primitives import interfaces
class Cipher(object):
def __init__(self, algorithm, mode, backend=None):
- super(Cipher, self).__init__()
-
if backend is None:
from cryptography.hazmat.bindings import (
_default_backend as backend,
)
+ if not isinstance(algorithm, interfaces.CipherAlgorithm):
+ raise TypeError("Expected interface of interfaces.CipherAlgorithm")
+
self.algorithm = algorithm
self.mode = mode
self._backend = backend
def encryptor(self):
- return _CipherContext(
- self._backend.ciphers.create_encrypt_ctx(self.algorithm,
- self.mode))
+ return _CipherContext(self._backend.create_symmetric_encryption_ctx(
+ self.algorithm, self.mode
+ ))
def decryptor(self):
- return _CipherContext(
- self._backend.ciphers.create_decrypt_ctx(self.algorithm,
- self.mode))
+ return _CipherContext(self._backend.create_symmetric_decryption_ctx(
+ self.algorithm, self.mode
+ ))
-@interfaces.register(interfaces.CipherContext)
+@utils.register_interface(interfaces.CipherContext)
class _CipherContext(object):
def __init__(self, ctx):
self._ctx = ctx
def update(self, data):
if self._ctx is None:
- raise ValueError("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized")
return self._ctx.update(data)
def finalize(self):
if self._ctx is None:
- raise ValueError("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized")
data = self._ctx.finalize()
self._ctx = None
return data
diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py
index e54872a6..1d0de689 100644
--- a/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/cryptography/hazmat/primitives/ciphers/modes.py
@@ -13,49 +13,46 @@
from __future__ import absolute_import, division, print_function
+from cryptography import utils
from cryptography.hazmat.primitives import interfaces
-@interfaces.register(interfaces.Mode)
-@interfaces.register(interfaces.ModeWithInitializationVector)
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
class CBC(object):
name = "CBC"
def __init__(self, initialization_vector):
- super(CBC, self).__init__()
self.initialization_vector = initialization_vector
-@interfaces.register(interfaces.Mode)
+@utils.register_interface(interfaces.Mode)
class ECB(object):
name = "ECB"
-@interfaces.register(interfaces.Mode)
-@interfaces.register(interfaces.ModeWithInitializationVector)
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
class OFB(object):
name = "OFB"
def __init__(self, initialization_vector):
- super(OFB, self).__init__()
self.initialization_vector = initialization_vector
-@interfaces.register(interfaces.Mode)
-@interfaces.register(interfaces.ModeWithInitializationVector)
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
class CFB(object):
name = "CFB"
def __init__(self, initialization_vector):
- super(CFB, self).__init__()
self.initialization_vector = initialization_vector
-@interfaces.register(interfaces.Mode)
-@interfaces.register(interfaces.ModeWithNonce)
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithNonce)
class CTR(object):
name = "CTR"
def __init__(self, nonce):
- super(CTR, self).__init__()
self.nonce = nonce
diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py
index bdad5e16..93fc8c42 100644
--- a/cryptography/hazmat/primitives/hashes.py
+++ b/cryptography/hazmat/primitives/hashes.py
@@ -15,10 +15,12 @@ from __future__ import absolute_import, division, print_function
import six
+from cryptography import utils
+from cryptography.exceptions import AlreadyFinalized
from cryptography.hazmat.primitives import interfaces
-@interfaces.register(interfaces.HashContext)
+@utils.register_interface(interfaces.HashContext)
class Hash(object):
def __init__(self, algorithm, backend=None, ctx=None):
if not isinstance(algorithm, interfaces.HashAlgorithm):
@@ -32,74 +34,82 @@ class Hash(object):
self._backend = backend
if ctx is None:
- self._ctx = self._backend.hashes.create_ctx(self.algorithm)
+ self._ctx = self._backend.create_hash_ctx(self.algorithm)
else:
- self._ctx = None
+ self._ctx = ctx
def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
if isinstance(data, six.text_type):
raise TypeError("Unicode-objects must be encoded before hashing")
- self._backend.hashes.update_ctx(self._ctx, data)
+ self._ctx.update(data)
def copy(self):
- return self.__class__(self.algorithm, backend=self._backend,
- ctx=self._backend.hashes.copy_ctx(self._ctx))
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ return Hash(
+ self.algorithm, backend=self._backend, ctx=self._ctx.copy()
+ )
def finalize(self):
- return self._backend.hashes.finalize_ctx(self._ctx,
- self.algorithm.digest_size)
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ digest = self._ctx.finalize()
+ self._ctx = None
+ return digest
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class SHA1(object):
name = "sha1"
digest_size = 20
block_size = 64
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class SHA224(object):
name = "sha224"
digest_size = 28
block_size = 64
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class SHA256(object):
name = "sha256"
digest_size = 32
block_size = 64
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class SHA384(object):
name = "sha384"
digest_size = 48
block_size = 128
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class SHA512(object):
name = "sha512"
digest_size = 64
block_size = 128
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class RIPEMD160(object):
name = "ripemd160"
digest_size = 20
block_size = 64
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class Whirlpool(object):
name = "whirlpool"
digest_size = 64
block_size = 64
-@interfaces.register(interfaces.HashAlgorithm)
+@utils.register_interface(interfaces.HashAlgorithm)
class MD5(object):
name = "md5"
digest_size = 16
diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py
index 1457ed78..08dfae01 100644
--- a/cryptography/hazmat/primitives/hmac.py
+++ b/cryptography/hazmat/primitives/hmac.py
@@ -15,13 +15,14 @@ from __future__ import absolute_import, division, print_function
import six
+from cryptography import utils
+from cryptography.exceptions import AlreadyFinalized
from cryptography.hazmat.primitives import interfaces
-@interfaces.register(interfaces.HashContext)
+@utils.register_interface(interfaces.HashContext)
class HMAC(object):
def __init__(self, key, algorithm, ctx=None, backend=None):
- super(HMAC, self).__init__()
if not isinstance(algorithm, interfaces.HashAlgorithm):
raise TypeError("Expected instance of interfaces.HashAlgorithm.")
self.algorithm = algorithm
@@ -33,19 +34,30 @@ class HMAC(object):
self._backend = backend
self._key = key
if ctx is None:
- self._ctx = self._backend.hmacs.create_ctx(key, self.algorithm)
+ self._ctx = self._backend.create_hmac_ctx(key, self.algorithm)
else:
self._ctx = ctx
def update(self, msg):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
if isinstance(msg, six.text_type):
raise TypeError("Unicode-objects must be encoded before hashing")
- self._backend.hmacs.update_ctx(self._ctx, msg)
+ self._ctx.update(msg)
def copy(self):
- return self.__class__(self._key, self.algorithm, backend=self._backend,
- ctx=self._backend.hmacs.copy_ctx(self._ctx))
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ return HMAC(
+ self._key,
+ self.algorithm,
+ backend=self._backend,
+ ctx=self._ctx.copy()
+ )
def finalize(self):
- return self._backend.hmacs.finalize_ctx(self._ctx,
- self.algorithm.digest_size)
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized")
+ digest = self._ctx.finalize()
+ self._ctx = None
+ return digest
diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py
index 67dbe6fa..8cc9d42c 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -18,11 +18,18 @@ import abc
import six
-def register(iface):
- def register_decorator(klass):
- iface.register(klass)
- return klass
- return register_decorator
+class CipherAlgorithm(six.with_metaclass(abc.ABCMeta)):
+ @abc.abstractproperty
+ def name(self):
+ """
+ A string naming this mode. (e.g. AES, Camellia)
+ """
+
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The size of the key being used as an integer in bits. (e.g. 128, 256)
+ """
class Mode(six.with_metaclass(abc.ABCMeta)):
diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py
index ddcadd89..2dbac752 100644
--- a/cryptography/hazmat/primitives/padding.py
+++ b/cryptography/hazmat/primitives/padding.py
@@ -13,12 +13,12 @@
import six
+from cryptography import utils
from cryptography.hazmat.primitives import interfaces
class PKCS7(object):
def __init__(self, block_size):
- super(PKCS7, self).__init__()
if not (0 <= block_size < 256):
raise ValueError("block_size must be in range(0, 256)")
@@ -34,10 +34,9 @@ class PKCS7(object):
return _PKCS7UnpaddingContext(self.block_size)
-@interfaces.register(interfaces.PaddingContext)
+@utils.register_interface(interfaces.PaddingContext)
class _PKCS7PaddingContext(object):
def __init__(self, block_size):
- super(_PKCS7PaddingContext, self).__init__()
self.block_size = block_size
# TODO: O(n ** 2) complexity for repeated concatentation, we should use
# zero-buffer (#193)
@@ -69,10 +68,9 @@ class _PKCS7PaddingContext(object):
return result
-@interfaces.register(interfaces.PaddingContext)
+@utils.register_interface(interfaces.PaddingContext)
class _PKCS7UnpaddingContext(object):
def __init__(self, block_size):
- super(_PKCS7UnpaddingContext, self).__init__()
self.block_size = block_size
# TODO: O(n ** 2) complexity for repeated concatentation, we should use
# zero-buffer (#193)
@@ -101,12 +99,12 @@ class _PKCS7UnpaddingContext(object):
if self._buffer is None:
raise ValueError("Context was already finalized")
- if not self._buffer:
+ if len(self._buffer) != self.block_size // 8:
raise ValueError("Invalid padding bytes")
pad_size = six.indexbytes(self._buffer, -1)
- if pad_size > self.block_size // 8:
+ if not (0 < pad_size <= self.block_size // 8):
raise ValueError("Invalid padding bytes")
mismatch = 0
diff --git a/cryptography/utils.py b/cryptography/utils.py
new file mode 100644
index 00000000..e697d515
--- /dev/null
+++ b/cryptography/utils.py
@@ -0,0 +1,21 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://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.
+
+from __future__ import absolute_import, division, print_function
+
+
+def register_interface(iface):
+ def register_decorator(klass):
+ iface.register(klass)
+ return klass
+ return register_decorator