aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml48
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py8
-rw-r--r--cryptography/hazmat/primitives/ciphers/algorithms.py15
-rw-r--r--docs/hazmat/primitives/symmetric-encryption.rst13
-rw-r--r--tests/hazmat/primitives/test_ciphers.py12
-rw-r--r--tests/hazmat/primitives/test_seed.py92
-rw-r--r--tests/test_utils.py126
-rw-r--r--tests/utils.py55
8 files changed, 316 insertions, 53 deletions
diff --git a/.travis.yml b/.travis.yml
index 7d5663d8..6a235140 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,11 +6,6 @@ compiler:
- clang
- gcc
env:
- # this global section can be removed when
- # https://github.com/travis-ci/travis-ci/issues/1844 is fixed
- global:
- - CI=true
- - TRAVIS=true
matrix:
- TOX_ENV=py26
- TOX_ENV=py27
@@ -50,49 +45,6 @@ notifications:
matrix:
exclude:
- os: osx
- env: TOX_ENV=py26
- compiler: gcc
- - os: osx
- env: TOX_ENV=py27
- compiler: gcc
- - os: osx
- env: TOX_ENV=py32
- compiler: gcc
- - os: osx
- env: TOX_ENV=py33
- compiler: gcc
- - os: osx
- env: TOX_ENV=py34
- compiler: gcc
- - os: osx
- env: TOX_ENV=pypy
- compiler: gcc
- - os: osx
- env: TOX_ENV=py26 OPENSSL=0.9.8
- compiler: gcc
- - os: osx
- env: TOX_ENV=py27 OPENSSL=0.9.8
- compiler: gcc
- - os: osx
- env: TOX_ENV=py32 OPENSSL=0.9.8
- compiler: gcc
- - os: osx
- env: TOX_ENV=py33 OPENSSL=0.9.8
- compiler: gcc
- - os: osx
- env: TOX_ENV=py34 OPENSSL=0.9.8
- compiler: gcc
- - os: osx
- env: TOX_ENV=pypy OPENSSL=0.9.8
- compiler: gcc
- - os: osx
- env: TOX_ENV=docs
- compiler: gcc
- - os: osx
- env: TOX_ENV=pep8
- compiler: gcc
- - os: osx
- env: TOX_ENV=py3pep8
compiler: gcc
- os: osx
env: TOX_ENV=pep8
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index bbcfa327..021ce8c4 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -35,7 +35,7 @@ from cryptography.hazmat.primitives.asymmetric.padding import (
MGF1, PKCS1v15, PSS
)
from cryptography.hazmat.primitives.ciphers.algorithms import (
- AES, ARC4, Blowfish, CAST5, Camellia, IDEA, TripleDES
+ AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES
)
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CFB, CTR, ECB, GCM, OFB
@@ -167,6 +167,12 @@ class Backend(object):
mode_cls,
GetCipherByName("bf-{mode.name}")
)
+ for mode_cls in [CBC, CFB, OFB, ECB]:
+ self.register_cipher_adapter(
+ SEED,
+ mode_cls,
+ GetCipherByName("seed-{mode.name}")
+ )
for cipher_cls, mode_cls in itertools.product(
[CAST5, IDEA],
[CBC, OFB, CFB, ECB],
diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py
index 2d37e0cf..52daf178 100644
--- a/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -130,3 +130,18 @@ class IDEA(object):
@property
def key_size(self):
return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class SEED(object):
+ name = "SEED"
+ block_size = 128
+ key_sizes = frozenset([128])
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 28de611e..1a4df222 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -130,6 +130,17 @@ Algorithms
:param bytes key: The secret key, This must be kept secret. 40 to 128 bits
in length in increments of 8 bits.
+.. class:: SEED(key)
+
+ .. versionadded:: 0.4
+
+ SEED is a block cipher developed by the Korea Information Security Agency (
+ KISA). It is defined in :rfc:`4269` and is used broadly throughout South
+ Korean industry, but rarely found elsewhere.
+
+ :param bytes key: The secret key. This must be kept secret. ``128`` bits in
+ length.
+
Weak ciphers
------------
@@ -176,7 +187,7 @@ Weak ciphers
is susceptible to attacks when using weak keys. It is recommended that you
do not use this cipher for new applications.
- :param bytes key: The secret key This must be kept secret. ``128`` bits in
+ :param bytes key: The secret key. This must be kept secret. ``128`` bits in
length.
diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py
index 9f8123eb..99ef043a 100644
--- a/tests/hazmat/primitives/test_ciphers.py
+++ b/tests/hazmat/primitives/test_ciphers.py
@@ -20,7 +20,7 @@ import pytest
from cryptography.exceptions import _Reasons
from cryptography.hazmat.primitives import ciphers
from cryptography.hazmat.primitives.ciphers.algorithms import (
- AES, ARC4, Blowfish, CAST5, Camellia, IDEA, TripleDES
+ AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES
)
from cryptography.hazmat.primitives.ciphers.modes import ECB
@@ -127,6 +127,16 @@ class TestIDEA(object):
IDEA(b"\x00" * 17)
+class TestSEED(object):
+ def test_key_size(self):
+ cipher = SEED(b"\x00" * 16)
+ assert cipher.key_size == 128
+
+ def test_invalid_key_size(self):
+ with pytest.raises(ValueError):
+ SEED(b"\x00" * 17)
+
+
def test_invalid_backend():
pretend_backend = object()
diff --git a/tests/hazmat/primitives/test_seed.py b/tests/hazmat/primitives/test_seed.py
new file mode 100644
index 00000000..35f89e56
--- /dev/null
+++ b/tests/hazmat/primitives/test_seed.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.SEED("\x00" * 16), modes.ECB()
+ ),
+ skip_message="Does not support SEED ECB",
+)
+@pytest.mark.cipher
+class TestSEEDModeECB(object):
+ test_ECB = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "SEED"),
+ ["rfc-4269.txt"],
+ lambda key, **kwargs: algorithms.SEED(binascii.unhexlify((key))),
+ lambda **kwargs: modes.ECB(),
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.SEED("\x00" * 16), modes.CBC("\x00" * 16)
+ ),
+ skip_message="Does not support SEED CBC",
+)
+@pytest.mark.cipher
+class TestSEEDModeCBC(object):
+ test_CBC = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "SEED"),
+ ["rfc-4196.txt"],
+ lambda key, **kwargs: algorithms.SEED(binascii.unhexlify((key))),
+ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv))
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.SEED("\x00" * 16), modes.OFB("\x00" * 16)
+ ),
+ skip_message="Does not support SEED OFB",
+)
+@pytest.mark.cipher
+class TestSEEDModeOFB(object):
+ test_OFB = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "SEED"),
+ ["seed-ofb.txt"],
+ lambda key, **kwargs: algorithms.SEED(binascii.unhexlify((key))),
+ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv))
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.SEED("\x00" * 16), modes.CFB("\x00" * 16)
+ ),
+ skip_message="Does not support SEED CFB",
+)
+@pytest.mark.cipher
+class TestSEEDModeCFB(object):
+ test_CFB = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "SEED"),
+ ["seed-cfb.txt"],
+ lambda key, **kwargs: algorithms.SEED(binascii.unhexlify((key))),
+ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv))
+ )
diff --git a/tests/test_utils.py b/tests/test_utils.py
index e95a1cff..b1962083 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -27,8 +27,9 @@ import cryptography_vectors
from .utils import (
check_backend_support, check_for_iface, load_cryptrec_vectors,
- load_fips_dsa_key_pair_vectors, load_hash_vectors, load_nist_vectors,
- load_pkcs1_vectors, load_rsa_nist_vectors, load_vectors_from_file,
+ load_fips_dsa_key_pair_vectors, load_fips_ecdsa_key_pair_vectors,
+ load_hash_vectors, load_nist_vectors, load_pkcs1_vectors,
+ load_rsa_nist_vectors, load_vectors_from_file,
raises_unsupported_algorithm, select_backends
)
@@ -1861,3 +1862,124 @@ def test_raises_unsupported_algorithm():
raise UnsupportedAlgorithm("An error.",
_Reasons.BACKEND_MISSING_INTERFACE)
assert exc_info.type is UnsupportedAlgorithm
+
+
+def test_load_fips_ecdsa_key_pair_vectors():
+ vector_data = textwrap.dedent("""
+ # CAVS 11.0
+ # "Key Pair" information
+ # Curves selected: P-192 K-233 B-571
+ # Generated on Wed Mar 16 16:16:42 2011
+
+
+ [P-192]
+
+ [B.4.2 Key Pair Generation by Testing Candidates]
+ N = 2
+
+ d = e5ce89a34adddf25ff3bf1ffe6803f57d0220de3118798ea
+ Qx = 8abf7b3ceb2b02438af19543d3e5b1d573fa9ac60085840f
+ Qy = a87f80182dcd56a6a061f81f7da393e7cffd5e0738c6b245
+
+ d = 7d14435714ad13ff23341cb567cc91198ff8617cc39751b2
+ Qx = 39dc723b19527daa1e80425209c56463481b9b47c51f8cbd
+ Qy = 432a3e84f2a16418834fabaf6b7d2341669512951f1672ad
+
+
+ [K-233]
+
+ [B.4.2 Key Pair Generation by Testing Candidates]
+ N = 2
+
+ d = 01da7422b50e3ff051f2aaaed10acea6cbf6110c517da2f4eaca8b5b87
+ Qx = 01c7475da9a161e4b3f7d6b086494063543a979e34b8d7ac44204d47bf9f
+ Qy = 0131cbd433f112871cc175943991b6a1350bf0cdd57ed8c831a2a7710c92
+
+ d = 530951158f7b1586978c196603c12d25607d2cb0557efadb23cd0ce8
+ Qx = d37500a0391d98d3070d493e2b392a2c79dc736c097ed24b7dd5ddec44
+ Qy = 01d996cc79f37d8dba143d4a8ad9a8a60ed7ea760aae1ddba34d883f65d9
+
+
+ [B-571]
+
+ [B.4.2 Key Pair Generation by Testing Candidates]
+ N = 2
+
+ d = 01443e93c7ef6802655f641ecbe95e75f1f15b02d2e172f49a32e22047d5c00ebe1b3f\
+f0456374461360667dbf07bc67f7d6135ee0d1d46a226a530fefe8ebf3b926e9fbad8d57a6
+ Qx = 053e3710d8e7d4138db0a369c97e5332c1be38a20a4a84c36f5e55ea9fd6f34545b86\
+4ea64f319e74b5ee9e4e1fa1b7c5b2db0e52467518f8c45b658824871d5d4025a6320ca06f8
+ Qy = 03a22cfd370c4a449b936ae97ab97aab11c57686cca99d14ef184f9417fad8bedae4d\
+f8357e3710bcda1833b30e297d4bf637938b995d231e557d13f062e81e830af5ab052208ead
+
+ d = 03d2bd44ca9eeee8c860a4873ed55a54bdfdf5dab4060df7292877960b85d1fd496aa3\
+3c587347213d7f6bf208a6ab4b430546e7b6ffbc3135bd12f44a28517867ca3c83a821d6f8
+ Qx = 07a7af10f6617090bade18b2e092d0dfdc87cd616db7f2db133477a82bfe3ea421ebb\
+7d6289980819292a719eb247195529ea60ad62862de0a26c72bfc49ecc81c2f9ed704e3168f
+ Qy = 0721496cf16f988b1aabef3368450441df8439a0ca794170f270ead56203d675b57f5\
+a4090a3a2f602a77ff3bac1417f7e25a683f667b3b91f105016a47afad46a0367b18e2bdf0c
+ """).splitlines()
+
+ expected = [
+ {
+ "curve": "secp192r1",
+ "d": int("e5ce89a34adddf25ff3bf1ffe6803f57d0220de3118798ea", 16),
+ "x": int("8abf7b3ceb2b02438af19543d3e5b1d573fa9ac60085840f", 16),
+ "y": int("a87f80182dcd56a6a061f81f7da393e7cffd5e0738c6b245", 16)
+ },
+
+ {
+ "curve": "secp192r1",
+ "d": int("7d14435714ad13ff23341cb567cc91198ff8617cc39751b2", 16),
+ "x": int("39dc723b19527daa1e80425209c56463481b9b47c51f8cbd", 16),
+ "y": int("432a3e84f2a16418834fabaf6b7d2341669512951f1672ad", 16),
+ },
+
+ {
+ "curve": "sect233k1",
+ "d": int("1da7422b50e3ff051f2aaaed10acea6cbf6110c517da2f4e"
+ "aca8b5b87", 16),
+ "x": int("1c7475da9a161e4b3f7d6b086494063543a979e34b8d7ac4"
+ "4204d47bf9f", 16),
+ "y": int("131cbd433f112871cc175943991b6a1350bf0cdd57ed8c83"
+ "1a2a7710c92", 16),
+ },
+
+ {
+ "curve": "sect233k1",
+ "d": int("530951158f7b1586978c196603c12d25607d2cb0557efadb"
+ "23cd0ce8", 16),
+ "x": int("d37500a0391d98d3070d493e2b392a2c79dc736c097ed24b"
+ "7dd5ddec44", 16),
+ "y": int("1d996cc79f37d8dba143d4a8ad9a8a60ed7ea760aae1ddba"
+ "34d883f65d9", 16),
+ },
+
+ {
+ "curve": "sect571r1",
+ "d": int("1443e93c7ef6802655f641ecbe95e75f1f15b02d2e172f49"
+ "a32e22047d5c00ebe1b3ff0456374461360667dbf07bc67f"
+ "7d6135ee0d1d46a226a530fefe8ebf3b926e9fbad8d57a6", 16),
+ "x": int("53e3710d8e7d4138db0a369c97e5332c1be38a20a4a84c36"
+ "f5e55ea9fd6f34545b864ea64f319e74b5ee9e4e1fa1b7c5"
+ "b2db0e52467518f8c45b658824871d5d4025a6320ca06f8", 16),
+ "y": int("3a22cfd370c4a449b936ae97ab97aab11c57686cca99d14e"
+ "f184f9417fad8bedae4df8357e3710bcda1833b30e297d4b"
+ "f637938b995d231e557d13f062e81e830af5ab052208ead", 16),
+ },
+
+ {
+ "curve": "sect571r1",
+ "d": int("3d2bd44ca9eeee8c860a4873ed55a54bdfdf5dab4060df72"
+ "92877960b85d1fd496aa33c587347213d7f6bf208a6ab4b4"
+ "30546e7b6ffbc3135bd12f44a28517867ca3c83a821d6f8", 16),
+ "x": int("7a7af10f6617090bade18b2e092d0dfdc87cd616db7f2db1"
+ "33477a82bfe3ea421ebb7d6289980819292a719eb2471955"
+ "29ea60ad62862de0a26c72bfc49ecc81c2f9ed704e3168f", 16),
+ "y": int("721496cf16f988b1aabef3368450441df8439a0ca794170f"
+ "270ead56203d675b57f5a4090a3a2f602a77ff3bac1417f7"
+ "e25a683f667b3b91f105016a47afad46a0367b18e2bdf0c", 16),
+ },
+ ]
+
+ assert expected == load_fips_ecdsa_key_pair_vectors(vector_data)
diff --git a/tests/utils.py b/tests/utils.py
index 6ee735a1..5fa7e7e0 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -427,3 +427,58 @@ def load_fips_dsa_key_pair_vectors(vector_data):
vectors[-1]['y'] = int(line.split("=")[1], 16)
return vectors
+
+
+def load_fips_ecdsa_key_pair_vectors(vector_data):
+ """
+ Loads data out of the FIPS ECDSA KeyPair vector files.
+ """
+ vectors = []
+ key_data = None
+
+ nist_name_map = {
+ "[P-192]": "secp192r1",
+ "[P-224]": "secp224r1",
+ "[P-256]": "secp192r1",
+ "[P-384]": "secp384r1",
+ "[P-521]": "secp521r1",
+ "[K-163]": "sect163k1",
+ "[K-233]": "sect233k1",
+ "[K-283]": "sect233k1",
+ "[K-409]": "sect409k1",
+ "[K-571]": "sect571k1",
+ "[B-163]": "sect163r2",
+ "[B-233]": "sect233r1",
+ "[B-283]": "sect283r1",
+ "[B-409]": "sect409r1",
+ "[B-571]": "sect571r1",
+ }
+
+ for line in vector_data:
+ line = line.strip()
+
+ if not line or line.startswith("#"):
+ continue
+
+ if line in nist_name_map:
+ curve_name = nist_name_map[line]
+
+ elif line.startswith("d = "):
+ if key_data is not None:
+ vectors.append(key_data)
+
+ key_data = {
+ "curve": curve_name,
+ "d": int(line.split("=")[1], 16)
+ }
+
+ elif key_data is not None:
+ if line.startswith("Qx = "):
+ key_data["x"] = int(line.split("=")[1], 16)
+ elif line.startswith("Qy = "):
+ key_data["y"] = int(line.split("=")[1], 16)
+
+ if key_data is not None:
+ vectors.append(key_data)
+
+ return vectors