diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2013-08-09 09:52:43 -0700 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2013-08-09 09:52:43 -0700 |
commit | ab4c507fefa52fc3c887b8d0d9786008952a6908 (patch) | |
tree | cdd07859176c312704e223caa6f2b099ad0e00ef | |
parent | 5de0392f9be95fcd87db096a3176c172f01009da (diff) | |
download | cryptography-ab4c507fefa52fc3c887b8d0d9786008952a6908.tar.gz cryptography-ab4c507fefa52fc3c887b8d0d9786008952a6908.tar.bz2 cryptography-ab4c507fefa52fc3c887b8d0d9786008952a6908.zip |
Many TODOs later, we can encrypt a thing
-rw-r--r-- | cryptography/bindings/openssl/__init__.py | 2 | ||||
-rw-r--r-- | cryptography/bindings/openssl/api.py | 62 | ||||
-rw-r--r-- | cryptography/primitives/block/base.py | 13 |
3 files changed, 74 insertions, 3 deletions
diff --git a/cryptography/bindings/openssl/__init__.py b/cryptography/bindings/openssl/__init__.py index 6c803fbc..103b1db0 100644 --- a/cryptography/bindings/openssl/__init__.py +++ b/cryptography/bindings/openssl/__init__.py @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cryptography.bindings.openssl import api +from cryptography.bindings.openssl.api import api __all__ = ["api"] diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index 3cc6a0e9..ee6e49dd 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import, division, print_function +import cffi class API(object): @@ -19,5 +19,65 @@ class API(object): OpenSSL API wrapper. """ + def __init__(self): + ffi = cffi.FFI() + self._populate_ffi(ffi) + self._ffi = ffi + self._lib = ffi.verify(""" + #include <openssl/evp.h> + """) + + def _populate_ffi(self, ffi): + ffi.cdef(""" + typedef struct { + ...; + } EVP_CIPHER_CTX; + typedef ... EVP_CIPHER; + typedef ... ENGINE; + + const EVP_CIPHER *EVP_get_cipherbyname(const char *); + int EVP_EncryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, + ENGINE *, unsigned char *, unsigned char *); + int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); + int EVP_EncryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, + unsigned char *, int); + int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); + """) + + def create_block_cipher_context(self, cipher, mode): + ctx = self._ffi.new("EVP_CIPHER_CTX *") + # TODO: compute real cipher + ciphername = b"AES-{}-CBC".format(len(cipher.key) * 8) + evp_cipher = self._lib.EVP_get_cipherbyname(ciphername) + if evp_cipher == self._ffi.NULL: + # TODO: figure out openssl errors + raise Exception + # TODO: only use the key and initialization_vector as needed + res = self._lib.EVP_EncryptInit_ex(ctx, evp_cipher, self._ffi.NULL, cipher.key, mode.initialization_vector) + if res == 0: + # TODO: figure out openssl errors + raise Exception + self._lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + return ctx + + def update_encrypt_context(self, ctx, plaintext): + buf = self._ffi.new("unsigned char[]", len(plaintext)) + outlen = self._ffi.new("int *") + res = self._lib.EVP_EncryptUpdate(ctx, buf, outlen, plaintext, len(plaintext)) + if res == 0: + # TODO: figure out openssl errors + raise Exception + return self._ffi.buffer(buf)[:outlen[0]] + + def finalize_encrypt_context(self, ctx): + # TODO: use real block size + buf = self._ffi.new("unsigned char[]", 16) + outlen = self._ffi.new("int *") + res = self._lib.EVP_EncryptFinal_ex(ctx, buf, outlen) + if res == 0: + # TODO: figure out openssl errors + raise Exception + return self._ffi.buffer(buf)[:outlen[0]] + api = API() diff --git a/cryptography/primitives/block/base.py b/cryptography/primitives/block/base.py index c2cc4327..ed37685d 100644 --- a/cryptography/primitives/block/base.py +++ b/cryptography/primitives/block/base.py @@ -1,8 +1,19 @@ +# TODO: which binding is used should be an option somewhere +from cryptography.bindings.openssl import api + + class BlockCipher(object): def __init__(self, cipher, mode): super(BlockCipher, self).__init__() self.cipher = cipher self.mode = mode + self._ctx = api.create_block_cipher_context(cipher, mode) + def encrypt(self, plaintext): - raise NotImplementedError + return api.update_encrypt_context(self._ctx, plaintext) + + def finalize(self): + result = api.finalize_encrypt_context(self._ctx) + self._ctx = None + return result |