Repository: pyca/cryptography

Issue:
Raise clearer error message when passing a unicode value as a symmetric key
Python: 2.7.3
cryptography==2.1.4
cffi==1.11.5
pip 9.0.1

```
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os

iv = os.urandom(16)
cipher = Cipher(algorithms.AES(key), modes.CFB8(iv),
                            backend=default_backend())
decryptor = cipher.decryptor()
raw_text = decryptor.update(encoded_text) + decryptor.finalize()
```

If `key` is unicode it will raise error.
```

/env/local/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/base.pyc in decryptor(self)
    125     def decryptor(self):
    126         ctx = self._backend.create_symmetric_decryption_ctx(
--> 127             self.algorithm, self.mode
    128         )
    129         return self._wrap_ctx(ctx, encrypt=False)

/env/local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.pyc in create_symmetric_decryption_ctx(self, cipher, mode)
    270 
    271     def create_symmetric_decryption_ctx(self, cipher, mode):
--> 272         return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
    273 
    274     def pbkdf2_hmac_supported(self, algorithm):

/env/local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/ciphers.pyc in __init__(self, backend, cipher, mode, operation)
    108             cipher.key,
    109             iv_nonce,
--> 110             operation
    111         )
    112         self._backend.openssl_assert(res != 0)
``` 

I have this fix temporary
```key = key.encode('utf-8') if isinstance(key, unicode) else key```
But should we do thi in `backends/openssl/ciphers.py` ?



Discussion:
We should improve this error message, but we will absolutely not support unicode keys. Keys are bytes, not text.
I want to help with this issue. I have already set up dev env.
I think raise TypeError with message like: "Only bytes type is allowed", or maybe something else?  @alex Maybe some hint.
Fantastic!

You should be able to use https://github.com/pyca/cryptography/blob/master/src/cryptography/utils.py#L28 to verify that the `key` is `bytes`.
I have changed code and add tests, but tests seem run on an old version of code. How can I force tests to use new version?

Update: problem solved
If you use tox (
https://cryptography.io/en/latest/development/getting-started/#running-tests)
this shouldn't be an issue.

On Mon, Jun 18, 2018 at 8:10 AM Vladyslav Moisieienkov <
notifications@github.com> wrote:

> I have changed code and add tests, but tests seem run on an old version of
> code. How can I force tests to use new version?
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/pyca/cryptography/issues/4157#issuecomment-398033108>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAADBHZ8gOMBaUPxz1mgEaNXzmdkcEKgks5t95ijgaJpZM4Sw4in>
> .
>


-- 
"I disapprove of what you say, but I will defend to the death your right to
say it." -- Evelyn Beatrice Hall (summarizing Voltaire)
"The people's good is the highest law." -- Cicero
GPG Key fingerprint: D1B3 ADC0 E023 8CA6


Resolving patch:
diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py
--- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -12,6 +12,9 @@
 
 
 def _verify_key_size(algorithm, key):
+    # Verify that the key is instance of bytes
+    utils._check_bytes("key", 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(


Test patch:
diff --git a/tests/hazmat/primitives/test_chacha20.py b/tests/hazmat/primitives/test_chacha20.py
--- a/tests/hazmat/primitives/test_chacha20.py
+++ b/tests/hazmat/primitives/test_chacha20.py
@@ -58,3 +58,7 @@ def test_invalid_nonce(self):
 
         with pytest.raises(TypeError):
             algorithms.ChaCha20(b"0" * 32, object())
+
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            algorithms.ChaCha20(u"0" * 32, b"0" * 16)
diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py
--- a/tests/hazmat/primitives/test_ciphers.py
+++ b/tests/hazmat/primitives/test_ciphers.py
@@ -36,6 +36,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             AES(binascii.unhexlify(b"0" * 12))
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            AES(u"0" * 32)
+
 
 class TestAESXTS(object):
     @pytest.mark.requires_backend_interface(interface=CipherBackend)
@@ -75,6 +79,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             Camellia(binascii.unhexlify(b"0" * 12))
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            Camellia(u"0" * 32)
+
 
 class TestTripleDES(object):
     @pytest.mark.parametrize("key", [
@@ -90,6 +98,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             TripleDES(binascii.unhexlify(b"0" * 12))
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            TripleDES(u"0" * 16)
+
 
 class TestBlowfish(object):
     @pytest.mark.parametrize(("key", "keysize"), [
@@ -103,6 +115,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             Blowfish(binascii.unhexlify(b"0" * 6))
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            Blowfish(u"0" * 8)
+
 
 class TestCAST5(object):
     @pytest.mark.parametrize(("key", "keysize"), [
@@ -116,6 +132,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             CAST5(binascii.unhexlify(b"0" * 34))
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            CAST5(u"0" * 10)
+
 
 class TestARC4(object):
     @pytest.mark.parametrize(("key", "keysize"), [
@@ -135,6 +155,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             ARC4(binascii.unhexlify(b"0" * 34))
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            ARC4(u"0" * 10)
+
 
 class TestIDEA(object):
     def test_key_size(self):
@@ -145,6 +169,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             IDEA(b"\x00" * 17)
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            IDEA(u"0" * 16)
+
 
 class TestSEED(object):
     def test_key_size(self):
@@ -155,6 +183,10 @@ def test_invalid_key_size(self):
         with pytest.raises(ValueError):
             SEED(b"\x00" * 17)
 
+    def test_invalid_key_type(self):
+        with pytest.raises(TypeError, match="key must be bytes"):
+            SEED(u"0" * 16)
+
 
 def test_invalid_backend():
     pretend_backend = object()