From 64e09322e3cbda39d673f985f495178209ff12f5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 7 Nov 2013 16:20:34 -0800 Subject: Fixed a bug in padding, and also made it more constant time --- cryptography/hazmat/primitives/padding.py | 34 ++++++++++++++++++++++++++++--- tests/hazmat/primitives/test_padding.py | 1 + 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index ddcadd89..de889685 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -11,11 +11,34 @@ # See the License for the specific language governing permissions and # limitations under the License. +import cffi + import six from cryptography.hazmat.primitives import interfaces +_ffi = cffi.FFI() +_ffi.cdef(""" +unsigned int Cryptography_constant_time_lt(unsigned int, unsigned int); +""") +_lib = _ffi.verify(""" +/* Returns the value of the input with the most-significant-bit copied to all + of the bits. This relies on implementation details of computers with 2's + complement representations of integers, which is not required by the C + standard. */ +static unsigned int Cryptography_DUPLICATE_MSB_TO_ALL(unsigned int a) { + return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1)); +} + +/* This returns 0xFF if a < b else 0x00, but does so in a constant time + fashion */ +unsigned int Cryptography_constant_time_lt(unsigned int a, unsigned int b) { + a -= b; + return Cryptography_DUPLICATE_MSB_TO_ALL(a); +} +""") + class PKCS7(object): def __init__(self, block_size): super(PKCS7, self).__init__() @@ -104,14 +127,19 @@ class _PKCS7UnpaddingContext(object): if not self._buffer: raise ValueError("Invalid padding bytes") - pad_size = six.indexbytes(self._buffer, -1) + 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: raise ValueError("Invalid padding bytes") + mismatch = 0 - for b in six.iterbytes(self._buffer[-pad_size:]): - mismatch |= b ^ pad_size + for i in xrange(self.block_size // 8): + mask = _lib.Cryptography_constant_time_lt(i, pad_size) + b = six.indexbytes(self._buffer, self.block_size // 8 - 1 - i) + mismatch |= (mask & (pad_size ^ b)) if mismatch != 0: raise ValueError("Invalid padding bytes") diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py index 3cefafaf..91d58439 100644 --- a/tests/hazmat/primitives/test_padding.py +++ b/tests/hazmat/primitives/test_padding.py @@ -29,6 +29,7 @@ class TestPKCS7(object): (128, b"1111111111111111"), (128, b"111111111111111\x06"), (128, b""), + (128, b"\x06" * 6), ]) def test_invalid_padding(self, size, padded): unpadder = padding.PKCS7(size).unpadder() -- cgit v1.2.3 From 4a9a80d22216329447c4983e2e819dcfe209974e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 7 Nov 2013 16:29:29 -0800 Subject: py3k fix --- cryptography/hazmat/primitives/padding.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index de889685..74d49a0f 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -14,6 +14,7 @@ import cffi import six +from six.moves import xrange from cryptography.hazmat.primitives import interfaces -- cgit v1.2.3 From ab8719a903266fda3203bcdfbad7bd510c97c217 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 7 Nov 2013 17:20:20 -0800 Subject: flake8 fixes --- cryptography/hazmat/primitives/padding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 74d49a0f..23a6c032 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -40,6 +40,7 @@ unsigned int Cryptography_constant_time_lt(unsigned int a, unsigned int b) { } """) + class PKCS7(object): def __init__(self, block_size): super(PKCS7, self).__init__() @@ -135,7 +136,6 @@ class _PKCS7UnpaddingContext(object): if pad_size > self.block_size // 8: raise ValueError("Invalid padding bytes") - mismatch = 0 for i in xrange(self.block_size // 8): mask = _lib.Cryptography_constant_time_lt(i, pad_size) -- cgit v1.2.3 From 6b3be7f0078bd69f39b6666f7ea84040b7274e68 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 8 Nov 2013 09:17:48 -0800 Subject: More constant time, better --- cryptography/hazmat/primitives/padding.py | 7 +------ tests/hazmat/primitives/test_padding.py | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 23a6c032..34bdfd89 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -126,15 +126,10 @@ class _PKCS7UnpaddingContext(object): if self._buffer is None: raise ValueError("Context was already finalized") - if not self._buffer: - raise ValueError("Invalid padding bytes") - 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: - raise ValueError("Invalid padding bytes") mismatch = 0 for i in xrange(self.block_size // 8): @@ -142,7 +137,7 @@ class _PKCS7UnpaddingContext(object): b = six.indexbytes(self._buffer, self.block_size // 8 - 1 - i) mismatch |= (mask & (pad_size ^ b)) - if mismatch != 0: + if mismatch != 0 or not (0 < pad_size <= self.block_size // 8): raise ValueError("Invalid padding bytes") res = self._buffer[:-pad_size] diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py index 91d58439..6a2b6243 100644 --- a/tests/hazmat/primitives/test_padding.py +++ b/tests/hazmat/primitives/test_padding.py @@ -30,6 +30,7 @@ class TestPKCS7(object): (128, b"111111111111111\x06"), (128, b""), (128, b"\x06" * 6), + (128, b"\x00" * 16), ]) def test_invalid_padding(self, size, padded): unpadder = padding.PKCS7(size).unpadder() -- cgit v1.2.3 From 4a6f5dcddef1b9a3afbe8cc47b7483e3589781fe Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 15 Nov 2013 11:17:36 -0800 Subject: Move all unpadding logic to C --- cryptography/hazmat/primitives/padding.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 34bdfd89..ec575195 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -21,9 +21,11 @@ from cryptography.hazmat.primitives import interfaces _ffi = cffi.FFI() _ffi.cdef(""" -unsigned int Cryptography_constant_time_lt(unsigned int, unsigned int); +bool Cryptography_check_padding(uint8_t *, unsigned int); """) _lib = _ffi.verify(""" +#include + /* Returns the value of the input with the most-significant-bit copied to all of the bits. This relies on implementation details of computers with 2's complement representations of integers, which is not required by the C @@ -38,9 +40,22 @@ unsigned int Cryptography_constant_time_lt(unsigned int a, unsigned int b) { a -= b; return Cryptography_DUPLICATE_MSB_TO_ALL(a); } + +bool Cryptography_check_padding(uint8_t *data, unsigned int block_len) { + unsigned int i; + uint8_t pad_size = data[block_len - 1]; + uint8_t mismatch = 0; + for (i = 0; i < block_len; i++) { + unsigned int mask = Cryptography_constant_time_lt(i, pad_size); + uint8_t b = data[block_len - 1 - i]; + mismatch |= (mask & (pad_size ^ b)); + } + return mismatch == 0; +} """) + class PKCS7(object): def __init__(self, block_size): super(PKCS7, self).__init__() @@ -131,13 +146,9 @@ class _PKCS7UnpaddingContext(object): pad_size = six.indexbytes(self._buffer, -1) - mismatch = 0 - for i in xrange(self.block_size // 8): - mask = _lib.Cryptography_constant_time_lt(i, pad_size) - b = six.indexbytes(self._buffer, self.block_size // 8 - 1 - i) - mismatch |= (mask & (pad_size ^ b)) + valid = _lib.Cryptography_check_padding(self._buffer, self.block_size // 8) - if mismatch != 0 or not (0 < pad_size <= self.block_size // 8): + if not valid or not (0 < pad_size <= self.block_size // 8): raise ValueError("Invalid padding bytes") res = self._buffer[:-pad_size] -- cgit v1.2.3 From 1bbb7ce8b5e5c6379227dcb79c51bddbda6e4d23 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 15 Nov 2013 15:59:06 -0800 Subject: Fixed flake8 issues --- cryptography/hazmat/primitives/padding.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index ec575195..b07f5014 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -14,7 +14,6 @@ import cffi import six -from six.moves import xrange from cryptography.hazmat.primitives import interfaces @@ -55,7 +54,6 @@ bool Cryptography_check_padding(uint8_t *data, unsigned int block_len) { """) - class PKCS7(object): def __init__(self, block_size): super(PKCS7, self).__init__() @@ -146,7 +144,9 @@ class _PKCS7UnpaddingContext(object): pad_size = six.indexbytes(self._buffer, -1) - valid = _lib.Cryptography_check_padding(self._buffer, self.block_size // 8) + valid = _lib.Cryptography_check_padding( + self._buffer, self.block_size // 8 + ) if not valid or not (0 < pad_size <= self.block_size // 8): raise ValueError("Invalid padding bytes") -- cgit v1.2.3 From 0c679c64241d74dd02bda891c9f04508cd535535 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 16 Nov 2013 08:16:24 -0800 Subject: const correctness --- cryptography/hazmat/primitives/padding.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index b07f5014..926a4bbd 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -20,7 +20,7 @@ from cryptography.hazmat.primitives import interfaces _ffi = cffi.FFI() _ffi.cdef(""" -bool Cryptography_check_padding(uint8_t *, unsigned int); +bool Cryptography_check_padding(const uint8_t *, unsigned int); """) _lib = _ffi.verify(""" #include @@ -40,7 +40,7 @@ unsigned int Cryptography_constant_time_lt(unsigned int a, unsigned int b) { return Cryptography_DUPLICATE_MSB_TO_ALL(a); } -bool Cryptography_check_padding(uint8_t *data, unsigned int block_len) { +bool Cryptography_check_padding(const uint8_t *data, unsigned int block_len) { unsigned int i; uint8_t pad_size = data[block_len - 1]; uint8_t mismatch = 0; -- cgit v1.2.3 From c925b10c9a1638240a3be833d9e7271d4e3767ed Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 18 Nov 2013 09:39:33 -0800 Subject: Even more constant time --- cryptography/hazmat/primitives/padding.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 926a4bbd..03c03e37 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -24,6 +24,7 @@ bool Cryptography_check_padding(const uint8_t *, unsigned int); """) _lib = _ffi.verify(""" #include +#include /* Returns the value of the input with the most-significant-bit copied to all of the bits. This relies on implementation details of computers with 2's @@ -49,7 +50,13 @@ bool Cryptography_check_padding(const uint8_t *data, unsigned int block_len) { uint8_t b = data[block_len - 1 - i]; mismatch |= (mask & (pad_size ^ b)); } - return mismatch == 0; + + /* Make sure any bits set are copied to the lowest bit */ + mismatch |= mismatch >> 4; + mismatch |= mismatch >> 2; + mismatch |= mismatch >> 1; + /* Now check the low bit to see if it's set */ + return (mismatch & 1) == 0; } """) -- cgit v1.2.3 From cadf114a546a370d43c2c8e176dae311030904f7 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 18 Nov 2013 09:49:53 -0800 Subject: Make this comment more accurate --- cryptography/hazmat/primitives/padding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 03c03e37..00ac379c 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -34,7 +34,7 @@ static unsigned int Cryptography_DUPLICATE_MSB_TO_ALL(unsigned int a) { return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1)); } -/* This returns 0xFF if a < b else 0x00, but does so in a constant time +/* This returns 0xFFFF if a < b else 0x00, but does so in a constant time fashion */ unsigned int Cryptography_constant_time_lt(unsigned int a, unsigned int b) { a -= b; -- cgit v1.2.3 From 051d47c9518b7ef4f7bca51df37eadaadad7d56e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 18 Nov 2013 09:51:51 -0800 Subject: Use types more precisely --- cryptography/hazmat/primitives/padding.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 00ac379c..b03b4a61 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -20,7 +20,7 @@ from cryptography.hazmat.primitives import interfaces _ffi = cffi.FFI() _ffi.cdef(""" -bool Cryptography_check_padding(const uint8_t *, unsigned int); +bool Cryptography_check_padding(const uint8_t *, uint8_t); """) _lib = _ffi.verify(""" #include @@ -30,19 +30,19 @@ _lib = _ffi.verify(""" of the bits. This relies on implementation details of computers with 2's complement representations of integers, which is not required by the C standard. */ -static unsigned int Cryptography_DUPLICATE_MSB_TO_ALL(unsigned int a) { - return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1)); +static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) { + return (uint8_t)((int8_t)(a) >> (sizeof(int8_t) * 8 - 1)); } -/* This returns 0xFFFF if a < b else 0x00, but does so in a constant time +/* This returns 0xFF if a < b else 0x00, but does so in a constant time fashion */ -unsigned int Cryptography_constant_time_lt(unsigned int a, unsigned int b) { +uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) { a -= b; return Cryptography_DUPLICATE_MSB_TO_ALL(a); } -bool Cryptography_check_padding(const uint8_t *data, unsigned int block_len) { - unsigned int i; +bool Cryptography_check_padding(const uint8_t *data, uint8_t block_len) { + uint8_t i; uint8_t pad_size = data[block_len - 1]; uint8_t mismatch = 0; for (i = 0; i < block_len; i++) { -- cgit v1.2.3 From 4dd04c8f6eca8a85a57349a5be952f8c2f51ec6c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 18 Nov 2013 10:19:57 -0800 Subject: Remove unused include --- cryptography/hazmat/primitives/padding.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index b03b4a61..938afcec 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -24,7 +24,6 @@ bool Cryptography_check_padding(const uint8_t *, uint8_t); """) _lib = _ffi.verify(""" #include -#include /* Returns the value of the input with the most-significant-bit copied to all of the bits. This relies on implementation details of computers with 2's -- cgit v1.2.3 From cdea8aa87bd98ad6277262803f4a2b8cb48153a3 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 18 Nov 2013 15:00:33 -0800 Subject: No more undefined behavior --- cryptography/hazmat/primitives/padding.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 938afcec..8df4549e 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -26,11 +26,9 @@ _lib = _ffi.verify(""" #include /* Returns the value of the input with the most-significant-bit copied to all - of the bits. This relies on implementation details of computers with 2's - complement representations of integers, which is not required by the C - standard. */ + of the bits. */ static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) { - return (uint8_t)((int8_t)(a) >> (sizeof(int8_t) * 8 - 1)); + return -(a >> (sizeof(uint8_t) * 8 - 1)); } /* This returns 0xFF if a < b else 0x00, but does so in a constant time -- cgit v1.2.3 From 41b148725fd688016098ecab51956b08fb890439 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 18 Nov 2013 15:05:03 -0800 Subject: This is a static function --- cryptography/hazmat/primitives/padding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 8df4549e..f1c64f4d 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -33,7 +33,7 @@ static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) { /* This returns 0xFF if a < b else 0x00, but does so in a constant time fashion */ -uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) { +static uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) { a -= b; return Cryptography_DUPLICATE_MSB_TO_ALL(a); } -- cgit v1.2.3 From 04b8330d0a719b7f312207e7098c44f55a25fe39 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 18 Nov 2013 15:16:29 -0800 Subject: Use an instruction that is more likely to be constant time on a modern x86 CPU --- cryptography/hazmat/primitives/padding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index f1c64f4d..bc7a768d 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -28,7 +28,7 @@ _lib = _ffi.verify(""" /* Returns the value of the input with the most-significant-bit copied to all of the bits. */ static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) { - return -(a >> (sizeof(uint8_t) * 8 - 1)); + return (1 - (a >> (sizeof(uint8_t) * 8 - 1))) - 1; } /* This returns 0xFF if a < b else 0x00, but does so in a constant time -- cgit v1.2.3 From 2c03c89cce729f08496756bcac5f8564b5599dca Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 10:44:51 -0800 Subject: Even fewer secret branches before the data is valid --- cryptography/hazmat/primitives/padding.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index bc7a768d..d185fb6f 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -48,6 +48,9 @@ bool Cryptography_check_padding(const uint8_t *data, uint8_t block_len) { mismatch |= (mask & (pad_size ^ b)); } + /* Check to make sure the pad_size was within the valid range. */ + mismatch |= ~(0 < pad_size <= block_len); + /* Make sure any bits set are copied to the lowest bit */ mismatch |= mismatch >> 4; mismatch |= mismatch >> 2; @@ -146,15 +149,15 @@ class _PKCS7UnpaddingContext(object): if len(self._buffer) != self.block_size // 8: raise ValueError("Invalid padding bytes") - pad_size = six.indexbytes(self._buffer, -1) valid = _lib.Cryptography_check_padding( self._buffer, self.block_size // 8 ) - if not valid or not (0 < pad_size <= self.block_size // 8): + if not valid: raise ValueError("Invalid padding bytes") + pad_size = six.indexbytes(self._buffer, -1) res = self._buffer[:-pad_size] self._buffer = None return res -- cgit v1.2.3 From 624947cd6d884a10d5f1e984612f25ea07a1ffbb Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 10:46:58 -0800 Subject: Doh, fix --- cryptography/hazmat/primitives/padding.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index d185fb6f..4e834726 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -49,7 +49,8 @@ bool Cryptography_check_padding(const uint8_t *data, uint8_t block_len) { } /* Check to make sure the pad_size was within the valid range. */ - mismatch |= ~(0 < pad_size <= block_len); + mismatch |= !(0 < pad_size); + mismatch |= !(pad_size <= block_len); /* Make sure any bits set are copied to the lowest bit */ mismatch |= mismatch >> 4; -- cgit v1.2.3 From 844c2870be39af0872cd68e6204597d6663561cd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 10:48:37 -0800 Subject: Constant time comparisons here --- cryptography/hazmat/primitives/padding.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 4e834726..cf7dbecd 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -49,8 +49,8 @@ bool Cryptography_check_padding(const uint8_t *data, uint8_t block_len) { } /* Check to make sure the pad_size was within the valid range. */ - mismatch |= !(0 < pad_size); - mismatch |= !(pad_size <= block_len); + mismatch |= ~Cryptography_constant_time_lt(0, pad_size); + mismatch |= Cryptography_constant_time_lt(block_len, pad_size); /* Make sure any bits set are copied to the lowest bit */ mismatch |= mismatch >> 4; -- cgit v1.2.3 From fa1b5bf92e7429c03811050cb2b4b316808da70f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 11:01:03 -0800 Subject: flake8 --- cryptography/hazmat/primitives/padding.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index cf7dbecd..6e583b24 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -150,7 +150,6 @@ class _PKCS7UnpaddingContext(object): if len(self._buffer) != self.block_size // 8: raise ValueError("Invalid padding bytes") - valid = _lib.Cryptography_check_padding( self._buffer, self.block_size // 8 ) -- cgit v1.2.3 From 769073b7d3a9cc397eb916bda00bb34eb5cbd130 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 11:04:13 -0800 Subject: name this function correcctly --- cryptography/hazmat/primitives/padding.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 6e583b24..6849d149 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -20,7 +20,7 @@ from cryptography.hazmat.primitives import interfaces _ffi = cffi.FFI() _ffi.cdef(""" -bool Cryptography_check_padding(const uint8_t *, uint8_t); +bool Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t); """) _lib = _ffi.verify(""" #include @@ -38,7 +38,7 @@ static uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) { return Cryptography_DUPLICATE_MSB_TO_ALL(a); } -bool Cryptography_check_padding(const uint8_t *data, uint8_t block_len) { +bool Cryptography_check_pkcs7_padding(const uint8_t *data, uint8_t block_len) { uint8_t i; uint8_t pad_size = data[block_len - 1]; uint8_t mismatch = 0; @@ -150,7 +150,7 @@ class _PKCS7UnpaddingContext(object): if len(self._buffer) != self.block_size // 8: raise ValueError("Invalid padding bytes") - valid = _lib.Cryptography_check_padding( + valid = _lib.Cryptography_check_pkcs7_padding( self._buffer, self.block_size // 8 ) -- cgit v1.2.3 From 1a278a81663e4a81c7dacaacf1c3aa5a6ace8907 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 27 Nov 2013 13:40:45 -0600 Subject: Learn how to spell a word --- docs/hazmat/primitives/symmetric-encryption.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 4ab91408..edf3c050 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -89,7 +89,7 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. Block ciphers require that plaintext or ciphertext always be a multiple of their block size, because of that **padding** is often required to make a message the correct size. ``CipherContext`` will not automatically apply - any padding; you'll need to add your own. For block ciphers the reccomended + any padding; you'll need to add your own. For block ciphers the recommended padding is :class:`cryptography.hazmat.primitives.padding.PKCS7`. If you are using a stream cipher mode (such as :class:`cryptography.hazmat.primitives.modes.CTR`) you don't have to worry -- cgit v1.2.3 From 22e80cb96e034679750a38702aaa55e30da05f69 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 20 Nov 2013 21:27:00 -0600 Subject: GCM support --- cryptography/exceptions.py | 4 + cryptography/hazmat/bindings/openssl/backend.py | 43 +++++++++- cryptography/hazmat/primitives/ciphers/base.py | 50 +++++++++-- cryptography/hazmat/primitives/ciphers/modes.py | 11 +++ cryptography/hazmat/primitives/interfaces.py | 18 ++++ docs/exceptions.rst | 5 ++ docs/hazmat/primitives/symmetric-encryption.rst | 48 +++++++++++ tests/hazmat/primitives/test_aes.py | 21 ++++- tests/hazmat/primitives/test_block.py | 17 +++- tests/hazmat/primitives/test_utils.py | 25 +++++- tests/hazmat/primitives/utils.py | 105 +++++++++++++++++++++++- 11 files changed, 334 insertions(+), 13 deletions(-) diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py index c2e71493..f2a731f0 100644 --- a/cryptography/exceptions.py +++ b/cryptography/exceptions.py @@ -18,3 +18,7 @@ class UnsupportedAlgorithm(Exception): class AlreadyFinalized(Exception): pass + + +class NotFinalized(Exception): + pass diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 9f8ea939..08afa4d6 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -28,7 +28,7 @@ from cryptography.hazmat.primitives.ciphers.algorithms import ( AES, Blowfish, Camellia, CAST5, TripleDES, ARC4, ) from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, CTR, ECB, OFB, CFB + CBC, CTR, ECB, OFB, CFB, GCM, ) @@ -186,6 +186,11 @@ class Backend(object): type(None), GetCipherByName("rc4") ) + self.register_cipher_adapter( + AES, + GCM, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + ) def create_symmetric_encryption_ctx(self, cipher, mode): return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) @@ -238,6 +243,9 @@ class _CipherContext(object): def __init__(self, backend, cipher, mode, operation): self._backend = backend self._cipher = cipher + self._mode = mode + self._operation = operation + self._tag = None ctx = self._backend.lib.EVP_CIPHER_CTX_new() ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free) @@ -270,6 +278,20 @@ class _CipherContext(object): ctx, len(cipher.key) ) assert res != 0 + if isinstance(mode, GCM): + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_IVLEN, + len(iv_nonce), self._backend.ffi.NULL + ) + assert res != 0 + if operation == self._DECRYPT: + assert mode.tag is not None + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_TAG, + len(mode.tag), mode.tag + ) + assert res != 0 + # pass key/iv res = self._backend.lib.EVP_CipherInit_ex(ctx, self._backend.ffi.NULL, self._backend.ffi.NULL, @@ -298,10 +320,29 @@ class _CipherContext(object): if res == 0: self._backend._handle_error() + if (isinstance(self._mode, GCM) and + self._operation == self._ENCRYPT): + block_byte_size = self._cipher.block_size // 8 + tag_buf = self._backend.ffi.new("unsigned char[]", block_byte_size) + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_GET_TAG, + block_byte_size, tag_buf + ) + assert res != 0 + size = self._cipher.block_size + self._tag = self._backend.ffi.buffer(tag_buf)[:size] + res = self._backend.lib.EVP_CIPHER_CTX_cleanup(self._ctx) assert res == 1 return self._backend.ffi.buffer(buf)[:outlen[0]] + def add_data(self, data): + outlen = self._backend.ffi.new("int *") + res = self._backend.lib.EVP_CipherUpdate( + self._ctx, self._backend.ffi.NULL, outlen, data, len(data) + ) + assert res != 0 + @utils.register_interface(interfaces.HashContext) class _HashContext(object): diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 48e6da6f..5a4e7850 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -14,7 +14,7 @@ from __future__ import absolute_import, division, print_function from cryptography import utils -from cryptography.exceptions import AlreadyFinalized +from cryptography.exceptions import AlreadyFinalized, NotFinalized from cryptography.hazmat.primitives import interfaces @@ -28,20 +28,39 @@ class Cipher(object): self._backend = backend def encryptor(self): - return _CipherContext(self._backend.create_symmetric_encryption_ctx( - self.algorithm, self.mode - )) + if isinstance(self.mode, interfaces.ModeWithAAD): + return _AEADCipherContext( + self._backend.create_symmetric_encryption_ctx( + self.algorithm, self.mode + ) + ) + else: + return _CipherContext( + self._backend.create_symmetric_encryption_ctx( + self.algorithm, self.mode + ) + ) def decryptor(self): - return _CipherContext(self._backend.create_symmetric_decryption_ctx( - self.algorithm, self.mode - )) + if isinstance(self.mode, interfaces.ModeWithAAD): + return _AEADCipherContext( + self._backend.create_symmetric_decryption_ctx( + self.algorithm, self.mode + ) + ) + else: + return _CipherContext( + self._backend.create_symmetric_decryption_ctx( + self.algorithm, self.mode + ) + ) @utils.register_interface(interfaces.CipherContext) class _CipherContext(object): def __init__(self, ctx): self._ctx = ctx + self._tag = None def update(self, data): if self._ctx is None: @@ -52,5 +71,22 @@ class _CipherContext(object): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") data = self._ctx.finalize() + self._tag = self._ctx._tag self._ctx = None return data + + +@utils.register_interface(interfaces.AEADCipherContext) +@utils.register_interface(interfaces.CipherContext) +class _AEADCipherContext(_CipherContext): + def add_data(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized") + self._ctx.add_data(data) + + @property + def tag(self): + if self._ctx is not None: + raise NotFinalized("You must finalize encryption before " + "getting the tag") + return self._tag diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index 1d0de689..cb191d98 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -56,3 +56,14 @@ class CTR(object): def __init__(self, nonce): self.nonce = nonce + + +@utils.register_interface(interfaces.Mode) +@utils.register_interface(interfaces.ModeWithInitializationVector) +@utils.register_interface(interfaces.ModeWithAAD) +class GCM(object): + name = "GCM" + + def __init__(self, initialization_vector, tag=None): + self.initialization_vector = initialization_vector + self.tag = tag diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 8cc9d42c..574c8226 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -56,6 +56,10 @@ class ModeWithNonce(six.with_metaclass(abc.ABCMeta)): """ +class ModeWithAAD(six.with_metaclass(abc.ABCMeta)): + pass + + class CipherContext(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def update(self, data): @@ -70,6 +74,20 @@ class CipherContext(six.with_metaclass(abc.ABCMeta)): """ +class AEADCipherContext(six.with_metaclass(abc.ABCMeta)): + @abc.abstractproperty + def tag(self): + """ + Returns tag bytes after finalizing encryption. + """ + + @abc.abstractmethod + def add_data(self, data): + """ + add_data takes bytes and returns nothing. + """ + + class PaddingContext(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def update(self, data): diff --git a/docs/exceptions.rst b/docs/exceptions.rst index c6f5a7cc..7ec3cd27 100644 --- a/docs/exceptions.rst +++ b/docs/exceptions.rst @@ -7,6 +7,11 @@ Exceptions This is raised when a context is used after being finalized. +.. class:: NotFinalized + + This is raised when the AEAD tag property is accessed on a context + before it is finalized. + .. class:: UnsupportedAlgorithm diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index edf3c050..5b249c06 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -118,6 +118,27 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. :meth:`update` and :meth:`finalize` will raise :class:`~cryptography.exceptions.AlreadyFinalized`. +.. class:: AEADCipherContext + + When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object + with an AEAD mode you will receive a return object conforming to the + ``AEADCipherContext`` interface in addition to the ``CipherContext`` + interface. ``AEADCipherContext`` contains an additional method ``add_data`` + for adding additional authenticated by non-encrypted data. You should call + this before calls to ``update``. When you are done call ``finalize()`` to + finish the operation. Once this is complete you can obtain the tag value + from the ``tag`` property. + + .. method:: add_data(data) + + :param bytes data: The data you wish to authenticate but not encrypt. + :raises: :class:`~cryptography.exceptions.AlreadyFinalized` + + .. method:: tag + + :return bytes: Returns the tag value as bytes. + :raises: :class:`~cryptography.exceptions.NotFinalized` + .. _symmetric-encryption-algorithms: Algorithms @@ -295,6 +316,33 @@ Modes reuse an ``initialization_vector`` with a given ``key``. +.. class:: GCM(initialization_vector, tag=None) + + GCM (Galois Counter Mode) is a mode of operation for block ciphers. It + is an AEAD (authenticated encryption with additional data) mode. + + :param bytes initialization_vector: Must be random bytes. They do not need + to be kept secret (they can be included + in a transmitted message). Recommended + to be 96-bit by NIST, but can be up to + 2\ :sup:`64` - 1 bits. Do not reuse an + ``initialization_vector`` with a given + ``key``. + + .. doctest:: + + >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv)) + >>> encryptor = cipher.encryptor() + >>> encryptor.add_data(b"authenticated but encrypted payload") + >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() + >>> tag = encryptor.tag + >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag)) + >>> decryptor = cipher.decryptor() + >>> decryptor.add_data(b"authenticated but encrypted payload") + >>> decryptor.update(ct) + decryptor.finalize() + 'a secret message' + Insecure Modes -------------- diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py index d178da7b..f7b0b9a0 100644 --- a/tests/hazmat/primitives/test_aes.py +++ b/tests/hazmat/primitives/test_aes.py @@ -18,7 +18,7 @@ import os from cryptography.hazmat.primitives.ciphers import algorithms, modes -from .utils import generate_encrypt_test +from .utils import generate_encrypt_test, generate_aead_test from ...utils import ( load_nist_vectors, load_openssl_vectors, ) @@ -132,3 +132,22 @@ class TestAES(object): ), skip_message="Does not support AES CTR", ) + + test_GCM = generate_aead_test( + load_nist_vectors, + os.path.join("ciphers", "AES", "GCM"), + [ + "gcmDecrypt128.rsp", + "gcmDecrypt192.rsp", + "gcmDecrypt256.rsp", + "gcmEncryptExtIV128.rsp", + "gcmEncryptExtIV192.rsp", + "gcmEncryptExtIV256.rsp", + ], + lambda key: algorithms.AES(key), + lambda iv, tag: modes.GCM(iv, tag), + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.GCM("\x00" * 12) + ), + skip_message="Does not support AES GCM", + ) diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index f6c44b47..296821a4 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -18,12 +18,16 @@ import binascii import pytest from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm, AlreadyFinalized +from cryptography.exceptions import ( + UnsupportedAlgorithm, AlreadyFinalized, +) from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, modes ) +from .utils import generate_aead_use_after_finalize_test + @utils.register_interface(interfaces.CipherAlgorithm) class DummyCipher(object): @@ -120,3 +124,14 @@ class TestCipherContext(object): decryptor.update(b"1") with pytest.raises(ValueError): decryptor.finalize() + + +class TestAEADCipherContext(object): + test_use_after_finalize = generate_aead_use_after_finalize_test( + algorithms.AES, + modes.GCM, + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.GCM("\x00" * 12) + ), + skip_message="Does not support AES GCM", + ) diff --git a/tests/hazmat/primitives/test_utils.py b/tests/hazmat/primitives/test_utils.py index cee0b20e..f286e02d 100644 --- a/tests/hazmat/primitives/test_utils.py +++ b/tests/hazmat/primitives/test_utils.py @@ -2,7 +2,8 @@ import pytest from .utils import ( base_hash_test, encrypt_test, hash_test, long_string_hash_test, - base_hmac_test, hmac_test, stream_encryption_test + base_hmac_test, hmac_test, stream_encryption_test, aead_test, + aead_use_after_finalize_test, ) @@ -17,6 +18,28 @@ class TestEncryptTest(object): assert exc_info.value.args[0] == "message!" +class TestAEADTest(object): + def test_skips_if_only_if_returns_false(self): + with pytest.raises(pytest.skip.Exception) as exc_info: + aead_test( + None, None, None, None, + only_if=lambda backend: False, + skip_message="message!" + ) + assert exc_info.value.args[0] == "message!" + + +class TestAEADFinalizeTest(object): + def test_skips_if_only_if_returns_false(self): + with pytest.raises(pytest.skip.Exception) as exc_info: + aead_use_after_finalize_test( + None, None, None, + only_if=lambda backend: False, + skip_message="message!" + ) + assert exc_info.value.args[0] == "message!" + + class TestHashTest(object): def test_skips_if_only_if_returns_false(self): with pytest.raises(pytest.skip.Exception) as exc_info: diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 6c67ddb3..839ff822 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -4,9 +4,11 @@ import os import pytest from cryptography.hazmat.bindings import _ALL_BACKENDS -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives import hmac +from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.exceptions import ( + AlreadyFinalized, NotFinalized, +) from ...utils import load_vectors_from_file @@ -54,6 +56,72 @@ def encrypt_test(backend, cipher_factory, mode_factory, params, only_if, assert actual_plaintext == binascii.unhexlify(plaintext) +def generate_aead_test(param_loader, path, file_names, cipher_factory, + mode_factory, only_if, skip_message): + def test_aead(self): + for backend in _ALL_BACKENDS: + for file_name in file_names: + for params in load_vectors_from_file( + os.path.join(path, file_name), + param_loader + ): + yield ( + aead_test, + backend, + cipher_factory, + mode_factory, + params, + only_if, + skip_message + ) + return test_aead + + +def aead_test(backend, cipher_factory, mode_factory, params, only_if, + skip_message): + if not only_if(backend): + pytest.skip(skip_message) + if params.get("pt") is not None: + plaintext = params.pop("pt") + ciphertext = params.pop("ct") + aad = params.pop("aad") + if params.get("fail") is True: + cipher = Cipher( + cipher_factory(binascii.unhexlify(params["key"])), + mode_factory(binascii.unhexlify(params["iv"]), + binascii.unhexlify(params["tag"])), + backend + ) + decryptor = cipher.decryptor() + decryptor.add_data(binascii.unhexlify(aad)) + actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext)) + with pytest.raises(AssertionError): + decryptor.finalize() + else: + cipher = Cipher( + cipher_factory(binascii.unhexlify(params["key"])), + mode_factory(binascii.unhexlify(params["iv"]), None), + backend + ) + encryptor = cipher.encryptor() + encryptor.add_data(binascii.unhexlify(aad)) + actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext)) + actual_ciphertext += encryptor.finalize() + tag_len = len(params["tag"]) + assert binascii.hexlify(encryptor.tag)[:tag_len] == params["tag"] + cipher = Cipher( + cipher_factory(binascii.unhexlify(params["key"])), + mode_factory(binascii.unhexlify(params["iv"]), + binascii.unhexlify(params["tag"])), + backend + ) + decryptor = cipher.decryptor() + decryptor.add_data(binascii.unhexlify(aad)) + actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext)) + actual_plaintext += decryptor.finalize() + assert actual_plaintext == binascii.unhexlify(plaintext) + + def generate_stream_encryption_test(param_loader, path, file_names, cipher_factory, only_if=None, skip_message=None): @@ -237,3 +305,36 @@ def base_hmac_test(backend, algorithm, only_if, skip_message): h_copy = h.copy() assert h != h_copy assert h._ctx != h_copy._ctx + + +def generate_aead_use_after_finalize_test(cipher_factory, mode_factory, + only_if, skip_message): + def test_aead_use_after_finalize(self): + for backend in _ALL_BACKENDS: + yield ( + aead_use_after_finalize_test, + backend, + cipher_factory, + mode_factory, + only_if, + skip_message + ) + return test_aead_use_after_finalize + + +def aead_use_after_finalize_test(backend, cipher_factory, mode_factory, + only_if, skip_message): + if not only_if(backend): + pytest.skip(skip_message) + cipher = Cipher( + cipher_factory(binascii.unhexlify(b"0" * 32)), + mode_factory(binascii.unhexlify(b"0" * 24)), + backend + ) + encryptor = cipher.encryptor() + encryptor.update(b"a" * 16) + with pytest.raises(NotFinalized): + encryptor.tag + encryptor.finalize() + with pytest.raises(AlreadyFinalized): + encryptor.add_data(b"b" * 16) -- cgit v1.2.3 From cf6032648a93329e93f40a3654c68d8d57cf0d63 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 21 Nov 2013 11:19:45 -0600 Subject: fix buffer size bug for gcm tag fetch --- cryptography/hazmat/bindings/openssl/backend.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 08afa4d6..fdb67628 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -329,8 +329,7 @@ class _CipherContext(object): block_byte_size, tag_buf ) assert res != 0 - size = self._cipher.block_size - self._tag = self._backend.ffi.buffer(tag_buf)[:size] + self._tag = self._backend.ffi.buffer(tag_buf)[:] res = self._backend.lib.EVP_CIPHER_CTX_cleanup(self._ctx) assert res == 1 -- cgit v1.2.3 From 65c4e0a396b9d4183d9ce16b27742d407eb9d91d Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 21 Nov 2013 11:20:56 -0600 Subject: gcm doc fixes --- docs/hazmat/primitives/symmetric-encryption.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 5b249c06..bd9a3f60 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -122,7 +122,7 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object with an AEAD mode you will receive a return object conforming to the - ``AEADCipherContext`` interface in addition to the ``CipherContext`` + ``AEADCipherContext`` interface, in addition to the ``CipherContext`` interface. ``AEADCipherContext`` contains an additional method ``add_data`` for adding additional authenticated by non-encrypted data. You should call this before calls to ``update``. When you are done call ``finalize()`` to @@ -134,7 +134,7 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. :param bytes data: The data you wish to authenticate but not encrypt. :raises: :class:`~cryptography.exceptions.AlreadyFinalized` - .. method:: tag + .. attribute:: tag :return bytes: Returns the tag value as bytes. :raises: :class:`~cryptography.exceptions.NotFinalized` -- cgit v1.2.3 From a5e1081098be6734f8abe31ce0b84c72490f4cb3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 21 Nov 2013 11:21:21 -0600 Subject: add tag as abstractproperty for modewithaad --- cryptography/hazmat/primitives/interfaces.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 574c8226..f216686a 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -57,7 +57,11 @@ class ModeWithNonce(six.with_metaclass(abc.ABCMeta)): class ModeWithAAD(six.with_metaclass(abc.ABCMeta)): - pass + @abc.abstractproperty + def tag(self): + """ + The value of the tag supplied to the constructor of this mode. + """ class CipherContext(six.with_metaclass(abc.ABCMeta)): -- cgit v1.2.3 From cc9ec987e82d1c4e2d42e6ef41664a090425287c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 21 Nov 2013 11:21:35 -0600 Subject: rename NotFinalized exception to NotYetFinalized because alex is right ...it does read better that way --- cryptography/exceptions.py | 2 +- cryptography/hazmat/primitives/ciphers/base.py | 6 +++--- tests/hazmat/primitives/utils.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py index f2a731f0..8b286679 100644 --- a/cryptography/exceptions.py +++ b/cryptography/exceptions.py @@ -20,5 +20,5 @@ class AlreadyFinalized(Exception): pass -class NotFinalized(Exception): +class NotYetFinalized(Exception): pass diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 5a4e7850..3a27030a 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -14,7 +14,7 @@ from __future__ import absolute_import, division, print_function from cryptography import utils -from cryptography.exceptions import AlreadyFinalized, NotFinalized +from cryptography.exceptions import AlreadyFinalized, NotYetFinalized from cryptography.hazmat.primitives import interfaces @@ -87,6 +87,6 @@ class _AEADCipherContext(_CipherContext): @property def tag(self): if self._ctx is not None: - raise NotFinalized("You must finalize encryption before " - "getting the tag") + raise NotYetFinalized("You must finalize encryption before " + "getting the tag") return self._tag diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 839ff822..98455556 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -7,7 +7,7 @@ from cryptography.hazmat.bindings import _ALL_BACKENDS from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.exceptions import ( - AlreadyFinalized, NotFinalized, + AlreadyFinalized, NotYetFinalized, ) from ...utils import load_vectors_from_file @@ -333,7 +333,7 @@ def aead_use_after_finalize_test(backend, cipher_factory, mode_factory, ) encryptor = cipher.encryptor() encryptor.update(b"a" * 16) - with pytest.raises(NotFinalized): + with pytest.raises(NotYetFinalized): encryptor.tag encryptor.finalize() with pytest.raises(AlreadyFinalized): -- cgit v1.2.3 From 24316fd1945909ef720ceb0e294752c4d3b6bbb2 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 22 Nov 2013 13:30:46 -0600 Subject: _AEADCipherContext refactor * No longer extends _CipherContext * Remove _tag from _CipherContext * This change duplicates a small amount of code from _CipherContext --- cryptography/hazmat/primitives/ciphers/base.py | 21 ++++++++++++++++++--- tests/hazmat/primitives/utils.py | 4 ++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 3a27030a..89e56547 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -60,7 +60,6 @@ class Cipher(object): class _CipherContext(object): def __init__(self, ctx): self._ctx = ctx - self._tag = None def update(self, data): if self._ctx is None: @@ -71,14 +70,30 @@ class _CipherContext(object): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") data = self._ctx.finalize() - self._tag = self._ctx._tag self._ctx = None return data @utils.register_interface(interfaces.AEADCipherContext) @utils.register_interface(interfaces.CipherContext) -class _AEADCipherContext(_CipherContext): +class _AEADCipherContext(object): + def __init__(self, ctx): + self._ctx = ctx + self._tag = None + + def update(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized") + return self._ctx.update(data) + + def finalize(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized") + data = self._ctx.finalize() + self._tag = self._ctx._tag + self._ctx = None + return data + def add_data(self, data): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 98455556..2a99cab9 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -338,3 +338,7 @@ def aead_use_after_finalize_test(backend, cipher_factory, mode_factory, encryptor.finalize() with pytest.raises(AlreadyFinalized): encryptor.add_data(b"b" * 16) + with pytest.raises(AlreadyFinalized): + encryptor.update(b"b" * 16) + with pytest.raises(AlreadyFinalized): + encryptor.finalize() -- cgit v1.2.3 From 6331daa36902edf5a5dd04e4e3fa0e188db59420 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 22 Nov 2013 13:42:02 -0600 Subject: gcm doc improvements --- docs/hazmat/primitives/symmetric-encryption.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index bd9a3f60..4e7990b0 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -137,7 +137,8 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. .. attribute:: tag :return bytes: Returns the tag value as bytes. - :raises: :class:`~cryptography.exceptions.NotFinalized` + :raises: :class:`~cryptography.exceptions.NotYetFinalized` if called + before the context is finalized. .. _symmetric-encryption-algorithms: @@ -319,7 +320,10 @@ Modes .. class:: GCM(initialization_vector, tag=None) GCM (Galois Counter Mode) is a mode of operation for block ciphers. It - is an AEAD (authenticated encryption with additional data) mode. + is an AEAD (authenticated encryption with additional data) mode. AEAD + is a type of block cipher mode that encrypts the message as well as + authenticating it (and optionally additional data that is not encrypted) + simultaneously. :param bytes initialization_vector: Must be random bytes. They do not need to be kept secret (they can be included -- cgit v1.2.3 From ce9c611feb4db781fcab5b7bbc68b936816d6a73 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 22 Nov 2013 14:10:59 -0600 Subject: enforce AEAD add_data before update --- cryptography/exceptions.py | 4 ++++ cryptography/hazmat/primitives/ciphers/base.py | 8 +++++++- docs/exceptions.rst | 9 ++++++++- tests/hazmat/primitives/test_block.py | 4 ++-- tests/hazmat/primitives/test_utils.py | 4 ++-- tests/hazmat/primitives/utils.py | 18 ++++++++++-------- 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py index 8b286679..d56db214 100644 --- a/cryptography/exceptions.py +++ b/cryptography/exceptions.py @@ -20,5 +20,9 @@ class AlreadyFinalized(Exception): pass +class AlreadyUpdated(Exception): + pass + + class NotYetFinalized(Exception): pass diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 89e56547..7c315898 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -14,7 +14,9 @@ from __future__ import absolute_import, division, print_function from cryptography import utils -from cryptography.exceptions import AlreadyFinalized, NotYetFinalized +from cryptography.exceptions import ( + AlreadyFinalized, NotYetFinalized, AlreadyUpdated, +) from cryptography.hazmat.primitives import interfaces @@ -80,10 +82,12 @@ class _AEADCipherContext(object): def __init__(self, ctx): self._ctx = ctx self._tag = None + self._updated = False def update(self, data): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") + self._updated = True return self._ctx.update(data) def finalize(self): @@ -97,6 +101,8 @@ class _AEADCipherContext(object): def add_data(self, data): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") + if self._updated: + raise AlreadyUpdated("Update has been called on this context") self._ctx.add_data(data) @property diff --git a/docs/exceptions.rst b/docs/exceptions.rst index 7ec3cd27..087066b8 100644 --- a/docs/exceptions.rst +++ b/docs/exceptions.rst @@ -7,12 +7,19 @@ Exceptions This is raised when a context is used after being finalized. -.. class:: NotFinalized + +.. class:: NotYetFinalized This is raised when the AEAD tag property is accessed on a context before it is finalized. +.. class:: AlreadyUpdated + + This is raised when additional data is added to a context after update + has already been called. + + .. class:: UnsupportedAlgorithm This is raised when a backend doesn't support the requested algorithm (or diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index 296821a4..2806efd5 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -26,7 +26,7 @@ from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, modes ) -from .utils import generate_aead_use_after_finalize_test +from .utils import generate_aead_exception_test @utils.register_interface(interfaces.CipherAlgorithm) @@ -127,7 +127,7 @@ class TestCipherContext(object): class TestAEADCipherContext(object): - test_use_after_finalize = generate_aead_use_after_finalize_test( + test_aead_exceptions = generate_aead_exception_test( algorithms.AES, modes.GCM, only_if=lambda backend: backend.cipher_supported( diff --git a/tests/hazmat/primitives/test_utils.py b/tests/hazmat/primitives/test_utils.py index f286e02d..ebb8b5c4 100644 --- a/tests/hazmat/primitives/test_utils.py +++ b/tests/hazmat/primitives/test_utils.py @@ -3,7 +3,7 @@ import pytest from .utils import ( base_hash_test, encrypt_test, hash_test, long_string_hash_test, base_hmac_test, hmac_test, stream_encryption_test, aead_test, - aead_use_after_finalize_test, + aead_exception_test, ) @@ -32,7 +32,7 @@ class TestAEADTest(object): class TestAEADFinalizeTest(object): def test_skips_if_only_if_returns_false(self): with pytest.raises(pytest.skip.Exception) as exc_info: - aead_use_after_finalize_test( + aead_exception_test( None, None, None, only_if=lambda backend: False, skip_message="message!" diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 2a99cab9..8df02e78 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -7,7 +7,7 @@ from cryptography.hazmat.bindings import _ALL_BACKENDS from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.exceptions import ( - AlreadyFinalized, NotYetFinalized, + AlreadyFinalized, NotYetFinalized, AlreadyUpdated, ) from ...utils import load_vectors_from_file @@ -307,23 +307,23 @@ def base_hmac_test(backend, algorithm, only_if, skip_message): assert h._ctx != h_copy._ctx -def generate_aead_use_after_finalize_test(cipher_factory, mode_factory, - only_if, skip_message): - def test_aead_use_after_finalize(self): +def generate_aead_exception_test(cipher_factory, mode_factory, + only_if, skip_message): + def test_aead_exception(self): for backend in _ALL_BACKENDS: yield ( - aead_use_after_finalize_test, + aead_exception_test, backend, cipher_factory, mode_factory, only_if, skip_message ) - return test_aead_use_after_finalize + return test_aead_exception -def aead_use_after_finalize_test(backend, cipher_factory, mode_factory, - only_if, skip_message): +def aead_exception_test(backend, cipher_factory, mode_factory, + only_if, skip_message): if not only_if(backend): pytest.skip(skip_message) cipher = Cipher( @@ -335,6 +335,8 @@ def aead_use_after_finalize_test(backend, cipher_factory, mode_factory, encryptor.update(b"a" * 16) with pytest.raises(NotYetFinalized): encryptor.tag + with pytest.raises(AlreadyUpdated): + encryptor.add_data(b"b" * 16) encryptor.finalize() with pytest.raises(AlreadyFinalized): encryptor.add_data(b"b" * 16) -- cgit v1.2.3 From a4bfc08b8d2ed312eeb1b0558ac20f285feb8cc2 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 22 Nov 2013 19:57:37 -0600 Subject: invalidtag exception for gcm This exception is probably not safe. It depends on the assumption that if ERR_get_error returns a 0 then it is an AEAD tag error. --- cryptography/exceptions.py | 4 ++++ cryptography/hazmat/bindings/openssl/backend.py | 5 +++-- tests/hazmat/primitives/utils.py | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py index d56db214..e9d88199 100644 --- a/cryptography/exceptions.py +++ b/cryptography/exceptions.py @@ -26,3 +26,7 @@ class AlreadyUpdated(Exception): class NotYetFinalized(Exception): pass + + +class InvalidTag(Exception): + pass diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index fdb67628..527706bc 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -19,7 +19,7 @@ import sys import cffi from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.exceptions import UnsupportedAlgorithm, InvalidTag from cryptography.hazmat.bindings.interfaces import ( CipherBackend, HashBackend, HMACBackend ) @@ -200,7 +200,8 @@ class Backend(object): def _handle_error(self): code = self.lib.ERR_get_error() - assert code != 0 + if not code: + raise InvalidTag lib = self.lib.ERR_GET_LIB(code) func = self.lib.ERR_GET_FUNC(code) reason = self.lib.ERR_GET_REASON(code) diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 8df02e78..39f5ae82 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -7,7 +7,7 @@ from cryptography.hazmat.bindings import _ALL_BACKENDS from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.exceptions import ( - AlreadyFinalized, NotYetFinalized, AlreadyUpdated, + AlreadyFinalized, NotYetFinalized, AlreadyUpdated, InvalidTag, ) from ...utils import load_vectors_from_file @@ -95,7 +95,7 @@ def aead_test(backend, cipher_factory, mode_factory, params, only_if, decryptor = cipher.decryptor() decryptor.add_data(binascii.unhexlify(aad)) actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext)) - with pytest.raises(AssertionError): + with pytest.raises(InvalidTag): decryptor.finalize() else: cipher = Cipher( -- cgit v1.2.3 From 2631c2b7be22f15f83810df1b8664bf388ad02a6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 24 Nov 2013 10:20:50 -0600 Subject: gcm doc fixes (per review from alex) --- docs/hazmat/primitives/symmetric-encryption.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 4e7990b0..3ed8c9e2 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -323,7 +323,8 @@ Modes is an AEAD (authenticated encryption with additional data) mode. AEAD is a type of block cipher mode that encrypts the message as well as authenticating it (and optionally additional data that is not encrypted) - simultaneously. + simultaneously. Additional means of verifying integrity (like + :doc:`HMAC `) are not necessary. :param bytes initialization_vector: Must be random bytes. They do not need to be kept secret (they can be included @@ -338,12 +339,12 @@ Modes >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv)) >>> encryptor = cipher.encryptor() - >>> encryptor.add_data(b"authenticated but encrypted payload") + >>> encryptor.add_data(b"authenticated but not encrypted payload") >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() >>> tag = encryptor.tag >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag)) >>> decryptor = cipher.decryptor() - >>> decryptor.add_data(b"authenticated but encrypted payload") + >>> decryptor.add_data(b"authenticated but not encrypted payload") >>> decryptor.update(ct) + decryptor.finalize() 'a secret message' -- cgit v1.2.3 From bc31fb22979df3f034ce286fab20da71be76fe58 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 24 Nov 2013 11:03:53 -0600 Subject: rename add_data to authenticate_additional_data for clarity (hopefully) --- cryptography/hazmat/bindings/openssl/backend.py | 2 +- cryptography/hazmat/primitives/ciphers/base.py | 4 ++-- cryptography/hazmat/primitives/interfaces.py | 4 ++-- docs/hazmat/primitives/symmetric-encryption.rst | 16 ++++++++-------- tests/hazmat/primitives/utils.py | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 527706bc..1a534011 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -336,7 +336,7 @@ class _CipherContext(object): assert res == 1 return self._backend.ffi.buffer(buf)[:outlen[0]] - def add_data(self, data): + def authenticate_additional_data(self, data): outlen = self._backend.ffi.new("int *") res = self._backend.lib.EVP_CipherUpdate( self._ctx, self._backend.ffi.NULL, outlen, data, len(data) diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 7c315898..c8c4533b 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -98,12 +98,12 @@ class _AEADCipherContext(object): self._ctx = None return data - def add_data(self, data): + def authenticate_additional_data(self, data): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") if self._updated: raise AlreadyUpdated("Update has been called on this context") - self._ctx.add_data(data) + self._ctx.authenticate_additional_data(data) @property def tag(self): diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index f216686a..c0548dfd 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -86,9 +86,9 @@ class AEADCipherContext(six.with_metaclass(abc.ABCMeta)): """ @abc.abstractmethod - def add_data(self, data): + def authenticate_additional_data(self, data): """ - add_data takes bytes and returns nothing. + authenticate_additional_data takes bytes and returns nothing. """ diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 3ed8c9e2..d123d15c 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -123,13 +123,13 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object with an AEAD mode you will receive a return object conforming to the ``AEADCipherContext`` interface, in addition to the ``CipherContext`` - interface. ``AEADCipherContext`` contains an additional method ``add_data`` - for adding additional authenticated by non-encrypted data. You should call - this before calls to ``update``. When you are done call ``finalize()`` to - finish the operation. Once this is complete you can obtain the tag value - from the ``tag`` property. + interface. ``AEADCipherContext`` contains an additional method + ``authenticate_additional_data`` for adding additional authenticated but + unencrypted data. You should call this before calls to ``update``. When you + are done call ``finalize()`` to finish the operation. Once this is complete + you can obtain the tag value from the ``tag`` property. - .. method:: add_data(data) + .. method:: authenticate_additional_data(data) :param bytes data: The data you wish to authenticate but not encrypt. :raises: :class:`~cryptography.exceptions.AlreadyFinalized` @@ -339,12 +339,12 @@ Modes >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv)) >>> encryptor = cipher.encryptor() - >>> encryptor.add_data(b"authenticated but not encrypted payload") + >>> encryptor.authenticate_additional_data(b"authenticated but not encrypted payload") >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() >>> tag = encryptor.tag >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag)) >>> decryptor = cipher.decryptor() - >>> decryptor.add_data(b"authenticated but not encrypted payload") + >>> decryptor.authenticate_additional_data(b"authenticated but not encrypted payload") >>> decryptor.update(ct) + decryptor.finalize() 'a secret message' diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 39f5ae82..b6f9e0f5 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -93,7 +93,7 @@ def aead_test(backend, cipher_factory, mode_factory, params, only_if, backend ) decryptor = cipher.decryptor() - decryptor.add_data(binascii.unhexlify(aad)) + decryptor.authenticate_additional_data(binascii.unhexlify(aad)) actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext)) with pytest.raises(InvalidTag): decryptor.finalize() @@ -104,7 +104,7 @@ def aead_test(backend, cipher_factory, mode_factory, params, only_if, backend ) encryptor = cipher.encryptor() - encryptor.add_data(binascii.unhexlify(aad)) + encryptor.authenticate_additional_data(binascii.unhexlify(aad)) actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext)) actual_ciphertext += encryptor.finalize() tag_len = len(params["tag"]) @@ -116,7 +116,7 @@ def aead_test(backend, cipher_factory, mode_factory, params, only_if, backend ) decryptor = cipher.decryptor() - decryptor.add_data(binascii.unhexlify(aad)) + decryptor.authenticate_additional_data(binascii.unhexlify(aad)) actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext)) actual_plaintext += decryptor.finalize() assert actual_plaintext == binascii.unhexlify(plaintext) @@ -336,10 +336,10 @@ def aead_exception_test(backend, cipher_factory, mode_factory, with pytest.raises(NotYetFinalized): encryptor.tag with pytest.raises(AlreadyUpdated): - encryptor.add_data(b"b" * 16) + encryptor.authenticate_additional_data(b"b" * 16) encryptor.finalize() with pytest.raises(AlreadyFinalized): - encryptor.add_data(b"b" * 16) + encryptor.authenticate_additional_data(b"b" * 16) with pytest.raises(AlreadyFinalized): encryptor.update(b"b" * 16) with pytest.raises(AlreadyFinalized): -- cgit v1.2.3 From 4664108ac1771b694f917b9ef70d358638371c04 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 24 Nov 2013 11:14:27 -0600 Subject: simplify code for wrapping ciphercontext/aeadciphercontext --- cryptography/hazmat/primitives/ciphers/base.py | 34 +++++++++----------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index c8c4533b..3f6ca0fe 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -30,32 +30,22 @@ class Cipher(object): self._backend = backend def encryptor(self): - if isinstance(self.mode, interfaces.ModeWithAAD): - return _AEADCipherContext( - self._backend.create_symmetric_encryption_ctx( - self.algorithm, self.mode - ) - ) - else: - return _CipherContext( - self._backend.create_symmetric_encryption_ctx( - self.algorithm, self.mode - ) - ) + ctx = self._backend.create_symmetric_encryption_ctx( + self.algorithm, self.mode + ) + return self._wrap_ctx(ctx) def decryptor(self): + ctx = self._backend.create_symmetric_decryption_ctx( + self.algorithm, self.mode + ) + return self._wrap_ctx(ctx) + + def _wrap_ctx(self, ctx): if isinstance(self.mode, interfaces.ModeWithAAD): - return _AEADCipherContext( - self._backend.create_symmetric_decryption_ctx( - self.algorithm, self.mode - ) - ) + return _AEADCipherContext(ctx) else: - return _CipherContext( - self._backend.create_symmetric_decryption_ctx( - self.algorithm, self.mode - ) - ) + return _CipherContext(ctx) @utils.register_interface(interfaces.CipherContext) -- cgit v1.2.3 From 0092c205657789e15848c7848eec768720de468f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 24 Nov 2013 11:39:14 -0600 Subject: raise TypeError if you attempt to get the tag attribute on a decrypt * To support this the _AEADCipherContext in base.py now needs to be aware of whether it is encrypting/decrypting --- cryptography/hazmat/primitives/ciphers/base.py | 14 +++++++++----- docs/hazmat/primitives/symmetric-encryption.rst | 1 + tests/hazmat/primitives/utils.py | 9 +++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 3f6ca0fe..252a9feb 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -33,17 +33,17 @@ class Cipher(object): ctx = self._backend.create_symmetric_encryption_ctx( self.algorithm, self.mode ) - return self._wrap_ctx(ctx) + return self._wrap_ctx(ctx, True) def decryptor(self): ctx = self._backend.create_symmetric_decryption_ctx( self.algorithm, self.mode ) - return self._wrap_ctx(ctx) + return self._wrap_ctx(ctx, False) - def _wrap_ctx(self, ctx): + def _wrap_ctx(self, ctx, encrypt): if isinstance(self.mode, interfaces.ModeWithAAD): - return _AEADCipherContext(ctx) + return _AEADCipherContext(ctx, encrypt) else: return _CipherContext(ctx) @@ -69,10 +69,11 @@ class _CipherContext(object): @utils.register_interface(interfaces.AEADCipherContext) @utils.register_interface(interfaces.CipherContext) class _AEADCipherContext(object): - def __init__(self, ctx): + def __init__(self, ctx, encrypt): self._ctx = ctx self._tag = None self._updated = False + self._encrypt = encrypt def update(self, data): if self._ctx is None: @@ -97,6 +98,9 @@ class _AEADCipherContext(object): @property def tag(self): + if not self._encrypt: + raise TypeError("The tag attribute is unavailable on a " + "decryption context") if self._ctx is not None: raise NotYetFinalized("You must finalize encryption before " "getting the tag") diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index d123d15c..f35357d0 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -139,6 +139,7 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. :return bytes: Returns the tag value as bytes. :raises: :class:`~cryptography.exceptions.NotYetFinalized` if called before the context is finalized. + :raises TypeError: If called on a decryption context. .. _symmetric-encryption-algorithms: diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index b6f9e0f5..58b9a917 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -344,3 +344,12 @@ def aead_exception_test(backend, cipher_factory, mode_factory, encryptor.update(b"b" * 16) with pytest.raises(AlreadyFinalized): encryptor.finalize() + cipher = Cipher( + cipher_factory(binascii.unhexlify(b"0" * 32)), + mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16), + backend + ) + decryptor = cipher.decryptor() + decryptor.update(b"a" * 16) + with pytest.raises(TypeError): + decryptor.tag -- cgit v1.2.3 From a8b35f4a882ddd02fefed69163e9f226eab99ce9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 24 Nov 2013 11:51:22 -0600 Subject: make _CipherContext in backend.py compliant with AEADCipherContext * Might make more sense to split it into _CipherContext and _AEADCipherContext like we do in base.py, but there would be quite a bit of duplicate code. --- cryptography/hazmat/bindings/openssl/backend.py | 5 +++++ cryptography/hazmat/primitives/ciphers/base.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 1a534011..4d9a8ce5 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -237,6 +237,7 @@ class GetCipherByName(object): @utils.register_interface(interfaces.CipherContext) +@utils.register_interface(interfaces.AEADCipherContext) class _CipherContext(object): _ENCRYPT = 1 _DECRYPT = 0 @@ -343,6 +344,10 @@ class _CipherContext(object): ) assert res != 0 + @property + def tag(self): + return self._tag + @utils.register_interface(interfaces.HashContext) class _HashContext(object): diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 252a9feb..a6f06b82 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -85,7 +85,7 @@ class _AEADCipherContext(object): if self._ctx is None: raise AlreadyFinalized("Context was already finalized") data = self._ctx.finalize() - self._tag = self._ctx._tag + self._tag = self._ctx.tag self._ctx = None return data -- cgit v1.2.3 From 86699be866b1ef3390da31f74a63980e4d2b7d99 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 24 Nov 2013 12:17:51 -0600 Subject: narrow the potential cases where invalidtag can be raised --- cryptography/hazmat/bindings/openssl/backend.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 4d9a8ce5..e9ecc800 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -198,10 +198,11 @@ class Backend(object): def create_symmetric_decryption_ctx(self, cipher, mode): return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT) - def _handle_error(self): + def _handle_error(self, mode): code = self.lib.ERR_get_error() - if not code: + if not code and isinstance(mode, GCM): raise InvalidTag + assert code != 0 lib = self.lib.ERR_GET_LIB(code) func = self.lib.ERR_GET_FUNC(code) reason = self.lib.ERR_GET_REASON(code) @@ -320,7 +321,7 @@ class _CipherContext(object): outlen = self._backend.ffi.new("int *") res = self._backend.lib.EVP_CipherFinal_ex(self._ctx, buf, outlen) if res == 0: - self._backend._handle_error() + self._backend._handle_error(self._mode) if (isinstance(self._mode, GCM) and self._operation == self._ENCRYPT): -- cgit v1.2.3 From 67abc864cb64033333aa08a03fba1dd153074dfd Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 25 Nov 2013 14:29:35 -0600 Subject: document tag param for GCM object --- docs/hazmat/primitives/symmetric-encryption.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index f35357d0..70c3d2f4 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -335,6 +335,9 @@ Modes ``initialization_vector`` with a given ``key``. + :param bytes tag: The tag bytes to verify during decryption. Must be provided + for decryption, but is ignored when encrypting. + .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes -- cgit v1.2.3 From 26c8c6adcb9a6485966070418080a17cd2445bed Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 29 Nov 2013 16:24:56 -0600 Subject: begin adding warnings to GCM mode --- docs/hazmat/primitives/symmetric-encryption.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 70c3d2f4..a77e0e79 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -320,6 +320,12 @@ Modes .. class:: GCM(initialization_vector, tag=None) + .. warning:: + + When using this mode you MUST not use the decrypted data until every + byte has been decrypted. GCM provides NO guarantees of ciphertext + integrity until decryption is complete. + GCM (Galois Counter Mode) is a mode of operation for block ciphers. It is an AEAD (authenticated encryption with additional data) mode. AEAD is a type of block cipher mode that encrypts the message as well as -- cgit v1.2.3 From e0b5bb18c3963ebaa66d537d2cf00c2cc0dd804c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 29 Nov 2013 16:35:04 -0600 Subject: explicit backend fix for gcm docs --- docs/hazmat/primitives/symmetric-encryption.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index a77e0e79..aefc2d7e 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -347,12 +347,12 @@ Modes .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv)) + >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend) >>> encryptor = cipher.encryptor() >>> encryptor.authenticate_additional_data(b"authenticated but not encrypted payload") >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() >>> tag = encryptor.tag - >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag)) + >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag), backend) >>> decryptor = cipher.decryptor() >>> decryptor.authenticate_additional_data(b"authenticated but not encrypted payload") >>> decryptor.update(ct) + decryptor.finalize() -- cgit v1.2.3 From 5a40896cbeae2cc2673c86aa18d3953314e760ba Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 29 Nov 2013 17:19:25 -0600 Subject: create AEADEncryptionContext and DecryptionContext --- cryptography/hazmat/bindings/openssl/backend.py | 2 ++ cryptography/hazmat/primitives/ciphers/base.py | 19 +++++++++++++------ cryptography/hazmat/primitives/interfaces.py | 16 +++++++++++----- tests/hazmat/primitives/utils.py | 2 +- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index e9ecc800..7d3eb3d7 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -239,6 +239,8 @@ class GetCipherByName(object): @utils.register_interface(interfaces.CipherContext) @utils.register_interface(interfaces.AEADCipherContext) +@utils.register_interface(interfaces.AEADEncryptionContext) +@utils.register_interface(interfaces.AEADDecryptionContext) class _CipherContext(object): _ENCRYPT = 1 _DECRYPT = 0 diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index a6f06b82..f24fd000 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -43,7 +43,10 @@ class Cipher(object): def _wrap_ctx(self, ctx, encrypt): if isinstance(self.mode, interfaces.ModeWithAAD): - return _AEADCipherContext(ctx, encrypt) + if encrypt: + return _AEADEncryptionContext(ctx) + else: + return _AEADDecryptionContext(ctx) else: return _CipherContext(ctx) @@ -69,11 +72,10 @@ class _CipherContext(object): @utils.register_interface(interfaces.AEADCipherContext) @utils.register_interface(interfaces.CipherContext) class _AEADCipherContext(object): - def __init__(self, ctx, encrypt): + def __init__(self, ctx): self._ctx = ctx self._tag = None self._updated = False - self._encrypt = encrypt def update(self, data): if self._ctx is None: @@ -96,11 +98,16 @@ class _AEADCipherContext(object): raise AlreadyUpdated("Update has been called on this context") self._ctx.authenticate_additional_data(data) + +@utils.register_interface(interfaces.AEADDecryptionContext) +class _AEADDecryptionContext(_AEADCipherContext): + pass + + +@utils.register_interface(interfaces.AEADEncryptionContext) +class _AEADEncryptionContext(_AEADCipherContext): @property def tag(self): - if not self._encrypt: - raise TypeError("The tag attribute is unavailable on a " - "decryption context") if self._ctx is not None: raise NotYetFinalized("You must finalize encryption before " "getting the tag") diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index c0548dfd..1884e560 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -79,17 +79,23 @@ class CipherContext(six.with_metaclass(abc.ABCMeta)): class AEADCipherContext(six.with_metaclass(abc.ABCMeta)): + @abc.abstractmethod + def authenticate_additional_data(self, data): + """ + authenticate_additional_data takes bytes and returns nothing. + """ + + +class AEADEncryptionContext(six.with_metaclass(abc.ABCMeta)): @abc.abstractproperty def tag(self): """ Returns tag bytes after finalizing encryption. """ - @abc.abstractmethod - def authenticate_additional_data(self, data): - """ - authenticate_additional_data takes bytes and returns nothing. - """ + +class AEADDecryptionContext(six.with_metaclass(abc.ABCMeta)): + pass class PaddingContext(six.with_metaclass(abc.ABCMeta)): diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 58b9a917..9aa3a89a 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -351,5 +351,5 @@ def aead_exception_test(backend, cipher_factory, mode_factory, ) decryptor = cipher.decryptor() decryptor.update(b"a" * 16) - with pytest.raises(TypeError): + with pytest.raises(AttributeError): decryptor.tag -- cgit v1.2.3 From 5b828b142b4e8fea021567038e2dba6cf6cd9221 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 29 Nov 2013 17:32:08 -0600 Subject: attempt to document the new interfaces for AEAD --- docs/hazmat/primitives/symmetric-encryption.rst | 26 +++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index aefc2d7e..9d4f0355 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -122,24 +122,38 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object with an AEAD mode you will receive a return object conforming to the - ``AEADCipherContext`` interface, in addition to the ``CipherContext`` - interface. ``AEADCipherContext`` contains an additional method + ``AEADCipherContext`` interface (in addition to the ``CipherContext`` + interface and either the ``AEADEncryptionContext`` or ``AEADDecryptionContext`` + interface). ``AEADCipherContext`` contains an additional method ``authenticate_additional_data`` for adding additional authenticated but unencrypted data. You should call this before calls to ``update``. When you - are done call ``finalize()`` to finish the operation. Once this is complete - you can obtain the tag value from the ``tag`` property. + are done call ``finalize()`` to finish the operation. .. method:: authenticate_additional_data(data) :param bytes data: The data you wish to authenticate but not encrypt. :raises: :class:`~cryptography.exceptions.AlreadyFinalized` +.. class:: AEADEncryptionContext + + When creating an encryption context using ``encryptor()`` on a ``Cipher`` + object with an AEAD mode you will receive a return object conforming to the + ``AEADEncryptionContext`` interface (as well as ``AEADCipherContext``). + This interface provides one additional attribute ``tag``. ``tag`` can only + be obtained after ``finalize()``. + .. attribute:: tag :return bytes: Returns the tag value as bytes. :raises: :class:`~cryptography.exceptions.NotYetFinalized` if called before the context is finalized. - :raises TypeError: If called on a decryption context. + +.. class:: AEADDecryptionContext + + When creating an encryption context using ``encryptor()`` on a ``Cipher`` + object with an AEAD mode you will receive a return object conforming to the + ``AEADDecryptionContext`` interface (as well as ``AEADCipherContext``). This + interface does not provide any additional methods or attributes. .. _symmetric-encryption-algorithms: @@ -320,7 +334,7 @@ Modes .. class:: GCM(initialization_vector, tag=None) - .. warning:: + .. danger:: When using this mode you MUST not use the decrypted data until every byte has been decrypted. GCM provides NO guarantees of ciphertext -- cgit v1.2.3 From 89d19a411edba0cb52da89801e3de1ddfd9f0dc5 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 3 Dec 2013 17:30:19 -0600 Subject: rename ModeWithAAD to ModeWithAuthenticationTag --- cryptography/hazmat/primitives/ciphers/base.py | 2 +- cryptography/hazmat/primitives/ciphers/modes.py | 2 +- cryptography/hazmat/primitives/interfaces.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index f24fd000..cdaf2c0c 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -42,7 +42,7 @@ class Cipher(object): return self._wrap_ctx(ctx, False) def _wrap_ctx(self, ctx, encrypt): - if isinstance(self.mode, interfaces.ModeWithAAD): + if isinstance(self.mode, interfaces.ModeWithAuthenticationTag): if encrypt: return _AEADEncryptionContext(ctx) else: diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index cb191d98..e1c70185 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -60,7 +60,7 @@ class CTR(object): @utils.register_interface(interfaces.Mode) @utils.register_interface(interfaces.ModeWithInitializationVector) -@utils.register_interface(interfaces.ModeWithAAD) +@utils.register_interface(interfaces.ModeWithAuthenticationTag) class GCM(object): name = "GCM" diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 1884e560..582876fe 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -56,7 +56,7 @@ class ModeWithNonce(six.with_metaclass(abc.ABCMeta)): """ -class ModeWithAAD(six.with_metaclass(abc.ABCMeta)): +class ModeWithAuthenticationTag(six.with_metaclass(abc.ABCMeta)): @abc.abstractproperty def tag(self): """ -- cgit v1.2.3 From 128b948b3cb5840b35ae12613b2215bfe9f098bd Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 3 Dec 2013 17:34:26 -0600 Subject: remove AEADDecryptionContext per review. decryption will return AEADCipherContext and encryption returns AEADEncryptionContext --- cryptography/hazmat/bindings/openssl/backend.py | 1 - cryptography/hazmat/primitives/ciphers/base.py | 7 +------ cryptography/hazmat/primitives/interfaces.py | 4 ---- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 7d3eb3d7..1b19ddaa 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -240,7 +240,6 @@ class GetCipherByName(object): @utils.register_interface(interfaces.CipherContext) @utils.register_interface(interfaces.AEADCipherContext) @utils.register_interface(interfaces.AEADEncryptionContext) -@utils.register_interface(interfaces.AEADDecryptionContext) class _CipherContext(object): _ENCRYPT = 1 _DECRYPT = 0 diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index cdaf2c0c..b8615cb9 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -46,7 +46,7 @@ class Cipher(object): if encrypt: return _AEADEncryptionContext(ctx) else: - return _AEADDecryptionContext(ctx) + return _AEADCipherContext(ctx) else: return _CipherContext(ctx) @@ -99,11 +99,6 @@ class _AEADCipherContext(object): self._ctx.authenticate_additional_data(data) -@utils.register_interface(interfaces.AEADDecryptionContext) -class _AEADDecryptionContext(_AEADCipherContext): - pass - - @utils.register_interface(interfaces.AEADEncryptionContext) class _AEADEncryptionContext(_AEADCipherContext): @property diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 582876fe..e3f4f586 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -94,10 +94,6 @@ class AEADEncryptionContext(six.with_metaclass(abc.ABCMeta)): """ -class AEADDecryptionContext(six.with_metaclass(abc.ABCMeta)): - pass - - class PaddingContext(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def update(self, data): -- cgit v1.2.3 From 5578c66babf3cb214114617bdd29c28129f31c37 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 3 Dec 2013 17:37:42 -0600 Subject: improve language for gcm docs --- docs/hazmat/primitives/symmetric-encryption.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 9d4f0355..c97d6b0b 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -340,11 +340,11 @@ Modes byte has been decrypted. GCM provides NO guarantees of ciphertext integrity until decryption is complete. - GCM (Galois Counter Mode) is a mode of operation for block ciphers. It - is an AEAD (authenticated encryption with additional data) mode. AEAD - is a type of block cipher mode that encrypts the message as well as - authenticating it (and optionally additional data that is not encrypted) - simultaneously. Additional means of verifying integrity (like + GCM (Galois Counter Mode) is a mode of operation for block ciphers. An + AEAD (authenticated encryption with additional data) mode is a type of + block cipher mode that encrypts the message as well as authenticating it + (and optionally additional data that is not encrypted) simultaneously. + Additional means of verifying integrity (like :doc:`HMAC `) are not necessary. :param bytes initialization_vector: Must be random bytes. They do not need -- cgit v1.2.3 From cd28a7cca32c734ddd7f7ad353b27b2cf276aa6e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 3 Dec 2013 18:17:57 -0600 Subject: remove AEADDecryptionContext references from GCM docs --- docs/hazmat/primitives/symmetric-encryption.rst | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index c97d6b0b..bb0308bc 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -123,11 +123,11 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object with an AEAD mode you will receive a return object conforming to the ``AEADCipherContext`` interface (in addition to the ``CipherContext`` - interface and either the ``AEADEncryptionContext`` or ``AEADDecryptionContext`` - interface). ``AEADCipherContext`` contains an additional method - ``authenticate_additional_data`` for adding additional authenticated but - unencrypted data. You should call this before calls to ``update``. When you - are done call ``finalize()`` to finish the operation. + interface). If it is an encryption context it will additionally be an + ``AEADEncryptionContext`` interface. ``AEADCipherContext`` contains an + additional method ``authenticate_additional_data`` for adding additional + authenticated but unencrypted data. You should call this before calls to + ``update``. When you are done call ``finalize()`` to finish the operation. .. method:: authenticate_additional_data(data) @@ -148,13 +148,6 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. :raises: :class:`~cryptography.exceptions.NotYetFinalized` if called before the context is finalized. -.. class:: AEADDecryptionContext - - When creating an encryption context using ``encryptor()`` on a ``Cipher`` - object with an AEAD mode you will receive a return object conforming to the - ``AEADDecryptionContext`` interface (as well as ``AEADCipherContext``). This - interface does not provide any additional methods or attributes. - .. _symmetric-encryption-algorithms: Algorithms -- cgit v1.2.3 From 672843712d6b42404fea27a07a87b70d850cc0dd Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 3 Dec 2013 18:58:14 -0600 Subject: link to NIST GCM PDF where NIST recommends 96-bit IV for perf with GCM Clarify that 96-bit IV is only recommended in performance critical situations...otherwise feel free to use something longer. --- docs/hazmat/primitives/symmetric-encryption.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index bb0308bc..8d8d558b 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -342,11 +342,12 @@ Modes :param bytes initialization_vector: Must be random bytes. They do not need to be kept secret (they can be included - in a transmitted message). Recommended - to be 96-bit by NIST, but can be up to - 2\ :sup:`64` - 1 bits. Do not reuse an - ``initialization_vector`` with a given - ``key``. + in a transmitted message). NIST + `recommends 96-bit IV length`_ for + performance critical situations, but it + can be up to 2\ :sup:`64` - 1 bits. + Do not reuse an ``initialization_vector`` + with a given ``key``. :param bytes tag: The tag bytes to verify during decryption. Must be provided for decryption, but is ignored when encrypting. @@ -384,3 +385,4 @@ Insecure Modes .. _`described by Colin Percival`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html +.. _`recommends 96-bit IV length`: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf -- cgit v1.2.3 From d4f938303d1c5813bf23a8acfe9326817bcd95e9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 4 Dec 2013 16:31:59 -0600 Subject: Be more specific about when you can trust authentication on GCM --- docs/hazmat/primitives/symmetric-encryption.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 8d8d558b..977a897b 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -329,9 +329,10 @@ Modes .. danger:: - When using this mode you MUST not use the decrypted data until every - byte has been decrypted. GCM provides NO guarantees of ciphertext - integrity until decryption is complete. + When using this mode you MUST not use the decrypted data until + :meth:`cryptography.hazmat.primitives.interfaces.CipherContext.finalize` + has been called. GCM provides NO guarantees of ciphertext integrity + until decryption is complete. GCM (Galois Counter Mode) is a mode of operation for block ciphers. An AEAD (authenticated encryption with additional data) mode is a type of -- cgit v1.2.3 From 9c3088fe12d844a2007e0eff0eb947af53de7f60 Mon Sep 17 00:00:00 2001 From: Julian Krause Date: Wed, 4 Dec 2013 14:49:50 -0800 Subject: Beginnings of a constant_time module. --- cryptography/hazmat/primitives/constant_time.py | 53 +++++++++++++++++++++++++ docs/hazmat/primitives/constant-time.rst | 24 +++++++++++ docs/hazmat/primitives/index.rst | 1 + tests/hazmat/primitives/test_constant_time.py | 41 +++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 cryptography/hazmat/primitives/constant_time.py create mode 100644 docs/hazmat/primitives/constant-time.rst create mode 100644 tests/hazmat/primitives/test_constant_time.py diff --git a/cryptography/hazmat/primitives/constant_time.py b/cryptography/hazmat/primitives/constant_time.py new file mode 100644 index 00000000..a8351504 --- /dev/null +++ b/cryptography/hazmat/primitives/constant_time.py @@ -0,0 +1,53 @@ +# 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 + +import cffi + +import six + + +_ffi = cffi.FFI() +_ffi.cdef(""" +bool Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *, size_t); +""") +_lib = _ffi.verify(""" +#include + +bool Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a, uint8_t *b, + size_t len_b) { + size_t i = 0; + uint8_t mismatch = 0; + if (len_a != len_b) { + return false; + } + for (i = 0; i < len_a; i++) { + mismatch |= a[i] ^ b[i]; + } + + /* Make sure any bits set are copied to the lowest bit */ + mismatch |= mismatch >> 4; + mismatch |= mismatch >> 2; + mismatch |= mismatch >> 1; + /* Now check the low bit to see if it's set */ + return (mismatch & 1) == 0; +} +""") + + +def bytes_eq(a, b): + if isinstance(a, six.text_type) or isinstance(b, six.text_type): + raise TypeError("Unicode-objects must be encoded before comparing") + + return _lib.Cryptography_constant_time_bytes_eq(a, len(a), b, len(b)) == 1 diff --git a/docs/hazmat/primitives/constant-time.rst b/docs/hazmat/primitives/constant-time.rst new file mode 100644 index 00000000..2e8e26d7 --- /dev/null +++ b/docs/hazmat/primitives/constant-time.rst @@ -0,0 +1,24 @@ +.. hazmat:: + +Constant time functions +======================= + +.. currentmodule:: cryptography.hazmat.primitives.constant_time + +In order for cryptographic operations to not leak information through timing +side channels, constant time operations need to be made available. + +.. function:: bytes_eq(a, b) + + Compare ``a`` and ``b`` to one another in constant time. + + .. doctest:: + + >>> from cryptography.hazmat.primitives import constant_time + >>> constant_time.bytes_eq(b"foo", b"foo") + True + >>> constant_time.bytes_eq(b"foo", b"bar") + False + + :param a: ``bytes``. + :param b: ``bytes``. diff --git a/docs/hazmat/primitives/index.rst b/docs/hazmat/primitives/index.rst index 614c414a..b115fdbc 100644 --- a/docs/hazmat/primitives/index.rst +++ b/docs/hazmat/primitives/index.rst @@ -10,4 +10,5 @@ Primitives hmac symmetric-encryption padding + constant-time interfaces diff --git a/tests/hazmat/primitives/test_constant_time.py b/tests/hazmat/primitives/test_constant_time.py new file mode 100644 index 00000000..dd910dee --- /dev/null +++ b/tests/hazmat/primitives/test_constant_time.py @@ -0,0 +1,41 @@ +# 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 + +import pytest + +import six + +from cryptography.hazmat.primitives import constant_time + + +class TestConstantTimeBytesEq(object): + def test_reject_unicode(self): + with pytest.raises(TypeError): + constant_time.bytes_eq(b"foo", six.u("foo")) + + with pytest.raises(TypeError): + constant_time.bytes_eq(six.u("foo"), b"foo") + + with pytest.raises(TypeError): + constant_time.bytes_eq(six.u("foo"), six.u("foo")) + + def test_compares(self): + assert constant_time.bytes_eq(b"foo", b"foo") is True + + assert constant_time.bytes_eq(b"foo", b"bar") is False + + assert constant_time.bytes_eq(b"foobar", b"foo") is False + + assert constant_time.bytes_eq(b"foo", b"foobar") is False -- cgit v1.2.3 From 0d23e94a09ea8c88d51692696363d9215c57b72a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 4 Dec 2013 17:28:24 -0600 Subject: Don't show so much stuff --- docs/hazmat/primitives/symmetric-encryption.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 977a897b..e2cce195 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -330,7 +330,7 @@ Modes .. danger:: When using this mode you MUST not use the decrypted data until - :meth:`cryptography.hazmat.primitives.interfaces.CipherContext.finalize` + :meth:`~cryptography.hazmat.primitives.interfaces.CipherContext.finalize` has been called. GCM provides NO guarantees of ciphertext integrity until decryption is complete. -- cgit v1.2.3 From b91221dd7f27b3dcc09d3ad55645b12da08780cf Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 4 Dec 2013 17:56:40 -0600 Subject: raise ValueErrors when supplying/not supplying tags for GCM --- cryptography/hazmat/bindings/openssl/backend.py | 8 +++++- tests/hazmat/primitives/test_block.py | 12 ++++++++- tests/hazmat/primitives/test_utils.py | 15 +++++++++-- tests/hazmat/primitives/utils.py | 35 +++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 1b19ddaa..6ab4dc26 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -289,12 +289,18 @@ class _CipherContext(object): ) assert res != 0 if operation == self._DECRYPT: - assert mode.tag is not None + if not mode.tag: + raise ValueError("Authentication tag must be supplied " + "when decrypting") res = self._backend.lib.EVP_CIPHER_CTX_ctrl( ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_TAG, len(mode.tag), mode.tag ) assert res != 0 + else: + if mode.tag: + raise ValueError("Authentication tag must be None when " + "encrypting") # pass key/iv res = self._backend.lib.EVP_CipherInit_ex(ctx, self._backend.ffi.NULL, diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index 2806efd5..02de3861 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -26,7 +26,9 @@ from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, modes ) -from .utils import generate_aead_exception_test +from .utils import ( + generate_aead_exception_test, generate_aead_tag_exception_test +) @utils.register_interface(interfaces.CipherAlgorithm) @@ -135,3 +137,11 @@ class TestAEADCipherContext(object): ), skip_message="Does not support AES GCM", ) + test_aead_tag_exceptions = generate_aead_tag_exception_test( + algorithms.AES, + modes.GCM, + only_if=lambda backend: backend.cipher_supported( + algorithms.AES("\x00" * 16), modes.GCM("\x00" * 12) + ), + skip_message="Does not support AES GCM", + ) diff --git a/tests/hazmat/primitives/test_utils.py b/tests/hazmat/primitives/test_utils.py index ebb8b5c4..c39364c7 100644 --- a/tests/hazmat/primitives/test_utils.py +++ b/tests/hazmat/primitives/test_utils.py @@ -3,7 +3,7 @@ import pytest from .utils import ( base_hash_test, encrypt_test, hash_test, long_string_hash_test, base_hmac_test, hmac_test, stream_encryption_test, aead_test, - aead_exception_test, + aead_exception_test, aead_tag_exception_test, ) @@ -29,7 +29,7 @@ class TestAEADTest(object): assert exc_info.value.args[0] == "message!" -class TestAEADFinalizeTest(object): +class TestAEADExceptionTest(object): def test_skips_if_only_if_returns_false(self): with pytest.raises(pytest.skip.Exception) as exc_info: aead_exception_test( @@ -40,6 +40,17 @@ class TestAEADFinalizeTest(object): assert exc_info.value.args[0] == "message!" +class TestAEADTagExceptionTest(object): + def test_skips_if_only_if_returns_false(self): + with pytest.raises(pytest.skip.Exception) as exc_info: + aead_tag_exception_test( + None, None, None, + only_if=lambda backend: False, + skip_message="message!" + ) + assert exc_info.value.args[0] == "message!" + + class TestHashTest(object): def test_skips_if_only_if_returns_false(self): with pytest.raises(pytest.skip.Exception) as exc_info: diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 9aa3a89a..705983a0 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -353,3 +353,38 @@ def aead_exception_test(backend, cipher_factory, mode_factory, decryptor.update(b"a" * 16) with pytest.raises(AttributeError): decryptor.tag + + +def generate_aead_tag_exception_test(cipher_factory, mode_factory, + only_if, skip_message): + def test_aead_tag_exception(self): + for backend in _ALL_BACKENDS: + yield ( + aead_tag_exception_test, + backend, + cipher_factory, + mode_factory, + only_if, + skip_message + ) + return test_aead_tag_exception + + +def aead_tag_exception_test(backend, cipher_factory, mode_factory, + only_if, skip_message): + if not only_if(backend): + pytest.skip(skip_message) + cipher = Cipher( + cipher_factory(binascii.unhexlify(b"0" * 32)), + mode_factory(binascii.unhexlify(b"0" * 24)), + backend + ) + with pytest.raises(ValueError): + cipher.decryptor() + cipher = Cipher( + cipher_factory(binascii.unhexlify(b"0" * 32)), + mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16), + backend + ) + with pytest.raises(ValueError): + cipher.encryptor() -- cgit v1.2.3 From d6f14daf49036a434bc0a6b190457694f8703be1 Mon Sep 17 00:00:00 2001 From: Julian Krause Date: Thu, 5 Dec 2013 11:06:27 -0800 Subject: Improve documentation. --- docs/conf.py | 1 + docs/hazmat/primitives/constant-time.rst | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 77050e72..c6479ef3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -257,6 +257,7 @@ texinfo_documents = [ # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' +linkcheck_ignore = [r'http://rdist.root.org/'] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/hazmat/primitives/constant-time.rst b/docs/hazmat/primitives/constant-time.rst index 2e8e26d7..4e00e9b9 100644 --- a/docs/hazmat/primitives/constant-time.rst +++ b/docs/hazmat/primitives/constant-time.rst @@ -6,11 +6,17 @@ Constant time functions .. currentmodule:: cryptography.hazmat.primitives.constant_time In order for cryptographic operations to not leak information through timing -side channels, constant time operations need to be made available. +side channels, constant time operations need to be used. + +One should use these functions whenever you are comparing a secret to +something received. This includes things like HMAC signatures as described by +a `timing attack on KeyCzar`_. + .. function:: bytes_eq(a, b) - Compare ``a`` and ``b`` to one another in constant time. + Compare ``a`` and ``b`` to one another in constant time if they are of the + same length. .. doctest:: @@ -20,5 +26,9 @@ side channels, constant time operations need to be made available. >>> constant_time.bytes_eq(b"foo", b"bar") False - :param a: ``bytes``. - :param b: ``bytes``. + :param a bytes: The left-hand side. + :param b bytes: The right-hand side. + :returns boolean: True if ``a`` has the same bytes as ``b``. + + +.. _`timing attack on KeyCzar`: http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/ -- cgit v1.2.3 From 8b02863cd304ce89010f15cdb80e03dcc3c507fe Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 6 Dec 2013 09:02:51 -0600 Subject: Rreduce code duplication --- .../hazmat/primitives/ciphers/algorithms.py | 59 ++++++---------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py index 75a87265..a206b273 100644 --- a/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -17,6 +17,15 @@ from cryptography import utils from cryptography.hazmat.primitives import interfaces +def _verify_key_size(algorithm, key): + # Verify that the key size matches the expected key size + if len(key) * 8 not in algorithm.key_sizes: + raise ValueError("Invalid key size ({0}) for {1}".format( + len(key) * 8, algorithm.name + )) + return key + + @utils.register_interface(interfaces.CipherAlgorithm) class AES(object): name = "AES" @@ -24,13 +33,7 @@ class AES(object): key_sizes = frozenset([128, 192, 256]) def __init__(self, key): - 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 - )) + self.key = _verify_key_size(self, key) @property def key_size(self): @@ -44,13 +47,7 @@ class Camellia(object): key_sizes = frozenset([128, 192, 256]) def __init__(self, key): - 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 - )) + self.key = _verify_key_size(self, key) @property def key_size(self): @@ -68,13 +65,7 @@ class TripleDES(object): key += key + key elif len(key) == 16: key += key[:8] - 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 - )) + self.key = _verify_key_size(self, key) @property def key_size(self): @@ -88,13 +79,7 @@ class Blowfish(object): key_sizes = frozenset(range(32, 449, 8)) def __init__(self, key): - 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 - )) + self.key = _verify_key_size(self, key) @property def key_size(self): @@ -105,16 +90,10 @@ class Blowfish(object): class CAST5(object): name = "CAST5" block_size = 64 - key_sizes = frozenset([40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128]) + key_sizes = frozenset(range(40, 129, 8)) def __init__(self, key): - 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 - )) + self.key = _verify_key_size(self, key) @property def key_size(self): @@ -128,13 +107,7 @@ class ARC4(object): 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 - if self.key_size not in self.key_sizes: - raise ValueError("Invalid key size ({0}) for {1}".format( - self.key_size, self.name - )) + self.key = _verify_key_size(self, key) @property def key_size(self): -- cgit v1.2.3 From a07925a154e2b28db30499c5a3cf40fedc451d10 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 6 Dec 2013 11:49:42 -0600 Subject: update docs to explain tag requirements and valueerror --- docs/hazmat/bindings/interfaces.rst | 4 ++++ docs/hazmat/primitives/symmetric-encryption.rst | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/bindings/interfaces.rst b/docs/hazmat/bindings/interfaces.rst index c55d86dc..711c82c2 100644 --- a/docs/hazmat/bindings/interfaces.rst +++ b/docs/hazmat/bindings/interfaces.rst @@ -69,6 +69,8 @@ A specific ``backend`` may provide one or more of these interfaces. :returns: :class:`~cryptography.hazmat.primitives.interfaces.CipherContext` + :raises ValueError: When tag is not None in an AEAD mode + .. method:: create_symmetric_decryption_ctx(cipher, mode) @@ -86,6 +88,8 @@ A specific ``backend`` may provide one or more of these interfaces. :returns: :class:`~cryptography.hazmat.primitives.interfaces.CipherContext` + :raises ValueError: When tag is None in an AEAD mode + .. class:: HashBackend diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 8d8d558b..46148689 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -349,8 +349,8 @@ Modes Do not reuse an ``initialization_vector`` with a given ``key``. - :param bytes tag: The tag bytes to verify during decryption. Must be provided - for decryption, but is ignored when encrypting. + :param bytes tag: The tag bytes to verify during decryption. When encrypting + this must be None. .. doctest:: -- cgit v1.2.3 From ffdecbfe9a72060e5335d10c946d00d852d4ced0 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 6 Dec 2013 23:13:40 -0600 Subject: expand rsa bindings --- cryptography/hazmat/bindings/openssl/rsa.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py index 21ed5d67..92770738 100644 --- a/cryptography/hazmat/bindings/openssl/rsa.py +++ b/cryptography/hazmat/bindings/openssl/rsa.py @@ -18,13 +18,28 @@ INCLUDES = """ TYPES = """ typedef ... RSA; typedef ... BN_GENCB; +static const int RSA_PKCS1_PADDING; +static const int RSA_SSLV23_PADDING; +static const int RSA_NO_PADDING; +static const int RSA_PKCS1_OAEP_PADDING; +static const int RSA_X931_PADDING; +static const int RSA_PKCS1_PSS_PADDING; """ FUNCTIONS = """ RSA *RSA_new(); void RSA_free(RSA *); +int RSA_size(const RSA *); int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *); int RSA_check_key(const RSA *); +int RSA_public_encrypt(int, const unsigned char *, unsigned char *, + RSA *, int); +int RSA_private_encrypt(int, const unsigned char *, unsigned char *, + RSA *, int); +int RSA_public_decrypt(int, const unsigned char *, unsigned char *, + RSA *, int); +int RSA_private_decrypt(int, const unsigned char *, unsigned char *, + RSA *, int); """ MACROS = """ -- cgit v1.2.3 From 5762b47bb21559a3d5bf2c1c9fd27a007ad895d5 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 7 Dec 2013 09:04:35 -0600 Subject: remove RSA PSS constant (for now), de-opaque RSA * --- cryptography/hazmat/bindings/openssl/rsa.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py index 92770738..8ee4b0cf 100644 --- a/cryptography/hazmat/bindings/openssl/rsa.py +++ b/cryptography/hazmat/bindings/openssl/rsa.py @@ -16,14 +16,23 @@ INCLUDES = """ """ TYPES = """ -typedef ... RSA; +typedef struct rsa_st { + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + ...; +} RSA; typedef ... BN_GENCB; static const int RSA_PKCS1_PADDING; static const int RSA_SSLV23_PADDING; static const int RSA_NO_PADDING; static const int RSA_PKCS1_OAEP_PADDING; static const int RSA_X931_PADDING; -static const int RSA_PKCS1_PSS_PADDING; """ FUNCTIONS = """ -- cgit v1.2.3 From 953ebf8ab4b14c96ce921caea6a619dbf69dfa77 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 8 Dec 2013 10:28:30 -0800 Subject: Improved the docs -- more glossary entries, more advice for writing docs --- docs/contributing.rst | 3 +++ docs/glossary.rst | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/docs/contributing.rst b/docs/contributing.rst index 97f31e0b..4647818a 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -141,6 +141,9 @@ should begin with the "Hazardous Materials" warning: .. hazmat:: +When referring to a hypothetical individual (such as "a person receiving an +encrypted message") use gender neutral pronouns (they/them/their). + Development Environment ----------------------- diff --git a/docs/glossary.rst b/docs/glossary.rst index b6f2d06f..63e0a6ce 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -28,3 +28,14 @@ Glossary asymmetric cryptography Cryptographic operations where encryption and decryption use different keys. There are separate encryption and decryption keys. + + authentication + The process of verifying that a message was created by a specific + individual (or program). Like encryption, authentication can be either + symmetric or asymmetric. Authentication is necessary for effective + encryption. + + Ciphertext indistinguishability + This is a property of encryption systems whereby two encrypted messages + aren't distinguishable without knowing the encryption key. This is + considered a basic, necessary property for a working encryption system. -- cgit v1.2.3 From 494b574558a9f5b56ade082bac7bd32fa7d040c5 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 9 Dec 2013 10:16:58 -0600 Subject: add dec2bn --- cryptography/hazmat/bindings/openssl/bignum.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cryptography/hazmat/bindings/openssl/bignum.py b/cryptography/hazmat/bindings/openssl/bignum.py index fcfadff1..1b0fe5ab 100644 --- a/cryptography/hazmat/bindings/openssl/bignum.py +++ b/cryptography/hazmat/bindings/openssl/bignum.py @@ -28,6 +28,9 @@ int BN_set_word(BIGNUM *, BN_ULONG); char *BN_bn2hex(const BIGNUM *); int BN_hex2bn(BIGNUM **, const char *); +int BN_dec2bn(BIGNUM **, const char *); + +int BN_num_bits(const BIGNUM *); """ MACROS = """ -- cgit v1.2.3 From ac1bd5d4f2c77806affd88be8f1dd5d87a6028f6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 9 Dec 2013 10:17:14 -0600 Subject: add new error constants --- cryptography/hazmat/bindings/openssl/err.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py index 3dac6948..f31c2405 100644 --- a/cryptography/hazmat/bindings/openssl/err.py +++ b/cryptography/hazmat/bindings/openssl/err.py @@ -23,11 +23,18 @@ struct ERR_string_data_st { typedef struct ERR_string_data_st ERR_STRING_DATA; static const int ERR_LIB_EVP; +static const int ERR_LIB_PEM; static const int EVP_F_EVP_ENCRYPTFINAL_EX; static const int EVP_F_EVP_DECRYPTFINAL_EX; static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH; + +static const int PEM_F_PEM_READ_BIO_PRIVATEKEY; +static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO; + +static const int PEM_R_BAD_PASSWORD_READ; +static const int ASN1_R_BAD_PASSWORD_READ; """ FUNCTIONS = """ -- cgit v1.2.3 From 80544fbf7aa9f555721d4c769d842f04a8054ed2 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 9 Dec 2013 10:19:04 -0600 Subject: add publickey_dup --- cryptography/hazmat/bindings/openssl/rsa.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py index 8ee4b0cf..ad0d37b4 100644 --- a/cryptography/hazmat/bindings/openssl/rsa.py +++ b/cryptography/hazmat/bindings/openssl/rsa.py @@ -41,6 +41,7 @@ void RSA_free(RSA *); int RSA_size(const RSA *); int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *); int RSA_check_key(const RSA *); +RSA *RSAPublicKey_dup(RSA *); int RSA_public_encrypt(int, const unsigned char *, unsigned char *, RSA *, int); int RSA_private_encrypt(int, const unsigned char *, unsigned char *, -- cgit v1.2.3 From 65c9171cc1b7ab617dbb95524b0f3b019f8d65fb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 9 Dec 2013 18:03:11 -0600 Subject: add additional bindings to load private keys --- cryptography/hazmat/bindings/openssl/pem.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cryptography/hazmat/bindings/openssl/pem.py b/cryptography/hazmat/bindings/openssl/pem.py index 00f0dc36..cef7839f 100644 --- a/cryptography/hazmat/bindings/openssl/pem.py +++ b/cryptography/hazmat/bindings/openssl/pem.py @@ -29,6 +29,15 @@ int PEM_write_bio_PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, EVP_PKEY *PEM_read_bio_PrivateKey(BIO *, EVP_PKEY **, pem_password_cb *, void *); +int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, + char *, int, pem_password_cb *, void *); + +int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *, + char *, int, pem_password_cb *, void *); + +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *, EVP_PKEY **, pem_password_cb *, + void *); + int PEM_write_bio_X509_REQ(BIO *, X509_REQ *); X509_REQ *PEM_read_bio_X509_REQ(BIO *, X509_REQ **, pem_password_cb *, void *); -- cgit v1.2.3 From 0f13c4779c83a691dadd3b0b2a84526e17ad325b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 11 Dec 2013 18:10:58 -0600 Subject: add ENGINE set default methods --- cryptography/hazmat/bindings/openssl/engine.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cryptography/hazmat/bindings/openssl/engine.py b/cryptography/hazmat/bindings/openssl/engine.py index b76befce..457fb042 100644 --- a/cryptography/hazmat/bindings/openssl/engine.py +++ b/cryptography/hazmat/bindings/openssl/engine.py @@ -36,6 +36,18 @@ void ENGINE_load_builtin_engines(); int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int); int ENGINE_set_default(ENGINE *, unsigned int); int ENGINE_register_complete(ENGINE *); + +int ENGINE_set_default_RSA(ENGINE *); +int ENGINE_set_default_string(ENGINE *, const char *); +int ENGINE_set_default_DSA(ENGINE *); +int ENGINE_set_default_ECDH(ENGINE *); +int ENGINE_set_default_ECDSA(ENGINE *); +int ENGINE_set_default_DH(ENGINE *); +int ENGINE_set_default_RAND(ENGINE *); +int ENGINE_set_default_ciphers(ENGINE *); +int ENGINE_set_default_digests(ENGINE *); +int ENGINE_set_default_pkey_meths(ENGINE *); +int ENGINE_set_default_pkey_asn1_meths(ENGINE *); """ MACROS = """ -- cgit v1.2.3 From 878adad8cb8879a0b1db995ebee42c7af028a680 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 12 Dec 2013 11:20:33 -0600 Subject: remove two ENGINE_set_default_* functions default OS X OpenSSL lacks --- cryptography/hazmat/bindings/openssl/engine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/engine.py b/cryptography/hazmat/bindings/openssl/engine.py index 457fb042..1f377665 100644 --- a/cryptography/hazmat/bindings/openssl/engine.py +++ b/cryptography/hazmat/bindings/openssl/engine.py @@ -46,8 +46,6 @@ int ENGINE_set_default_DH(ENGINE *); int ENGINE_set_default_RAND(ENGINE *); int ENGINE_set_default_ciphers(ENGINE *); int ENGINE_set_default_digests(ENGINE *); -int ENGINE_set_default_pkey_meths(ENGINE *); -int ENGINE_set_default_pkey_asn1_meths(ENGINE *); """ MACROS = """ -- cgit v1.2.3 From ae9dc8b4c1ca40d3d38859cf06c411bc83e1665a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 12 Dec 2013 10:13:32 -0800 Subject: Use the HTTPS verion of the link to cffi --- docs/hazmat/bindings/openssl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/bindings/openssl.rst b/docs/hazmat/bindings/openssl.rst index 194eeb92..d6bfa672 100644 --- a/docs/hazmat/bindings/openssl.rst +++ b/docs/hazmat/bindings/openssl.rst @@ -21,5 +21,5 @@ These are `CFFI`_ bindings to the `OpenSSL`_ C library. and access constants. -.. _`CFFI`: http://cffi.readthedocs.org/ +.. _`CFFI`: https://cffi.readthedocs.org/ .. _`OpenSSL`: https://www.openssl.org/ -- cgit v1.2.3 From 5246e2db3100160b948a632e810010e1b23a9e91 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 12 Dec 2013 12:23:18 -0800 Subject: Fixed headers in docs --- docs/contributing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 4647818a..934bb45a 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -48,7 +48,7 @@ Additionally, every Python code file must contain from __future__ import absolute_import, division, print_function C bindings ----------- +~~~~~~~~~~ When binding C code with ``cffi`` we have our own style guide, it's pretty simple. @@ -161,7 +161,7 @@ dependencies, install ``cryptography`` in ``editable`` mode. For example: You are now ready to run the tests and build the documentation. Running Tests -------------- +~~~~~~~~~~~~~ ``cryptography`` unit tests are found in the ``tests/`` directory and are designed to be run using `pytest`_. `pytest`_ will discover the tests @@ -195,7 +195,7 @@ You may not have all the required Python versions installed, in which case you will see one or more ``InterpreterNotFound`` errors. Building Documentation ----------------------- +~~~~~~~~~~~~~~~~~~~~~~ ``cryptography`` documentation is stored in the ``docs/`` directory. It is written in `reStructured Text`_ and rendered using `Sphinx`_. -- cgit v1.2.3 From e21b0b25bdda1eaa5a29aa585dd858bd21ff1016 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 12 Dec 2013 12:39:05 -0800 Subject: Several policy reccomendations for API design --- docs/contributing.rst | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/contributing.rst b/docs/contributing.rst index 934bb45a..09833ed3 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -47,6 +47,40 @@ Additionally, every Python code file must contain from __future__ import absolute_import, division, print_function +API Considerations +~~~~~~~~~~~~~~~~~~ + +Most projects' APIs are designed with a philosophy of "make easy things easy, +and make hard things possible". One of the perils of writing cryptographic code +is that code that is secure looks just like code that isn't, and produces +results that are also difficult to distinguish. As a result ``cryptography`` +has, as a design philosophy: "make it hard to do insecure things". Here are a +few strategies for API design which should be both followed, and should inspire +other API choices: + +If it is incorrect to ignore the result of a method, it should raise an +exception, and not return a boolean ``True``/``False`` flag. For example, a +method to verify a signature should raise ``InvalidSignature``, and not return +whether the signature was valid. + +.. code-block:: python + + # This is bad. + def verify(sig): + # ... + return is_valid + + # Good! + def verify(sig): + # ... + if not is_valid: + raise InvalidSignature + +APIs at the :doc:`/hazmat/primitives/index` layer should always take an +explicit backend, APIs at the recipes layer should automatically use the +:func:`~cryptography.hazmat.bindings.default_backend`, but optionally allow +specifiying a different backend. + C bindings ~~~~~~~~~~ -- cgit v1.2.3 From 2cfff24f6d59402ef3616c1e5d253e1ab1c77867 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 12 Dec 2013 13:26:31 -0800 Subject: Supress the deprecation warnings by including an __APPLE__ only preamble. --- cryptography/hazmat/bindings/openssl/backend.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 1b19ddaa..d093684e 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -111,8 +111,19 @@ class Backend(object): # is legal, but the following will fail to compile: # int foo(int); # int foo(short); + + preamble = [ +""" +#ifdef __APPLE__ +# include +# undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +# define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#endif +""" + ] + lib = ffi.verify( - source="\n".join(includes + functions + customizations), + source="\n".join(preamble + includes + functions + customizations), libraries=["crypto", "ssl"], ) -- cgit v1.2.3 From 76ec34058a30026b62cc6f16a6c172fe5011798d Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 12 Dec 2013 13:42:23 -0800 Subject: Attempt to fix nebulous indentation complaints and also re-set after the includes. --- cryptography/hazmat/bindings/openssl/backend.py | 28 ++++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index d093684e..044e8cc9 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -112,18 +112,30 @@ class Backend(object): # int foo(int); # int foo(short); - preamble = [ -""" + pre_includes = [""" #ifdef __APPLE__ -# include -# undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -# define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#include +#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER #endif -""" - ] +"""] + + post_includes = [""" +#ifdef __APPLE__ +#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ + __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#endif +"""] lib = ffi.verify( - source="\n".join(preamble + includes + functions + customizations), + source="\n".join(pre_includes + + includes + + post_includes + + functions + + customizations), libraries=["crypto", "ssl"], ) -- cgit v1.2.3 From c4f9b1db8b6848b78dd348e9f2ce32752a7b2e39 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 12 Dec 2013 14:11:05 -0800 Subject: formatting more consistent with other cffi secitons. --- cryptography/hazmat/bindings/openssl/backend.py | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index 044e8cc9..d69fdc45 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -31,6 +31,24 @@ from cryptography.hazmat.primitives.ciphers.modes import ( CBC, CTR, ECB, OFB, CFB, GCM, ) +_OSX_PRE_INCLUDE = """ +#ifdef __APPLE__ +#include +#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#endif +""" + +_OSX_POST_INCLUDE = """ +#ifdef __APPLE__ +#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ + __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#endif +""" + @utils.register_interface(CipherBackend) @utils.register_interface(HashBackend) @@ -112,28 +130,10 @@ class Backend(object): # int foo(int); # int foo(short); - pre_includes = [""" -#ifdef __APPLE__ -#include -#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#endif -"""] - - post_includes = [""" -#ifdef __APPLE__ -#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ - __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#endif -"""] - lib = ffi.verify( - source="\n".join(pre_includes + + source="\n".join([_OSX_PRE_INCLUDE] + includes + - post_includes + + [_OSX_POST_INCLUDE] + functions + customizations), libraries=["crypto", "ssl"], -- cgit v1.2.3 From 2bc3334979ceaee2592e42b3135454ab63b4d009 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 12 Dec 2013 15:19:37 -0800 Subject: alex parens. --- cryptography/hazmat/bindings/openssl/backend.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py index d69fdc45..2e73180f 100644 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ b/cryptography/hazmat/bindings/openssl/backend.py @@ -131,11 +131,13 @@ class Backend(object): # int foo(short); lib = ffi.verify( - source="\n".join([_OSX_PRE_INCLUDE] + - includes + - [_OSX_POST_INCLUDE] + - functions + - customizations), + source="\n".join( + [_OSX_PRE_INCLUDE] + + includes + + [_OSX_POST_INCLUDE] + + functions + + customizations + ), libraries=["crypto", "ssl"], ) -- cgit v1.2.3 From 2a5b4a8aafcfa3122c366c4415294eca9ad8de7f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 12 Dec 2013 17:53:08 -0800 Subject: Fixed a mis-spelled word --- docs/contributing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 09833ed3..100f13f5 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -79,7 +79,7 @@ whether the signature was valid. APIs at the :doc:`/hazmat/primitives/index` layer should always take an explicit backend, APIs at the recipes layer should automatically use the :func:`~cryptography.hazmat.bindings.default_backend`, but optionally allow -specifiying a different backend. +specifying a different backend. C bindings ~~~~~~~~~~ -- cgit v1.2.3 From 31df5357132319de7c9eb7154dd72ddebcbc4afa Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 12 Dec 2013 18:03:26 -0800 Subject: More info in teh index --- docs/index.rst | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 1b88e24e..a1a650a8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,13 +6,26 @@ Welcome to ``cryptography`` ``cryptography`` is very young, and very incomplete. ``cryptography`` is a Python library which exposes cryptographic recipes and -primitives. +primitives. We hope it'll be your one-stop-shop for all your cryptographic +needs in Python. + +Installing +---------- + +We don't yet have a release on PyPI, for now you can install ``cryptography`` +directly from Github: + +.. code-block:: console + + $ pip install git+https://github.com/pyca/cryptography Why a new crypto library for Python? ------------------------------------ -We wanted to address a few issues with existing cryptography libraries in -Python: +If you've done cryptographic work in Python before, you've probably seen some +other libraries in Python, such as *M2Crypto*, *PyCrypto*, or *PyOpenSSL*. In +building ``cryptography`` we wanted to address a few issues we observed in the +existing libraries: * Lack of PyPy and Python 3 support. * Lack of maintenance. -- cgit v1.2.3 From 848f770c4ab33e0d1cd98c78480ae32d5c5f134e Mon Sep 17 00:00:00 2001 From: Julian Krause Date: Thu, 12 Dec 2013 20:55:39 -0800 Subject: Update documentation again to make it clearer what this is for. Moved to using Coda Hale's post. --- docs/conf.py | 2 -- docs/hazmat/primitives/constant-time.rst | 16 ++++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c6479ef3..5092e4d3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -257,7 +257,5 @@ texinfo_documents = [ # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' -linkcheck_ignore = [r'http://rdist.root.org/'] - # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/hazmat/primitives/constant-time.rst b/docs/hazmat/primitives/constant-time.rst index 4e00e9b9..4df73b3c 100644 --- a/docs/hazmat/primitives/constant-time.rst +++ b/docs/hazmat/primitives/constant-time.rst @@ -5,12 +5,16 @@ Constant time functions .. currentmodule:: cryptography.hazmat.primitives.constant_time -In order for cryptographic operations to not leak information through timing -side channels, constant time operations need to be used. +This module contains functions for operating with secret data in a way that +does not leak information about that data through how long it takes to perform +the operation. These functions should be used whenever operating on secret data +along with data that is user supplied. -One should use these functions whenever you are comparing a secret to -something received. This includes things like HMAC signatures as described by -a `timing attack on KeyCzar`_. +An example would be comparing a HMAC signature received from a client to the +one generated by the server code for authentication purposes. + +For more information about this sort of issue, see `Coda Hale's blog post`_ +about the timing attacks on KeyCzar and Java's ``MessageDigest.isEquals()``. .. function:: bytes_eq(a, b) @@ -31,4 +35,4 @@ a `timing attack on KeyCzar`_. :returns boolean: True if ``a`` has the same bytes as ``b``. -.. _`timing attack on KeyCzar`: http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/ +.. _`Coda Hale's blog post`: http://codahale.com/a-lesson-in-timing-attacks/ -- cgit v1.2.3 From 73cf187d7796c1c913a1607beae944a1d8cf233e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 13 Dec 2013 15:15:08 -0800 Subject: This warning doesn't add much value anymore --- docs/index.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index a1a650a8..2263c32f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,10 +1,6 @@ Welcome to ``cryptography`` =========================== -.. warning:: - - ``cryptography`` is very young, and very incomplete. - ``cryptography`` is a Python library which exposes cryptographic recipes and primitives. We hope it'll be your one-stop-shop for all your cryptographic needs in Python. -- cgit v1.2.3 From f56444df44faf8c030a82a042a198b6fa77caa72 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 13 Dec 2013 15:19:22 -0800 Subject: Always show where a baackend comes form in the docs --- docs/hazmat/primitives/symmetric-encryption.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 2f390175..ef6f0871 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -12,9 +12,6 @@ Symmetric Encryption key = binascii.unhexlify(b"0" * 32) iv = binascii.unhexlify(b"0" * 32) - from cryptography.hazmat.bindings import default_backend - backend = default_backend() - Symmetric encryption is a way to encrypt (hide the plaintext value) material where the sender and receiver both use the same key. Note that symmetric @@ -37,6 +34,8 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + >>> from cryptography.hazmat.bindings import default_backend + >>> backend = default_backend() >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) >>> encryptor = cipher.encryptor() >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() @@ -230,8 +229,9 @@ Weak Ciphers .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + >>> from cryptography.hazmat.bindings import default_backend >>> algorithm = algorithms.ARC4(key) - >>> cipher = Cipher(algorithm, mode=None, backend=backend) + >>> cipher = Cipher(algorithm, mode=None, backend=default_backend()) >>> encryptor = cipher.encryptor() >>> ct = encryptor.update(b"a secret message") >>> decryptor = cipher.decryptor() @@ -356,7 +356,8 @@ Modes .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend) + >>> from cryptography.hazmat.bindings import default_backend + >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend()) >>> encryptor = cipher.encryptor() >>> encryptor.authenticate_additional_data(b"authenticated but not encrypted payload") >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() -- cgit v1.2.3 From f3f0018fb956dcc075798bd3d2eb49916471f23c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 13 Dec 2013 19:22:33 -0800 Subject: Document the need for test coverage --- docs/contributing.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing.rst b/docs/contributing.rst index 100f13f5..a8010a9a 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -28,6 +28,7 @@ devastating, ``cryptography`` has a strict code review policy: * If somehow the tests get into a failing state on ``master`` (such as by a backwards incompatible release of a dependency) no pull requests may be merged until this is rectified. +* All merged patches must have 100% test coverage. The purpose of these policies is to minimize the chances we merge a change which jeopardizes our users' security. -- cgit v1.2.3 From 989061d070bdee122b07633e9a19e737fa816256 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 13 Dec 2013 20:22:14 -0800 Subject: Prefer executable code examples --- docs/hazmat/primitives/symmetric-encryption.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index ef6f0871..f3def845 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -266,7 +266,7 @@ Modes A good construction looks like: - .. code-block:: pycon + .. doctest:: >>> import os >>> iv = os.urandom(16) @@ -274,7 +274,7 @@ Modes While the following is bad and will leak information: - .. code-block:: pycon + .. doctest:: >>> iv = "a" * 16 >>> mode = CBC(iv) -- cgit v1.2.3 From f8796b15a279db82cdefcd00bebfef4cdef8fee8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 13 Dec 2013 20:28:55 -0800 Subject: Renamed bindings to backends --- cryptography/hazmat/backends/__init__.py | 23 ++ cryptography/hazmat/backends/interfaces.py | 66 ++++ cryptography/hazmat/backends/openssl/__init__.py | 17 + cryptography/hazmat/backends/openssl/asn1.py | 124 ++++++ cryptography/hazmat/backends/openssl/backend.py | 480 +++++++++++++++++++++++ cryptography/hazmat/backends/openssl/bignum.py | 40 ++ cryptography/hazmat/backends/openssl/bio.py | 173 ++++++++ cryptography/hazmat/backends/openssl/conf.py | 29 ++ cryptography/hazmat/backends/openssl/crypto.py | 40 ++ cryptography/hazmat/backends/openssl/dh.py | 31 ++ cryptography/hazmat/backends/openssl/dsa.py | 33 ++ cryptography/hazmat/backends/openssl/engine.py | 65 +++ cryptography/hazmat/backends/openssl/err.py | 76 ++++ cryptography/hazmat/backends/openssl/evp.py | 112 ++++++ cryptography/hazmat/backends/openssl/hmac.py | 90 +++++ cryptography/hazmat/backends/openssl/nid.py | 49 +++ cryptography/hazmat/backends/openssl/opensslv.py | 29 ++ cryptography/hazmat/backends/openssl/pem.py | 57 +++ cryptography/hazmat/backends/openssl/pkcs12.py | 37 ++ cryptography/hazmat/backends/openssl/pkcs7.py | 37 ++ cryptography/hazmat/backends/openssl/rand.py | 40 ++ cryptography/hazmat/backends/openssl/rsa.py | 59 +++ cryptography/hazmat/backends/openssl/ssl.py | 216 ++++++++++ cryptography/hazmat/backends/openssl/x509.py | 190 +++++++++ cryptography/hazmat/backends/openssl/x509name.py | 51 +++ cryptography/hazmat/backends/openssl/x509v3.py | 97 +++++ cryptography/hazmat/bindings/__init__.py | 23 -- cryptography/hazmat/bindings/interfaces.py | 66 ---- cryptography/hazmat/bindings/openssl/__init__.py | 17 - cryptography/hazmat/bindings/openssl/asn1.py | 124 ------ cryptography/hazmat/bindings/openssl/backend.py | 480 ----------------------- cryptography/hazmat/bindings/openssl/bignum.py | 40 -- cryptography/hazmat/bindings/openssl/bio.py | 173 -------- cryptography/hazmat/bindings/openssl/conf.py | 29 -- cryptography/hazmat/bindings/openssl/crypto.py | 40 -- cryptography/hazmat/bindings/openssl/dh.py | 31 -- cryptography/hazmat/bindings/openssl/dsa.py | 33 -- cryptography/hazmat/bindings/openssl/engine.py | 65 --- cryptography/hazmat/bindings/openssl/err.py | 76 ---- cryptography/hazmat/bindings/openssl/evp.py | 112 ------ cryptography/hazmat/bindings/openssl/hmac.py | 90 ----- cryptography/hazmat/bindings/openssl/nid.py | 49 --- cryptography/hazmat/bindings/openssl/opensslv.py | 29 -- cryptography/hazmat/bindings/openssl/pem.py | 57 --- cryptography/hazmat/bindings/openssl/pkcs12.py | 37 -- cryptography/hazmat/bindings/openssl/pkcs7.py | 37 -- cryptography/hazmat/bindings/openssl/rand.py | 40 -- cryptography/hazmat/bindings/openssl/rsa.py | 59 --- cryptography/hazmat/bindings/openssl/ssl.py | 216 ---------- cryptography/hazmat/bindings/openssl/x509.py | 190 --------- cryptography/hazmat/bindings/openssl/x509name.py | 51 --- cryptography/hazmat/bindings/openssl/x509v3.py | 97 ----- docs/architecture.rst | 6 +- docs/contributing.rst | 2 +- docs/hazmat/backends/index.rst | 34 ++ docs/hazmat/backends/interfaces.rst | 141 +++++++ docs/hazmat/backends/openssl.rst | 25 ++ docs/hazmat/bindings/index.rst | 34 -- docs/hazmat/bindings/interfaces.rst | 141 ------- docs/hazmat/bindings/openssl.rst | 25 -- docs/hazmat/primitives/cryptographic-hashes.rst | 4 +- docs/hazmat/primitives/hmac.rst | 4 +- docs/hazmat/primitives/symmetric-encryption.rst | 8 +- docs/index.rst | 2 +- tests/conftest.py | 2 +- tests/hazmat/bindings/test_openssl.py | 4 +- tests/hazmat/primitives/utils.py | 2 +- 67 files changed, 2478 insertions(+), 2478 deletions(-) create mode 100644 cryptography/hazmat/backends/__init__.py create mode 100644 cryptography/hazmat/backends/interfaces.py create mode 100644 cryptography/hazmat/backends/openssl/__init__.py create mode 100644 cryptography/hazmat/backends/openssl/asn1.py create mode 100644 cryptography/hazmat/backends/openssl/backend.py create mode 100644 cryptography/hazmat/backends/openssl/bignum.py create mode 100644 cryptography/hazmat/backends/openssl/bio.py create mode 100644 cryptography/hazmat/backends/openssl/conf.py create mode 100644 cryptography/hazmat/backends/openssl/crypto.py create mode 100644 cryptography/hazmat/backends/openssl/dh.py create mode 100644 cryptography/hazmat/backends/openssl/dsa.py create mode 100644 cryptography/hazmat/backends/openssl/engine.py create mode 100644 cryptography/hazmat/backends/openssl/err.py create mode 100644 cryptography/hazmat/backends/openssl/evp.py create mode 100644 cryptography/hazmat/backends/openssl/hmac.py create mode 100644 cryptography/hazmat/backends/openssl/nid.py create mode 100644 cryptography/hazmat/backends/openssl/opensslv.py create mode 100644 cryptography/hazmat/backends/openssl/pem.py create mode 100644 cryptography/hazmat/backends/openssl/pkcs12.py create mode 100644 cryptography/hazmat/backends/openssl/pkcs7.py create mode 100644 cryptography/hazmat/backends/openssl/rand.py create mode 100644 cryptography/hazmat/backends/openssl/rsa.py create mode 100644 cryptography/hazmat/backends/openssl/ssl.py create mode 100644 cryptography/hazmat/backends/openssl/x509.py create mode 100644 cryptography/hazmat/backends/openssl/x509name.py create mode 100644 cryptography/hazmat/backends/openssl/x509v3.py delete mode 100644 cryptography/hazmat/bindings/__init__.py delete mode 100644 cryptography/hazmat/bindings/interfaces.py delete mode 100644 cryptography/hazmat/bindings/openssl/__init__.py delete mode 100644 cryptography/hazmat/bindings/openssl/asn1.py delete mode 100644 cryptography/hazmat/bindings/openssl/backend.py delete mode 100644 cryptography/hazmat/bindings/openssl/bignum.py delete mode 100644 cryptography/hazmat/bindings/openssl/bio.py delete mode 100644 cryptography/hazmat/bindings/openssl/conf.py delete mode 100644 cryptography/hazmat/bindings/openssl/crypto.py delete mode 100644 cryptography/hazmat/bindings/openssl/dh.py delete mode 100644 cryptography/hazmat/bindings/openssl/dsa.py delete mode 100644 cryptography/hazmat/bindings/openssl/engine.py delete mode 100644 cryptography/hazmat/bindings/openssl/err.py delete mode 100644 cryptography/hazmat/bindings/openssl/evp.py delete mode 100644 cryptography/hazmat/bindings/openssl/hmac.py delete mode 100644 cryptography/hazmat/bindings/openssl/nid.py delete mode 100644 cryptography/hazmat/bindings/openssl/opensslv.py delete mode 100644 cryptography/hazmat/bindings/openssl/pem.py delete mode 100644 cryptography/hazmat/bindings/openssl/pkcs12.py delete mode 100644 cryptography/hazmat/bindings/openssl/pkcs7.py delete mode 100644 cryptography/hazmat/bindings/openssl/rand.py delete mode 100644 cryptography/hazmat/bindings/openssl/rsa.py delete mode 100644 cryptography/hazmat/bindings/openssl/ssl.py delete mode 100644 cryptography/hazmat/bindings/openssl/x509.py delete mode 100644 cryptography/hazmat/bindings/openssl/x509name.py delete mode 100644 cryptography/hazmat/bindings/openssl/x509v3.py create mode 100644 docs/hazmat/backends/index.rst create mode 100644 docs/hazmat/backends/interfaces.rst create mode 100644 docs/hazmat/backends/openssl.rst delete mode 100644 docs/hazmat/bindings/index.rst delete mode 100644 docs/hazmat/bindings/interfaces.rst delete mode 100644 docs/hazmat/bindings/openssl.rst diff --git a/cryptography/hazmat/backends/__init__.py b/cryptography/hazmat/backends/__init__.py new file mode 100644 index 00000000..215aa4d3 --- /dev/null +++ b/cryptography/hazmat/backends/__init__.py @@ -0,0 +1,23 @@ +# 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 cryptography.hazmat.backends import openssl + + +_ALL_BACKENDS = [ + openssl.backend +] + + +def default_backend(): + return openssl.backend diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py new file mode 100644 index 00000000..912476bb --- /dev/null +++ b/cryptography/hazmat/backends/interfaces.py @@ -0,0 +1,66 @@ +# 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 + +import abc + +import six + + +class CipherBackend(six.with_metaclass(abc.ABCMeta)): + @abc.abstractmethod + def cipher_supported(self, cipher, mode): + """ + Return True if the given cipher and mode are supported. + """ + + @abc.abstractmethod + def register_cipher_adapter(self, cipher, mode, adapter): + """ + Register an adapter for a cipher and mode to a backend specific object. + """ + + @abc.abstractmethod + def create_symmetric_encryption_ctx(self, cipher, mode): + """ + Get a CipherContext that can be used for encryption. + """ + + @abc.abstractmethod + def create_symmetric_decryption_ctx(self, cipher, mode): + """ + Get a CipherContext that can be used for decryption. + """ + + +class HashBackend(six.with_metaclass(abc.ABCMeta)): + @abc.abstractmethod + def hash_supported(self, algorithm): + """ + Return True if the hash algorithm is supported by this backend. + """ + + @abc.abstractmethod + def create_hash_ctx(self, algorithm): + """ + Create a HashContext for calculating a message digest. + """ + + +class HMACBackend(six.with_metaclass(abc.ABCMeta)): + @abc.abstractmethod + def create_hmac_ctx(self, key, algorithm): + """ + Create a HashContext for calculating a message authentication code. + """ diff --git a/cryptography/hazmat/backends/openssl/__init__.py b/cryptography/hazmat/backends/openssl/__init__.py new file mode 100644 index 00000000..a8dfad06 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/__init__.py @@ -0,0 +1,17 @@ +# 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 cryptography.hazmat.backends.openssl.backend import backend + + +__all__ = ["backend"] diff --git a/cryptography/hazmat/backends/openssl/asn1.py b/cryptography/hazmat/backends/openssl/asn1.py new file mode 100644 index 00000000..719a523c --- /dev/null +++ b/cryptography/hazmat/backends/openssl/asn1.py @@ -0,0 +1,124 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... time_t; + +typedef int ASN1_BOOLEAN; +typedef ... ASN1_INTEGER; + +struct asn1_string_st { + int length; + int type; + unsigned char *data; + long flags; +}; + +typedef struct asn1_string_st ASN1_OCTET_STRING; +typedef struct asn1_string_st ASN1_IA5STRING; +typedef ... ASN1_OBJECT; +typedef ... ASN1_STRING; +typedef ... ASN1_TYPE; +typedef ... ASN1_GENERALIZEDTIME; +typedef ... ASN1_ENUMERATED; +typedef ... ASN1_ITEM; +typedef ... ASN1_VALUE; + +typedef struct { + ...; +} ASN1_TIME; +typedef const ASN1_ITEM ASN1_ITEM_EXP; + +typedef ... ASN1_UTCTIME; + +static const int V_ASN1_GENERALIZEDTIME; + +static const int MBSTRING_UTF8; +""" + +FUNCTIONS = """ +ASN1_OBJECT *ASN1_OBJECT_new(); +void ASN1_OBJECT_free(ASN1_OBJECT *); + +/* ASN1 OBJECT IDENTIFIER */ +ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **, const unsigned char **, long); +int i2d_ASN1_OBJECT(ASN1_OBJECT *, unsigned char **); + +/* ASN1 STRING */ +ASN1_STRING *ASN1_STRING_new(); +ASN1_STRING *ASN1_STRING_type_new(int); +void ASN1_STRING_free(ASN1_STRING *); +unsigned char *ASN1_STRING_data(ASN1_STRING *); +int ASN1_STRING_set(ASN1_STRING *, const void *, int); +int ASN1_STRING_type(ASN1_STRING *); +int ASN1_STRING_to_UTF8(unsigned char **, ASN1_STRING *); + +/* ASN1 OCTET STRING */ +ASN1_OCTET_STRING *ASN1_OCTET_STRING_new(); +void ASN1_OCTET_STRING_free(ASN1_OCTET_STRING *); +int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *, const unsigned char *, int); + +/* ASN1 INTEGER */ +ASN1_INTEGER *ASN1_INTEGER_new(); +void ASN1_INTEGER_free(ASN1_INTEGER *); +int ASN1_INTEGER_set(ASN1_INTEGER *, long); +int i2a_ASN1_INTEGER(BIO *, ASN1_INTEGER *); + +/* ASN1 TIME */ +ASN1_TIME *ASN1_TIME_new(); +ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *, + ASN1_GENERALIZEDTIME **); + +/* ASN1 UTCTIME */ +int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t); + +/* ASN1 GENERALIZEDTIME */ +int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *); +void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *); +int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *); + +/* ASN1 ENUMERATED */ +ASN1_ENUMERATED *ASN1_ENUMERATED_new(); +void ASN1_ENUMERATED_free(ASN1_ENUMERATED *); +int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long); + +ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long, + const ASN1_ITEM *); +""" + +MACROS = """ +ASN1_TIME *M_ASN1_TIME_dup(void *); +ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM *); + +/* These aren't macros these arguments are all const X on openssl > 1.0.x */ + +int ASN1_STRING_length(ASN1_STRING *); +ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *); +int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *); + +ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(ASN1_OCTET_STRING *); +int ASN1_OCTET_STRING_cmp(ASN1_OCTET_STRING *, ASN1_OCTET_STRING *); + +ASN1_INTEGER *ASN1_INTEGER_dup(ASN1_INTEGER *); +int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *); +long ASN1_INTEGER_get(ASN1_INTEGER *); + +BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *); +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py new file mode 100644 index 00000000..bd092bec --- /dev/null +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -0,0 +1,480 @@ +# 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 + +import itertools +import sys + +import cffi + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, InvalidTag +from cryptography.hazmat.backends.interfaces import ( + CipherBackend, HashBackend, HMACBackend +) +from cryptography.hazmat.primitives import interfaces +from cryptography.hazmat.primitives.ciphers.algorithms import ( + AES, Blowfish, Camellia, CAST5, TripleDES, ARC4, +) +from cryptography.hazmat.primitives.ciphers.modes import ( + CBC, CTR, ECB, OFB, CFB, GCM, +) + +_OSX_PRE_INCLUDE = """ +#ifdef __APPLE__ +#include +#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ + DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#endif +""" + +_OSX_POST_INCLUDE = """ +#ifdef __APPLE__ +#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ + __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER +#endif +""" + + +@utils.register_interface(CipherBackend) +@utils.register_interface(HashBackend) +@utils.register_interface(HMACBackend) +class Backend(object): + """ + OpenSSL API wrapper. + """ + _modules = [ + "asn1", + "bignum", + "bio", + "conf", + "crypto", + "dh", + "dsa", + "engine", + "err", + "evp", + "hmac", + "nid", + "opensslv", + "pem", + "pkcs7", + "pkcs12", + "rand", + "rsa", + "ssl", + "x509", + "x509name", + "x509v3", + ] + + ffi = None + lib = None + + def __init__(self): + self._ensure_ffi_initialized() + + self._cipher_registry = {} + self._register_default_ciphers() + + @classmethod + def _ensure_ffi_initialized(cls): + if cls.ffi is not None and cls.lib is not None: + return + + ffi = cffi.FFI() + includes = [] + functions = [] + macros = [] + customizations = [] + for name in cls._modules: + module_name = "cryptography.hazmat.backends.openssl." + name + __import__(module_name) + module = sys.modules[module_name] + + ffi.cdef(module.TYPES) + + macros.append(module.MACROS) + functions.append(module.FUNCTIONS) + includes.append(module.INCLUDES) + customizations.append(module.CUSTOMIZATIONS) + + # loop over the functions & macros after declaring all the types + # so we can set interdependent types in different files and still + # have them all defined before we parse the funcs & macros + for func in functions: + ffi.cdef(func) + for macro in macros: + ffi.cdef(macro) + + # We include functions here so that if we got any of their definitions + # wrong, the underlying C compiler will explode. In C you are allowed + # to re-declare a function if it has the same signature. That is: + # int foo(int); + # int foo(int); + # is legal, but the following will fail to compile: + # int foo(int); + # int foo(short); + + lib = ffi.verify( + source="\n".join( + [_OSX_PRE_INCLUDE] + + includes + + [_OSX_POST_INCLUDE] + + functions + + customizations + ), + libraries=["crypto", "ssl"], + ) + + cls.ffi = ffi + cls.lib = lib + cls.lib.OpenSSL_add_all_algorithms() + cls.lib.SSL_load_error_strings() + + def openssl_version_text(self): + """ + Friendly string name of linked OpenSSL. + + Example: OpenSSL 1.0.1e 11 Feb 2013 + """ + 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") + ) + self.register_cipher_adapter( + AES, + GCM, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + ) + + 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) + + def _handle_error(self, mode): + code = self.lib.ERR_get_error() + if not code and isinstance(mode, GCM): + raise InvalidTag + assert code != 0 + lib = self.lib.ERR_GET_LIB(code) + func = self.lib.ERR_GET_FUNC(code) + reason = self.lib.ERR_GET_REASON(code) + return self._handle_error_code(lib, func, reason) + + def _handle_error_code(self, lib, func, reason): + if lib == self.lib.ERR_LIB_EVP: + if func == self.lib.EVP_F_EVP_ENCRYPTFINAL_EX: + if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: + raise ValueError( + "The length of the provided data is not a multiple of " + "the block length" + ) + elif func == self.lib.EVP_F_EVP_DECRYPTFINAL_EX: + if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: + raise ValueError( + "The length of the provided data is not a multiple of " + "the block length" + ) + + raise SystemError( + "Unknown error code from OpenSSL, you should probably file a bug." + ) + + +class GetCipherByName(object): + def __init__(self, fmt): + self._fmt = fmt + + def __call__(self, backend, cipher, mode): + cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() + return backend.lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +@utils.register_interface(interfaces.CipherContext) +@utils.register_interface(interfaces.AEADCipherContext) +@utils.register_interface(interfaces.AEADEncryptionContext) +class _CipherContext(object): + _ENCRYPT = 1 + _DECRYPT = 0 + + def __init__(self, backend, cipher, mode, operation): + self._backend = backend + self._cipher = cipher + self._mode = mode + self._operation = operation + self._tag = None + + ctx = self._backend.lib.EVP_CIPHER_CTX_new() + ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free) + + registry = self._backend._cipher_registry + try: + adapter = registry[type(cipher), type(mode)] + except KeyError: + raise UnsupportedAlgorithm + + evp_cipher = adapter(self._backend, cipher, mode) + if evp_cipher == self._backend.ffi.NULL: + raise UnsupportedAlgorithm + + if isinstance(mode, interfaces.ModeWithInitializationVector): + iv_nonce = mode.initialization_vector + elif isinstance(mode, interfaces.ModeWithNonce): + iv_nonce = mode.nonce + else: + iv_nonce = self._backend.ffi.NULL + # begin init with cipher and operation type + res = self._backend.lib.EVP_CipherInit_ex(ctx, evp_cipher, + self._backend.ffi.NULL, + self._backend.ffi.NULL, + self._backend.ffi.NULL, + operation) + assert res != 0 + # set the key length to handle variable key ciphers + res = self._backend.lib.EVP_CIPHER_CTX_set_key_length( + ctx, len(cipher.key) + ) + assert res != 0 + if isinstance(mode, GCM): + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_IVLEN, + len(iv_nonce), self._backend.ffi.NULL + ) + assert res != 0 + if operation == self._DECRYPT: + if not mode.tag: + raise ValueError("Authentication tag must be supplied " + "when decrypting") + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_TAG, + len(mode.tag), mode.tag + ) + assert res != 0 + else: + if mode.tag: + raise ValueError("Authentication tag must be None when " + "encrypting") + + # pass key/iv + res = self._backend.lib.EVP_CipherInit_ex(ctx, self._backend.ffi.NULL, + self._backend.ffi.NULL, + cipher.key, + iv_nonce, + operation) + assert res != 0 + # We purposely disable padding here as it's handled higher up in the + # API. + self._backend.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + self._ctx = ctx + + def update(self, data): + buf = self._backend.ffi.new("unsigned char[]", + 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)) + assert res != 0 + return self._backend.ffi.buffer(buf)[:outlen[0]] + + def finalize(self): + 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) + if res == 0: + self._backend._handle_error(self._mode) + + if (isinstance(self._mode, GCM) and + self._operation == self._ENCRYPT): + block_byte_size = self._cipher.block_size // 8 + tag_buf = self._backend.ffi.new("unsigned char[]", block_byte_size) + res = self._backend.lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_GET_TAG, + block_byte_size, tag_buf + ) + assert res != 0 + self._tag = self._backend.ffi.buffer(tag_buf)[:] + + res = self._backend.lib.EVP_CIPHER_CTX_cleanup(self._ctx) + assert res == 1 + return self._backend.ffi.buffer(buf)[:outlen[0]] + + def authenticate_additional_data(self, data): + outlen = self._backend.ffi.new("int *") + res = self._backend.lib.EVP_CipherUpdate( + self._ctx, self._backend.ffi.NULL, outlen, data, len(data) + ) + assert res != 0 + + @property + def tag(self): + return self._tag + + +@utils.register_interface(interfaces.HashContext) +class _HashContext(object): + def __init__(self, backend, algorithm, ctx=None): + self.algorithm = algorithm + + 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 + + self._ctx = ctx + + 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 _HashContext(self._backend, self.algorithm, ctx=copied_ctx) + + def update(self, data): + res = self._backend.lib.EVP_DigestUpdate(self._ctx, data, len(data)) + assert res != 0 + + 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(self._ctx) + assert res == 1 + return self._backend.ffi.buffer(buf)[:] + + +@utils.register_interface(interfaces.HashContext) +class _HMACContext(object): + def __init__(self, backend, key, algorithm, ctx=None): + self.algorithm = algorithm + self._backend = backend + + 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 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 update(self, data): + res = self._backend.lib.Cryptography_HMAC_Update( + self._ctx, data, len(data) + ) + assert res != 0 + + 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 + self._backend.lib.HMAC_CTX_cleanup(self._ctx) + return self._backend.ffi.buffer(buf)[:] + + +backend = Backend() diff --git a/cryptography/hazmat/backends/openssl/bignum.py b/cryptography/hazmat/backends/openssl/bignum.py new file mode 100644 index 00000000..1b0fe5ab --- /dev/null +++ b/cryptography/hazmat/backends/openssl/bignum.py @@ -0,0 +1,40 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... BIGNUM; +typedef ... BN_ULONG; +""" + +FUNCTIONS = """ +BIGNUM *BN_new(); +void BN_free(BIGNUM *); + +int BN_set_word(BIGNUM *, BN_ULONG); + +char *BN_bn2hex(const BIGNUM *); +int BN_hex2bn(BIGNUM **, const char *); +int BN_dec2bn(BIGNUM **, const char *); + +int BN_num_bits(const BIGNUM *); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/bio.py b/cryptography/hazmat/backends/openssl/bio.py new file mode 100644 index 00000000..c23dd0d8 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/bio.py @@ -0,0 +1,173 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef struct bio_st BIO; +typedef void bio_info_cb(BIO *, int, const char *, int, long, long); +struct bio_method_st { + int type; + const char *name; + int (*bwrite)(BIO *, const char *, int); + int (*bread)(BIO *, char *, int); + int (*bputs)(BIO *, const char *); + int (*bgets)(BIO *, char*, int); + long (*ctrl)(BIO *, int, long, void *); + int (*create)(BIO *); + int (*destroy)(BIO *); + long (*callback_ctrl)(BIO *, int, bio_info_cb *); + ...; +}; +typedef struct bio_method_st BIO_METHOD; +struct bio_st { + BIO_METHOD *method; + long (*callback)(struct bio_st*, int, const char*, int, long, long); + char *cb_arg; + int init; + int shutdown; + int flags; + int retry_reason; + int num; + void *ptr; + struct bio_st *next_bio; + struct bio_st *prev_bio; + int references; + unsigned long num_read; + unsigned long num_write; + ...; +}; +typedef ... BUF_MEM; +""" + +FUNCTIONS = """ +BIO* BIO_new(BIO_METHOD *); +int BIO_set(BIO *, BIO_METHOD *); +int BIO_free(BIO *); +void BIO_vfree(BIO *); +void BIO_free_all(BIO *); +BIO *BIO_push(BIO *, BIO *); +BIO *BIO_pop(BIO *); +BIO *BIO_next(BIO *); +BIO *BIO_find_type(BIO *, int); +int BIO_method_type(const BIO *); +BIO_METHOD *BIO_s_mem(); +BIO *BIO_new_mem_buf(void *, int); +BIO_METHOD *BIO_s_file(); +BIO *BIO_new_file(const char *, const char *); +BIO *BIO_new_fp(FILE *, int); +BIO_METHOD *BIO_s_fd(); +BIO *BIO_new_fd(int, int); +BIO_METHOD *BIO_s_socket(); +BIO *BIO_new_socket(int, int); +BIO_METHOD *BIO_s_null(); +long BIO_ctrl(BIO *, int, long, void *); +long BIO_callback_ctrl( + BIO *, + int, + void (*)(struct bio_st *, int, const char *, int, long, long) +); +char* BIO_ptr_ctrl(BIO *bp, int cmd, long larg); +long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); +size_t BIO_ctrl_pending(BIO *b); +size_t BIO_ctrl_wpending(BIO *b); +int BIO_read(BIO *, void *, int); +int BIO_gets(BIO *, char *, int); +int BIO_write(BIO *, const void *, int); +int BIO_puts(BIO *, const char *); +BIO_METHOD *BIO_f_null(); +BIO_METHOD *BIO_f_buffer(); +""" + +MACROS = """ +long BIO_set_fd(BIO *, long, int); +long BIO_get_fd(BIO *, char *); +long BIO_set_mem_eof_return(BIO *, int); +long BIO_get_mem_data(BIO *, char **); +long BIO_set_mem_buf(BIO *, BUF_MEM *, int); +long BIO_get_mem_ptr(BIO *, BUF_MEM **); +long BIO_set_fp(BIO *, FILE *, int); +long BIO_get_fp(BIO *, FILE **); +int BIO_read_filename(BIO *, char *); +int BIO_write_filename(BIO *, char *); +int BIO_append_filename(BIO *, char *); +int BIO_rw_filename(BIO *, char *); +int BIO_should_read(BIO *); +int BIO_should_write(BIO *); +int BIO_should_io_special(BIO *); +int BIO_retry_type(BIO *); +int BIO_should_retry(BIO *); +int BIO_reset(BIO *); +int BIO_seek(BIO *, int); +int BIO_tell(BIO *); +int BIO_flush(BIO *); +int BIO_eof(BIO *); +int BIO_set_close(BIO *,long); +int BIO_get_close(BIO *); +int BIO_pending(BIO *); +int BIO_wpending(BIO *); +int BIO_get_info_callback(BIO *, bio_info_cb **); +int BIO_set_info_callback(BIO *, bio_info_cb *); +long BIO_get_buffer_num_lines(BIO *); +long BIO_set_read_buffer_size(BIO *, long); +long BIO_set_write_buffer_size(BIO *, long); +long BIO_set_buffer_size(BIO *, long); +long BIO_set_buffer_read_data(BIO *, void *, long); +#define BIO_TYPE_MEM ... +#define BIO_TYPE_FILE ... +#define BIO_TYPE_FD ... +#define BIO_TYPE_SOCKET ... +#define BIO_TYPE_CONNECT ... +#define BIO_TYPE_ACCEPT ... +#define BIO_TYPE_NULL ... +#define BIO_CLOSE ... +#define BIO_NOCLOSE ... +#define BIO_TYPE_SOURCE_SINK ... +#define BIO_CTRL_RESET ... +#define BIO_CTRL_EOF ... +#define BIO_CTRL_SET ... +#define BIO_CTRL_SET_CLOSE ... +#define BIO_CTRL_FLUSH ... +#define BIO_CTRL_DUP ... +#define BIO_CTRL_GET_CLOSE ... +#define BIO_CTRL_INFO ... +#define BIO_CTRL_GET ... +#define BIO_CTRL_PENDING ... +#define BIO_CTRL_WPENDING ... +#define BIO_C_FILE_SEEK ... +#define BIO_C_FILE_TELL ... +#define BIO_TYPE_NONE ... +#define BIO_TYPE_PROXY_CLIENT ... +#define BIO_TYPE_PROXY_SERVER ... +#define BIO_TYPE_NBIO_TEST ... +#define BIO_TYPE_BER ... +#define BIO_TYPE_BIO ... +#define BIO_TYPE_DESCRIPTOR ... +#define BIO_FLAGS_READ ... +#define BIO_FLAGS_WRITE ... +#define BIO_FLAGS_IO_SPECIAL ... +#define BIO_FLAGS_RWS ... +#define BIO_FLAGS_SHOULD_RETRY ... +#define BIO_TYPE_NULL_FILTER ... +#define BIO_TYPE_SSL ... +#define BIO_TYPE_MD ... +#define BIO_TYPE_BUFFER ... +#define BIO_TYPE_CIPHER ... +#define BIO_TYPE_BASE64 ... +#define BIO_TYPE_FILTER ... +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/conf.py b/cryptography/hazmat/backends/openssl/conf.py new file mode 100644 index 00000000..4846252c --- /dev/null +++ b/cryptography/hazmat/backends/openssl/conf.py @@ -0,0 +1,29 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... CONF; +""" + +FUNCTIONS = """ +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/crypto.py b/cryptography/hazmat/backends/openssl/crypto.py new file mode 100644 index 00000000..773d9b14 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/crypto.py @@ -0,0 +1,40 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +""" + +FUNCTIONS = """ +void CRYPTO_free(void *); +int CRYPTO_mem_ctrl(int); +int CRYPTO_is_mem_check_on(); +void CRYPTO_mem_leaks(struct bio_st *); +void CRYPTO_cleanup_all_ex_data(); +""" + +MACROS = """ +void CRYPTO_add(int *, int, int); +void CRYPTO_malloc_init(); +void CRYPTO_malloc_debug_init(); +#define CRYPTO_MEM_CHECK_ON ... +#define CRYPTO_MEM_CHECK_OFF ... +#define CRYPTO_MEM_CHECK_ENABLE ... +#define CRYPTO_MEM_CHECK_DISABLE ... +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/dh.py b/cryptography/hazmat/backends/openssl/dh.py new file mode 100644 index 00000000..b8fbf368 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/dh.py @@ -0,0 +1,31 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... DH; +""" + +FUNCTIONS = """ +DH *DH_new(); +void DH_free(DH *); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/dsa.py b/cryptography/hazmat/backends/openssl/dsa.py new file mode 100644 index 00000000..e6c369a6 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/dsa.py @@ -0,0 +1,33 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... DSA; +""" + +FUNCTIONS = """ +DSA *DSA_generate_parameters(int, unsigned char *, int, int *, unsigned long *, + void (*)(int, int, void *), void *); +int DSA_generate_key(DSA *); +void DSA_free(DSA *); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/engine.py b/cryptography/hazmat/backends/openssl/engine.py new file mode 100644 index 00000000..1f377665 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/engine.py @@ -0,0 +1,65 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... ENGINE; +""" + +FUNCTIONS = """ +ENGINE *ENGINE_get_first(); +ENGINE *ENGINE_get_last(); +ENGINE *ENGINE_get_next(ENGINE *); +ENGINE *ENGINE_get_prev(ENGINE *); +int ENGINE_add(ENGINE *); +int ENGINE_remove(ENGINE *); +ENGINE *ENGINE_by_id(const char *); +int ENGINE_init(ENGINE *); +int ENGINE_finish(ENGINE *); +int ENGINE_free(ENGINE *); +void ENGINE_cleanup(); +void ENGINE_load_dynamic(); +void ENGINE_load_builtin_engines(); +int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int); +int ENGINE_set_default(ENGINE *, unsigned int); +int ENGINE_register_complete(ENGINE *); + +int ENGINE_set_default_RSA(ENGINE *); +int ENGINE_set_default_string(ENGINE *, const char *); +int ENGINE_set_default_DSA(ENGINE *); +int ENGINE_set_default_ECDH(ENGINE *); +int ENGINE_set_default_ECDSA(ENGINE *); +int ENGINE_set_default_DH(ENGINE *); +int ENGINE_set_default_RAND(ENGINE *); +int ENGINE_set_default_ciphers(ENGINE *); +int ENGINE_set_default_digests(ENGINE *); +""" + +MACROS = """ +#define ENGINE_METHOD_RSA ... +#define ENGINE_METHOD_DSA ... +#define ENGINE_METHOD_RAND ... +#define ENGINE_METHOD_ECDH ... +#define ENGINE_METHOD_ECDSA ... +#define ENGINE_METHOD_CIPHERS ... +#define ENGINE_METHOD_DIGESTS ... +#define ENGINE_METHOD_STORE ... +#define ENGINE_METHOD_ALL ... +#define ENGINE_METHOD_NONE ... +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/err.py b/cryptography/hazmat/backends/openssl/err.py new file mode 100644 index 00000000..f31c2405 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/err.py @@ -0,0 +1,76 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +struct ERR_string_data_st { + unsigned long error; + const char *string; +}; +typedef struct ERR_string_data_st ERR_STRING_DATA; + +static const int ERR_LIB_EVP; +static const int ERR_LIB_PEM; + +static const int EVP_F_EVP_ENCRYPTFINAL_EX; +static const int EVP_F_EVP_DECRYPTFINAL_EX; + +static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH; + +static const int PEM_F_PEM_READ_BIO_PRIVATEKEY; +static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO; + +static const int PEM_R_BAD_PASSWORD_READ; +static const int ASN1_R_BAD_PASSWORD_READ; +""" + +FUNCTIONS = """ +void ERR_load_crypto_strings(); +void ERR_free_strings(); +char* ERR_error_string(unsigned long, char *); +void ERR_error_string_n(unsigned long, char *, size_t); +const char* ERR_lib_error_string(unsigned long); +const char* ERR_func_error_string(unsigned long); +const char* ERR_reason_error_string(unsigned long); +void ERR_print_errors(BIO *); +void ERR_print_errors_fp(FILE *); +unsigned long ERR_get_error(); +unsigned long ERR_peek_error(); +unsigned long ERR_peek_last_error(); +unsigned long ERR_get_error_line(const char **, int *); +unsigned long ERR_peek_error_line(const char **, int *); +unsigned long ERR_peek_last_error_line(const char **, int *); +unsigned long ERR_get_error_line_data(const char **, int *, + const char **, int *); +unsigned long ERR_peek_error_line_data(const char **, + int *, const char **, int *); +unsigned long ERR_peek_last_error_line_data(const char **, + int *, const char **, int *); +void ERR_put_error(int, int, int, const char *, int); +void ERR_add_error_data(int, ...); +int ERR_get_next_error_library(); +""" + +MACROS = """ +unsigned long ERR_PACK(int, int, int); +int ERR_GET_LIB(unsigned long); +int ERR_GET_FUNC(unsigned long); +int ERR_GET_REASON(unsigned long); +int ERR_FATAL_ERROR(unsigned long); +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/evp.py b/cryptography/hazmat/backends/openssl/evp.py new file mode 100644 index 00000000..8cb44610 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/evp.py @@ -0,0 +1,112 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... EVP_CIPHER; +typedef struct { + const EVP_CIPHER *cipher; + ENGINE *engine; + int encrypt; + ...; +} EVP_CIPHER_CTX; +typedef ... EVP_MD; +typedef struct env_md_ctx_st EVP_MD_CTX; + +typedef struct evp_pkey_st { + int type; + ...; +} EVP_PKEY; +static const int EVP_PKEY_RSA; +static const int EVP_PKEY_DSA; +static const int Cryptography_EVP_CTRL_GCM_SET_IVLEN; +static const int Cryptography_EVP_CTRL_GCM_GET_TAG; +static const int Cryptography_EVP_CTRL_GCM_SET_TAG; +""" + +FUNCTIONS = """ +void OpenSSL_add_all_algorithms(); + +const EVP_CIPHER *EVP_get_cipherbyname(const char *); +int EVP_EncryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, + const unsigned char *, const unsigned char *); +int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); +int EVP_EncryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, + const unsigned char *, int); +int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); +int EVP_DecryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, + const unsigned char *, const unsigned char *); +int EVP_DecryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, + const unsigned char *, int); +int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); +int EVP_CipherInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, + const unsigned char *, const unsigned char *, int); +int EVP_CipherUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, + const unsigned char *, int); +int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); +int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); +const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *); +int EVP_CIPHER_block_size(const EVP_CIPHER *); +void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); +EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(); +void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); +int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *, int); + +EVP_MD_CTX *EVP_MD_CTX_create(); +int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *); +int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *); +int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t); +int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); +int EVP_MD_CTX_cleanup(EVP_MD_CTX *); +void EVP_MD_CTX_destroy(EVP_MD_CTX *); +const EVP_MD *EVP_get_digestbyname(const char *); +const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *); +int EVP_MD_size(const EVP_MD *); + +EVP_PKEY *EVP_PKEY_new(); +void EVP_PKEY_free(EVP_PKEY *); +int EVP_PKEY_type(int); +int EVP_PKEY_bits(EVP_PKEY *); +RSA *EVP_PKEY_get1_RSA(EVP_PKEY *); + +int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *); +int EVP_SignUpdate(EVP_MD_CTX *, const void *, size_t); +int EVP_SignFinal(EVP_MD_CTX *, unsigned char *, unsigned int *, EVP_PKEY *); + +int EVP_VerifyInit(EVP_MD_CTX *, const EVP_MD *); +int EVP_VerifyUpdate(EVP_MD_CTX *, const void *, size_t); +int EVP_VerifyFinal(EVP_MD_CTX *, const unsigned char *, unsigned int, + EVP_PKEY *); +""" + +MACROS = """ +int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *); +int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *); +int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *); +int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *); +""" + +CUSTOMIZATIONS = """ +#ifdef EVP_CTRL_GCM_SET_TAG +const int Cryptography_EVP_CTRL_GCM_GET_TAG = EVP_CTRL_GCM_GET_TAG; +const int Cryptography_EVP_CTRL_GCM_SET_TAG = EVP_CTRL_GCM_SET_TAG; +const int Cryptography_EVP_CTRL_GCM_SET_IVLEN = EVP_CTRL_GCM_SET_IVLEN; +#else +const int Cryptography_EVP_CTRL_GCM_GET_TAG = -1; +const int Cryptography_EVP_CTRL_GCM_SET_TAG = -1; +const int Cryptography_EVP_CTRL_GCM_SET_IVLEN = -1; +#endif +""" diff --git a/cryptography/hazmat/backends/openssl/hmac.py b/cryptography/hazmat/backends/openssl/hmac.py new file mode 100644 index 00000000..10e67141 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/hmac.py @@ -0,0 +1,90 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef struct { ...; } HMAC_CTX; +""" + +FUNCTIONS = """ +void HMAC_CTX_init(HMAC_CTX *); +void HMAC_CTX_cleanup(HMAC_CTX *); + +int Cryptography_HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, + ENGINE *); +int Cryptography_HMAC_Update(HMAC_CTX *, const unsigned char *, size_t); +int Cryptography_HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *); +int Cryptography_HMAC_CTX_copy(HMAC_CTX *, HMAC_CTX *); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +int Cryptography_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, + const EVP_MD *md, ENGINE *impl) { +#if OPENSSL_VERSION_NUMBER >= 0x010000000 + return HMAC_Init_ex(ctx, key, key_len, md, impl); +#else + HMAC_Init_ex(ctx, key, key_len, md, impl); + return 1; +#endif +} + +int Cryptography_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, + size_t data_len) { +#if OPENSSL_VERSION_NUMBER >= 0x010000000 + return HMAC_Update(ctx, data, data_len); +#else + HMAC_Update(ctx, data, data_len); + return 1; +#endif +} + +int Cryptography_HMAC_Final(HMAC_CTX *ctx, unsigned char *digest, + unsigned int *digest_len) { +#if OPENSSL_VERSION_NUMBER >= 0x010000000 + return HMAC_Final(ctx, digest, digest_len); +#else + HMAC_Final(ctx, digest, digest_len); + return 1; +#endif +} + +int Cryptography_HMAC_CTX_copy(HMAC_CTX *dst_ctx, HMAC_CTX *src_ctx) { +#if OPENSSL_VERSION_NUMBER >= 0x010000000 + return HMAC_CTX_copy(dst_ctx, src_ctx); +#else + HMAC_CTX_init(dst_ctx); + if (!EVP_MD_CTX_copy_ex(&dst_ctx->i_ctx, &src_ctx->i_ctx)) { + goto err; + } + if (!EVP_MD_CTX_copy_ex(&dst_ctx->o_ctx, &src_ctx->o_ctx)) { + goto err; + } + if (!EVP_MD_CTX_copy_ex(&dst_ctx->md_ctx, &src_ctx->md_ctx)) { + goto err; + } + memcpy(dst_ctx->key, src_ctx->key, HMAC_MAX_MD_CBLOCK); + dst_ctx->key_length = src_ctx->key_length; + dst_ctx->md = src_ctx->md; + return 1; + + err: + return 0; +#endif +} +""" diff --git a/cryptography/hazmat/backends/openssl/nid.py b/cryptography/hazmat/backends/openssl/nid.py new file mode 100644 index 00000000..9816dde4 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/nid.py @@ -0,0 +1,49 @@ +# 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. + +INCLUDES = "" + +TYPES = """ +static const int NID_undef; +static const int NID_dsa; +static const int NID_dsaWithSHA; +static const int NID_dsaWithSHA1; +static const int NID_md2; +static const int NID_md4; +static const int NID_md5; +static const int NID_mdc2; +static const int NID_ripemd160; +static const int NID_sha; +static const int NID_sha1; +static const int NID_sha256; +static const int NID_sha384; +static const int NID_sha512; +static const int NID_sha224; +static const int NID_sha; +static const int NID_ecdsa_with_SHA1; +static const int NID_ecdsa_with_SHA224; +static const int NID_ecdsa_with_SHA256; +static const int NID_ecdsa_with_SHA384; +static const int NID_ecdsa_with_SHA512; +static const int NID_crl_reason; +static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC; +""" + +FUNCTIONS = """ +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/opensslv.py b/cryptography/hazmat/backends/openssl/opensslv.py new file mode 100644 index 00000000..d463776c --- /dev/null +++ b/cryptography/hazmat/backends/openssl/opensslv.py @@ -0,0 +1,29 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +static char *const OPENSSL_VERSION_TEXT; +""" + +FUNCTIONS = """ +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/pem.py b/cryptography/hazmat/backends/openssl/pem.py new file mode 100644 index 00000000..cef7839f --- /dev/null +++ b/cryptography/hazmat/backends/openssl/pem.py @@ -0,0 +1,57 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata); +""" + +FUNCTIONS = """ +X509 *PEM_read_bio_X509(BIO *, X509 **, pem_password_cb *, void *); +int PEM_write_bio_X509(BIO *, X509 *); + +int PEM_write_bio_PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, + unsigned char *, int, pem_password_cb *, void *); + +EVP_PKEY *PEM_read_bio_PrivateKey(BIO *, EVP_PKEY **, pem_password_cb *, + void *); + +int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, + char *, int, pem_password_cb *, void *); + +int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *, + char *, int, pem_password_cb *, void *); + +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *, EVP_PKEY **, pem_password_cb *, + void *); + +int PEM_write_bio_X509_REQ(BIO *, X509_REQ *); + +X509_REQ *PEM_read_bio_X509_REQ(BIO *, X509_REQ **, pem_password_cb *, void *); + +X509_CRL *PEM_read_bio_X509_CRL(BIO *, X509_CRL **, pem_password_cb *, void *); + +int PEM_write_bio_X509_CRL(BIO *, X509_CRL *); + +PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *); +DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/pkcs12.py b/cryptography/hazmat/backends/openssl/pkcs12.py new file mode 100644 index 00000000..d91d100f --- /dev/null +++ b/cryptography/hazmat/backends/openssl/pkcs12.py @@ -0,0 +1,37 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... PKCS12; +""" + +FUNCTIONS = """ +void PKCS12_free(PKCS12 *); + +PKCS12 *d2i_PKCS12_bio(BIO *, PKCS12 **); +int i2d_PKCS12_bio(BIO *, PKCS12 *); +""" + +MACROS = """ +int PKCS12_parse(PKCS12 *, const char *, EVP_PKEY **, X509 **, + struct stack_st_X509 **); +PKCS12 *PKCS12_create(char *, char *, EVP_PKEY *, X509 *, + struct stack_st_X509 *, int, int, int, int, int); +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/pkcs7.py b/cryptography/hazmat/backends/openssl/pkcs7.py new file mode 100644 index 00000000..60ea3c52 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/pkcs7.py @@ -0,0 +1,37 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef struct { + ASN1_OBJECT *type; + ...; +} PKCS7; +""" + +FUNCTIONS = """ +void PKCS7_free(PKCS7 *); +""" + +MACROS = """ +int PKCS7_type_is_signed(PKCS7 *); +int PKCS7_type_is_enveloped(PKCS7 *); +int PKCS7_type_is_signedAndEnveloped(PKCS7 *); +int PKCS7_type_is_data(PKCS7 *); +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/rand.py b/cryptography/hazmat/backends/openssl/rand.py new file mode 100644 index 00000000..848ee05a --- /dev/null +++ b/cryptography/hazmat/backends/openssl/rand.py @@ -0,0 +1,40 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +""" + +FUNCTIONS = """ +void RAND_seed(const void *, int); +void RAND_add(const void *, int, double); +int RAND_status(); +int RAND_egd(const char *); +int RAND_egd_bytes(const char *, int); +int RAND_query_egd_bytes(const char *, unsigned char *, int); +const char *RAND_file_name(char *, size_t); +int RAND_load_file(const char *, long); +int RAND_write_file(const char *); +void RAND_cleanup(); +int RAND_bytes(unsigned char *, int); +int RAND_pseudo_bytes(unsigned char *, int); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/rsa.py b/cryptography/hazmat/backends/openssl/rsa.py new file mode 100644 index 00000000..ad0d37b4 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/rsa.py @@ -0,0 +1,59 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef struct rsa_st { + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + ...; +} RSA; +typedef ... BN_GENCB; +static const int RSA_PKCS1_PADDING; +static const int RSA_SSLV23_PADDING; +static const int RSA_NO_PADDING; +static const int RSA_PKCS1_OAEP_PADDING; +static const int RSA_X931_PADDING; +""" + +FUNCTIONS = """ +RSA *RSA_new(); +void RSA_free(RSA *); +int RSA_size(const RSA *); +int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *); +int RSA_check_key(const RSA *); +RSA *RSAPublicKey_dup(RSA *); +int RSA_public_encrypt(int, const unsigned char *, unsigned char *, + RSA *, int); +int RSA_private_encrypt(int, const unsigned char *, unsigned char *, + RSA *, int); +int RSA_public_decrypt(int, const unsigned char *, unsigned char *, + RSA *, int); +int RSA_private_decrypt(int, const unsigned char *, unsigned char *, + RSA *, int); +""" + +MACROS = """ +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/ssl.py b/cryptography/hazmat/backends/openssl/ssl.py new file mode 100644 index 00000000..04611309 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/ssl.py @@ -0,0 +1,216 @@ +# 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. + +INCLUDES = """ +#include +""" + +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 = """ +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/backends/openssl/x509.py b/cryptography/hazmat/backends/openssl/x509.py new file mode 100644 index 00000000..b2ee672e --- /dev/null +++ b/cryptography/hazmat/backends/openssl/x509.py @@ -0,0 +1,190 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef struct { + ASN1_OBJECT *algorithm; + ...; +} X509_ALGOR; + +typedef struct { + X509_ALGOR *signature; + ...; +} X509_CINF; + +typedef struct { + ASN1_OBJECT *object; + ASN1_BOOLEAN critical; + ASN1_OCTET_STRING *value; +} X509_EXTENSION; + +typedef ... X509_EXTENSIONS; + +typedef ... X509_REQ; + +typedef ... x509_revoked_st; + +typedef struct { + ASN1_INTEGER *serialNumber; + ASN1_TIME *revocationDate; + X509_EXTENSIONS *extensions; + int sequence; + ...; +} X509_REVOKED; + +typedef struct { + struct x509_revoked_st *revoked; + ...; +} X509_CRL_INFO; + +typedef struct { + X509_CRL_INFO *crl; + ...; +} X509_CRL; + +typedef struct { + X509_CINF *cert_info; + ...; +} X509; + +typedef ... X509_STORE; +typedef ... NETSCAPE_SPKI; +""" + +FUNCTIONS = """ +X509 *X509_new(); +void X509_free(X509 *); +X509 *X509_dup(X509 *); + +int X509_print_ex(BIO *, X509 *, unsigned long, unsigned long); + +int X509_set_version(X509 *, long); + +EVP_PKEY *X509_get_pubkey(X509 *); +int X509_set_pubkey(X509 *, EVP_PKEY *); + +unsigned char *X509_alias_get0(X509 *, int *); +int X509_sign(X509 *, EVP_PKEY *, const EVP_MD *); + +int X509_digest(const X509 *, const EVP_MD *, unsigned char *, unsigned int *); + +ASN1_TIME *X509_gmtime_adj(ASN1_TIME *, long); + +unsigned long X509_subject_name_hash(X509 *); + +X509_NAME *X509_get_subject_name(X509 *); +int X509_set_subject_name(X509 *, X509_NAME *); + +X509_NAME *X509_get_issuer_name(X509 *); +int X509_set_issuer_name(X509 *, X509_NAME *); + +int X509_get_ext_count(X509 *); +int X509_add_ext(X509 *, X509_EXTENSION *, int); +X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *); +X509_EXTENSION *X509_get_ext(X509 *, int); +int X509_EXTENSION_get_critical(X509_EXTENSION *); +ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *); +void X509_EXTENSION_free(X509_EXTENSION *); + +int X509_REQ_set_version(X509_REQ *, long); +X509_REQ *X509_REQ_new(); +void X509_REQ_free(X509_REQ *); +int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *); +int X509_REQ_sign(X509_REQ *, EVP_PKEY *, const EVP_MD *); +int X509_REQ_verify(X509_REQ *, EVP_PKEY *); +EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *); +int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *); +int X509_REQ_print_ex(BIO *, X509_REQ *, unsigned long, unsigned long); + +int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int); +ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *); + +X509_REVOKED *X509_REVOKED_new(); +void X509_REVOKED_free(X509_REVOKED *); + +int X509_REVOKED_set_serialNumber(X509_REVOKED *, ASN1_INTEGER *); + +int X509_REVOKED_add1_ext_i2d(X509_REVOKED *, int, void *, int, unsigned long); + +X509_CRL *d2i_X509_CRL_bio(BIO *, X509_CRL **); +X509_CRL *X509_CRL_new(); +void X509_CRL_free(X509_CRL *); +int X509_CRL_add0_revoked(X509_CRL *, X509_REVOKED *); +int i2d_X509_CRL_bio(BIO *, X509_CRL *); +int X509_CRL_print(BIO *, X509_CRL *); +int X509_CRL_set_issuer_name(X509_CRL *, X509_NAME *); +int X509_CRL_sign(X509_CRL *, EVP_PKEY *, const EVP_MD *); + +int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *, EVP_PKEY *); +int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *, EVP_PKEY *, const EVP_MD *); +char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *); +EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *); +int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *, EVP_PKEY *); +NETSCAPE_SPKI *NETSCAPE_SPKI_new(); +void NETSCAPE_SPKI_free(NETSCAPE_SPKI *); + +/* ASN1 serialization */ +int i2d_X509_bio(BIO *, X509 *); +X509 *d2i_X509_bio(BIO *, X509 **); + +int i2d_X509_REQ_bio(BIO *, X509_REQ *); +X509_REQ *d2i_X509_REQ_bio(BIO *, X509_REQ **); + +int i2d_PrivateKey_bio(BIO *, EVP_PKEY *); +EVP_PKEY *d2i_PrivateKey_bio(BIO *, EVP_PKEY **); + +ASN1_INTEGER *X509_get_serialNumber(X509 *); +int X509_set_serialNumber(X509 *, ASN1_INTEGER *); + +/* X509_STORE */ +X509_STORE *X509_STORE_new(); +void X509_STORE_free(X509_STORE *); +int X509_STORE_add_cert(X509_STORE *, X509 *); +""" + +MACROS = """ +long X509_get_version(X509 *); + +ASN1_TIME *X509_get_notBefore(X509 *); +ASN1_TIME *X509_get_notAfter(X509 *); + +long X509_REQ_get_version(X509_REQ *); +X509_NAME *X509_REQ_get_subject_name(X509_REQ *); + +struct stack_st_X509 *sk_X509_new_null(); +void sk_X509_free(struct stack_st_X509 *); +int sk_X509_num(struct stack_st_X509 *); +int sk_X509_push(struct stack_st_X509 *, X509 *); +X509 *sk_X509_value(struct stack_st_X509 *, int); + +X509_EXTENSIONS *sk_X509_EXTENSION_new_null(); +int sk_X509_EXTENSION_num(X509_EXTENSIONS *); +X509_EXTENSION *sk_X509_EXTENSION_value(X509_EXTENSIONS *, int); +int sk_X509_EXTENSION_push(X509_EXTENSIONS *, X509_EXTENSION *); +void sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int); +void sk_X509_EXTENSION_free(X509_EXTENSIONS *); + +int sk_X509_REVOKED_num(struct x509_revoked_st *); +X509_REVOKED *sk_X509_REVOKED_value(struct x509_revoked_st *, int); + +/* These aren't macros these arguments are all const X on openssl > 1.0.x */ +int X509_CRL_set_lastUpdate(X509_CRL *, const ASN1_TIME *); +int X509_CRL_set_nextUpdate(X509_CRL *, const ASN1_TIME *); +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/x509name.py b/cryptography/hazmat/backends/openssl/x509name.py new file mode 100644 index 00000000..896f0ae4 --- /dev/null +++ b/cryptography/hazmat/backends/openssl/x509name.py @@ -0,0 +1,51 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef ... X509_NAME; +typedef ... X509_NAME_ENTRY; +""" + +FUNCTIONS = """ +int X509_NAME_entry_count(X509_NAME *); +X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *, int); +ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *); +ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *); +unsigned long X509_NAME_hash(X509_NAME *); + +int i2d_X509_NAME(X509_NAME *, unsigned char **); +int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, unsigned char *, + int, int, int); +X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *, int); +void X509_NAME_ENTRY_free(X509_NAME_ENTRY *); +int X509_NAME_get_index_by_NID(X509_NAME *, int, int); +int X509_NAME_cmp(const X509_NAME *, const X509_NAME *); +char *X509_NAME_oneline(X509_NAME *, char *, int); +X509_NAME *X509_NAME_dup(X509_NAME *); +void X509_NAME_free(X509_NAME *); +""" + +MACROS = """ +struct stack_st_X509_NAME *sk_X509_NAME_new_null(); +int sk_X509_NAME_num(struct stack_st_X509_NAME *); +int sk_X509_NAME_push(struct stack_st_X509_NAME *, X509_NAME *); +X509_NAME *sk_X509_NAME_value(struct stack_st_X509_NAME *, int); +void sk_X509_NAME_free(struct stack_st_X509_NAME *); +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/backends/openssl/x509v3.py b/cryptography/hazmat/backends/openssl/x509v3.py new file mode 100644 index 00000000..bc26236c --- /dev/null +++ b/cryptography/hazmat/backends/openssl/x509v3.py @@ -0,0 +1,97 @@ +# 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. + +INCLUDES = """ +#include +""" + +TYPES = """ +typedef struct { + X509 *issuer_cert; + X509 *subject_cert; + ...; +} X509V3_CTX; + +typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char **, long); + +typedef struct { + ASN1_ITEM_EXP *it; + X509V3_EXT_D2I d2i; + ...; +} X509V3_EXT_METHOD; + +static const int GEN_OTHERNAME; +static const int GEN_EMAIL; +static const int GEN_X400; +static const int GEN_DNS; +static const int GEN_URI; +static const int GEN_DIRNAME; +static const int GEN_EDIPARTY; +static const int GEN_IPADD; +static const int GEN_RID; + +typedef struct { + ...; +} OTHERNAME; + +typedef struct { + ...; +} EDIPARTYNAME; + +typedef struct { + int type; + union { + char *ptr; + OTHERNAME *otherName; /* otherName */ + ASN1_IA5STRING *rfc822Name; + ASN1_IA5STRING *dNSName; + ASN1_TYPE *x400Address; + X509_NAME *directoryName; + EDIPARTYNAME *ediPartyName; + ASN1_IA5STRING *uniformResourceIdentifier; + ASN1_OCTET_STRING *iPAddress; + ASN1_OBJECT *registeredID; + + /* Old names */ + ASN1_OCTET_STRING *ip; /* iPAddress */ + X509_NAME *dirn; /* dirn */ + ASN1_IA5STRING *ia5; /* rfc822Name, dNSName, */ + /* uniformResourceIdentifier */ + ASN1_OBJECT *rid; /* registeredID */ + ASN1_TYPE *other; /* x400Address */ + } d; + ...; +} GENERAL_NAME; + +typedef struct stack_st_GENERAL_NAME GENERAL_NAMES; +""" + +FUNCTIONS = """ +void X509V3_set_ctx(X509V3_CTX *, X509 *, X509 *, X509_REQ *, X509_CRL *, int); +X509_EXTENSION *X509V3_EXT_nconf(CONF *, X509V3_CTX *, char *, char *); +int GENERAL_NAME_print(BIO *, GENERAL_NAME *); +""" + +MACROS = """ +void *X509V3_set_ctx_nodb(X509V3_CTX *); +int sk_GENERAL_NAME_num(struct stack_st_GENERAL_NAME *); +int sk_GENERAL_NAME_push(struct stack_st_GENERAL_NAME *, GENERAL_NAME *); +GENERAL_NAME *sk_GENERAL_NAME_value(struct stack_st_GENERAL_NAME *, int); + +/* These aren't macros these functions are all const X on openssl > 1.0.x */ +const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *); +const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int); +""" + +CUSTOMIZATIONS = """ +""" diff --git a/cryptography/hazmat/bindings/__init__.py b/cryptography/hazmat/bindings/__init__.py deleted file mode 100644 index bd158198..00000000 --- a/cryptography/hazmat/bindings/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# 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 cryptography.hazmat.bindings import openssl - - -_ALL_BACKENDS = [ - openssl.backend -] - - -def default_backend(): - return openssl.backend diff --git a/cryptography/hazmat/bindings/interfaces.py b/cryptography/hazmat/bindings/interfaces.py deleted file mode 100644 index 912476bb..00000000 --- a/cryptography/hazmat/bindings/interfaces.py +++ /dev/null @@ -1,66 +0,0 @@ -# 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 - -import abc - -import six - - -class CipherBackend(six.with_metaclass(abc.ABCMeta)): - @abc.abstractmethod - def cipher_supported(self, cipher, mode): - """ - Return True if the given cipher and mode are supported. - """ - - @abc.abstractmethod - def register_cipher_adapter(self, cipher, mode, adapter): - """ - Register an adapter for a cipher and mode to a backend specific object. - """ - - @abc.abstractmethod - def create_symmetric_encryption_ctx(self, cipher, mode): - """ - Get a CipherContext that can be used for encryption. - """ - - @abc.abstractmethod - def create_symmetric_decryption_ctx(self, cipher, mode): - """ - Get a CipherContext that can be used for decryption. - """ - - -class HashBackend(six.with_metaclass(abc.ABCMeta)): - @abc.abstractmethod - def hash_supported(self, algorithm): - """ - Return True if the hash algorithm is supported by this backend. - """ - - @abc.abstractmethod - def create_hash_ctx(self, algorithm): - """ - Create a HashContext for calculating a message digest. - """ - - -class HMACBackend(six.with_metaclass(abc.ABCMeta)): - @abc.abstractmethod - def create_hmac_ctx(self, key, algorithm): - """ - Create a HashContext for calculating a message authentication code. - """ diff --git a/cryptography/hazmat/bindings/openssl/__init__.py b/cryptography/hazmat/bindings/openssl/__init__.py deleted file mode 100644 index 44267efd..00000000 --- a/cryptography/hazmat/bindings/openssl/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# 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 cryptography.hazmat.bindings.openssl.backend import backend - - -__all__ = ["backend"] diff --git a/cryptography/hazmat/bindings/openssl/asn1.py b/cryptography/hazmat/bindings/openssl/asn1.py deleted file mode 100644 index 719a523c..00000000 --- a/cryptography/hazmat/bindings/openssl/asn1.py +++ /dev/null @@ -1,124 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... time_t; - -typedef int ASN1_BOOLEAN; -typedef ... ASN1_INTEGER; - -struct asn1_string_st { - int length; - int type; - unsigned char *data; - long flags; -}; - -typedef struct asn1_string_st ASN1_OCTET_STRING; -typedef struct asn1_string_st ASN1_IA5STRING; -typedef ... ASN1_OBJECT; -typedef ... ASN1_STRING; -typedef ... ASN1_TYPE; -typedef ... ASN1_GENERALIZEDTIME; -typedef ... ASN1_ENUMERATED; -typedef ... ASN1_ITEM; -typedef ... ASN1_VALUE; - -typedef struct { - ...; -} ASN1_TIME; -typedef const ASN1_ITEM ASN1_ITEM_EXP; - -typedef ... ASN1_UTCTIME; - -static const int V_ASN1_GENERALIZEDTIME; - -static const int MBSTRING_UTF8; -""" - -FUNCTIONS = """ -ASN1_OBJECT *ASN1_OBJECT_new(); -void ASN1_OBJECT_free(ASN1_OBJECT *); - -/* ASN1 OBJECT IDENTIFIER */ -ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **, const unsigned char **, long); -int i2d_ASN1_OBJECT(ASN1_OBJECT *, unsigned char **); - -/* ASN1 STRING */ -ASN1_STRING *ASN1_STRING_new(); -ASN1_STRING *ASN1_STRING_type_new(int); -void ASN1_STRING_free(ASN1_STRING *); -unsigned char *ASN1_STRING_data(ASN1_STRING *); -int ASN1_STRING_set(ASN1_STRING *, const void *, int); -int ASN1_STRING_type(ASN1_STRING *); -int ASN1_STRING_to_UTF8(unsigned char **, ASN1_STRING *); - -/* ASN1 OCTET STRING */ -ASN1_OCTET_STRING *ASN1_OCTET_STRING_new(); -void ASN1_OCTET_STRING_free(ASN1_OCTET_STRING *); -int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *, const unsigned char *, int); - -/* ASN1 INTEGER */ -ASN1_INTEGER *ASN1_INTEGER_new(); -void ASN1_INTEGER_free(ASN1_INTEGER *); -int ASN1_INTEGER_set(ASN1_INTEGER *, long); -int i2a_ASN1_INTEGER(BIO *, ASN1_INTEGER *); - -/* ASN1 TIME */ -ASN1_TIME *ASN1_TIME_new(); -ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *, - ASN1_GENERALIZEDTIME **); - -/* ASN1 UTCTIME */ -int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t); - -/* ASN1 GENERALIZEDTIME */ -int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *); -void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *); -int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *); - -/* ASN1 ENUMERATED */ -ASN1_ENUMERATED *ASN1_ENUMERATED_new(); -void ASN1_ENUMERATED_free(ASN1_ENUMERATED *); -int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long); - -ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long, - const ASN1_ITEM *); -""" - -MACROS = """ -ASN1_TIME *M_ASN1_TIME_dup(void *); -ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM *); - -/* These aren't macros these arguments are all const X on openssl > 1.0.x */ - -int ASN1_STRING_length(ASN1_STRING *); -ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *); -int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *); - -ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(ASN1_OCTET_STRING *); -int ASN1_OCTET_STRING_cmp(ASN1_OCTET_STRING *, ASN1_OCTET_STRING *); - -ASN1_INTEGER *ASN1_INTEGER_dup(ASN1_INTEGER *); -int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *); -long ASN1_INTEGER_get(ASN1_INTEGER *); - -BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *); -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py deleted file mode 100644 index f19c8cca..00000000 --- a/cryptography/hazmat/bindings/openssl/backend.py +++ /dev/null @@ -1,480 +0,0 @@ -# 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 - -import itertools -import sys - -import cffi - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm, InvalidTag -from cryptography.hazmat.bindings.interfaces import ( - CipherBackend, HashBackend, HMACBackend -) -from cryptography.hazmat.primitives import interfaces -from cryptography.hazmat.primitives.ciphers.algorithms import ( - AES, Blowfish, Camellia, CAST5, TripleDES, ARC4, -) -from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, CTR, ECB, OFB, CFB, GCM, -) - -_OSX_PRE_INCLUDE = """ -#ifdef __APPLE__ -#include -#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ - DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#endif -""" - -_OSX_POST_INCLUDE = """ -#ifdef __APPLE__ -#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ - __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#endif -""" - - -@utils.register_interface(CipherBackend) -@utils.register_interface(HashBackend) -@utils.register_interface(HMACBackend) -class Backend(object): - """ - OpenSSL API wrapper. - """ - _modules = [ - "asn1", - "bignum", - "bio", - "conf", - "crypto", - "dh", - "dsa", - "engine", - "err", - "evp", - "hmac", - "nid", - "opensslv", - "pem", - "pkcs7", - "pkcs12", - "rand", - "rsa", - "ssl", - "x509", - "x509name", - "x509v3", - ] - - ffi = None - lib = None - - def __init__(self): - self._ensure_ffi_initialized() - - self._cipher_registry = {} - self._register_default_ciphers() - - @classmethod - def _ensure_ffi_initialized(cls): - if cls.ffi is not None and cls.lib is not None: - return - - ffi = cffi.FFI() - includes = [] - functions = [] - macros = [] - customizations = [] - for name in cls._modules: - module_name = "cryptography.hazmat.bindings.openssl." + name - __import__(module_name) - module = sys.modules[module_name] - - ffi.cdef(module.TYPES) - - macros.append(module.MACROS) - functions.append(module.FUNCTIONS) - includes.append(module.INCLUDES) - customizations.append(module.CUSTOMIZATIONS) - - # loop over the functions & macros after declaring all the types - # so we can set interdependent types in different files and still - # have them all defined before we parse the funcs & macros - for func in functions: - ffi.cdef(func) - for macro in macros: - ffi.cdef(macro) - - # We include functions here so that if we got any of their definitions - # wrong, the underlying C compiler will explode. In C you are allowed - # to re-declare a function if it has the same signature. That is: - # int foo(int); - # int foo(int); - # is legal, but the following will fail to compile: - # int foo(int); - # int foo(short); - - lib = ffi.verify( - source="\n".join( - [_OSX_PRE_INCLUDE] + - includes + - [_OSX_POST_INCLUDE] + - functions + - customizations - ), - libraries=["crypto", "ssl"], - ) - - cls.ffi = ffi - cls.lib = lib - cls.lib.OpenSSL_add_all_algorithms() - cls.lib.SSL_load_error_strings() - - def openssl_version_text(self): - """ - Friendly string name of linked OpenSSL. - - Example: OpenSSL 1.0.1e 11 Feb 2013 - """ - 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") - ) - self.register_cipher_adapter( - AES, - GCM, - GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") - ) - - 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) - - def _handle_error(self, mode): - code = self.lib.ERR_get_error() - if not code and isinstance(mode, GCM): - raise InvalidTag - assert code != 0 - lib = self.lib.ERR_GET_LIB(code) - func = self.lib.ERR_GET_FUNC(code) - reason = self.lib.ERR_GET_REASON(code) - return self._handle_error_code(lib, func, reason) - - def _handle_error_code(self, lib, func, reason): - if lib == self.lib.ERR_LIB_EVP: - if func == self.lib.EVP_F_EVP_ENCRYPTFINAL_EX: - if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: - raise ValueError( - "The length of the provided data is not a multiple of " - "the block length" - ) - elif func == self.lib.EVP_F_EVP_DECRYPTFINAL_EX: - if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: - raise ValueError( - "The length of the provided data is not a multiple of " - "the block length" - ) - - raise SystemError( - "Unknown error code from OpenSSL, you should probably file a bug." - ) - - -class GetCipherByName(object): - def __init__(self, fmt): - self._fmt = fmt - - def __call__(self, backend, cipher, mode): - cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() - return backend.lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) - - -@utils.register_interface(interfaces.CipherContext) -@utils.register_interface(interfaces.AEADCipherContext) -@utils.register_interface(interfaces.AEADEncryptionContext) -class _CipherContext(object): - _ENCRYPT = 1 - _DECRYPT = 0 - - def __init__(self, backend, cipher, mode, operation): - self._backend = backend - self._cipher = cipher - self._mode = mode - self._operation = operation - self._tag = None - - ctx = self._backend.lib.EVP_CIPHER_CTX_new() - ctx = self._backend.ffi.gc(ctx, self._backend.lib.EVP_CIPHER_CTX_free) - - registry = self._backend._cipher_registry - try: - adapter = registry[type(cipher), type(mode)] - except KeyError: - raise UnsupportedAlgorithm - - evp_cipher = adapter(self._backend, cipher, mode) - if evp_cipher == self._backend.ffi.NULL: - raise UnsupportedAlgorithm - - if isinstance(mode, interfaces.ModeWithInitializationVector): - iv_nonce = mode.initialization_vector - elif isinstance(mode, interfaces.ModeWithNonce): - iv_nonce = mode.nonce - else: - iv_nonce = self._backend.ffi.NULL - # begin init with cipher and operation type - res = self._backend.lib.EVP_CipherInit_ex(ctx, evp_cipher, - self._backend.ffi.NULL, - self._backend.ffi.NULL, - self._backend.ffi.NULL, - operation) - assert res != 0 - # set the key length to handle variable key ciphers - res = self._backend.lib.EVP_CIPHER_CTX_set_key_length( - ctx, len(cipher.key) - ) - assert res != 0 - if isinstance(mode, GCM): - res = self._backend.lib.EVP_CIPHER_CTX_ctrl( - ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_IVLEN, - len(iv_nonce), self._backend.ffi.NULL - ) - assert res != 0 - if operation == self._DECRYPT: - if not mode.tag: - raise ValueError("Authentication tag must be supplied " - "when decrypting") - res = self._backend.lib.EVP_CIPHER_CTX_ctrl( - ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_SET_TAG, - len(mode.tag), mode.tag - ) - assert res != 0 - else: - if mode.tag: - raise ValueError("Authentication tag must be None when " - "encrypting") - - # pass key/iv - res = self._backend.lib.EVP_CipherInit_ex(ctx, self._backend.ffi.NULL, - self._backend.ffi.NULL, - cipher.key, - iv_nonce, - operation) - assert res != 0 - # We purposely disable padding here as it's handled higher up in the - # API. - self._backend.lib.EVP_CIPHER_CTX_set_padding(ctx, 0) - self._ctx = ctx - - def update(self, data): - buf = self._backend.ffi.new("unsigned char[]", - 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)) - assert res != 0 - return self._backend.ffi.buffer(buf)[:outlen[0]] - - def finalize(self): - 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) - if res == 0: - self._backend._handle_error(self._mode) - - if (isinstance(self._mode, GCM) and - self._operation == self._ENCRYPT): - block_byte_size = self._cipher.block_size // 8 - tag_buf = self._backend.ffi.new("unsigned char[]", block_byte_size) - res = self._backend.lib.EVP_CIPHER_CTX_ctrl( - self._ctx, self._backend.lib.Cryptography_EVP_CTRL_GCM_GET_TAG, - block_byte_size, tag_buf - ) - assert res != 0 - self._tag = self._backend.ffi.buffer(tag_buf)[:] - - res = self._backend.lib.EVP_CIPHER_CTX_cleanup(self._ctx) - assert res == 1 - return self._backend.ffi.buffer(buf)[:outlen[0]] - - def authenticate_additional_data(self, data): - outlen = self._backend.ffi.new("int *") - res = self._backend.lib.EVP_CipherUpdate( - self._ctx, self._backend.ffi.NULL, outlen, data, len(data) - ) - assert res != 0 - - @property - def tag(self): - return self._tag - - -@utils.register_interface(interfaces.HashContext) -class _HashContext(object): - def __init__(self, backend, algorithm, ctx=None): - self.algorithm = algorithm - - 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 - - self._ctx = ctx - - 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 _HashContext(self._backend, self.algorithm, ctx=copied_ctx) - - def update(self, data): - res = self._backend.lib.EVP_DigestUpdate(self._ctx, data, len(data)) - assert res != 0 - - 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(self._ctx) - assert res == 1 - return self._backend.ffi.buffer(buf)[:] - - -@utils.register_interface(interfaces.HashContext) -class _HMACContext(object): - def __init__(self, backend, key, algorithm, ctx=None): - self.algorithm = algorithm - self._backend = backend - - 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 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 update(self, data): - res = self._backend.lib.Cryptography_HMAC_Update( - self._ctx, data, len(data) - ) - assert res != 0 - - 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 - self._backend.lib.HMAC_CTX_cleanup(self._ctx) - return self._backend.ffi.buffer(buf)[:] - - -backend = Backend() diff --git a/cryptography/hazmat/bindings/openssl/bignum.py b/cryptography/hazmat/bindings/openssl/bignum.py deleted file mode 100644 index 1b0fe5ab..00000000 --- a/cryptography/hazmat/bindings/openssl/bignum.py +++ /dev/null @@ -1,40 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... BIGNUM; -typedef ... BN_ULONG; -""" - -FUNCTIONS = """ -BIGNUM *BN_new(); -void BN_free(BIGNUM *); - -int BN_set_word(BIGNUM *, BN_ULONG); - -char *BN_bn2hex(const BIGNUM *); -int BN_hex2bn(BIGNUM **, const char *); -int BN_dec2bn(BIGNUM **, const char *); - -int BN_num_bits(const BIGNUM *); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/bio.py b/cryptography/hazmat/bindings/openssl/bio.py deleted file mode 100644 index c23dd0d8..00000000 --- a/cryptography/hazmat/bindings/openssl/bio.py +++ /dev/null @@ -1,173 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef struct bio_st BIO; -typedef void bio_info_cb(BIO *, int, const char *, int, long, long); -struct bio_method_st { - int type; - const char *name; - int (*bwrite)(BIO *, const char *, int); - int (*bread)(BIO *, char *, int); - int (*bputs)(BIO *, const char *); - int (*bgets)(BIO *, char*, int); - long (*ctrl)(BIO *, int, long, void *); - int (*create)(BIO *); - int (*destroy)(BIO *); - long (*callback_ctrl)(BIO *, int, bio_info_cb *); - ...; -}; -typedef struct bio_method_st BIO_METHOD; -struct bio_st { - BIO_METHOD *method; - long (*callback)(struct bio_st*, int, const char*, int, long, long); - char *cb_arg; - int init; - int shutdown; - int flags; - int retry_reason; - int num; - void *ptr; - struct bio_st *next_bio; - struct bio_st *prev_bio; - int references; - unsigned long num_read; - unsigned long num_write; - ...; -}; -typedef ... BUF_MEM; -""" - -FUNCTIONS = """ -BIO* BIO_new(BIO_METHOD *); -int BIO_set(BIO *, BIO_METHOD *); -int BIO_free(BIO *); -void BIO_vfree(BIO *); -void BIO_free_all(BIO *); -BIO *BIO_push(BIO *, BIO *); -BIO *BIO_pop(BIO *); -BIO *BIO_next(BIO *); -BIO *BIO_find_type(BIO *, int); -int BIO_method_type(const BIO *); -BIO_METHOD *BIO_s_mem(); -BIO *BIO_new_mem_buf(void *, int); -BIO_METHOD *BIO_s_file(); -BIO *BIO_new_file(const char *, const char *); -BIO *BIO_new_fp(FILE *, int); -BIO_METHOD *BIO_s_fd(); -BIO *BIO_new_fd(int, int); -BIO_METHOD *BIO_s_socket(); -BIO *BIO_new_socket(int, int); -BIO_METHOD *BIO_s_null(); -long BIO_ctrl(BIO *, int, long, void *); -long BIO_callback_ctrl( - BIO *, - int, - void (*)(struct bio_st *, int, const char *, int, long, long) -); -char* BIO_ptr_ctrl(BIO *bp, int cmd, long larg); -long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); -size_t BIO_ctrl_pending(BIO *b); -size_t BIO_ctrl_wpending(BIO *b); -int BIO_read(BIO *, void *, int); -int BIO_gets(BIO *, char *, int); -int BIO_write(BIO *, const void *, int); -int BIO_puts(BIO *, const char *); -BIO_METHOD *BIO_f_null(); -BIO_METHOD *BIO_f_buffer(); -""" - -MACROS = """ -long BIO_set_fd(BIO *, long, int); -long BIO_get_fd(BIO *, char *); -long BIO_set_mem_eof_return(BIO *, int); -long BIO_get_mem_data(BIO *, char **); -long BIO_set_mem_buf(BIO *, BUF_MEM *, int); -long BIO_get_mem_ptr(BIO *, BUF_MEM **); -long BIO_set_fp(BIO *, FILE *, int); -long BIO_get_fp(BIO *, FILE **); -int BIO_read_filename(BIO *, char *); -int BIO_write_filename(BIO *, char *); -int BIO_append_filename(BIO *, char *); -int BIO_rw_filename(BIO *, char *); -int BIO_should_read(BIO *); -int BIO_should_write(BIO *); -int BIO_should_io_special(BIO *); -int BIO_retry_type(BIO *); -int BIO_should_retry(BIO *); -int BIO_reset(BIO *); -int BIO_seek(BIO *, int); -int BIO_tell(BIO *); -int BIO_flush(BIO *); -int BIO_eof(BIO *); -int BIO_set_close(BIO *,long); -int BIO_get_close(BIO *); -int BIO_pending(BIO *); -int BIO_wpending(BIO *); -int BIO_get_info_callback(BIO *, bio_info_cb **); -int BIO_set_info_callback(BIO *, bio_info_cb *); -long BIO_get_buffer_num_lines(BIO *); -long BIO_set_read_buffer_size(BIO *, long); -long BIO_set_write_buffer_size(BIO *, long); -long BIO_set_buffer_size(BIO *, long); -long BIO_set_buffer_read_data(BIO *, void *, long); -#define BIO_TYPE_MEM ... -#define BIO_TYPE_FILE ... -#define BIO_TYPE_FD ... -#define BIO_TYPE_SOCKET ... -#define BIO_TYPE_CONNECT ... -#define BIO_TYPE_ACCEPT ... -#define BIO_TYPE_NULL ... -#define BIO_CLOSE ... -#define BIO_NOCLOSE ... -#define BIO_TYPE_SOURCE_SINK ... -#define BIO_CTRL_RESET ... -#define BIO_CTRL_EOF ... -#define BIO_CTRL_SET ... -#define BIO_CTRL_SET_CLOSE ... -#define BIO_CTRL_FLUSH ... -#define BIO_CTRL_DUP ... -#define BIO_CTRL_GET_CLOSE ... -#define BIO_CTRL_INFO ... -#define BIO_CTRL_GET ... -#define BIO_CTRL_PENDING ... -#define BIO_CTRL_WPENDING ... -#define BIO_C_FILE_SEEK ... -#define BIO_C_FILE_TELL ... -#define BIO_TYPE_NONE ... -#define BIO_TYPE_PROXY_CLIENT ... -#define BIO_TYPE_PROXY_SERVER ... -#define BIO_TYPE_NBIO_TEST ... -#define BIO_TYPE_BER ... -#define BIO_TYPE_BIO ... -#define BIO_TYPE_DESCRIPTOR ... -#define BIO_FLAGS_READ ... -#define BIO_FLAGS_WRITE ... -#define BIO_FLAGS_IO_SPECIAL ... -#define BIO_FLAGS_RWS ... -#define BIO_FLAGS_SHOULD_RETRY ... -#define BIO_TYPE_NULL_FILTER ... -#define BIO_TYPE_SSL ... -#define BIO_TYPE_MD ... -#define BIO_TYPE_BUFFER ... -#define BIO_TYPE_CIPHER ... -#define BIO_TYPE_BASE64 ... -#define BIO_TYPE_FILTER ... -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/conf.py b/cryptography/hazmat/bindings/openssl/conf.py deleted file mode 100644 index 4846252c..00000000 --- a/cryptography/hazmat/bindings/openssl/conf.py +++ /dev/null @@ -1,29 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... CONF; -""" - -FUNCTIONS = """ -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/crypto.py b/cryptography/hazmat/bindings/openssl/crypto.py deleted file mode 100644 index 773d9b14..00000000 --- a/cryptography/hazmat/bindings/openssl/crypto.py +++ /dev/null @@ -1,40 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -""" - -FUNCTIONS = """ -void CRYPTO_free(void *); -int CRYPTO_mem_ctrl(int); -int CRYPTO_is_mem_check_on(); -void CRYPTO_mem_leaks(struct bio_st *); -void CRYPTO_cleanup_all_ex_data(); -""" - -MACROS = """ -void CRYPTO_add(int *, int, int); -void CRYPTO_malloc_init(); -void CRYPTO_malloc_debug_init(); -#define CRYPTO_MEM_CHECK_ON ... -#define CRYPTO_MEM_CHECK_OFF ... -#define CRYPTO_MEM_CHECK_ENABLE ... -#define CRYPTO_MEM_CHECK_DISABLE ... -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/dh.py b/cryptography/hazmat/bindings/openssl/dh.py deleted file mode 100644 index b8fbf368..00000000 --- a/cryptography/hazmat/bindings/openssl/dh.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... DH; -""" - -FUNCTIONS = """ -DH *DH_new(); -void DH_free(DH *); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py deleted file mode 100644 index e6c369a6..00000000 --- a/cryptography/hazmat/bindings/openssl/dsa.py +++ /dev/null @@ -1,33 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... DSA; -""" - -FUNCTIONS = """ -DSA *DSA_generate_parameters(int, unsigned char *, int, int *, unsigned long *, - void (*)(int, int, void *), void *); -int DSA_generate_key(DSA *); -void DSA_free(DSA *); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/engine.py b/cryptography/hazmat/bindings/openssl/engine.py deleted file mode 100644 index 1f377665..00000000 --- a/cryptography/hazmat/bindings/openssl/engine.py +++ /dev/null @@ -1,65 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... ENGINE; -""" - -FUNCTIONS = """ -ENGINE *ENGINE_get_first(); -ENGINE *ENGINE_get_last(); -ENGINE *ENGINE_get_next(ENGINE *); -ENGINE *ENGINE_get_prev(ENGINE *); -int ENGINE_add(ENGINE *); -int ENGINE_remove(ENGINE *); -ENGINE *ENGINE_by_id(const char *); -int ENGINE_init(ENGINE *); -int ENGINE_finish(ENGINE *); -int ENGINE_free(ENGINE *); -void ENGINE_cleanup(); -void ENGINE_load_dynamic(); -void ENGINE_load_builtin_engines(); -int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int); -int ENGINE_set_default(ENGINE *, unsigned int); -int ENGINE_register_complete(ENGINE *); - -int ENGINE_set_default_RSA(ENGINE *); -int ENGINE_set_default_string(ENGINE *, const char *); -int ENGINE_set_default_DSA(ENGINE *); -int ENGINE_set_default_ECDH(ENGINE *); -int ENGINE_set_default_ECDSA(ENGINE *); -int ENGINE_set_default_DH(ENGINE *); -int ENGINE_set_default_RAND(ENGINE *); -int ENGINE_set_default_ciphers(ENGINE *); -int ENGINE_set_default_digests(ENGINE *); -""" - -MACROS = """ -#define ENGINE_METHOD_RSA ... -#define ENGINE_METHOD_DSA ... -#define ENGINE_METHOD_RAND ... -#define ENGINE_METHOD_ECDH ... -#define ENGINE_METHOD_ECDSA ... -#define ENGINE_METHOD_CIPHERS ... -#define ENGINE_METHOD_DIGESTS ... -#define ENGINE_METHOD_STORE ... -#define ENGINE_METHOD_ALL ... -#define ENGINE_METHOD_NONE ... -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py deleted file mode 100644 index f31c2405..00000000 --- a/cryptography/hazmat/bindings/openssl/err.py +++ /dev/null @@ -1,76 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -struct ERR_string_data_st { - unsigned long error; - const char *string; -}; -typedef struct ERR_string_data_st ERR_STRING_DATA; - -static const int ERR_LIB_EVP; -static const int ERR_LIB_PEM; - -static const int EVP_F_EVP_ENCRYPTFINAL_EX; -static const int EVP_F_EVP_DECRYPTFINAL_EX; - -static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH; - -static const int PEM_F_PEM_READ_BIO_PRIVATEKEY; -static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO; - -static const int PEM_R_BAD_PASSWORD_READ; -static const int ASN1_R_BAD_PASSWORD_READ; -""" - -FUNCTIONS = """ -void ERR_load_crypto_strings(); -void ERR_free_strings(); -char* ERR_error_string(unsigned long, char *); -void ERR_error_string_n(unsigned long, char *, size_t); -const char* ERR_lib_error_string(unsigned long); -const char* ERR_func_error_string(unsigned long); -const char* ERR_reason_error_string(unsigned long); -void ERR_print_errors(BIO *); -void ERR_print_errors_fp(FILE *); -unsigned long ERR_get_error(); -unsigned long ERR_peek_error(); -unsigned long ERR_peek_last_error(); -unsigned long ERR_get_error_line(const char **, int *); -unsigned long ERR_peek_error_line(const char **, int *); -unsigned long ERR_peek_last_error_line(const char **, int *); -unsigned long ERR_get_error_line_data(const char **, int *, - const char **, int *); -unsigned long ERR_peek_error_line_data(const char **, - int *, const char **, int *); -unsigned long ERR_peek_last_error_line_data(const char **, - int *, const char **, int *); -void ERR_put_error(int, int, int, const char *, int); -void ERR_add_error_data(int, ...); -int ERR_get_next_error_library(); -""" - -MACROS = """ -unsigned long ERR_PACK(int, int, int); -int ERR_GET_LIB(unsigned long); -int ERR_GET_FUNC(unsigned long); -int ERR_GET_REASON(unsigned long); -int ERR_FATAL_ERROR(unsigned long); -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/evp.py b/cryptography/hazmat/bindings/openssl/evp.py deleted file mode 100644 index 8cb44610..00000000 --- a/cryptography/hazmat/bindings/openssl/evp.py +++ /dev/null @@ -1,112 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... EVP_CIPHER; -typedef struct { - const EVP_CIPHER *cipher; - ENGINE *engine; - int encrypt; - ...; -} EVP_CIPHER_CTX; -typedef ... EVP_MD; -typedef struct env_md_ctx_st EVP_MD_CTX; - -typedef struct evp_pkey_st { - int type; - ...; -} EVP_PKEY; -static const int EVP_PKEY_RSA; -static const int EVP_PKEY_DSA; -static const int Cryptography_EVP_CTRL_GCM_SET_IVLEN; -static const int Cryptography_EVP_CTRL_GCM_GET_TAG; -static const int Cryptography_EVP_CTRL_GCM_SET_TAG; -""" - -FUNCTIONS = """ -void OpenSSL_add_all_algorithms(); - -const EVP_CIPHER *EVP_get_cipherbyname(const char *); -int EVP_EncryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, - const unsigned char *, const unsigned char *); -int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); -int EVP_EncryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, - const unsigned char *, int); -int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); -int EVP_DecryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, - const unsigned char *, const unsigned char *); -int EVP_DecryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, - const unsigned char *, int); -int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); -int EVP_CipherInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, - const unsigned char *, const unsigned char *, int); -int EVP_CipherUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, - const unsigned char *, int); -int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); -int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); -const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *); -int EVP_CIPHER_block_size(const EVP_CIPHER *); -void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); -EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(); -void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); -int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *, int); - -EVP_MD_CTX *EVP_MD_CTX_create(); -int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *); -int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *); -int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t); -int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); -int EVP_MD_CTX_cleanup(EVP_MD_CTX *); -void EVP_MD_CTX_destroy(EVP_MD_CTX *); -const EVP_MD *EVP_get_digestbyname(const char *); -const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *); -int EVP_MD_size(const EVP_MD *); - -EVP_PKEY *EVP_PKEY_new(); -void EVP_PKEY_free(EVP_PKEY *); -int EVP_PKEY_type(int); -int EVP_PKEY_bits(EVP_PKEY *); -RSA *EVP_PKEY_get1_RSA(EVP_PKEY *); - -int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *); -int EVP_SignUpdate(EVP_MD_CTX *, const void *, size_t); -int EVP_SignFinal(EVP_MD_CTX *, unsigned char *, unsigned int *, EVP_PKEY *); - -int EVP_VerifyInit(EVP_MD_CTX *, const EVP_MD *); -int EVP_VerifyUpdate(EVP_MD_CTX *, const void *, size_t); -int EVP_VerifyFinal(EVP_MD_CTX *, const unsigned char *, unsigned int, - EVP_PKEY *); -""" - -MACROS = """ -int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *); -int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *); -int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *); -int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *); -""" - -CUSTOMIZATIONS = """ -#ifdef EVP_CTRL_GCM_SET_TAG -const int Cryptography_EVP_CTRL_GCM_GET_TAG = EVP_CTRL_GCM_GET_TAG; -const int Cryptography_EVP_CTRL_GCM_SET_TAG = EVP_CTRL_GCM_SET_TAG; -const int Cryptography_EVP_CTRL_GCM_SET_IVLEN = EVP_CTRL_GCM_SET_IVLEN; -#else -const int Cryptography_EVP_CTRL_GCM_GET_TAG = -1; -const int Cryptography_EVP_CTRL_GCM_SET_TAG = -1; -const int Cryptography_EVP_CTRL_GCM_SET_IVLEN = -1; -#endif -""" diff --git a/cryptography/hazmat/bindings/openssl/hmac.py b/cryptography/hazmat/bindings/openssl/hmac.py deleted file mode 100644 index 10e67141..00000000 --- a/cryptography/hazmat/bindings/openssl/hmac.py +++ /dev/null @@ -1,90 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef struct { ...; } HMAC_CTX; -""" - -FUNCTIONS = """ -void HMAC_CTX_init(HMAC_CTX *); -void HMAC_CTX_cleanup(HMAC_CTX *); - -int Cryptography_HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, - ENGINE *); -int Cryptography_HMAC_Update(HMAC_CTX *, const unsigned char *, size_t); -int Cryptography_HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *); -int Cryptography_HMAC_CTX_copy(HMAC_CTX *, HMAC_CTX *); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -int Cryptography_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, - const EVP_MD *md, ENGINE *impl) { -#if OPENSSL_VERSION_NUMBER >= 0x010000000 - return HMAC_Init_ex(ctx, key, key_len, md, impl); -#else - HMAC_Init_ex(ctx, key, key_len, md, impl); - return 1; -#endif -} - -int Cryptography_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, - size_t data_len) { -#if OPENSSL_VERSION_NUMBER >= 0x010000000 - return HMAC_Update(ctx, data, data_len); -#else - HMAC_Update(ctx, data, data_len); - return 1; -#endif -} - -int Cryptography_HMAC_Final(HMAC_CTX *ctx, unsigned char *digest, - unsigned int *digest_len) { -#if OPENSSL_VERSION_NUMBER >= 0x010000000 - return HMAC_Final(ctx, digest, digest_len); -#else - HMAC_Final(ctx, digest, digest_len); - return 1; -#endif -} - -int Cryptography_HMAC_CTX_copy(HMAC_CTX *dst_ctx, HMAC_CTX *src_ctx) { -#if OPENSSL_VERSION_NUMBER >= 0x010000000 - return HMAC_CTX_copy(dst_ctx, src_ctx); -#else - HMAC_CTX_init(dst_ctx); - if (!EVP_MD_CTX_copy_ex(&dst_ctx->i_ctx, &src_ctx->i_ctx)) { - goto err; - } - if (!EVP_MD_CTX_copy_ex(&dst_ctx->o_ctx, &src_ctx->o_ctx)) { - goto err; - } - if (!EVP_MD_CTX_copy_ex(&dst_ctx->md_ctx, &src_ctx->md_ctx)) { - goto err; - } - memcpy(dst_ctx->key, src_ctx->key, HMAC_MAX_MD_CBLOCK); - dst_ctx->key_length = src_ctx->key_length; - dst_ctx->md = src_ctx->md; - return 1; - - err: - return 0; -#endif -} -""" diff --git a/cryptography/hazmat/bindings/openssl/nid.py b/cryptography/hazmat/bindings/openssl/nid.py deleted file mode 100644 index 9816dde4..00000000 --- a/cryptography/hazmat/bindings/openssl/nid.py +++ /dev/null @@ -1,49 +0,0 @@ -# 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. - -INCLUDES = "" - -TYPES = """ -static const int NID_undef; -static const int NID_dsa; -static const int NID_dsaWithSHA; -static const int NID_dsaWithSHA1; -static const int NID_md2; -static const int NID_md4; -static const int NID_md5; -static const int NID_mdc2; -static const int NID_ripemd160; -static const int NID_sha; -static const int NID_sha1; -static const int NID_sha256; -static const int NID_sha384; -static const int NID_sha512; -static const int NID_sha224; -static const int NID_sha; -static const int NID_ecdsa_with_SHA1; -static const int NID_ecdsa_with_SHA224; -static const int NID_ecdsa_with_SHA256; -static const int NID_ecdsa_with_SHA384; -static const int NID_ecdsa_with_SHA512; -static const int NID_crl_reason; -static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC; -""" - -FUNCTIONS = """ -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/opensslv.py b/cryptography/hazmat/bindings/openssl/opensslv.py deleted file mode 100644 index d463776c..00000000 --- a/cryptography/hazmat/bindings/openssl/opensslv.py +++ /dev/null @@ -1,29 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -static char *const OPENSSL_VERSION_TEXT; -""" - -FUNCTIONS = """ -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/pem.py b/cryptography/hazmat/bindings/openssl/pem.py deleted file mode 100644 index cef7839f..00000000 --- a/cryptography/hazmat/bindings/openssl/pem.py +++ /dev/null @@ -1,57 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata); -""" - -FUNCTIONS = """ -X509 *PEM_read_bio_X509(BIO *, X509 **, pem_password_cb *, void *); -int PEM_write_bio_X509(BIO *, X509 *); - -int PEM_write_bio_PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, - unsigned char *, int, pem_password_cb *, void *); - -EVP_PKEY *PEM_read_bio_PrivateKey(BIO *, EVP_PKEY **, pem_password_cb *, - void *); - -int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, - char *, int, pem_password_cb *, void *); - -int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *, - char *, int, pem_password_cb *, void *); - -EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *, EVP_PKEY **, pem_password_cb *, - void *); - -int PEM_write_bio_X509_REQ(BIO *, X509_REQ *); - -X509_REQ *PEM_read_bio_X509_REQ(BIO *, X509_REQ **, pem_password_cb *, void *); - -X509_CRL *PEM_read_bio_X509_CRL(BIO *, X509_CRL **, pem_password_cb *, void *); - -int PEM_write_bio_X509_CRL(BIO *, X509_CRL *); - -PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *); -DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/pkcs12.py b/cryptography/hazmat/bindings/openssl/pkcs12.py deleted file mode 100644 index d91d100f..00000000 --- a/cryptography/hazmat/bindings/openssl/pkcs12.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... PKCS12; -""" - -FUNCTIONS = """ -void PKCS12_free(PKCS12 *); - -PKCS12 *d2i_PKCS12_bio(BIO *, PKCS12 **); -int i2d_PKCS12_bio(BIO *, PKCS12 *); -""" - -MACROS = """ -int PKCS12_parse(PKCS12 *, const char *, EVP_PKEY **, X509 **, - struct stack_st_X509 **); -PKCS12 *PKCS12_create(char *, char *, EVP_PKEY *, X509 *, - struct stack_st_X509 *, int, int, int, int, int); -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/pkcs7.py b/cryptography/hazmat/bindings/openssl/pkcs7.py deleted file mode 100644 index 60ea3c52..00000000 --- a/cryptography/hazmat/bindings/openssl/pkcs7.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef struct { - ASN1_OBJECT *type; - ...; -} PKCS7; -""" - -FUNCTIONS = """ -void PKCS7_free(PKCS7 *); -""" - -MACROS = """ -int PKCS7_type_is_signed(PKCS7 *); -int PKCS7_type_is_enveloped(PKCS7 *); -int PKCS7_type_is_signedAndEnveloped(PKCS7 *); -int PKCS7_type_is_data(PKCS7 *); -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/rand.py b/cryptography/hazmat/bindings/openssl/rand.py deleted file mode 100644 index 848ee05a..00000000 --- a/cryptography/hazmat/bindings/openssl/rand.py +++ /dev/null @@ -1,40 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -""" - -FUNCTIONS = """ -void RAND_seed(const void *, int); -void RAND_add(const void *, int, double); -int RAND_status(); -int RAND_egd(const char *); -int RAND_egd_bytes(const char *, int); -int RAND_query_egd_bytes(const char *, unsigned char *, int); -const char *RAND_file_name(char *, size_t); -int RAND_load_file(const char *, long); -int RAND_write_file(const char *); -void RAND_cleanup(); -int RAND_bytes(unsigned char *, int); -int RAND_pseudo_bytes(unsigned char *, int); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py deleted file mode 100644 index ad0d37b4..00000000 --- a/cryptography/hazmat/bindings/openssl/rsa.py +++ /dev/null @@ -1,59 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef struct rsa_st { - BIGNUM *n; - BIGNUM *e; - BIGNUM *d; - BIGNUM *p; - BIGNUM *q; - BIGNUM *dmp1; - BIGNUM *dmq1; - BIGNUM *iqmp; - ...; -} RSA; -typedef ... BN_GENCB; -static const int RSA_PKCS1_PADDING; -static const int RSA_SSLV23_PADDING; -static const int RSA_NO_PADDING; -static const int RSA_PKCS1_OAEP_PADDING; -static const int RSA_X931_PADDING; -""" - -FUNCTIONS = """ -RSA *RSA_new(); -void RSA_free(RSA *); -int RSA_size(const RSA *); -int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *); -int RSA_check_key(const RSA *); -RSA *RSAPublicKey_dup(RSA *); -int RSA_public_encrypt(int, const unsigned char *, unsigned char *, - RSA *, int); -int RSA_private_encrypt(int, const unsigned char *, unsigned char *, - RSA *, int); -int RSA_public_decrypt(int, const unsigned char *, unsigned char *, - RSA *, int); -int RSA_private_decrypt(int, const unsigned char *, unsigned char *, - RSA *, int); -""" - -MACROS = """ -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py deleted file mode 100644 index 04611309..00000000 --- a/cryptography/hazmat/bindings/openssl/ssl.py +++ /dev/null @@ -1,216 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -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 = """ -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/bindings/openssl/x509.py b/cryptography/hazmat/bindings/openssl/x509.py deleted file mode 100644 index b2ee672e..00000000 --- a/cryptography/hazmat/bindings/openssl/x509.py +++ /dev/null @@ -1,190 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef struct { - ASN1_OBJECT *algorithm; - ...; -} X509_ALGOR; - -typedef struct { - X509_ALGOR *signature; - ...; -} X509_CINF; - -typedef struct { - ASN1_OBJECT *object; - ASN1_BOOLEAN critical; - ASN1_OCTET_STRING *value; -} X509_EXTENSION; - -typedef ... X509_EXTENSIONS; - -typedef ... X509_REQ; - -typedef ... x509_revoked_st; - -typedef struct { - ASN1_INTEGER *serialNumber; - ASN1_TIME *revocationDate; - X509_EXTENSIONS *extensions; - int sequence; - ...; -} X509_REVOKED; - -typedef struct { - struct x509_revoked_st *revoked; - ...; -} X509_CRL_INFO; - -typedef struct { - X509_CRL_INFO *crl; - ...; -} X509_CRL; - -typedef struct { - X509_CINF *cert_info; - ...; -} X509; - -typedef ... X509_STORE; -typedef ... NETSCAPE_SPKI; -""" - -FUNCTIONS = """ -X509 *X509_new(); -void X509_free(X509 *); -X509 *X509_dup(X509 *); - -int X509_print_ex(BIO *, X509 *, unsigned long, unsigned long); - -int X509_set_version(X509 *, long); - -EVP_PKEY *X509_get_pubkey(X509 *); -int X509_set_pubkey(X509 *, EVP_PKEY *); - -unsigned char *X509_alias_get0(X509 *, int *); -int X509_sign(X509 *, EVP_PKEY *, const EVP_MD *); - -int X509_digest(const X509 *, const EVP_MD *, unsigned char *, unsigned int *); - -ASN1_TIME *X509_gmtime_adj(ASN1_TIME *, long); - -unsigned long X509_subject_name_hash(X509 *); - -X509_NAME *X509_get_subject_name(X509 *); -int X509_set_subject_name(X509 *, X509_NAME *); - -X509_NAME *X509_get_issuer_name(X509 *); -int X509_set_issuer_name(X509 *, X509_NAME *); - -int X509_get_ext_count(X509 *); -int X509_add_ext(X509 *, X509_EXTENSION *, int); -X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *); -X509_EXTENSION *X509_get_ext(X509 *, int); -int X509_EXTENSION_get_critical(X509_EXTENSION *); -ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *); -void X509_EXTENSION_free(X509_EXTENSION *); - -int X509_REQ_set_version(X509_REQ *, long); -X509_REQ *X509_REQ_new(); -void X509_REQ_free(X509_REQ *); -int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *); -int X509_REQ_sign(X509_REQ *, EVP_PKEY *, const EVP_MD *); -int X509_REQ_verify(X509_REQ *, EVP_PKEY *); -EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *); -int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *); -int X509_REQ_print_ex(BIO *, X509_REQ *, unsigned long, unsigned long); - -int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int); -ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *); - -X509_REVOKED *X509_REVOKED_new(); -void X509_REVOKED_free(X509_REVOKED *); - -int X509_REVOKED_set_serialNumber(X509_REVOKED *, ASN1_INTEGER *); - -int X509_REVOKED_add1_ext_i2d(X509_REVOKED *, int, void *, int, unsigned long); - -X509_CRL *d2i_X509_CRL_bio(BIO *, X509_CRL **); -X509_CRL *X509_CRL_new(); -void X509_CRL_free(X509_CRL *); -int X509_CRL_add0_revoked(X509_CRL *, X509_REVOKED *); -int i2d_X509_CRL_bio(BIO *, X509_CRL *); -int X509_CRL_print(BIO *, X509_CRL *); -int X509_CRL_set_issuer_name(X509_CRL *, X509_NAME *); -int X509_CRL_sign(X509_CRL *, EVP_PKEY *, const EVP_MD *); - -int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *, EVP_PKEY *); -int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *, EVP_PKEY *, const EVP_MD *); -char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *); -EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *); -int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *, EVP_PKEY *); -NETSCAPE_SPKI *NETSCAPE_SPKI_new(); -void NETSCAPE_SPKI_free(NETSCAPE_SPKI *); - -/* ASN1 serialization */ -int i2d_X509_bio(BIO *, X509 *); -X509 *d2i_X509_bio(BIO *, X509 **); - -int i2d_X509_REQ_bio(BIO *, X509_REQ *); -X509_REQ *d2i_X509_REQ_bio(BIO *, X509_REQ **); - -int i2d_PrivateKey_bio(BIO *, EVP_PKEY *); -EVP_PKEY *d2i_PrivateKey_bio(BIO *, EVP_PKEY **); - -ASN1_INTEGER *X509_get_serialNumber(X509 *); -int X509_set_serialNumber(X509 *, ASN1_INTEGER *); - -/* X509_STORE */ -X509_STORE *X509_STORE_new(); -void X509_STORE_free(X509_STORE *); -int X509_STORE_add_cert(X509_STORE *, X509 *); -""" - -MACROS = """ -long X509_get_version(X509 *); - -ASN1_TIME *X509_get_notBefore(X509 *); -ASN1_TIME *X509_get_notAfter(X509 *); - -long X509_REQ_get_version(X509_REQ *); -X509_NAME *X509_REQ_get_subject_name(X509_REQ *); - -struct stack_st_X509 *sk_X509_new_null(); -void sk_X509_free(struct stack_st_X509 *); -int sk_X509_num(struct stack_st_X509 *); -int sk_X509_push(struct stack_st_X509 *, X509 *); -X509 *sk_X509_value(struct stack_st_X509 *, int); - -X509_EXTENSIONS *sk_X509_EXTENSION_new_null(); -int sk_X509_EXTENSION_num(X509_EXTENSIONS *); -X509_EXTENSION *sk_X509_EXTENSION_value(X509_EXTENSIONS *, int); -int sk_X509_EXTENSION_push(X509_EXTENSIONS *, X509_EXTENSION *); -void sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int); -void sk_X509_EXTENSION_free(X509_EXTENSIONS *); - -int sk_X509_REVOKED_num(struct x509_revoked_st *); -X509_REVOKED *sk_X509_REVOKED_value(struct x509_revoked_st *, int); - -/* These aren't macros these arguments are all const X on openssl > 1.0.x */ -int X509_CRL_set_lastUpdate(X509_CRL *, const ASN1_TIME *); -int X509_CRL_set_nextUpdate(X509_CRL *, const ASN1_TIME *); -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/x509name.py b/cryptography/hazmat/bindings/openssl/x509name.py deleted file mode 100644 index 896f0ae4..00000000 --- a/cryptography/hazmat/bindings/openssl/x509name.py +++ /dev/null @@ -1,51 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... X509_NAME; -typedef ... X509_NAME_ENTRY; -""" - -FUNCTIONS = """ -int X509_NAME_entry_count(X509_NAME *); -X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *, int); -ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *); -ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *); -unsigned long X509_NAME_hash(X509_NAME *); - -int i2d_X509_NAME(X509_NAME *, unsigned char **); -int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, unsigned char *, - int, int, int); -X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *, int); -void X509_NAME_ENTRY_free(X509_NAME_ENTRY *); -int X509_NAME_get_index_by_NID(X509_NAME *, int, int); -int X509_NAME_cmp(const X509_NAME *, const X509_NAME *); -char *X509_NAME_oneline(X509_NAME *, char *, int); -X509_NAME *X509_NAME_dup(X509_NAME *); -void X509_NAME_free(X509_NAME *); -""" - -MACROS = """ -struct stack_st_X509_NAME *sk_X509_NAME_new_null(); -int sk_X509_NAME_num(struct stack_st_X509_NAME *); -int sk_X509_NAME_push(struct stack_st_X509_NAME *, X509_NAME *); -X509_NAME *sk_X509_NAME_value(struct stack_st_X509_NAME *, int); -void sk_X509_NAME_free(struct stack_st_X509_NAME *); -""" - -CUSTOMIZATIONS = """ -""" diff --git a/cryptography/hazmat/bindings/openssl/x509v3.py b/cryptography/hazmat/bindings/openssl/x509v3.py deleted file mode 100644 index bc26236c..00000000 --- a/cryptography/hazmat/bindings/openssl/x509v3.py +++ /dev/null @@ -1,97 +0,0 @@ -# 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. - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef struct { - X509 *issuer_cert; - X509 *subject_cert; - ...; -} X509V3_CTX; - -typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char **, long); - -typedef struct { - ASN1_ITEM_EXP *it; - X509V3_EXT_D2I d2i; - ...; -} X509V3_EXT_METHOD; - -static const int GEN_OTHERNAME; -static const int GEN_EMAIL; -static const int GEN_X400; -static const int GEN_DNS; -static const int GEN_URI; -static const int GEN_DIRNAME; -static const int GEN_EDIPARTY; -static const int GEN_IPADD; -static const int GEN_RID; - -typedef struct { - ...; -} OTHERNAME; - -typedef struct { - ...; -} EDIPARTYNAME; - -typedef struct { - int type; - union { - char *ptr; - OTHERNAME *otherName; /* otherName */ - ASN1_IA5STRING *rfc822Name; - ASN1_IA5STRING *dNSName; - ASN1_TYPE *x400Address; - X509_NAME *directoryName; - EDIPARTYNAME *ediPartyName; - ASN1_IA5STRING *uniformResourceIdentifier; - ASN1_OCTET_STRING *iPAddress; - ASN1_OBJECT *registeredID; - - /* Old names */ - ASN1_OCTET_STRING *ip; /* iPAddress */ - X509_NAME *dirn; /* dirn */ - ASN1_IA5STRING *ia5; /* rfc822Name, dNSName, */ - /* uniformResourceIdentifier */ - ASN1_OBJECT *rid; /* registeredID */ - ASN1_TYPE *other; /* x400Address */ - } d; - ...; -} GENERAL_NAME; - -typedef struct stack_st_GENERAL_NAME GENERAL_NAMES; -""" - -FUNCTIONS = """ -void X509V3_set_ctx(X509V3_CTX *, X509 *, X509 *, X509_REQ *, X509_CRL *, int); -X509_EXTENSION *X509V3_EXT_nconf(CONF *, X509V3_CTX *, char *, char *); -int GENERAL_NAME_print(BIO *, GENERAL_NAME *); -""" - -MACROS = """ -void *X509V3_set_ctx_nodb(X509V3_CTX *); -int sk_GENERAL_NAME_num(struct stack_st_GENERAL_NAME *); -int sk_GENERAL_NAME_push(struct stack_st_GENERAL_NAME *, GENERAL_NAME *); -GENERAL_NAME *sk_GENERAL_NAME_value(struct stack_st_GENERAL_NAME *, int); - -/* These aren't macros these functions are all const X on openssl > 1.0.x */ -const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *); -const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int); -""" - -CUSTOMIZATIONS = """ -""" diff --git a/docs/architecture.rst b/docs/architecture.rst index 5ca2c252..bacde1bb 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -8,6 +8,6 @@ Architecture ``cryptography.hazmat.primitives``. * ``cryptography.hazmat.primitives``: This packages contains low level algorithms, things like ``AES`` or ``SHA1``. This is implemented on top of - ``cryptography.hazmat.bindings``. -* ``cryptography.hazmat.bindings``: This package contains bindings to low level - cryptographic libraries. Our initial target will be OpenSSL. + ``cryptography.hazmat.backends``. +* ``cryptography.hazmat.backends``: This package contains bindings to low level + cryptographic libraries. Our initial target is OpenSSL. diff --git a/docs/contributing.rst b/docs/contributing.rst index a8010a9a..cb9c7283 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -79,7 +79,7 @@ whether the signature was valid. APIs at the :doc:`/hazmat/primitives/index` layer should always take an explicit backend, APIs at the recipes layer should automatically use the -:func:`~cryptography.hazmat.bindings.default_backend`, but optionally allow +:func:`~cryptography.hazmat.backends.default_backend`, but optionally allow specifying a different backend. C bindings diff --git a/docs/hazmat/backends/index.rst b/docs/hazmat/backends/index.rst new file mode 100644 index 00000000..a89cf0d5 --- /dev/null +++ b/docs/hazmat/backends/index.rst @@ -0,0 +1,34 @@ +.. hazmat:: + +Bindings +======== + +.. toctree:: + :maxdepth: 1 + + openssl + interfaces + + +Getting a Backend Provider +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. currentmodule:: cryptography.hazmat.backends + +``cryptography`` aims to support multiple backends to ensure it can provide +the widest number of supported cryptographic algorithms as well as supporting +platform specific implementations. + +You can get the default backend by calling +:func:`~default_backend`. + +The default backend will change over time as we implement new backends and +the libraries we use in those backends changes. + + +.. function:: default_backend() + + :returns: An object that provides at least + :class:`~interfaces.CipherBackend`, :class:`~interfaces.HashBackend`, and + :class:`~interfaces.HMACBackend`. + diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst new file mode 100644 index 00000000..b524943d --- /dev/null +++ b/docs/hazmat/backends/interfaces.rst @@ -0,0 +1,141 @@ +.. hazmat:: + +Backend Interfaces +================== + +.. currentmodule:: cryptography.hazmat.backends.interfaces + + +Backend implementations may provide a number of interfaces to support operations +such as :doc:`/hazmat/primitives/symmetric-encryption`, +:doc:`/hazmat/primitives/cryptographic-hashes`, and +:doc:`/hazmat/primitives/hmac`. + +A specific ``backend`` may provide one or more of these interfaces. + + +.. class:: CipherBackend + + A backend which provides methods for using ciphers for encryption + and decryption. + + .. method:: cipher_supported(cipher, mode) + + Check if a ``cipher`` and ``mode`` combination is supported by + this backend. + + :param cipher: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` + provider. + :param mode: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider. + + :returns: ``True`` if the specified ``cipher`` and ``mode`` combination + is supported by this backend, otherwise ``False`` + + .. method:: register_cipher_adapter(cipher_cls, mode_cls, adapter) + + Register an adapter which can be used to create a backend specific + object from instances of the + :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` and + the :class:`~cryptography.hazmat.primitives.interfaces.Mode` primitives. + + :param cipher_cls: A class whose instances provide + :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` + :param mode_cls: A class whose instances provide: + :class:`~cryptography.hazmat.primitives.interfaces.Mode` + :param adapter: A ``function`` that takes 3 arguments, ``backend`` (a + :class:`CipherBackend` provider), ``cipher`` (a + :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` + provider ), and ``mode`` (a + :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider). + It returns a backend specific object which may be used to construct + a :class:`~cryptogrpahy.hazmat.primitives.interfaces.CipherContext`. + + + .. method:: create_symmetric_encryption_ctx(cipher, mode) + + Create a + :class:`~cryptogrpahy.hazmat.primitives.interfaces.CipherContext` that + can be used for encrypting data with the symmetric ``cipher`` using + the given ``mode``. + + :param cipher: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` + provider. + :param mode: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider. + + :returns: + :class:`~cryptography.hazmat.primitives.interfaces.CipherContext` + + :raises ValueError: When tag is not None in an AEAD mode + + + .. method:: create_symmetric_decryption_ctx(cipher, mode) + + Create a + :class:`~cryptogrpahy.hazmat.primitives.interfaces.CipherContext` that + can be used for decrypting data with the symmetric ``cipher`` using + the given ``mode``. + + :param cipher: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` + provider. + :param mode: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider. + + :returns: + :class:`~cryptography.hazmat.primitives.interfaces.CipherContext` + + :raises ValueError: When tag is None in an AEAD mode + + +.. class:: HashBackend + + A backend with methods for using cryptographic hash functions. + + .. method:: hash_supported(algorithm) + + Check if the specified ``algorithm`` is supported by this backend. + + :param algorithm: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm` + provider. + + :returns: ``True`` if the specified ``algorithm`` is supported by this + backend, otherwise ``False``. + + + .. method:: create_hash_ctx(algorithm) + + Create a + :class:`~cryptogrpahy.hazmat.primitives.interfaces.HashContext` that + uses the specified ``algorithm`` to calculate a message digest. + + :param algorithm: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm` + provider. + + :returns: + :class:`~cryptography.hazmat.primitives.interfaces.HashContext` + + +.. class:: HMACBackend + + A backend with methods for using cryptographic hash functions as message + authentication codes. + + .. method:: create_hmac_ctx(algorithm) + + Create a + :class:`~cryptogrpahy.hazmat.primitives.interfaces.HashContext` that + uses the specified ``algorithm`` to calculate a hash-based message + authentication code. + + :param algorithm: An instance of a + :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm` + provider. + + :returns: + :class:`~cryptography.hazmat.primitives.interfaces.HashContext` diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst new file mode 100644 index 00000000..12fbff04 --- /dev/null +++ b/docs/hazmat/backends/openssl.rst @@ -0,0 +1,25 @@ +.. hazmat:: + +OpenSSL +======= + +These are `CFFI`_ bindings to the `OpenSSL`_ C library. + +.. data:: cryptography.hazmat.backends.openssl.backend + + This is the exposed API for the OpenSSL bindings. It has two public + attributes: + + .. attribute:: ffi + + This is a :class:`cffi.FFI` instance. It can be used to allocate and + otherwise manipulate OpenSSL structures. + + .. attribute:: lib + + This is a ``cffi`` library. It can be used to call OpenSSL functions, + and access constants. + + +.. _`CFFI`: https://cffi.readthedocs.org/ +.. _`OpenSSL`: https://www.openssl.org/ diff --git a/docs/hazmat/bindings/index.rst b/docs/hazmat/bindings/index.rst deleted file mode 100644 index 746f4596..00000000 --- a/docs/hazmat/bindings/index.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. hazmat:: - -Bindings -======== - -.. toctree:: - :maxdepth: 1 - - openssl - interfaces - - -Getting a Backend Provider -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. currentmodule:: cryptography.hazmat.bindings - -``cryptography`` aims to support multiple backends to ensure it can provide -the widest number of supported cryptographic algorithms as well as supporting -platform specific implementations. - -You can get the default backend by calling -:func:`~default_backend`. - -The default backend will change over time as we implement new backends and -the libraries we use in those backends changes. - - -.. function:: default_backend() - - :returns: An object that provides at least - :class:`~interfaces.CipherBackend`, :class:`~interfaces.HashBackend`, and - :class:`~interfaces.HMACBackend`. - diff --git a/docs/hazmat/bindings/interfaces.rst b/docs/hazmat/bindings/interfaces.rst deleted file mode 100644 index 711c82c2..00000000 --- a/docs/hazmat/bindings/interfaces.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. hazmat:: - -Backend Interfaces -================== - -.. currentmodule:: cryptography.hazmat.bindings.interfaces - - -Backend implementations may provide a number of interfaces to support operations -such as :doc:`/hazmat/primitives/symmetric-encryption`, -:doc:`/hazmat/primitives/cryptographic-hashes`, and -:doc:`/hazmat/primitives/hmac`. - -A specific ``backend`` may provide one or more of these interfaces. - - -.. class:: CipherBackend - - A backend which provides methods for using ciphers for encryption - and decryption. - - .. method:: cipher_supported(cipher, mode) - - Check if a ``cipher`` and ``mode`` combination is supported by - this backend. - - :param cipher: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` - provider. - :param mode: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider. - - :returns: ``True`` if the specified ``cipher`` and ``mode`` combination - is supported by this backend, otherwise ``False`` - - .. method:: register_cipher_adapter(cipher_cls, mode_cls, adapter) - - Register an adapter which can be used to create a backend specific - object from instances of the - :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` and - the :class:`~cryptography.hazmat.primitives.interfaces.Mode` primitives. - - :param cipher_cls: A class whose instances provide - :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` - :param mode_cls: A class whose instances provide: - :class:`~cryptography.hazmat.primitives.interfaces.Mode` - :param adapter: A ``function`` that takes 3 arguments, ``backend`` (a - :class:`CipherBackend` provider), ``cipher`` (a - :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` - provider ), and ``mode`` (a - :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider). - It returns a backend specific object which may be used to construct - a :class:`~cryptogrpahy.hazmat.primitives.interfaces.CipherContext`. - - - .. method:: create_symmetric_encryption_ctx(cipher, mode) - - Create a - :class:`~cryptogrpahy.hazmat.primitives.interfaces.CipherContext` that - can be used for encrypting data with the symmetric ``cipher`` using - the given ``mode``. - - :param cipher: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` - provider. - :param mode: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider. - - :returns: - :class:`~cryptography.hazmat.primitives.interfaces.CipherContext` - - :raises ValueError: When tag is not None in an AEAD mode - - - .. method:: create_symmetric_decryption_ctx(cipher, mode) - - Create a - :class:`~cryptogrpahy.hazmat.primitives.interfaces.CipherContext` that - can be used for decrypting data with the symmetric ``cipher`` using - the given ``mode``. - - :param cipher: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm` - provider. - :param mode: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.Mode` provider. - - :returns: - :class:`~cryptography.hazmat.primitives.interfaces.CipherContext` - - :raises ValueError: When tag is None in an AEAD mode - - -.. class:: HashBackend - - A backend with methods for using cryptographic hash functions. - - .. method:: hash_supported(algorithm) - - Check if the specified ``algorithm`` is supported by this backend. - - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm` - provider. - - :returns: ``True`` if the specified ``algorithm`` is supported by this - backend, otherwise ``False``. - - - .. method:: create_hash_ctx(algorithm) - - Create a - :class:`~cryptogrpahy.hazmat.primitives.interfaces.HashContext` that - uses the specified ``algorithm`` to calculate a message digest. - - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm` - provider. - - :returns: - :class:`~cryptography.hazmat.primitives.interfaces.HashContext` - - -.. class:: HMACBackend - - A backend with methods for using cryptographic hash functions as message - authentication codes. - - .. method:: create_hmac_ctx(algorithm) - - Create a - :class:`~cryptogrpahy.hazmat.primitives.interfaces.HashContext` that - uses the specified ``algorithm`` to calculate a hash-based message - authentication code. - - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm` - provider. - - :returns: - :class:`~cryptography.hazmat.primitives.interfaces.HashContext` diff --git a/docs/hazmat/bindings/openssl.rst b/docs/hazmat/bindings/openssl.rst deleted file mode 100644 index d6bfa672..00000000 --- a/docs/hazmat/bindings/openssl.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. hazmat:: - -OpenSSL -======= - -These are `CFFI`_ bindings to the `OpenSSL`_ C library. - -.. data:: cryptography.hazmat.bindings.openssl.backend - - This is the exposed API for the OpenSSL bindings. It has two public - attributes: - - .. attribute:: ffi - - This is a :class:`cffi.FFI` instance. It can be used to allocate and - otherwise manipulate OpenSSL structures. - - .. attribute:: lib - - This is a ``cffi`` library. It can be used to call OpenSSL functions, - and access constants. - - -.. _`CFFI`: https://cffi.readthedocs.org/ -.. _`OpenSSL`: https://www.openssl.org/ diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst index 312d7e69..90ca198a 100644 --- a/docs/hazmat/primitives/cryptographic-hashes.rst +++ b/docs/hazmat/primitives/cryptographic-hashes.rst @@ -20,7 +20,7 @@ Message Digests .. doctest:: - >>> from cryptography.hazmat.bindings import default_backend + >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) >>> digest.update(b"abc") @@ -39,7 +39,7 @@ Message Digests provider such as those described in :ref:`below `. :param backend: A - :class:`~cryptography.hazmat.bindings.interfaces.HashBackend` + :class:`~cryptography.hazmat.backends.interfaces.HashBackend` provider. .. method:: update(data) diff --git a/docs/hazmat/primitives/hmac.rst b/docs/hazmat/primitives/hmac.rst index db5e98d3..0c0d0220 100644 --- a/docs/hazmat/primitives/hmac.rst +++ b/docs/hazmat/primitives/hmac.rst @@ -27,7 +27,7 @@ message. .. doctest:: - >>> from cryptography.hazmat.bindings import default_backend + >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes, hmac >>> h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend()) >>> h.update(b"message to hash") @@ -41,7 +41,7 @@ message. provider such as those described in :ref:`Cryptographic Hashes `. :param backend: A - :class:`~cryptography.hazmat.bindings.interfaces.HMACBackend` + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` provider. .. method:: update(msg) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index ef6f0871..9fccf552 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -34,7 +34,7 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.bindings import default_backend + >>> from cryptography.hazmat.backends import default_backend >>> backend = default_backend() >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) >>> encryptor = cipher.encryptor() @@ -51,7 +51,7 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_. provider such as those described :ref:`below `. :param backend: A - :class:`~cryptography.hazmat.bindings.interfaces.CipherBackend` + :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` provider. .. method:: encryptor() @@ -229,7 +229,7 @@ Weak Ciphers .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.bindings import default_backend + >>> from cryptography.hazmat.backends import default_backend >>> algorithm = algorithms.ARC4(key) >>> cipher = Cipher(algorithm, mode=None, backend=default_backend()) >>> encryptor = cipher.encryptor() @@ -356,7 +356,7 @@ Modes .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.bindings import default_backend + >>> from cryptography.hazmat.backends import default_backend >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend()) >>> encryptor = cipher.encryptor() >>> encryptor.authenticate_additional_data(b"authenticated but not encrypted payload") diff --git a/docs/index.rst b/docs/index.rst index 2263c32f..776c9d37 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -53,4 +53,4 @@ Hazardous Materials :maxdepth: 2 hazmat/primitives/index - hazmat/bindings/index + hazmat/backends/index diff --git a/tests/conftest.py b/tests/conftest.py index fab40b14..71662802 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ def pytest_generate_tests(metafunc): - from cryptography.hazmat.bindings import _ALL_BACKENDS + from cryptography.hazmat.backends import _ALL_BACKENDS if "backend" in metafunc.fixturenames: metafunc.parametrize("backend", _ALL_BACKENDS) diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 1eb6f200..962959b9 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -15,8 +15,8 @@ import pytest from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.bindings import default_backend -from cryptography.hazmat.bindings.openssl.backend import backend, Backend +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.backends.openssl.backend import backend, Backend from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 705983a0..b06f9b29 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -3,7 +3,7 @@ import os import pytest -from cryptography.hazmat.bindings import _ALL_BACKENDS +from cryptography.hazmat.backends import _ALL_BACKENDS from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.exceptions import ( -- cgit v1.2.3 From 41e5ab64e9526c1e759034bafb3d75c1492ff54d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 13 Dec 2013 20:41:49 -0800 Subject: Also rename teh tests --- tests/hazmat/backends/__init__.py | 0 tests/hazmat/backends/test_openssl.py | 97 +++++++++++++++++++++++++++++++++++ tests/hazmat/bindings/__init__.py | 0 tests/hazmat/bindings/test_openssl.py | 97 ----------------------------------- 4 files changed, 97 insertions(+), 97 deletions(-) create mode 100644 tests/hazmat/backends/__init__.py create mode 100644 tests/hazmat/backends/test_openssl.py delete mode 100644 tests/hazmat/bindings/__init__.py delete mode 100644 tests/hazmat/bindings/test_openssl.py diff --git a/tests/hazmat/backends/__init__.py b/tests/hazmat/backends/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py new file mode 100644 index 00000000..962959b9 --- /dev/null +++ b/tests/hazmat/backends/test_openssl.py @@ -0,0 +1,97 @@ +# 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. + +import pytest + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.backends.openssl.backend import backend, Backend +from cryptography.hazmat.primitives import interfaces +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.algorithms import AES +from cryptography.hazmat.primitives.ciphers.modes import CBC + + +class DummyMode(object): + pass + + +@utils.register_interface(interfaces.CipherAlgorithm) +class DummyCipher(object): + pass + + +class TestOpenSSL(object): + def test_backend_exists(self): + assert backend + + def test_is_default(self): + assert backend == default_backend() + + def test_openssl_version_text(self): + """ + This test checks the value of OPENSSL_VERSION_TEXT. + + Unfortunately, this define does not appear to have a + formal content definition, so for now we'll test to see + if it starts with OpenSSL as that appears to be true + for every OpenSSL. + """ + assert backend.openssl_version_text().startswith("OpenSSL") + + def test_supports_cipher(self): + assert backend.cipher_supported(None, None) is False + + def test_register_duplicate_cipher_adapter(self): + with pytest.raises(ValueError): + backend.register_cipher_adapter(AES, CBC, None) + + def test_instances_share_ffi(self): + b = Backend() + assert b.ffi is backend.ffi + assert b.lib is backend.lib + + def test_nonexistent_cipher(self): + b = Backend() + b.register_cipher_adapter( + DummyCipher, + DummyMode, + lambda backend, cipher, mode: backend.ffi.NULL + ) + cipher = Cipher( + DummyCipher(), DummyMode(), backend=b, + ) + with pytest.raises(UnsupportedAlgorithm): + cipher.encryptor() + + def test_handle_unknown_error(self): + with pytest.raises(SystemError): + backend._handle_error_code(0, 0, 0) + + with pytest.raises(SystemError): + backend._handle_error_code(backend.lib.ERR_LIB_EVP, 0, 0) + + with pytest.raises(SystemError): + backend._handle_error_code( + backend.lib.ERR_LIB_EVP, + backend.lib.EVP_F_EVP_ENCRYPTFINAL_EX, + 0 + ) + + with pytest.raises(SystemError): + backend._handle_error_code( + backend.lib.ERR_LIB_EVP, + backend.lib.EVP_F_EVP_DECRYPTFINAL_EX, + 0 + ) diff --git a/tests/hazmat/bindings/__init__.py b/tests/hazmat/bindings/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py deleted file mode 100644 index 962959b9..00000000 --- a/tests/hazmat/bindings/test_openssl.py +++ /dev/null @@ -1,97 +0,0 @@ -# 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. - -import pytest - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.backends.openssl.backend import backend, Backend -from cryptography.hazmat.primitives import interfaces -from cryptography.hazmat.primitives.ciphers import Cipher -from cryptography.hazmat.primitives.ciphers.algorithms import AES -from cryptography.hazmat.primitives.ciphers.modes import CBC - - -class DummyMode(object): - pass - - -@utils.register_interface(interfaces.CipherAlgorithm) -class DummyCipher(object): - pass - - -class TestOpenSSL(object): - def test_backend_exists(self): - assert backend - - def test_is_default(self): - assert backend == default_backend() - - def test_openssl_version_text(self): - """ - This test checks the value of OPENSSL_VERSION_TEXT. - - Unfortunately, this define does not appear to have a - formal content definition, so for now we'll test to see - if it starts with OpenSSL as that appears to be true - for every OpenSSL. - """ - assert backend.openssl_version_text().startswith("OpenSSL") - - def test_supports_cipher(self): - assert backend.cipher_supported(None, None) is False - - def test_register_duplicate_cipher_adapter(self): - with pytest.raises(ValueError): - backend.register_cipher_adapter(AES, CBC, None) - - def test_instances_share_ffi(self): - b = Backend() - assert b.ffi is backend.ffi - assert b.lib is backend.lib - - def test_nonexistent_cipher(self): - b = Backend() - b.register_cipher_adapter( - DummyCipher, - DummyMode, - lambda backend, cipher, mode: backend.ffi.NULL - ) - cipher = Cipher( - DummyCipher(), DummyMode(), backend=b, - ) - with pytest.raises(UnsupportedAlgorithm): - cipher.encryptor() - - def test_handle_unknown_error(self): - with pytest.raises(SystemError): - backend._handle_error_code(0, 0, 0) - - with pytest.raises(SystemError): - backend._handle_error_code(backend.lib.ERR_LIB_EVP, 0, 0) - - with pytest.raises(SystemError): - backend._handle_error_code( - backend.lib.ERR_LIB_EVP, - backend.lib.EVP_F_EVP_ENCRYPTFINAL_EX, - 0 - ) - - with pytest.raises(SystemError): - backend._handle_error_code( - backend.lib.ERR_LIB_EVP, - backend.lib.EVP_F_EVP_DECRYPTFINAL_EX, - 0 - ) -- cgit v1.2.3 From d83c5909c9de44dd523f057edffbdb33a9ae89e6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 13 Dec 2013 20:43:54 -0800 Subject: Need to include the imports --- docs/hazmat/primitives/symmetric-encryption.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index f3def845..55b2dcd4 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -269,6 +269,7 @@ Modes .. doctest:: >>> import os + >>> from cryptography.hazmat.primitives.ciphers.modes import CBC >>> iv = os.urandom(16) >>> mode = CBC(iv) @@ -276,6 +277,7 @@ Modes .. doctest:: + >>> from cryptography.hazmat.primitives.ciphers.modes import CBC >>> iv = "a" * 16 >>> mode = CBC(iv) -- cgit v1.2.3 From 383a04cf47cef37ec94dcc56f52c0e6a18013dcb Mon Sep 17 00:00:00 2001 From: Julian Krause Date: Fri, 13 Dec 2013 23:47:17 -0800 Subject: Remove plural. --- docs/hazmat/primitives/constant-time.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/primitives/constant-time.rst b/docs/hazmat/primitives/constant-time.rst index 4df73b3c..632e7c68 100644 --- a/docs/hazmat/primitives/constant-time.rst +++ b/docs/hazmat/primitives/constant-time.rst @@ -14,7 +14,7 @@ An example would be comparing a HMAC signature received from a client to the one generated by the server code for authentication purposes. For more information about this sort of issue, see `Coda Hale's blog post`_ -about the timing attacks on KeyCzar and Java's ``MessageDigest.isEquals()``. +about the timing attacks on KeyCzar and Java's ``MessageDigest.isEqual()``. .. function:: bytes_eq(a, b) -- cgit v1.2.3 From 960cf5ea24d7ccddf014b3feb546b52796992b91 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 15 Dec 2013 10:24:35 -0800 Subject: Test that docs compile under latex as well --needed for PDF building --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 56603da2..39fe024f 100644 --- a/tox.ini +++ b/tox.ini @@ -17,6 +17,7 @@ deps = basepython = python2.7 commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html sphinx-build -W -b linkcheck docs docs/_build/html -- cgit v1.2.3