]> Cypherpunks.ru repositories - pygost.git/blob - pygost/test_cms.py
Simplify GOST3410Curve initialization
[pygost.git] / pygost / test_cms.py
1 # coding: utf-8
2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2019 Sergey Matveev <stargrave@stargrave.org>
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 from base64 import b64decode
19 from unittest import skipIf
20 from unittest import TestCase
21
22 from pygost.gost28147 import cfb_decrypt
23 from pygost.gost3410 import CURVES
24 from pygost.gost3410 import prv_unmarshal
25 from pygost.gost3410 import pub_unmarshal
26 from pygost.gost3410 import public_key
27 from pygost.gost3410 import verify
28 from pygost.gost3410_vko import kek_34102012256
29 from pygost.gost3410_vko import ukm_unmarshal
30 from pygost.gost34112012256 import GOST34112012256
31 from pygost.gost34112012512 import GOST34112012512
32 from pygost.utils import hexdec
33 from pygost.wrap import unwrap_cryptopro
34 from pygost.wrap import unwrap_gost
35
36 try:
37     from pyderasn import DecodePathDefBy
38     from pyderasn import OctetString
39
40     from pygost.asn1schemas.cms import ContentInfo
41     from pygost.asn1schemas.oids import id_envelopedData
42     from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
43     from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
44 except ImportError:
45     pyderasn_exists = False
46 else:
47     pyderasn_exists = True
48
49
50 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
51 class TestSigned(TestCase):
52     """SignedData test vectors from "Использование
53     алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10 в
54     криптографических сообщениях формата CMS" (TK26CMS.pdf)
55     """
56
57     def process_cms(
58             self,
59             content_info_raw,
60             prv_key_raw,
61             curve_name,
62             hasher,
63             mode,
64     ):
65         content_info, tail = ContentInfo().decode(content_info_raw)
66         self.assertSequenceEqual(tail, b"")
67         self.assertIsNotNone(content_info["content"].defined)
68         _, signed_data = content_info["content"].defined
69         self.assertEqual(len(signed_data["signerInfos"]), 1)
70         curve = CURVES[curve_name]
71         self.assertTrue(verify(
72             curve,
73             public_key(curve, prv_unmarshal(prv_key_raw)),
74             hasher(bytes(signed_data["encapContentInfo"]["eContent"])).digest()[::-1],
75             bytes(signed_data["signerInfos"][0]["signature"]),
76             mode=mode,
77         ))
78
79     def test_256(self):
80         content_info_raw = b64decode("""
81 MIIBBQYJKoZIhvcNAQcCoIH3MIH0AgEBMQ4wDAYIKoUDBwEBAgIFADAbBgkqhkiG
82 9w0BBwGgDgQMVGVzdCBtZXNzYWdlMYHBMIG+AgEBMFswVjEpMCcGCSqGSIb3DQEJ
83 ARYaR29zdFIzNDEwLTIwMTJAZXhhbXBsZS5jb20xKTAnBgNVBAMTIEdvc3RSMzQx
84 MC0yMDEyICgyNTYgYml0KSBleGFtcGxlAgEBMAwGCCqFAwcBAQICBQAwDAYIKoUD
85 BwEBAQEFAARAkptb2ekZbC94FaGDQeP70ExvTkXtOY9zgz3cCco/hxPhXUVo3eCx
86 VNwDQ8enFItJZ8DEX4blZ8QtziNCMl5HbA==
87         """)
88         prv_key_raw = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
89         self.process_cms(
90             content_info_raw,
91             prv_key_raw,
92             "id-GostR3410-2001-CryptoPro-XchA-ParamSet",
93             GOST34112012256,
94             2001,
95         )
96
97     def test_512(self):
98         content_info_raw = b64decode("""
99 MIIBSQYJKoZIhvcNAQcCoIIBOjCCATYCAQExDjAMBggqhQMHAQECAwUAMBsGCSqG
100 SIb3DQEHAaAOBAxUZXN0IG1lc3NhZ2UxggECMIH/AgEBMFswVjEpMCcGCSqGSIb3
101 DQEJARYaR29zdFIzNDEwLTIwMTJAZXhhbXBsZS5jb20xKTAnBgNVBAMTIEdvc3RS
102 MzQxMC0yMDEyICg1MTIgYml0KSBleGFtcGxlAgEBMAwGCCqFAwcBAQIDBQAwDAYI
103 KoUDBwEBAQIFAASBgFyVohNhMHUi/+RAF3Gh/cC7why6v+4jPWVlx1TYlXtV8Hje
104 hI2Y+rP52/LO6EUHG/XcwCBbUxmRWsbUSRRBAexmaafkSdvv2FFwC8kHOcti+UPX
105 PS+KRYxT8vhcsBLWWxDkc1McI7aF09hqtED36mQOfACzeJjEoUjALpmJob1V
106         """)
107         prv_key_raw = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
108         self.process_cms(
109             content_info_raw,
110             prv_key_raw,
111             "id-tc26-gost-3410-12-512-paramSetB",
112             GOST34112012512,
113             2012,
114         )
115
116
117 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
118 class TestDigested(TestCase):
119     """DigestedData test vectors from "Использование
120     алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10 в
121     криптографических сообщениях формата CMS" (TK26CMS.pdf)
122     """
123
124     def process_cms(self, content_info_raw, hasher):
125         content_info, tail = ContentInfo().decode(content_info_raw)
126         self.assertSequenceEqual(tail, b"")
127         self.assertIsNotNone(content_info["content"].defined)
128         _, digested_data = content_info["content"].defined
129         self.assertSequenceEqual(
130             hasher(bytes(digested_data["encapContentInfo"]["eContent"])).digest(),
131             bytes(digested_data["digest"]),
132         )
133
134     def test_256(self):
135         content_info_raw = b64decode("""
136 MIGdBgkqhkiG9w0BBwWggY8wgYwCAQAwDAYIKoUDBwEBAgIFADBXBgkqhkiG9w0B
137 BwGgSgRI0eUg4uXy8OgsINHy8Ojh7uboIOLt8/boLCDi5f7y+iDxIOzu8P8g8fLw
138 5evg7Ogg7eAg9fDg4fD7/yDv6/rq+yDI4+7w5eL7BCCd0v5OkECeXah/U5dtdAWw
139 wMrGKPxmmnQdUAY8VX6PUA==
140         """)
141         self.process_cms(content_info_raw, GOST34112012256)
142
143     def test_512(self):
144         content_info_raw = b64decode("""
145 MIG0BgkqhkiG9w0BBwWggaYwgaMCAQAwDAYIKoUDBwEBAgMFADBOBgkqhkiG9w0B
146 BwGgQQQ/MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAx
147 MjM0NTY3ODkwMTIzNDU2Nzg5MDEyBEAbVNAaSvW51cw9htaNKFRisZq8JHUiLzXA
148 hRIr5Lof+gCtMPh2ezqCOExldPAkwxHipIEzKwjvf0F5eJHBZG9I
149         """)
150         self.process_cms(content_info_raw, GOST34112012512)
151
152
153 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
154 class TestEnvelopedKTRI(TestCase):
155     """EnvelopedData KeyTransRecipientInfo-based test vectors from
156     "Использование алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10
157     в криптографических сообщениях формата CMS" (TK26CMS.pdf)
158     """
159
160     def process_cms(
161             self,
162             content_info_raw,
163             prv_key_our,
164             curve_name,
165             keker,
166             plaintext_expected,
167     ):
168         sbox = "id-tc26-gost-28147-param-Z"
169         content_info, tail = ContentInfo().decode(content_info_raw, ctx={
170             "defines_by_path": [
171                 (
172                     (
173                         "content",
174                         DecodePathDefBy(id_envelopedData),
175                         "recipientInfos",
176                         any,
177                         "ktri",
178                         "encryptedKey",
179                         DecodePathDefBy(spki_algorithm),
180                         "transportParameters",
181                         "ephemeralPublicKey",
182                         "algorithm",
183                         "algorithm",
184                     ),
185                     (
186                         (
187                             ("..", "subjectPublicKey"),
188                             {
189                                 id_tc26_gost3410_2012_256: OctetString(),
190                                 id_tc26_gost3410_2012_512: OctetString(),
191                             },
192                         ),
193                     ),
194                 ) for spki_algorithm in (
195                     id_tc26_gost3410_2012_256,
196                     id_tc26_gost3410_2012_512,
197                 )
198             ],
199         })
200         self.assertSequenceEqual(tail, b"")
201         self.assertIsNotNone(content_info["content"].defined)
202         _, enveloped_data = content_info["content"].defined
203         eci = enveloped_data["encryptedContentInfo"]
204         ri = enveloped_data["recipientInfos"][0]
205         self.assertIsNotNone(ri["ktri"]["encryptedKey"].defined)
206         _, encrypted_key = ri["ktri"]["encryptedKey"].defined
207         ukm = bytes(encrypted_key["transportParameters"]["ukm"])
208         spk = encrypted_key["transportParameters"]["ephemeralPublicKey"]["subjectPublicKey"]
209         self.assertIsNotNone(spk.defined)
210         _, pub_key_their = spk.defined
211         curve = CURVES[curve_name]
212         kek = keker(curve, prv_key_our, bytes(pub_key_their), ukm)
213         key_wrapped = bytes(encrypted_key["sessionEncryptedKey"]["encryptedKey"])
214         mac = bytes(encrypted_key["sessionEncryptedKey"]["macKey"])
215         cek = unwrap_cryptopro(kek, ukm + key_wrapped + mac, sbox=sbox)
216         ciphertext = bytes(eci["encryptedContent"])
217         self.assertIsNotNone(eci["contentEncryptionAlgorithm"]["parameters"].defined)
218         _, encryption_params = eci["contentEncryptionAlgorithm"]["parameters"].defined
219         iv = bytes(encryption_params["iv"])
220         self.assertSequenceEqual(
221             cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
222             plaintext_expected,
223         )
224
225     def test_256(self):
226         content_info_raw = b64decode("""
227 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
281         """)
282         prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
283
284         def keker(curve, prv, pub, ukm):
285             return kek_34102012256(
286                 curve,
287                 prv_unmarshal(prv),
288                 pub_unmarshal(pub),
289                 ukm_unmarshal(ukm),
290                 mode=2001,
291             )
292
293         self.process_cms(
294             content_info_raw,
295             prv_key_our,
296             "id-GostR3410-2001-CryptoPro-XchA-ParamSet",
297             keker,
298             b"Test data to encrypt.\n" * 100,
299         )
300
301     def test_512(self):
302         content_info_raw = b64decode("""
303 MIIB0gYJKoZIhvcNAQcDoIIBwzCCAb8CAQAxggF8MIIBeAIBADBbMFYxKTAnBgkq
304 hkiG9w0BCQEWGkdvc3RSMzQxMC0yMDEyQGV4YW1wbGUuY29tMSkwJwYDVQQDEyBH
305 b3N0UjM0MTAtMjAxMiA1MTIgYml0cyBleGNoYW5nZQIBATAhBggqhQMHAQEBAjAV
306 BgkqhQMHAQIBAgIGCCqFAwcBAQIDBIHyMIHvMCgEIIsYzbVLn33aLinQ7SLNA7y+
307 Lrm02khqDCfXrNS9iiMhBATerS8zoIHCBgkqhQMHAQIFAQGggaowIQYIKoUDBwEB
308 AQIwFQYJKoUDBwECAQICBggqhQMHAQECAwOBhAAEgYAYiTVLKpSGaAvjJEDQ0hdK
309 qR/jek5Q9Q2pXC+NkOimQh7dpCi+wcaHlPcBk96hmpnOFvLaiokX8V6jqtBl5gdk
310 M40kOXv8kcDdTzEVKA/ZLxA8xanL+gTD6ZjaPsUu06nsA2MoMBWcHLUzueaP3bGT
311 /yHTV+Za5xdcQehag/lNBgQIvCw4uUl0XC4wOgYJKoZIhvcNAQcBMB8GBiqFAwIC
312 FTAVBAj+1QzaXaN9FwYJKoUDBwECBQEBgAyK54euw0sHhEVEkA0=
313         """)
314         prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
315
316         def keker(curve, prv, pub, ukm):
317             return kek_34102012256(
318                 curve,
319                 prv_unmarshal(prv),
320                 pub_unmarshal(pub, mode=2012),
321                 ukm_unmarshal(ukm),
322             )
323
324         self.process_cms(
325             content_info_raw,
326             prv_key_our,
327             "id-tc26-gost-3410-12-512-paramSetB",
328             keker,
329             b"Test message",
330         )
331
332
333 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
334 class TestEnvelopedKARI(TestCase):
335     """EnvelopedData KeyAgreeRecipientInfo-based test vectors from
336     "Использование алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10
337     в криптографических сообщениях формата CMS" (TK26CMS.pdf)
338     """
339
340     def process_cms(
341             self,
342             content_info_raw,
343             prv_key_our,
344             curve_name,
345             keker,
346             plaintext_expected,
347     ):
348         sbox = "id-tc26-gost-28147-param-Z"
349         content_info, tail = ContentInfo().decode(content_info_raw, ctx={
350             "defines_by_path": [
351                 (
352                     (
353                         "content",
354                         DecodePathDefBy(id_envelopedData),
355                         "recipientInfos",
356                         any,
357                         "kari",
358                         "originator",
359                         "originatorKey",
360                         "algorithm",
361                         "algorithm",
362                     ),
363                     (
364                         (
365                             ("..", "publicKey"),
366                             {
367                                 id_tc26_gost3410_2012_256: OctetString(),
368                                 id_tc26_gost3410_2012_512: OctetString(),
369                             },
370                         ),
371                     ),
372                 ) for spki_algorithm in (
373                     id_tc26_gost3410_2012_256,
374                     id_tc26_gost3410_2012_512,
375                 )
376             ],
377         })
378         self.assertSequenceEqual(tail, b"")
379         self.assertIsNotNone(content_info["content"].defined)
380         _, enveloped_data = content_info["content"].defined
381         eci = enveloped_data["encryptedContentInfo"]
382         kari = enveloped_data["recipientInfos"][0]["kari"]
383         self.assertIsNotNone(kari["originator"]["originatorKey"]["publicKey"].defined)
384         _, pub_key_their = kari["originator"]["originatorKey"]["publicKey"].defined
385         ukm = bytes(kari["ukm"])
386         rek = kari["recipientEncryptedKeys"][0]
387         curve = CURVES[curve_name]
388         kek = keker(curve, prv_key_our, bytes(pub_key_their), ukm)
389         self.assertIsNotNone(rek["encryptedKey"].defined)
390         _, encrypted_key = rek["encryptedKey"].defined
391         key_wrapped = bytes(encrypted_key["encryptedKey"])
392         mac = bytes(encrypted_key["macKey"])
393         cek = unwrap_gost(kek, ukm + key_wrapped + mac, sbox=sbox)
394         ciphertext = bytes(eci["encryptedContent"])
395         self.assertIsNotNone(eci["contentEncryptionAlgorithm"]["parameters"].defined)
396         _, encryption_params = eci["contentEncryptionAlgorithm"]["parameters"].defined
397         iv = bytes(encryption_params["iv"])
398         self.assertSequenceEqual(
399             cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
400             plaintext_expected,
401         )
402
403     def test_256(self):
404         content_info_raw = b64decode("""
405 MIIBhgYJKoZIhvcNAQcDoIIBdzCCAXMCAQIxggEwoYIBLAIBA6BooWYwHwYIKoUD
406 BwEBAQEwEwYHKoUDAgIkAAYIKoUDBwEBAgIDQwAEQPAdWM4pO38iZ49UjaXQpq+a
407 jhTa4KwY4B9TFMK7AiYmbFKE0eX/wvu69kFMQ2o3OJTnMOlr1WHiPYOmNO6C5hOh
408 CgQIX+vNomZakEIwIgYIKoUDBwEBAQEwFgYHKoUDAgINADALBgkqhQMHAQIFAQEw
409 gYwwgYkwWzBWMSkwJwYJKoZIhvcNAQkBFhpHb3N0UjM0MTAtMjAxMkBleGFtcGxl
410 LmNvbTEpMCcGA1UEAxMgR29zdFIzNDEwLTIwMTIgMjU2IGJpdHMgZXhjaGFuZ2UC
411 AQEEKjAoBCCNhrZOr7x2fsjjQAeDMv/tSoNRQSSQzzxgqdnYxJ3fIAQEgYLqVDA6
412 BgkqhkiG9w0BBwEwHwYGKoUDAgIVMBUECHVmR/S+hlYiBgkqhQMHAQIFAQGADEI9
413 UNjyuY+54uVcHw==
414         """)
415         prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
416
417         def keker(curve, prv, pub, ukm):
418             return kek_34102012256(
419                 curve,
420                 prv_unmarshal(prv),
421                 pub_unmarshal(pub),
422                 ukm_unmarshal(ukm),
423                 mode=2001,
424             )
425
426         self.process_cms(
427             content_info_raw,
428             prv_key_our,
429             "id-GostR3410-2001-CryptoPro-XchA-ParamSet",
430             keker,
431             b"Test message",
432         )
433
434     def test_512(self):
435         content_info_raw = b64decode("""
436 MIIBzAYJKoZIhvcNAQcDoIIBvTCCAbkCAQIxggF2oYIBcgIBA6CBraGBqjAhBggq
437 hQMHAQEBAjAVBgkqhQMHAQIBAgIGCCqFAwcBAQIDA4GEAASBgCB0nQy/Ljva/mRj
438 w6o+eDKIvnxwYIQB5XCHhZhCpHNZiWcFxFpYXZLWRPKifOxV7NStvqGE1+fkfhBe
439 btkQu0tdC1XL3LO2Cp/jX16XhW/IP5rKV84qWr1Owy/6tnSsNRb+ez6IttwVvaVV
440 pA6ONFy9p9gawoC8nitvAVJkWW0PoQoECDVfxzxgMTAHMCIGCCqFAwcBAQECMBYG
441 ByqFAwICDQAwCwYJKoUDBwECBQEBMIGMMIGJMFswVjEpMCcGCSqGSIb3DQEJARYa
442 R29zdFIzNDEwLTIwMTJAZXhhbXBsZS5jb20xKTAnBgNVBAMTIEdvc3RSMzQxMC0y
443 MDEyIDUxMiBiaXRzIGV4Y2hhbmdlAgEBBCowKAQg8C/OcxRR0Uq8nDjHrQlayFb3
444 WFUZEnEuAKcuG6dTOawEBLhi9hIwOgYJKoZIhvcNAQcBMB8GBiqFAwICFTAVBAiD
445 1wH+CX6CwgYJKoUDBwECBQEBgAzUvQI4H2zRfgNgdlY=
446         """)
447         prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
448
449         def keker(curve, prv, pub, ukm):
450             return kek_34102012256(
451                 curve,
452                 prv_unmarshal(prv),
453                 pub_unmarshal(pub, mode=2012),
454                 ukm_unmarshal(ukm),
455             )
456
457         self.process_cms(
458             content_info_raw,
459             prv_key_our,
460             "id-tc26-gost-3410-12-512-paramSetB",
461             keker,
462             b"Test message",
463         )