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