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