1## This file is part of Scapy
2## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
3##               2015, 2016, 2017 Maxence Tury
4## This program is published under a GPLv2 license
5
6"""
7Block ciphers.
8"""
9
10from __future__ import absolute_import
11from scapy.config import conf
12from scapy.utils import strxor
13from scapy.layers.tls.crypto.ciphers import CipherError
14import scapy.modules.six as six
15
16if conf.crypto_valid:
17    from cryptography.utils import register_interface
18    from cryptography.hazmat.primitives.ciphers import (Cipher, algorithms, modes,
19                                                        BlockCipherAlgorithm,
20                                                        CipherAlgorithm)
21    from cryptography.hazmat.backends.openssl.backend import (backend,
22                                                              GetCipherByName)
23
24
25_tls_block_cipher_algs = {}
26
27class _BlockCipherMetaclass(type):
28    """
29    Cipher classes are automatically registered through this metaclass.
30    Furthermore, their name attribute is extracted from their class name.
31    """
32    def __new__(cls, ciph_name, bases, dct):
33        if ciph_name != "_BlockCipher":
34            dct["name"] = ciph_name[7:]     # remove leading "Cipher_"
35        the_class = super(_BlockCipherMetaclass, cls).__new__(cls, ciph_name,
36                                                              bases, dct)
37        if ciph_name != "_BlockCipher":
38            _tls_block_cipher_algs[ciph_name[7:]] = the_class
39        return the_class
40
41
42class _BlockCipher(six.with_metaclass(_BlockCipherMetaclass, object)):
43    type = "block"
44
45    def __init__(self, key=None, iv=None):
46        self.ready = {"key": True, "iv": True}
47        if key is None:
48            self.ready["key"] = False
49            if hasattr(self, "expanded_key_len"):
50                l = self.expanded_key_len
51            else:
52                l = self.key_len
53            key = b"\0" * l
54        if not iv:
55            self.ready["iv"] = False
56            iv = b"\0" * self.block_size
57
58        # we use super() in order to avoid any deadlock with __setattr__
59        super(_BlockCipher, self).__setattr__("key", key)
60        super(_BlockCipher, self).__setattr__("iv", iv)
61
62        self._cipher = Cipher(self.pc_cls(key),
63                              self.pc_cls_mode(iv),
64                              backend=backend)
65
66    def __setattr__(self, name, val):
67        if name == "key":
68            if self._cipher is not None:
69                self._cipher.algorithm.key = val
70            self.ready["key"] = True
71        elif name == "iv":
72            if self._cipher is not None:
73                self._cipher.mode._initialization_vector = val
74            self.ready["iv"] = True
75        super(_BlockCipher, self).__setattr__(name, val)
76
77
78    def encrypt(self, data):
79        """
80        Encrypt the data. Also, update the cipher iv. This is needed for SSLv3
81        and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.post_build().
82        """
83        if False in six.itervalues(self.ready):
84            raise CipherError(data)
85        encryptor = self._cipher.encryptor()
86        tmp = encryptor.update(data) + encryptor.finalize()
87        self.iv = tmp[-self.block_size:]
88        return tmp
89
90    def decrypt(self, data):
91        """
92        Decrypt the data. Also, update the cipher iv. This is needed for SSLv3
93        and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.pre_dissect().
94        If we lack the key, we raise a CipherError which contains the input.
95        """
96        if False in six.itervalues(self.ready):
97            raise CipherError(data)
98        decryptor = self._cipher.decryptor()
99        tmp = decryptor.update(data) + decryptor.finalize()
100        self.iv = data[-self.block_size:]
101        return tmp
102
103    def snapshot(self):
104        c = self.__class__(self.key, self.iv)
105        c.ready = self.ready.copy()
106        return c
107
108
109if conf.crypto_valid:
110    class Cipher_AES_128_CBC(_BlockCipher):
111        pc_cls = algorithms.AES
112        pc_cls_mode = modes.CBC
113        block_size = 16
114        key_len = 16
115
116    class Cipher_AES_256_CBC(Cipher_AES_128_CBC):
117        key_len = 32
118
119
120    class Cipher_CAMELLIA_128_CBC(_BlockCipher):
121        pc_cls = algorithms.Camellia
122        pc_cls_mode = modes.CBC
123        block_size = 16
124        key_len = 16
125
126    class Cipher_CAMELLIA_256_CBC(Cipher_CAMELLIA_128_CBC):
127        key_len = 32
128
129
130### Mostly deprecated ciphers
131
132if conf.crypto_valid:
133    class Cipher_DES_CBC(_BlockCipher):
134        pc_cls = algorithms.TripleDES
135        pc_cls_mode = modes.CBC
136        block_size = 8
137        key_len = 8
138
139    class Cipher_DES40_CBC(Cipher_DES_CBC):
140        """
141        This is an export cipher example. The key length has been weakened to 5
142        random bytes (i.e. 5 bytes will be extracted from the master_secret).
143        Yet, we still need to know the original length which will actually be
144        fed into the encryption algorithm. This is what expanded_key_len
145        is for, and it gets used in PRF.postprocess_key_for_export().
146        We never define this attribute with non-export ciphers.
147        """
148        expanded_key_len = 8
149        key_len = 5
150
151    class Cipher_3DES_EDE_CBC(_BlockCipher):
152        pc_cls = algorithms.TripleDES
153        pc_cls_mode = modes.CBC
154        block_size = 8
155        key_len = 24
156
157    class Cipher_IDEA_CBC(_BlockCipher):
158        pc_cls = algorithms.IDEA
159        pc_cls_mode = modes.CBC
160        block_size = 8
161        key_len = 16
162
163    class Cipher_SEED_CBC(_BlockCipher):
164        pc_cls = algorithms.SEED
165        pc_cls_mode = modes.CBC
166        block_size = 16
167        key_len = 16
168
169
170_sslv2_block_cipher_algs = {}
171
172if conf.crypto_valid:
173    _sslv2_block_cipher_algs.update({
174        "IDEA_128_CBC":     Cipher_IDEA_CBC,
175        "DES_64_CBC":       Cipher_DES_CBC,
176        "DES_192_EDE3_CBC": Cipher_3DES_EDE_CBC
177        })
178
179
180# We need some black magic for RC2, which is not registered by default
181# to the openssl backend of the cryptography library.
182# If the current version of openssl does not support rc2, the RC2 ciphers are
183# silently not declared, and the corresponding suites will have 'usable' False.
184
185if conf.crypto_valid:
186    @register_interface(BlockCipherAlgorithm)
187    @register_interface(CipherAlgorithm)
188    class _ARC2(object):
189        name = "RC2"
190        block_size = 64
191        key_sizes = frozenset([128])
192
193        def __init__(self, key):
194            self.key = algorithms._verify_key_size(self, key)
195
196        @property
197        def key_size(self):
198            return len(self.key) * 8
199
200
201    _gcbn_format = "{cipher.name}-{mode.name}"
202    if GetCipherByName(_gcbn_format)(backend, _ARC2, modes.CBC) != \
203            backend._ffi.NULL:
204
205        class Cipher_RC2_CBC(_BlockCipher):
206            pc_cls = _ARC2
207            pc_cls_mode = modes.CBC
208            block_size = 8
209            key_len = 16
210
211        class Cipher_RC2_CBC_40(Cipher_RC2_CBC):
212            expanded_key_len = 16
213            key_len = 5
214
215        backend.register_cipher_adapter(Cipher_RC2_CBC.pc_cls,
216                                        Cipher_RC2_CBC.pc_cls_mode,
217                                        GetCipherByName(_gcbn_format))
218
219        _sslv2_block_cipher_algs["RC2_128_CBC"] = Cipher_RC2_CBC
220
221
222_tls_block_cipher_algs.update(_sslv2_block_cipher_algs)
223
224