• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7import binascii
8import os
9
10import pytest
11
12from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons
13from cryptography.hazmat.backends.interfaces import HMACBackend
14from cryptography.hazmat.primitives import hashes
15from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand
16
17from ...utils import (
18    load_nist_vectors,
19    load_vectors_from_file,
20    raises_unsupported_algorithm,
21)
22
23
24@pytest.mark.requires_backend_interface(interface=HMACBackend)
25class TestHKDF(object):
26    def test_length_limit(self, backend):
27        big_length = 255 * hashes.SHA256().digest_size + 1
28
29        with pytest.raises(ValueError):
30            HKDF(
31                hashes.SHA256(),
32                big_length,
33                salt=None,
34                info=None,
35                backend=backend,
36            )
37
38    def test_already_finalized(self, backend):
39        hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend)
40
41        hkdf.derive(b"\x01" * 16)
42
43        with pytest.raises(AlreadyFinalized):
44            hkdf.derive(b"\x02" * 16)
45
46        hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend)
47
48        hkdf.verify(b"\x01" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u")
49
50        with pytest.raises(AlreadyFinalized):
51            hkdf.verify(b"\x02" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u")
52
53        hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend)
54
55    def test_verify(self, backend):
56        hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend)
57
58        hkdf.verify(b"\x01" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u")
59
60    def test_verify_invalid(self, backend):
61        hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend)
62
63        with pytest.raises(InvalidKey):
64            hkdf.verify(b"\x02" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u")
65
66    def test_unicode_typeerror(self, backend):
67        with pytest.raises(TypeError):
68            HKDF(hashes.SHA256(), 16, salt=u"foo", info=None, backend=backend)
69
70        with pytest.raises(TypeError):
71            HKDF(hashes.SHA256(), 16, salt=None, info=u"foo", backend=backend)
72
73        with pytest.raises(TypeError):
74            hkdf = HKDF(
75                hashes.SHA256(), 16, salt=None, info=None, backend=backend
76            )
77
78            hkdf.derive(u"foo")
79
80        with pytest.raises(TypeError):
81            hkdf = HKDF(
82                hashes.SHA256(), 16, salt=None, info=None, backend=backend
83            )
84
85            hkdf.verify(u"foo", b"bar")
86
87        with pytest.raises(TypeError):
88            hkdf = HKDF(
89                hashes.SHA256(), 16, salt=None, info=None, backend=backend
90            )
91
92            hkdf.verify(b"foo", u"bar")
93
94    def test_derive_short_output(self, backend):
95        hkdf = HKDF(hashes.SHA256(), 4, salt=None, info=None, backend=backend)
96
97        assert hkdf.derive(b"\x01" * 16) == b"gJ\xfb{"
98
99    def test_derive_long_output(self, backend):
100        vector = load_vectors_from_file(
101            os.path.join("KDF", "hkdf-generated.txt"), load_nist_vectors
102        )[0]
103        hkdf = HKDF(
104            hashes.SHA256(),
105            int(vector["l"]),
106            salt=vector["salt"],
107            info=vector["info"],
108            backend=backend,
109        )
110        ikm = binascii.unhexlify(vector["ikm"])
111
112        assert hkdf.derive(ikm) == binascii.unhexlify(vector["okm"])
113
114    def test_buffer_protocol(self, backend):
115        vector = load_vectors_from_file(
116            os.path.join("KDF", "hkdf-generated.txt"), load_nist_vectors
117        )[0]
118        hkdf = HKDF(
119            hashes.SHA256(),
120            int(vector["l"]),
121            salt=vector["salt"],
122            info=vector["info"],
123            backend=backend,
124        )
125        ikm = bytearray(binascii.unhexlify(vector["ikm"]))
126
127        assert hkdf.derive(ikm) == binascii.unhexlify(vector["okm"])
128
129
130@pytest.mark.requires_backend_interface(interface=HMACBackend)
131class TestHKDFExpand(object):
132    def test_derive(self, backend):
133        prk = binascii.unhexlify(
134            b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
135        )
136
137        okm = (
138            b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c"
139            b"5bf34007208d5b887185865"
140        )
141
142        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
143        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
144
145        assert binascii.hexlify(hkdf.derive(prk)) == okm
146
147    def test_buffer_protocol(self, backend):
148        prk = bytearray(
149            binascii.unhexlify(
150                b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2"
151                b"b3e5"
152            )
153        )
154
155        okm = (
156            b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c"
157            b"5bf34007208d5b887185865"
158        )
159
160        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
161        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
162
163        assert binascii.hexlify(hkdf.derive(prk)) == okm
164
165    def test_verify(self, backend):
166        prk = binascii.unhexlify(
167            b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
168        )
169
170        okm = (
171            b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c"
172            b"5bf34007208d5b887185865"
173        )
174
175        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
176        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
177
178        assert hkdf.verify(prk, binascii.unhexlify(okm)) is None
179
180    def test_invalid_verify(self, backend):
181        prk = binascii.unhexlify(
182            b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
183        )
184
185        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
186        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
187
188        with pytest.raises(InvalidKey):
189            hkdf.verify(prk, b"wrong key")
190
191    def test_already_finalized(self, backend):
192        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
193        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
194
195        hkdf.derive(b"first")
196
197        with pytest.raises(AlreadyFinalized):
198            hkdf.derive(b"second")
199
200    def test_unicode_error(self, backend):
201        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
202        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
203
204        with pytest.raises(TypeError):
205            hkdf.derive(u"first")
206
207
208def test_invalid_backend():
209    pretend_backend = object()
210
211    with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
212        HKDF(hashes.SHA256(), 16, None, None, pretend_backend)
213
214    with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
215        HKDFExpand(hashes.SHA256(), 16, None, pretend_backend)
216