aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cryptography/hazmat/backends/commoncrypto/backend.py14
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py8
-rw-r--r--cryptography/hazmat/primitives/ciphers/algorithms.py15
-rw-r--r--cryptography/hazmat/primitives/padding.py6
-rw-r--r--docs/changelog.rst1
-rw-r--r--docs/development/custom-vectors/cast5.rst1
-rw-r--r--docs/hazmat/primitives/key-derivation-functions.rst4
-rw-r--r--docs/hazmat/primitives/rsa.rst22
-rw-r--r--docs/hazmat/primitives/symmetric-encryption.rst13
-rw-r--r--docs/installation.rst25
-rw-r--r--tests/hazmat/primitives/test_cast5.py92
-rw-r--r--tests/hazmat/primitives/test_ciphers.py15
12 files changed, 196 insertions, 20 deletions
diff --git a/cryptography/hazmat/backends/commoncrypto/backend.py b/cryptography/hazmat/backends/commoncrypto/backend.py
index e5d4ee00..5c08a356 100644
--- a/cryptography/hazmat/backends/commoncrypto/backend.py
+++ b/cryptography/hazmat/backends/commoncrypto/backend.py
@@ -25,7 +25,7 @@ from cryptography.hazmat.backends.interfaces import (
from cryptography.hazmat.bindings.commoncrypto.binding import Binding
from cryptography.hazmat.primitives import interfaces, constant_time
from cryptography.hazmat.primitives.ciphers.algorithms import (
- AES, Blowfish, TripleDES, ARC4
+ AES, Blowfish, TripleDES, ARC4, CAST5
)
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CTR, ECB, OFB, CFB, GCM
@@ -198,6 +198,18 @@ class Backend(object):
mode_cls,
mode_const
)
+ for mode_cls, mode_const in [
+ (CBC, self._lib.kCCModeCBC),
+ (ECB, self._lib.kCCModeECB),
+ (CFB, self._lib.kCCModeCFB),
+ (OFB, self._lib.kCCModeOFB)
+ ]:
+ self._register_cipher_adapter(
+ CAST5,
+ self._lib.kCCAlgorithmCAST,
+ mode_cls,
+ mode_const
+ )
self._register_cipher_adapter(
ARC4,
self._lib.kCCAlgorithmRC4,
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index ce37e5c8..8a4aeac5 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -26,7 +26,7 @@ from cryptography.hazmat.bindings.openssl.binding import Binding
from cryptography.hazmat.primitives import interfaces, hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.ciphers.algorithms import (
- AES, Blowfish, Camellia, TripleDES, ARC4,
+ AES, Blowfish, Camellia, TripleDES, ARC4, CAST5
)
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CTR, ECB, OFB, CFB, GCM,
@@ -153,6 +153,12 @@ class Backend(object):
mode_cls,
GetCipherByName("bf-{mode.name}")
)
+ for mode_cls in [CBC, CFB, OFB, ECB]:
+ self.register_cipher_adapter(
+ CAST5,
+ mode_cls,
+ GetCipherByName("cast5-{mode.name}")
+ )
self.register_cipher_adapter(
ARC4,
type(None),
diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py
index 19cf1920..a5cfce92 100644
--- a/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -90,6 +90,21 @@ class Blowfish(object):
return len(self.key) * 8
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class CAST5(object):
+ name = "CAST5"
+ block_size = 64
+ key_sizes = frozenset(range(40, 129, 8))
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
@utils.register_interface(interfaces.CipherAlgorithm)
class ARC4(object):
name = "RC4"
diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py
index ddb2c63c..1717262c 100644
--- a/cryptography/hazmat/primitives/padding.py
+++ b/cryptography/hazmat/primitives/padding.py
@@ -86,8 +86,7 @@ class PKCS7(object):
class _PKCS7PaddingContext(object):
def __init__(self, block_size):
self.block_size = block_size
- # TODO: O(n ** 2) complexity for repeated concatentation, we should use
- # zero-buffer (#193)
+ # TODO: more copies than necessary, we should use zero-buffer (#193)
self._buffer = b""
def update(self, data):
@@ -120,8 +119,7 @@ class _PKCS7PaddingContext(object):
class _PKCS7UnpaddingContext(object):
def __init__(self, block_size):
self.block_size = block_size
- # TODO: O(n ** 2) complexity for repeated concatentation, we should use
- # zero-buffer (#193)
+ # TODO: more copies than necessary, we should use zero-buffer (#193)
self._buffer = b""
def update(self, data):
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 4d459bd9..cd289b6e 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -18,6 +18,7 @@ Changelog
* Added :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF`.
* Added :doc:`/hazmat/backends/multibackend`.
* Set default random for the :doc:`/hazmat/backends/openssl` to the OS random engine.
+* Added :class:`~cryptography.hazmat.primitives.ciphers.algorithms.CAST5` (CAST-128) support.
0.1 - 2014-01-08
~~~~~~~~~~~~~~~~
diff --git a/docs/development/custom-vectors/cast5.rst b/docs/development/custom-vectors/cast5.rst
index 7f1d72c1..09b3bdb1 100644
--- a/docs/development/custom-vectors/cast5.rst
+++ b/docs/development/custom-vectors/cast5.rst
@@ -23,5 +23,6 @@ Verification
The following go code was used to verify the vectors.
.. literalinclude:: /development/custom-vectors/cast5/verify_cast5.go
+ :language: go
Download link: :download:`verify_cast5.go </development/custom-vectors/cast5/verify_cast5.go>`
diff --git a/docs/hazmat/primitives/key-derivation-functions.rst b/docs/hazmat/primitives/key-derivation-functions.rst
index 1937c2ec..d8a0e241 100644
--- a/docs/hazmat/primitives/key-derivation-functions.rst
+++ b/docs/hazmat/primitives/key-derivation-functions.rst
@@ -129,6 +129,10 @@ Different KDFs are suitable for different tasks such as:
`HKDF`_ (HMAC-based Extract-and-Expand Key Derivation Function) is suitable
for deriving keys of a fixed size used for other cryptographic operations.
+ .. warning::
+
+ HKDF should not be used for password storage.
+
.. doctest::
>>> import os
diff --git a/docs/hazmat/primitives/rsa.rst b/docs/hazmat/primitives/rsa.rst
index 4925366a..e7ec4749 100644
--- a/docs/hazmat/primitives/rsa.rst
+++ b/docs/hazmat/primitives/rsa.rst
@@ -20,10 +20,10 @@ RSA
.. warning::
This method only checks a limited set of properties of its arguments.
- Using an RSA that you do not trust or with incorrect parameters may
- lead to insecure operation, crashes, and other undefined behavior. We
- recommend that you only ever load private keys that were generated with
- software you trust.
+ Using an RSA private key that you do not trust or with incorrect
+ parameters may lead to insecure operation, crashes, and other undefined
+ behavior. We recommend that you only ever load private keys that were
+ generated with software you trust.
This class conforms to the
@@ -32,9 +32,10 @@ RSA
:raises TypeError: This is raised when the arguments are not all integers.
- :raises ValueError: This is raised when the values of `p`, `q`,
- `private_exponent`, `public_exponent` or `modulus` do
- not match the bounds specified in `RFC 3447`_.
+ :raises ValueError: This is raised when the values of ``p``, ``q``,
+ ``private_exponent``, ``public_exponent``, or
+ ``modulus`` do not match the bounds specified in
+ :rfc:`3447`.
.. classmethod:: generate(public_exponent, key_size, backend)
@@ -68,12 +69,11 @@ RSA
:raises TypeError: This is raised when the arguments are not all integers.
- :raises ValueError: This is raised when the values of `public_exponent` or
- `modulus` do not match the bounds specified in
- `RFC 3447`_.
+ :raises ValueError: This is raised when the values of ``public_exponent``
+ or ``modulus`` do not match the bounds specified in
+ :rfc:`3447`.
.. _`RSA`: https://en.wikipedia.org/wiki/RSA_(cryptosystem)
.. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography
-.. _`RFC 3447`: https://tools.ietf.org/html/rfc3447
.. _`use 65537`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html
.. _`at least 2048`: http://www.ecrypt.eu.org/documents/D.SPA.20.pdf
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 85d8e8e3..d91dde9d 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -99,7 +99,6 @@ Algorithms
:param bytes key: The secret key, either ``128``, ``192``, or ``256`` bits.
This must be kept secret.
-
.. class:: TripleDES(key)
Triple DES (Data Encryption Standard), sometimes referred to as 3DES, is a
@@ -116,6 +115,17 @@ Algorithms
``56`` bits long), they can simply be concatenated to
produce the full key. This must be kept secret.
+.. class:: CAST5(key)
+
+ .. versionadded:: 0.2
+
+ CAST5 (also known as CAST-128) is a block cipher approved for use in the
+ Canadian government by the `Communications Security Establishment`_. It is
+ a variable key length cipher and supports keys from 40-128 bits in length.
+
+ :param bytes key: The secret key, 40-128 bits in length (in increments of
+ 8). This must be kept secret.
+
Weak Ciphers
------------
@@ -469,3 +479,4 @@ Interfaces
.. _`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
.. _`NIST SP-800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
+.. _`Communications Security Establishment`: http://www.cse-cst.gc.ca
diff --git a/docs/installation.rst b/docs/installation.rst
index 7e7348e2..f9c3574d 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -22,8 +22,31 @@ to include the corresponding locations. For example:
C:\> set INCLUDE=C:\OpenSSL-1.0.1f-64bit\include;%INCLUDE%
C:\> pip install cryptography
+Building cryptography on Linux
+------------------------------
+
+``cryptography`` should build very easily on Linux provided you have a C
+compiler, headers for Python (if you're not using ``pypy``), and headers for
+the OpenSSL and ``libffi`` libraries available on your system.
+
+Debian and Ubuntu systems
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For Debian and Ubuntu, the following command line will ensure the required
+dependencies are installed:
+
+.. code-block:: console
+
+ $ sudo apt-get install build-essential libssl-dev libffi-dev python-dev
+
+You should now be able to build and install cryptography with the usual
+
+.. code-block:: console
+
+ $ pip install cryptography
+
Using your own OpenSSL on Linux
--------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Python links to OpenSSL for its own purposes and this can sometimes cause
problems when you wish to use a different version of OpenSSL with cryptography.
diff --git a/tests/hazmat/primitives/test_cast5.py b/tests/hazmat/primitives/test_cast5.py
new file mode 100644
index 00000000..682b4496
--- /dev/null
+++ b/tests/hazmat/primitives/test_cast5.py
@@ -0,0 +1,92 @@
+# 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 binascii
+import os
+
+import pytest
+
+from cryptography.hazmat.primitives.ciphers import algorithms, modes
+
+from .utils import generate_encrypt_test
+from ...utils import load_nist_vectors
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.CAST5("\x00" * 16), modes.ECB()
+ ),
+ skip_message="Does not support CAST5 ECB",
+)
+@pytest.mark.cipher
+class TestCAST5_ECB(object):
+ test_ECB = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "CAST5"),
+ ["cast5-ecb.txt"],
+ lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))),
+ lambda **kwargs: modes.ECB(),
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.CAST5("\x00" * 16), modes.CBC("\x00" * 8)
+ ),
+ skip_message="Does not support CAST5 CBC",
+)
+@pytest.mark.cipher
+class TestCAST5_CBC(object):
+ test_CBC = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "CAST5"),
+ ["cast5-cbc.txt"],
+ lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))),
+ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv))
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.CAST5("\x00" * 16), modes.OFB("\x00" * 8)
+ ),
+ skip_message="Does not support CAST5 OFB",
+)
+@pytest.mark.cipher
+class TestCAST5_OFB(object):
+ test_OFB = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "CAST5"),
+ ["cast5-ofb.txt"],
+ lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))),
+ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv))
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.CAST5("\x00" * 16), modes.CFB("\x00" * 8)
+ ),
+ skip_message="Does not support CAST5 CFB",
+)
+@pytest.mark.cipher
+class TestCAST5_CFB(object):
+ test_CFB = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "CAST5"),
+ ["cast5-cfb.txt"],
+ lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))),
+ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv))
+ )
diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py
index 6a7b2f93..50cadf64 100644
--- a/tests/hazmat/primitives/test_ciphers.py
+++ b/tests/hazmat/primitives/test_ciphers.py
@@ -18,7 +18,7 @@ import binascii
import pytest
from cryptography.hazmat.primitives.ciphers.algorithms import (
- AES, Camellia, TripleDES, Blowfish, ARC4
+ AES, Camellia, TripleDES, Blowfish, ARC4, CAST5
)
@@ -80,6 +80,19 @@ class TestBlowfish(object):
Blowfish(binascii.unhexlify(b"0" * 6))
+class TestCAST5(object):
+ @pytest.mark.parametrize(("key", "keysize"), [
+ (b"0" * (keysize // 4), keysize) for keysize in range(40, 129, 8)
+ ])
+ def test_key_size(self, key, keysize):
+ cipher = CAST5(binascii.unhexlify(key))
+ assert cipher.key_size == keysize
+
+ def test_invalid_key_size(self):
+ with pytest.raises(ValueError):
+ CAST5(binascii.unhexlify(b"0" * 34))
+
+
class TestARC4(object):
@pytest.mark.parametrize(("key", "keysize"), [
(b"0" * 10, 40),