1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
7from cryptography import utils
8from cryptography.hazmat.primitives.ciphers import (
9    BlockCipherAlgorithm, CipherAlgorithm
10)
11from cryptography.hazmat.primitives.ciphers.modes import ModeWithNonce
12
13
14def _verify_key_size(algorithm, key):
15    # Verify that the key is instance of bytes
16    utils._check_byteslike("key", key)
17
18    # Verify that the key size matches the expected key size
19    if len(key) * 8 not in algorithm.key_sizes:
20        raise ValueError("Invalid key size ({0}) for {1}.".format(
21            len(key) * 8, algorithm.name
22        ))
23    return key
24
25
26@utils.register_interface(BlockCipherAlgorithm)
27@utils.register_interface(CipherAlgorithm)
28class AES(object):
29    name = "AES"
30    block_size = 128
31    # 512 added to support AES-256-XTS, which uses 512-bit keys
32    key_sizes = frozenset([128, 192, 256, 512])
33
34    def __init__(self, key):
35        self.key = _verify_key_size(self, key)
36
37    @property
38    def key_size(self):
39        return len(self.key) * 8
40
41
42@utils.register_interface(BlockCipherAlgorithm)
43@utils.register_interface(CipherAlgorithm)
44class Camellia(object):
45    name = "camellia"
46    block_size = 128
47    key_sizes = frozenset([128, 192, 256])
48
49    def __init__(self, key):
50        self.key = _verify_key_size(self, key)
51
52    @property
53    def key_size(self):
54        return len(self.key) * 8
55
56
57@utils.register_interface(BlockCipherAlgorithm)
58@utils.register_interface(CipherAlgorithm)
59class TripleDES(object):
60    name = "3DES"
61    block_size = 64
62    key_sizes = frozenset([64, 128, 192])
63
64    def __init__(self, key):
65        if len(key) == 8:
66            key += key + key
67        elif len(key) == 16:
68            key += key[:8]
69        self.key = _verify_key_size(self, key)
70
71    @property
72    def key_size(self):
73        return len(self.key) * 8
74
75
76@utils.register_interface(BlockCipherAlgorithm)
77@utils.register_interface(CipherAlgorithm)
78class Blowfish(object):
79    name = "Blowfish"
80    block_size = 64
81    key_sizes = frozenset(range(32, 449, 8))
82
83    def __init__(self, key):
84        self.key = _verify_key_size(self, key)
85
86    @property
87    def key_size(self):
88        return len(self.key) * 8
89
90
91@utils.register_interface(BlockCipherAlgorithm)
92@utils.register_interface(CipherAlgorithm)
93class CAST5(object):
94    name = "CAST5"
95    block_size = 64
96    key_sizes = frozenset(range(40, 129, 8))
97
98    def __init__(self, key):
99        self.key = _verify_key_size(self, key)
100
101    @property
102    def key_size(self):
103        return len(self.key) * 8
104
105
106@utils.register_interface(CipherAlgorithm)
107class ARC4(object):
108    name = "RC4"
109    key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256])
110
111    def __init__(self, key):
112        self.key = _verify_key_size(self, key)
113
114    @property
115    def key_size(self):
116        return len(self.key) * 8
117
118
119@utils.register_interface(CipherAlgorithm)
120class IDEA(object):
121    name = "IDEA"
122    block_size = 64
123    key_sizes = frozenset([128])
124
125    def __init__(self, key):
126        self.key = _verify_key_size(self, key)
127
128    @property
129    def key_size(self):
130        return len(self.key) * 8
131
132
133@utils.register_interface(BlockCipherAlgorithm)
134@utils.register_interface(CipherAlgorithm)
135class SEED(object):
136    name = "SEED"
137    block_size = 128
138    key_sizes = frozenset([128])
139
140    def __init__(self, key):
141        self.key = _verify_key_size(self, key)
142
143    @property
144    def key_size(self):
145        return len(self.key) * 8
146
147
148@utils.register_interface(CipherAlgorithm)
149@utils.register_interface(ModeWithNonce)
150class ChaCha20(object):
151    name = "ChaCha20"
152    key_sizes = frozenset([256])
153
154    def __init__(self, key, nonce):
155        self.key = _verify_key_size(self, key)
156        utils._check_byteslike("nonce", nonce)
157
158        if len(nonce) != 16:
159            raise ValueError("nonce must be 128-bits (16 bytes)")
160
161        self._nonce = nonce
162
163    nonce = utils.read_only_property("_nonce")
164
165    @property
166    def key_size(self):
167        return len(self.key) * 8
168