Merge pull request #911 from public/ecdsa-vector-loader

ECDSA vector loader
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index bbcfa32..021ce8c 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -35,7 +35,7 @@
     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 @@
                 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 2d37e0c..52daf17 100644
--- a/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -130,3 +130,18 @@
     @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 28de611..1a4df22 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -130,6 +130,17 @@
     :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 @@
     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 9f8123e..99ef043 100644
--- a/tests/hazmat/primitives/test_ciphers.py
+++ b/tests/hazmat/primitives/test_ciphers.py
@@ -20,7 +20,7 @@
 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 @@
             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 0000000..35f89e5
--- /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))
+    )