]> Cypherpunks.ru repositories - pygost.git/blob - pygost/test_cms.py
Raise copyright years
[pygost.git] / pygost / test_cms.py
1 # coding: utf-8
2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2021 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 six import text_type
22
23 from pygost.gost28147 import cfb_decrypt
24 from pygost.gost3410 import CURVES
25 from pygost.gost3410 import prv_unmarshal
26 from pygost.gost3410 import pub_marshal
27 from pygost.gost3410 import pub_unmarshal
28 from pygost.gost3410 import public_key
29 from pygost.gost3410 import verify
30 from pygost.gost3410_vko import kek_34102012256
31 from pygost.gost3410_vko import ukm_unmarshal
32 from pygost.gost34112012256 import GOST34112012256
33 from pygost.gost34112012512 import GOST34112012512
34 from pygost.gost3412 import GOST3412Kuznechik
35 from pygost.gost3412 import GOST3412Magma
36 from pygost.gost3413 import ctr_acpkm
37 from pygost.gost3413 import KEYSIZE
38 from pygost.gost3413 import mac as omac
39 from pygost.kdf import kdf_tree_gostr3411_2012_256
40 from pygost.kdf import keg
41 from pygost.utils import hexdec
42 from pygost.wrap import kimp15
43 from pygost.wrap import unwrap_cryptopro
44 from pygost.wrap import unwrap_gost
45
46 try:
47     from pyderasn import DecodePathDefBy
48     from pyderasn import OctetString
49
50     from pygost.asn1schemas.cms import ContentInfo
51     from pygost.asn1schemas.cms import SignedAttributes
52     from pygost.asn1schemas.oids import id_cms_mac_attr
53     from pygost.asn1schemas.oids import id_envelopedData
54     from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
55     from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm_omac
56     from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
57     from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm
58     from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm_omac
59     from pygost.asn1schemas.oids import id_gostr3412_2015_magma_wrap_kexp15
60     from pygost.asn1schemas.oids import id_messageDigest
61     from pygost.asn1schemas.oids import id_tc26_agreement_gost3410_2012_256
62     from pygost.asn1schemas.oids import id_tc26_agreement_gost3410_2012_512
63     from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
64     from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
65     from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetA
66     from pygost.asn1schemas.oids import id_tc26_gost3411_2012_256
67     from pygost.asn1schemas.oids import id_tc26_gost3411_2012_512
68     from pygost.asn1schemas.x509 import Certificate
69     from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
70 except ImportError:
71     pyderasn_exists = False
72 else:
73     pyderasn_exists = True
74
75
76 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
77 class TestSigned(TestCase):
78     """SignedData test vectors from "Использование
79     алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10 в
80     криптографических сообщениях формата CMS" (TK26CMS.pdf)
81     """
82
83     def process_cms(
84             self,
85             content_info_raw,
86             prv_key_raw,
87             curve_name,
88             hasher,
89     ):
90         content_info, tail = ContentInfo().decode(content_info_raw)
91         self.assertSequenceEqual(tail, b"")
92         self.assertIsNotNone(content_info["content"].defined)
93         _, signed_data = content_info["content"].defined
94         self.assertEqual(len(signed_data["signerInfos"]), 1)
95         curve = CURVES[curve_name]
96         self.assertTrue(verify(
97             curve,
98             public_key(curve, prv_unmarshal(prv_key_raw)),
99             hasher(bytes(signed_data["encapContentInfo"]["eContent"])).digest()[::-1],
100             bytes(signed_data["signerInfos"][0]["signature"]),
101         ))
102
103     def test_256(self):
104         content_info_raw = b64decode("""
105 MIIBBQYJKoZIhvcNAQcCoIH3MIH0AgEBMQ4wDAYIKoUDBwEBAgIFADAbBgkqhkiG
106 9w0BBwGgDgQMVGVzdCBtZXNzYWdlMYHBMIG+AgEBMFswVjEpMCcGCSqGSIb3DQEJ
107 ARYaR29zdFIzNDEwLTIwMTJAZXhhbXBsZS5jb20xKTAnBgNVBAMTIEdvc3RSMzQx
108 MC0yMDEyICgyNTYgYml0KSBleGFtcGxlAgEBMAwGCCqFAwcBAQICBQAwDAYIKoUD
109 BwEBAQEFAARAkptb2ekZbC94FaGDQeP70ExvTkXtOY9zgz3cCco/hxPhXUVo3eCx
110 VNwDQ8enFItJZ8DEX4blZ8QtziNCMl5HbA==
111         """)
112         prv_key_raw = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
113         self.process_cms(
114             content_info_raw,
115             prv_key_raw,
116             "id-GostR3410-2001-CryptoPro-XchA-ParamSet",
117             GOST34112012256,
118         )
119
120     def test_512(self):
121         content_info_raw = b64decode("""
122 MIIBSQYJKoZIhvcNAQcCoIIBOjCCATYCAQExDjAMBggqhQMHAQECAwUAMBsGCSqG
123 SIb3DQEHAaAOBAxUZXN0IG1lc3NhZ2UxggECMIH/AgEBMFswVjEpMCcGCSqGSIb3
124 DQEJARYaR29zdFIzNDEwLTIwMTJAZXhhbXBsZS5jb20xKTAnBgNVBAMTIEdvc3RS
125 MzQxMC0yMDEyICg1MTIgYml0KSBleGFtcGxlAgEBMAwGCCqFAwcBAQIDBQAwDAYI
126 KoUDBwEBAQIFAASBgFyVohNhMHUi/+RAF3Gh/cC7why6v+4jPWVlx1TYlXtV8Hje
127 hI2Y+rP52/LO6EUHG/XcwCBbUxmRWsbUSRRBAexmaafkSdvv2FFwC8kHOcti+UPX
128 PS+KRYxT8vhcsBLWWxDkc1McI7aF09hqtED36mQOfACzeJjEoUjALpmJob1V
129         """)
130         prv_key_raw = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
131         self.process_cms(
132             content_info_raw,
133             prv_key_raw,
134             "id-tc26-gost-3410-12-512-paramSetB",
135             GOST34112012512,
136         )
137
138
139 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
140 class TestDigested(TestCase):
141     """DigestedData test vectors from "Использование
142     алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10 в
143     криптографических сообщениях формата CMS" (TK26CMS.pdf)
144     """
145
146     def process_cms(self, content_info_raw, hasher):
147         content_info, tail = ContentInfo().decode(content_info_raw)
148         self.assertSequenceEqual(tail, b"")
149         self.assertIsNotNone(content_info["content"].defined)
150         _, digested_data = content_info["content"].defined
151         self.assertSequenceEqual(
152             hasher(bytes(digested_data["encapContentInfo"]["eContent"])).digest(),
153             bytes(digested_data["digest"]),
154         )
155
156     def test_256(self):
157         content_info_raw = b64decode("""
158 MIGdBgkqhkiG9w0BBwWggY8wgYwCAQAwDAYIKoUDBwEBAgIFADBXBgkqhkiG9w0B
159 BwGgSgRI0eUg4uXy8OgsINHy8Ojh7uboIOLt8/boLCDi5f7y+iDxIOzu8P8g8fLw
160 5evg7Ogg7eAg9fDg4fD7/yDv6/rq+yDI4+7w5eL7BCCd0v5OkECeXah/U5dtdAWw
161 wMrGKPxmmnQdUAY8VX6PUA==
162         """)
163         self.process_cms(content_info_raw, GOST34112012256)
164
165     def test_512(self):
166         content_info_raw = b64decode("""
167 MIG0BgkqhkiG9w0BBwWggaYwgaMCAQAwDAYIKoUDBwEBAgMFADBOBgkqhkiG9w0B
168 BwGgQQQ/MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAx
169 MjM0NTY3ODkwMTIzNDU2Nzg5MDEyBEAbVNAaSvW51cw9htaNKFRisZq8JHUiLzXA
170 hRIr5Lof+gCtMPh2ezqCOExldPAkwxHipIEzKwjvf0F5eJHBZG9I
171         """)
172         self.process_cms(content_info_raw, GOST34112012512)
173
174
175 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
176 class TestEnvelopedKTRI(TestCase):
177     """EnvelopedData KeyTransRecipientInfo-based test vectors from
178     "Использование алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10
179     в криптографических сообщениях формата CMS" (TK26CMS.pdf)
180     """
181
182     def process_cms(
183             self,
184             content_info_raw,
185             prv_key_our,
186             curve_name,
187             keker,
188             plaintext_expected,
189     ):
190         sbox = "id-tc26-gost-28147-param-Z"
191         content_info, tail = ContentInfo().decode(content_info_raw, ctx={
192             "defines_by_path": [
193                 (
194                     (
195                         "content",
196                         DecodePathDefBy(id_envelopedData),
197                         "recipientInfos",
198                         any,
199                         "ktri",
200                         "encryptedKey",
201                         DecodePathDefBy(spki_algorithm),
202                         "transportParameters",
203                         "ephemeralPublicKey",
204                         "algorithm",
205                         "algorithm",
206                     ),
207                     (
208                         (
209                             ("..", "subjectPublicKey"),
210                             {
211                                 id_tc26_gost3410_2012_256: OctetString(),
212                                 id_tc26_gost3410_2012_512: OctetString(),
213                             },
214                         ),
215                     ),
216                 ) for spki_algorithm in (
217                     id_tc26_gost3410_2012_256,
218                     id_tc26_gost3410_2012_512,
219                 )
220             ],
221         })
222         self.assertSequenceEqual(tail, b"")
223         self.assertIsNotNone(content_info["content"].defined)
224         _, enveloped_data = content_info["content"].defined
225         eci = enveloped_data["encryptedContentInfo"]
226         ri = enveloped_data["recipientInfos"][0]
227         self.assertIsNotNone(ri["ktri"]["encryptedKey"].defined)
228         _, encrypted_key = ri["ktri"]["encryptedKey"].defined
229         ukm = bytes(encrypted_key["transportParameters"]["ukm"])
230         spk = encrypted_key["transportParameters"]["ephemeralPublicKey"]["subjectPublicKey"]
231         self.assertIsNotNone(spk.defined)
232         _, pub_key_their = spk.defined
233         curve = CURVES[curve_name]
234         kek = keker(curve, prv_key_our, bytes(pub_key_their), ukm)
235         key_wrapped = bytes(encrypted_key["sessionEncryptedKey"]["encryptedKey"])
236         mac = bytes(encrypted_key["sessionEncryptedKey"]["macKey"])
237         cek = unwrap_cryptopro(kek, ukm + key_wrapped + mac, sbox=sbox)
238         ciphertext = bytes(eci["encryptedContent"])
239         self.assertIsNotNone(eci["contentEncryptionAlgorithm"]["parameters"].defined)
240         _, encryption_params = eci["contentEncryptionAlgorithm"]["parameters"].defined
241         iv = bytes(encryption_params["iv"])
242         self.assertSequenceEqual(
243             cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
244             plaintext_expected,
245         )
246
247     def test_256(self):
248         content_info_raw = b64decode("""
249 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
303         """)
304         prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
305
306         def keker(curve, prv, pub, ukm):
307             return kek_34102012256(
308                 curve,
309                 prv_unmarshal(prv),
310                 pub_unmarshal(pub),
311                 ukm_unmarshal(ukm),
312             )
313
314         self.process_cms(
315             content_info_raw,
316             prv_key_our,
317             "id-GostR3410-2001-CryptoPro-XchA-ParamSet",
318             keker,
319             b"Test data to encrypt.\n" * 100,
320         )
321
322     def test_512(self):
323         content_info_raw = b64decode("""
324 MIIB0gYJKoZIhvcNAQcDoIIBwzCCAb8CAQAxggF8MIIBeAIBADBbMFYxKTAnBgkq
325 hkiG9w0BCQEWGkdvc3RSMzQxMC0yMDEyQGV4YW1wbGUuY29tMSkwJwYDVQQDEyBH
326 b3N0UjM0MTAtMjAxMiA1MTIgYml0cyBleGNoYW5nZQIBATAhBggqhQMHAQEBAjAV
327 BgkqhQMHAQIBAgIGCCqFAwcBAQIDBIHyMIHvMCgEIIsYzbVLn33aLinQ7SLNA7y+
328 Lrm02khqDCfXrNS9iiMhBATerS8zoIHCBgkqhQMHAQIFAQGggaowIQYIKoUDBwEB
329 AQIwFQYJKoUDBwECAQICBggqhQMHAQECAwOBhAAEgYAYiTVLKpSGaAvjJEDQ0hdK
330 qR/jek5Q9Q2pXC+NkOimQh7dpCi+wcaHlPcBk96hmpnOFvLaiokX8V6jqtBl5gdk
331 M40kOXv8kcDdTzEVKA/ZLxA8xanL+gTD6ZjaPsUu06nsA2MoMBWcHLUzueaP3bGT
332 /yHTV+Za5xdcQehag/lNBgQIvCw4uUl0XC4wOgYJKoZIhvcNAQcBMB8GBiqFAwIC
333 FTAVBAj+1QzaXaN9FwYJKoUDBwECBQEBgAyK54euw0sHhEVEkA0=
334         """)
335         prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
336
337         def keker(curve, prv, pub, ukm):
338             return kek_34102012256(
339                 curve,
340                 prv_unmarshal(prv),
341                 pub_unmarshal(pub),
342                 ukm_unmarshal(ukm),
343             )
344
345         self.process_cms(
346             content_info_raw,
347             prv_key_our,
348             "id-tc26-gost-3410-12-512-paramSetB",
349             keker,
350             b"Test message",
351         )
352
353
354 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
355 class TestEnvelopedKARI(TestCase):
356     """EnvelopedData KeyAgreeRecipientInfo-based test vectors from
357     "Использование алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10
358     в криптографических сообщениях формата CMS" (TK26CMS.pdf)
359     """
360
361     def process_cms(
362             self,
363             content_info_raw,
364             prv_key_our,
365             curve_name,
366             keker,
367             plaintext_expected,
368     ):
369         sbox = "id-tc26-gost-28147-param-Z"
370         content_info, tail = ContentInfo().decode(content_info_raw, ctx={
371             "defines_by_path": [
372                 (
373                     (
374                         "content",
375                         DecodePathDefBy(id_envelopedData),
376                         "recipientInfos",
377                         any,
378                         "kari",
379                         "originator",
380                         "originatorKey",
381                         "algorithm",
382                         "algorithm",
383                     ),
384                     (
385                         (
386                             ("..", "publicKey"),
387                             {
388                                 id_tc26_gost3410_2012_256: OctetString(),
389                                 id_tc26_gost3410_2012_512: OctetString(),
390                             },
391                         ),
392                     ),
393                 ) for _ in (
394                     id_tc26_gost3410_2012_256,
395                     id_tc26_gost3410_2012_512,
396                 )
397             ],
398         })
399         self.assertSequenceEqual(tail, b"")
400         self.assertIsNotNone(content_info["content"].defined)
401         _, enveloped_data = content_info["content"].defined
402         eci = enveloped_data["encryptedContentInfo"]
403         kari = enveloped_data["recipientInfos"][0]["kari"]
404         self.assertIsNotNone(kari["originator"]["originatorKey"]["publicKey"].defined)
405         _, pub_key_their = kari["originator"]["originatorKey"]["publicKey"].defined
406         ukm = bytes(kari["ukm"])
407         rek = kari["recipientEncryptedKeys"][0]
408         curve = CURVES[curve_name]
409         kek = keker(curve, prv_key_our, bytes(pub_key_their), ukm)
410         self.assertIsNotNone(rek["encryptedKey"].defined)
411         _, encrypted_key = rek["encryptedKey"].defined
412         key_wrapped = bytes(encrypted_key["encryptedKey"])
413         mac = bytes(encrypted_key["macKey"])
414         cek = unwrap_gost(kek, ukm + key_wrapped + mac, sbox=sbox)
415         ciphertext = bytes(eci["encryptedContent"])
416         self.assertIsNotNone(eci["contentEncryptionAlgorithm"]["parameters"].defined)
417         _, encryption_params = eci["contentEncryptionAlgorithm"]["parameters"].defined
418         iv = bytes(encryption_params["iv"])
419         self.assertSequenceEqual(
420             cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
421             plaintext_expected,
422         )
423
424     def test_256(self):
425         content_info_raw = b64decode("""
426 MIIBhgYJKoZIhvcNAQcDoIIBdzCCAXMCAQIxggEwoYIBLAIBA6BooWYwHwYIKoUD
427 BwEBAQEwEwYHKoUDAgIkAAYIKoUDBwEBAgIDQwAEQPAdWM4pO38iZ49UjaXQpq+a
428 jhTa4KwY4B9TFMK7AiYmbFKE0eX/wvu69kFMQ2o3OJTnMOlr1WHiPYOmNO6C5hOh
429 CgQIX+vNomZakEIwIgYIKoUDBwEBAQEwFgYHKoUDAgINADALBgkqhQMHAQIFAQEw
430 gYwwgYkwWzBWMSkwJwYJKoZIhvcNAQkBFhpHb3N0UjM0MTAtMjAxMkBleGFtcGxl
431 LmNvbTEpMCcGA1UEAxMgR29zdFIzNDEwLTIwMTIgMjU2IGJpdHMgZXhjaGFuZ2UC
432 AQEEKjAoBCCNhrZOr7x2fsjjQAeDMv/tSoNRQSSQzzxgqdnYxJ3fIAQEgYLqVDA6
433 BgkqhkiG9w0BBwEwHwYGKoUDAgIVMBUECHVmR/S+hlYiBgkqhQMHAQIFAQGADEI9
434 UNjyuY+54uVcHw==
435         """)
436         prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
437
438         def keker(curve, prv, pub, ukm):
439             return kek_34102012256(
440                 curve,
441                 prv_unmarshal(prv),
442                 pub_unmarshal(pub),
443                 ukm_unmarshal(ukm),
444             )
445
446         self.process_cms(
447             content_info_raw,
448             prv_key_our,
449             "id-GostR3410-2001-CryptoPro-XchA-ParamSet",
450             keker,
451             b"Test message",
452         )
453
454     def test_512(self):
455         content_info_raw = b64decode("""
456 MIIBzAYJKoZIhvcNAQcDoIIBvTCCAbkCAQIxggF2oYIBcgIBA6CBraGBqjAhBggq
457 hQMHAQEBAjAVBgkqhQMHAQIBAgIGCCqFAwcBAQIDA4GEAASBgCB0nQy/Ljva/mRj
458 w6o+eDKIvnxwYIQB5XCHhZhCpHNZiWcFxFpYXZLWRPKifOxV7NStvqGE1+fkfhBe
459 btkQu0tdC1XL3LO2Cp/jX16XhW/IP5rKV84qWr1Owy/6tnSsNRb+ez6IttwVvaVV
460 pA6ONFy9p9gawoC8nitvAVJkWW0PoQoECDVfxzxgMTAHMCIGCCqFAwcBAQECMBYG
461 ByqFAwICDQAwCwYJKoUDBwECBQEBMIGMMIGJMFswVjEpMCcGCSqGSIb3DQEJARYa
462 R29zdFIzNDEwLTIwMTJAZXhhbXBsZS5jb20xKTAnBgNVBAMTIEdvc3RSMzQxMC0y
463 MDEyIDUxMiBiaXRzIGV4Y2hhbmdlAgEBBCowKAQg8C/OcxRR0Uq8nDjHrQlayFb3
464 WFUZEnEuAKcuG6dTOawEBLhi9hIwOgYJKoZIhvcNAQcBMB8GBiqFAwICFTAVBAiD
465 1wH+CX6CwgYJKoUDBwECBQEBgAzUvQI4H2zRfgNgdlY=
466         """)
467         prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
468
469         def keker(curve, prv, pub, ukm):
470             return kek_34102012256(
471                 curve,
472                 prv_unmarshal(prv),
473                 pub_unmarshal(pub),
474                 ukm_unmarshal(ukm),
475             )
476
477         self.process_cms(
478             content_info_raw,
479             prv_key_our,
480             "id-tc26-gost-3410-12-512-paramSetB",
481             keker,
482             b"Test message",
483         )
484
485
486 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
487 class TestR132356510252019(TestCase):
488     """Test vectors from Р 1323565.1.025-2019
489     """
490     def setUp(self):
491         self.curve256 = CURVES["id-tc26-gost-3410-2012-256-paramSetA"]
492         self.curve512 = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
493         self.psk = hexdec("8F5EEF8814D228FB2BBC5612323730CFA33DB7263CC2C0A01A6C6953F33D61D5")[::-1]
494
495         self.ca_prv = prv_unmarshal(hexdec("092F8D059E97E22B90B1AE99F0087FC4D26620B91550CBB437C191005A290810")[::-1])
496         self.ca_pub = public_key(self.curve256, self.ca_prv)
497         self.ca_cert = Certificate().decod(b64decode("""
498 MIIB8DCCAZ2gAwIBAgIEAYy6gTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
499 MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
500 MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA4MQ0wCwYDVQQKEwRUSzI2MScwJQYD
501 VQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwaDAhBggqhQMHAQEB
502 ATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABEAaSoKcjw54UACci6svELNF0IYM
503 RIW8urUsqamIpoG46XCqrVOuI6Q13N4dwcRsbZdqByf+GC2f5ZfO3baN5bTKo4GF
504 MIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzESoTowODENMAsGA1UE
505 ChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0
506 ggQBjLqBMB0GA1UdDgQWBBSA2Qz3mfhmTZNTiY7AnnEtp6cxEjAKBggqhQMHAQED
507 AgNBAAgv248F4OeNCkhlzJWec0evHYnMBlSzk1lDm0F875B7CqMrKh2MtJHXenbj
508 Gc2uRn2IwgmSf/LZDrYsKKqZSxk=
509 """))
510
511         self.sender256_prv = prv_unmarshal(hexdec("0B20810E449978C7C3B76C6FF77A16C532421139344A058EF56310B6B6F377E8")[::-1])
512         self.sender256_pub = public_key(self.curve256, self.sender256_prv)
513         self.sender256_cert = Certificate().decod(b64decode("""
514 MIIB8zCCAaCgAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
515 MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
516 MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYD
517 VQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwaDAhBggqhQMH
518 AQEBATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABECWKQ0TYllqg4GmY3tBJiyz
519 pXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpNNSHpQnm+jLAZhuJaJfqZ6VbT
520 o4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzESoTowODENMAsG
521 A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
522 Yml0ggQBjLqBMB0GA1UdDgQWBBTRnChHSWbQYwnJC62n2zu5Njd03zAKBggqhQMH
523 AQEDAgNBAB41oijaXSEn58l78y2rhxY35/lKEq4XWZ70FtsNlVxWATyzgO5Wliwn
524 t1O4GoZsxx8r6T/i7VG65UNmQlwdOKQ=
525 """))
526
527         self.recipient256_prv = prv_unmarshal(hexdec("0DC8DC1FF2BC114BABC3F1CA8C51E4F58610427E197B1C2FBDBA4AE58CBFB7CE")[::-1])
528         self.recipient256_pub = public_key(self.curve256, self.recipient256_prv)
529         self.recipient256_cert = Certificate().decod(b64decode("""
530 MIIB8jCCAZ+gAwIBAgIEAYy6gzAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
531 MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
532 MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA6MQ0wCwYDVQQKEwRUSzI2MSkwJwYD
533 VQQDEyBSRUNJUElFTlQ6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdDBoMCEGCCqFAwcB
534 AQEBMBUGCSqFAwcBAgEBAQYIKoUDBwEBAgIDQwAEQL8nghlzLGMKWHuWhNMPMN5u
535 L6SkGqRiJ6qZxZb+4dPKbBT9LNVvNKtwUed+BeE5kfqOfolPgFusnL1rnO9yREOj
536 gYUwgYIwYQYDVR0BBFowWIAUgNkM95n4Zk2TU4mOwJ5xLaenMRKhOjA4MQ0wCwYD
537 VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1i
538 aXSCBAGMuoEwHQYDVR0OBBYEFLue+PUb9Oe+pziBU+MvNejjgrzFMAoGCCqFAwcB
539 AQMCA0EAPP9Oad1/5jwokSjPpccsQ0xCdVYM+mGQ0IbpiZxQj8gnkt8sq4jR6Ya+
540 I/BDkbZNDNE27TU1p3t5rE9NMEeViA==
541 """))
542
543         self.sender512_prv = prv_unmarshal(hexdec("F95A5D44C5245F63F2E7DF8E782C1924EADCB8D06C52D91023179786154CBDB1561B4DF759D69F67EE1FBD5B68800E134BAA12818DA4F3AC75B0E5E6F9256911")[::-1])
544         self.sender512_pub = public_key(self.curve512, self.sender512_prv)
545         self.sender512_cert = Certificate().decod(b64decode("""
546 MIICNjCCAeOgAwIBAgIEAYy6hDAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
547 MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
548 MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYD
549 VQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDUxMi1iaXQwgaowIQYIKoUD
550 BwEBAQIwFQYJKoUDBwECAQIBBggqhQMHAQECAwOBhAAEgYC0i7davCkOGGVcYqFP
551 tS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO+K21LDpYVfDPs2Sqa13ZN+Ts
552 /JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0EmZf8T3ae/J1Jo6xGunecH1/G4
553 hMts9HYLnxbwJDMNVGuIHV6gzqOBhTCBgjBhBgNVHQEEWjBYgBSA2Qz3mfhmTZNT
554 iY7AnnEtp6cxEqE6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6
555 IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQUK+l9HAscONGx
556 zCcRpxRAmFHvlXowCgYIKoUDBwEBAwIDQQAbjA0Q41/rIKOOvjHKsAsoEJM+WJf6
557 /PKXg2JaStthmw99bdtwwkU/qDbcje2tF6mt+XWyQBXwvfeES1GFY9fJ
558 """))
559
560         self.recipient512_prv = prv_unmarshal(hexdec("A50315981F0A7C7FC05B4EB9591A62B1F84BD6FD518ACFCEDF0A7C9CF388D1F18757C056ADA5B38CBF24CDDB0F1519EF72DB1712CEF1920952E94AF1F9C575DC")[::-1])
561         self.recipient512_pub = public_key(self.curve512, self.recipient512_prv)
562         self.recipient512_cert = Certificate().decod(b64decode("""
563 MIICNTCCAeKgAwIBAgIEAYy6hTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
564 MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
565 MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA6MQ0wCwYDVQQKEwRUSzI2MSkwJwYD
566 VQQDEyBSRUNJUElFTlQ6IEdPU1QgMzQuMTAtMTIgNTEyLWJpdDCBqjAhBggqhQMH
567 AQEBAjAVBgkqhQMHAQIBAgEGCCqFAwcBAQIDA4GEAASBgKauwGYvUkzz19g0LP/p
568 zeRdmwy1m+QSy9W5ZrL/AGuJofm2ARjz40ozNbW6bp9hkHu8x66LX7u5zz+QeS2+
569 X5om18UXriComgO0+qhZbc+Hzu0eQ8FjOd8LpLk3TzzfBltfLOX5IiPLjeum+pSP
570 0QjoXAVcrop//B4yvZIukvROo4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJ
571 jsCecS2npzESoTowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjog
572 R09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBSrXT5VKhm/5uff
573 kwW0XpG19k6AajAKBggqhQMHAQEDAgNBAAJBpsHRrQKZGb22LOzaReEB8rl2MbIR
574 ja64NaM5h+cAFoHm6t/k+ziLh2A11rTakR+5of4NQ3EjEhuPtomP2tc=
575 """))
576
577     def test_certs(self):
578         """Certificates signatures
579         """
580         for prv, pub, curve, cert in (
581                 (self.ca_prv, self.ca_pub, self.curve256, self.ca_cert),
582                 (self.sender256_prv, self.sender256_pub, self.curve256, self.sender256_cert),
583                 (self.recipient256_prv, self.recipient256_pub, self.curve256, self.recipient256_cert),
584                 (self.sender512_prv, self.sender512_pub, self.curve512, self.sender512_cert),
585                 (self.recipient512_prv, self.recipient512_pub, self.curve512, self.recipient512_cert),
586         ):
587             pub_our = public_key(curve, prv)
588             self.assertEqual(pub_our, pub)
589             self.assertSequenceEqual(
590                 pub_marshal(pub_our),
591                 bytes(OctetString().decod(bytes(
592                     cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
593                 ))),
594             )
595
596         for cert in (
597                 self.ca_cert,
598                 self.sender256_cert,
599                 self.recipient256_cert,
600                 self.sender512_cert,
601                 self.recipient512_cert,
602         ):
603             self.assertTrue(verify(
604                 self.curve256,
605                 self.ca_pub,
606                 GOST34112012256(cert["tbsCertificate"].encode()).digest()[::-1],
607                 bytes(cert["signatureValue"]),
608             ))
609
610     def test_signed_with_attrs(self):
611         ci = ContentInfo().decod(b64decode("""
612 MIIENwYJKoZIhvcNAQcCoIIEKDCCBCQCAQExDDAKBggqhQMHAQECAzA7BgkqhkiG
613 9w0BBwGgLgQsyu7t8vDu6/zt++kg7/Do7OXwIOTr/yDx8vDz6vLz8PsgU2lnbmVk
614 RGF0YS6gggI6MIICNjCCAeOgAwIBAgIEAYy6hDAKBggqhQMHAQEDAjA4MQ0wCwYD
615 VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1i
616 aXQwHhcNMDEwMTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRU
617 SzI2MSowKAYDVQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDUxMi1iaXQw
618 gaowIQYIKoUDBwEBAQIwFQYJKoUDBwECAQIBBggqhQMHAQECAwOBhAAEgYC0i7da
619 vCkOGGVcYqFPtS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO+K21LDpYVfDP
620 s2Sqa13ZN+Ts/JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0EmZf8T3ae/J1Jo
621 6xGunecH1/G4hMts9HYLnxbwJDMNVGuIHV6gzqOBhTCBgjBhBgNVHQEEWjBYgBSA
622 2Qz3mfhmTZNTiY7AnnEtp6cxEqE6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMT
623 HkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQU
624 K+l9HAscONGxzCcRpxRAmFHvlXowCgYIKoUDBwEBAwIDQQAbjA0Q41/rIKOOvjHK
625 sAsoEJM+WJf6/PKXg2JaStthmw99bdtwwkU/qDbcje2tF6mt+XWyQBXwvfeES1GF
626 Y9fJMYIBlDCCAZACAQEwQDA4MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBU
627 SzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQCBAGMuoQwCgYIKoUDBwEBAgOgga0w
628 GAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkwMzIw
629 MTk1NTIyWjAiBgkqhkiG9w0BCWIxFQQTU2lnbmVkIGF0dHIncyB2YWx1ZTBPBgkq
630 hkiG9w0BCQQxQgRAUdPHEukF5BIfo9DoQIMdnB0ZLkzq0RueEUZSNv07A7C+GKWi
631 G62fueArg8uPCHPTUN6d/42p33fgMkEwH7f7cDAKBggqhQMHAQEBAgSBgGUnVka8
632 FvTlClmOtj/FUUacBdE/nEBeMLOO/535VDYrXlftPE6zQf/4ghS7TQG2VRGQ3GWD
633 +L3+W09A7d5uyyTEbvgtdllUG0OyqFwKmJEaYsMin87SFVs0cn1PGV1fOKeLluZa
634 bLx5whxd+mzlpekL5i6ImRX+TpERxrA/xSe5
635 """))
636         _, sd = ci["content"].defined
637         content = bytes(sd["encapContentInfo"]["eContent"])
638         self.assertEqual(
639             content.decode("cp1251"),
640             text_type(u"Контрольный пример для структуры SignedData."),
641         )
642         si = sd["signerInfos"][0]
643         self.assertEqual(
644             si["digestAlgorithm"]["algorithm"],
645             id_tc26_gost3411_2012_512,
646         )
647         digest = [
648             bytes(attr["attrValues"][0].defined[1]) for attr in si["signedAttrs"]
649             if attr["attrType"] == id_messageDigest
650         ][0]
651         self.assertSequenceEqual(digest, GOST34112012512(content).digest())
652         self.assertTrue(verify(
653             self.curve512,
654             self.sender512_pub,
655             GOST34112012512(
656                 SignedAttributes(si["signedAttrs"]).encode()
657             ).digest()[::-1],
658             bytes(si["signature"]),
659         ))
660
661     def test_signed_without_attrs(self):
662         ci = ContentInfo().decod(b64decode("""
663 MIIDAQYJKoZIhvcNAQcCoIIC8jCCAu4CAQExDDAKBggqhQMHAQECAjA7BgkqhkiG
664 9w0BBwGgLgQsyu7t8vDu6/zt++kg7/Do7OXwIOTr/yDx8vDz6vLz8PsgU2lnbmVk
665 RGF0YS6gggH3MIIB8zCCAaCgAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYD
666 VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1i
667 aXQwHhcNMDEwMTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRU
668 SzI2MSowKAYDVQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQw
669 aDAhBggqhQMHAQEBATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABECWKQ0TYllq
670 g4GmY3tBJiyzpXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpNNSHpQnm+jLAZ
671 huJaJfqZ6VbTo4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzES
672 oTowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4x
673 MC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBTRnChHSWbQYwnJC62n2zu5Njd0
674 3zAKBggqhQMHAQEDAgNBAB41oijaXSEn58l78y2rhxY35/lKEq4XWZ70FtsNlVxW
675 ATyzgO5Wliwnt1O4GoZsxx8r6T/i7VG65UNmQlwdOKQxgaIwgZ8CAQEwQDA4MQ0w
676 CwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1
677 Ni1iaXQCBAGMuoIwCgYIKoUDBwEBAgIwCgYIKoUDBwEBAQEEQC6jZPA59szL9FiA
678 0wC71EBE42ap6gKxklT800cu2FvbLu972GJYNSI7+UeanVU37OVWyenEXi2E5HkU
679 94kBe8Q=
680 """))
681         _, sd = ci["content"].defined
682         content = bytes(sd["encapContentInfo"]["eContent"])
683         self.assertEqual(
684             content.decode("cp1251"),
685             text_type(u"Контрольный пример для структуры SignedData."),
686         )
687         si = sd["signerInfos"][0]
688         self.assertEqual(
689             si["digestAlgorithm"]["algorithm"],
690             id_tc26_gost3411_2012_256,
691         )
692         self.assertTrue(verify(
693             self.curve256,
694             self.sender256_pub,
695             GOST34112012256(content).digest()[::-1],
696             bytes(si["signature"]),
697         ))
698
699     def test_kari_ephemeral(self):
700         ci = ContentInfo().decod(b64decode("""
701 MIIB/gYJKoZIhvcNAQcDoIIB7zCCAesCAQIxggFioYIBXgIBA6CBo6GBoDAXBggq
702 hQMHAQEBAjALBgkqhQMHAQIBAgEDgYQABIGAe+itJVNbHM35RHfzuwFJPYdPXqtW
703 8hNEF7Z/XFEE2T71SRkhFX7ozYKQNh/TkVY9D4vG0LnD9Znr/pJyOjpsNb+dPcKX
704 Kbk/0JQxoPGHxFzASVAFq0ov/yBe2XGFWMeKUqtaAr7SvoYS0oEhT5EuT8BXmecd
705 nRe7NqOzESpb15ahIgQgsqHxOcdOp03l11S7k3OH1k1HNa5F8m9ctrOzH2846FMw
706 FwYJKoUDBwEBBwIBMAoGCCqFAwcBAQYCMHYwdDBAMDgxDTALBgNVBAoTBFRLMjYx
707 JzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdAIEAYy6hQQw
708 SxLc18zMwzLwXbcKqYhV/VzsdBgVArOHsSBIbaThJWE7zI37VGPMQJM5VXJ7GVcL
709 MF0GCSqGSIb3DQEHATAfBgkqhQMHAQEFAgIwEgQQ6EeVlADDCz2cdEWKy+tM94Av
710 yIFl/Ie4VeFFuczTsMsIaOUEe3Jn9GeVp8hZSj3O2q4hslQ/u/+Gj4QkSHm/M0ih
711 ITAfBgkqhQMHAQAGAQExEgQQs1t6D3J3WCEvxunnEE15NQ==
712 """))
713         _, ed = ci["content"].defined
714         kari = ed["recipientInfos"][0]["kari"]
715         orig_key = kari["originator"]["originatorKey"]
716         self.assertEqual(orig_key["algorithm"]["algorithm"], id_tc26_gost3410_2012_512)
717         self.assertEqual(
718             GostR34102012PublicKeyParameters().decod(
719                 bytes(orig_key["algorithm"]["parameters"])
720             )["publicKeyParamSet"],
721             id_tc26_gost3410_2012_512_paramSetA,
722         )
723         orig_pub = pub_unmarshal(
724             bytes(OctetString().decod(bytes(orig_key["publicKey"]))),
725         )
726         ukm = bytes(kari["ukm"])
727         self.assertEqual(
728             kari["keyEncryptionAlgorithm"]["algorithm"],
729             id_gostr3412_2015_kuznyechik_wrap_kexp15,
730         )
731         self.assertEqual(
732             kari["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
733             id_tc26_agreement_gost3410_2012_512,
734         )
735         kexp = bytes(kari["recipientEncryptedKeys"][0]["encryptedKey"])
736         keymat = keg(self.curve512, self.recipient512_prv, orig_pub, ukm)
737         kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
738         cek = kimp15(
739             GOST3412Kuznechik(kek).encrypt,
740             GOST3412Kuznechik(kim).encrypt,
741             GOST3412Kuznechik.blocksize,
742             kexp,
743             ukm[24:24 + GOST3412Kuznechik.blocksize // 2],
744         )
745         eci = ed["encryptedContentInfo"]
746         self.assertEqual(
747             eci["contentEncryptionAlgorithm"]["algorithm"],
748             id_gostr3412_2015_kuznyechik_ctracpkm_omac,
749         )
750         eci_ukm = bytes(
751             eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
752         )
753         self.assertEqual(ed["unprotectedAttrs"][0]["attrType"], id_cms_mac_attr)
754         encrypted_mac = bytes(ed["unprotectedAttrs"][0]["attrValues"][0].defined[1])
755         encrypted_content = bytes(eci["encryptedContent"])
756         cek_enc, cek_mac = kdf_tree_gostr3411_2012_256(
757             cek, b"kdf tree", eci_ukm[GOST3412Kuznechik.blocksize // 2:], 2,
758         )
759         content_and_tag = ctr_acpkm(
760             GOST3412Kuznechik,
761             GOST3412Kuznechik(cek_enc).encrypt,
762             256 * 1024,
763             GOST3412Kuznechik.blocksize,
764             encrypted_content + encrypted_mac,
765             eci_ukm[:GOST3412Kuznechik.blocksize // 2],
766         )
767         content = content_and_tag[:-GOST3412Kuznechik.blocksize]
768         tag_expected = content_and_tag[-GOST3412Kuznechik.blocksize:]
769         self.assertSequenceEqual(
770             omac(
771                 GOST3412Kuznechik(cek_mac).encrypt,
772                 GOST3412Kuznechik.blocksize,
773                 content,
774             ),
775             tag_expected,
776         )
777         self.assertEqual(
778             content.decode("cp1251"),
779             text_type(u"Контрольный пример для структуры EnvelopedData."),
780         )
781
782     def test_kari_static(self):
783         ci = ContentInfo().decod(b64decode("""
784 MIIBawYJKoZIhvcNAQcDoIIBXDCCAVgCAQIxgfehgfQCAQOgQjBAMDgxDTALBgNV
785 BAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJp
786 dAIEAYy6gqEiBCBvcfyuSF57y8vVyaw8Z0ch3wjC4lPKTrpVRXty4Rhk5DAXBgkq
787 hQMHAQEHAQEwCgYIKoUDBwEBBgEwbjBsMEAwODENMAsGA1UEChMEVEsyNjEnMCUG
788 A1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0AgQBjLqDBChPbi6B
789 krXuLPexPAL2oUGCFWDGQHqINL5ExuMBG7/5XQRqriKARVa0MFkGCSqGSIb3DQEH
790 ATAbBgkqhQMHAQEFAQEwDgQMdNdCKnYAAAAwqTEDgC9O2bYyTGQJ8WUQGq0zHwzX
791 L0jFhWHTF1tcAxYmd9pX5i89UwIxhtYqyjX1QHju2g==
792 """))
793         _, ed = ci["content"].defined
794         kari = ed["recipientInfos"][0]["kari"]
795         ukm = bytes(kari["ukm"])
796         self.assertEqual(
797             kari["keyEncryptionAlgorithm"]["algorithm"],
798             id_gostr3412_2015_magma_wrap_kexp15,
799         )
800         self.assertEqual(
801             kari["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
802             id_tc26_agreement_gost3410_2012_256,
803         )
804         kexp = bytes(kari["recipientEncryptedKeys"][0]["encryptedKey"])
805         keymat = keg(
806             self.curve256,
807             self.recipient256_prv,
808             self.sender256_pub,
809             ukm,
810         )
811         kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
812         cek = kimp15(
813             GOST3412Magma(kek).encrypt,
814             GOST3412Magma(kim).encrypt,
815             GOST3412Magma.blocksize,
816             kexp,
817             ukm[24:24 + GOST3412Magma.blocksize // 2],
818         )
819         eci = ed["encryptedContentInfo"]
820         self.assertEqual(
821             eci["contentEncryptionAlgorithm"]["algorithm"],
822             id_gostr3412_2015_magma_ctracpkm,
823         )
824         eci_ukm = bytes(
825             eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
826         )
827         content = ctr_acpkm(
828             GOST3412Magma,
829             GOST3412Magma(cek).encrypt,
830             8 * 1024,
831             GOST3412Magma.blocksize,
832             bytes(eci["encryptedContent"]),
833             eci_ukm[:GOST3412Magma.blocksize // 2],
834         )
835         self.assertEqual(
836             content.decode("cp1251"),
837             text_type(u"Контрольный пример для структуры EnvelopedData."),
838         )
839
840     def test_ktri_256(self):
841         ci = ContentInfo().decod(b64decode("""
842 MIIBlQYJKoZIhvcNAQcDoIIBhjCCAYICAQAxggEcMIIBGAIBADBAMDgxDTALBgNV
843 BAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJp
844 dAIEAYy6gzAXBgkqhQMHAQEHAgEwCgYIKoUDBwEBBgEEgbcwgbQEMFiMredFR3Mv
845 3g2wqyVXRnrhYEBMNFaqqgBpHwPQh3bF98tt9HZPxRDCww0OPfxeuTBeMBcGCCqF
846 AwcBAQEBMAsGCSqFAwcBAgEBAQNDAARAdFJ9ww+3ptvQiaQpizCldNYhl4DB1rl8
847 Fx/2FIgnwssCbYRQ+UuRsTk9dfLLTGJG3JIEXKFxXWBgOrK965A5pAQg9f2/EHxG
848 DfetwCe1a6uUDCWD+wp5dYOpfkry8YRDEJgwXQYJKoZIhvcNAQcBMB8GCSqFAwcB
849 AQUCATASBBDUHNxmVclO/v3OaY9P7jxOgC+sD9CHGlEMRUpfGn6yfFDMExmYeby8
850 LzdPJe1MkYV0qQgdC1zI3nQ7/4taf+4zRA==
851 """))
852         _, ed = ci["content"].defined
853         ktri = ed["recipientInfos"][0]["ktri"]
854         self.assertEqual(
855             ktri["keyEncryptionAlgorithm"]["algorithm"],
856             id_gostr3412_2015_kuznyechik_wrap_kexp15,
857         )
858         self.assertEqual(
859             ktri["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
860             id_tc26_agreement_gost3410_2012_256,
861         )
862         _, encrypted_key = ktri["encryptedKey"].defined
863         self.assertEqual(
864             encrypted_key["ephemeralPublicKey"]["algorithm"]["algorithm"],
865             id_tc26_gost3410_2012_256,
866         )
867         pub = pub_unmarshal(bytes(OctetString().decod(
868             bytes(encrypted_key["ephemeralPublicKey"]["subjectPublicKey"])
869         )))
870         ukm = bytes(encrypted_key["ukm"])
871         kexp = bytes(encrypted_key["encryptedKey"])
872         keymat = keg(self.curve256, self.recipient256_prv, pub, ukm)
873         kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
874         cek = kimp15(
875             GOST3412Kuznechik(kek).encrypt,
876             GOST3412Kuznechik(kim).encrypt,
877             GOST3412Kuznechik.blocksize,
878             kexp,
879             ukm[24:24 + GOST3412Kuznechik.blocksize // 2],
880         )
881         eci = ed["encryptedContentInfo"]
882         self.assertEqual(
883             eci["contentEncryptionAlgorithm"]["algorithm"],
884             id_gostr3412_2015_kuznyechik_ctracpkm,
885         )
886         eci_ukm = bytes(
887             eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
888         )
889         content = ctr_acpkm(
890             GOST3412Kuznechik,
891             GOST3412Kuznechik(cek).encrypt,
892             256 * 1024,
893             GOST3412Kuznechik.blocksize,
894             bytes(eci["encryptedContent"]),
895             eci_ukm[:GOST3412Kuznechik.blocksize // 2],
896         )
897         self.assertEqual(
898             content.decode("cp1251"),
899             text_type(u"Контрольный пример для структуры EnvelopedData."),
900         )
901
902     def test_ktri_512(self):
903         ci = ContentInfo().decod(b64decode("""
904 MIIB5wYJKoZIhvcNAQcDoIIB2DCCAdQCAQAxggFXMIIBUwIBADBAMDgxDTALBgNVBAoTBFRL
905 MjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdAIEAYy6hTAXBgkq
906 hQMHAQEHAQEwCgYIKoUDBwEBBgIEgfIwge8EKDof9JLTJVuIfP+c+imDCGyOLtAYENkoXpeU
907 CdiGn0Lt65t3TN9G0bUwgaAwFwYIKoUDBwEBAQIwCwYJKoUDBwECAQIBA4GEAASBgDD9XXHn
908 0j4EwY3DGB1wzHeThPRDlCwIvpmqWy00QDhS3fLRWiETSe9uMLeg27zI/EiserKMasNZum/i
909 d09cmP8aTNIDNRtI5H9M0mH7LpEtY8L901MszvOKHLDYdemvz0JUqOvBtvoeQ6sV4Gl45zXx
910 HTzBWlBw1FLX/ITWLapaBCAa09foTeA+PObBznGuCOPoKy+xz/9IIVmZidI6EYkIrzBZBgkq
911 hkiG9w0BBwEwGwYJKoUDBwEBBQECMA4EDA4z1UwRL4WYzKFX/oAv8eEX3fWt6hxDpjO0rI7/
912 CiJ/CwYGCKODJ9h63vAwlsWwcPwAjxcsLvCNlv6i4NqhGTAXBgkqhQMHAQAGAQExCgQIs2DT
913 LuZ22Yw=
914 """))
915         _, ed = ci["content"].defined
916         ktri = ed["recipientInfos"][0]["ktri"]
917         self.assertEqual(
918             ktri["keyEncryptionAlgorithm"]["algorithm"],
919             id_gostr3412_2015_magma_wrap_kexp15,
920         )
921         self.assertEqual(
922             ktri["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
923             id_tc26_agreement_gost3410_2012_512,
924         )
925         _, encrypted_key = ktri["encryptedKey"].defined
926         self.assertEqual(
927             encrypted_key["ephemeralPublicKey"]["algorithm"]["algorithm"],
928             id_tc26_gost3410_2012_512,
929         )
930         pub = pub_unmarshal(
931             bytes(OctetString().decod(
932                 bytes(encrypted_key["ephemeralPublicKey"]["subjectPublicKey"])
933             )),
934         )
935         ukm = bytes(encrypted_key["ukm"])
936         kexp = bytes(encrypted_key["encryptedKey"])
937         keymat = keg(self.curve512, self.recipient512_prv, pub, ukm)
938         kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
939         cek = kimp15(
940             GOST3412Magma(kek).encrypt,
941             GOST3412Magma(kim).encrypt,
942             GOST3412Magma.blocksize,
943             kexp,
944             ukm[24:24 + GOST3412Magma.blocksize // 2],
945         )
946         eci = ed["encryptedContentInfo"]
947         self.assertEqual(
948             eci["contentEncryptionAlgorithm"]["algorithm"],
949             id_gostr3412_2015_magma_ctracpkm_omac,
950         )
951         eci_ukm = bytes(
952             eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
953         )
954         self.assertEqual(ed["unprotectedAttrs"][0]["attrType"], id_cms_mac_attr)
955         encrypted_mac = bytes(ed["unprotectedAttrs"][0]["attrValues"][0].defined[1])
956         encrypted_content = bytes(eci["encryptedContent"])
957         cek_enc, cek_mac = kdf_tree_gostr3411_2012_256(
958             cek, b"kdf tree", eci_ukm[GOST3412Magma.blocksize // 2:], 2,
959         )
960         content_and_tag = ctr_acpkm(
961             GOST3412Magma,
962             GOST3412Magma(cek_enc).encrypt,
963             8 * 1024,
964             GOST3412Magma.blocksize,
965             encrypted_content + encrypted_mac,
966             eci_ukm[:GOST3412Magma.blocksize // 2],
967         )
968         content = content_and_tag[:-GOST3412Magma.blocksize]
969         tag_expected = content_and_tag[-GOST3412Magma.blocksize:]
970         self.assertSequenceEqual(
971             omac(
972                 GOST3412Magma(cek_mac).encrypt,
973                 GOST3412Magma.blocksize,
974                 content,
975             ),
976             tag_expected,
977         )
978         self.assertEqual(
979             content.decode("cp1251"),
980             text_type(u"Контрольный пример для структуры EnvelopedData."),
981         )
982
983     def test_digested256(self):
984         ci = ContentInfo().decod(b64decode("""
985 MH0GCSqGSIb3DQEHBaBwMG4CAQAwCgYIKoUDBwEBAgIwOwYJKoZIhvcNAQcBoC4ELMru7fLw
986 7uv87fvpIO/w6Ozl8CDk6/8g8fLw8+ry8/D7IERpZ2VzdERhdGEuBCD/esPQYsGkzxZV8uUM
987 IAWt6SI8KtxBP8NyG8AGbJ8i/Q==
988 """))
989         _, dd = ci["content"].defined
990         eci = dd["encapContentInfo"]
991         self.assertSequenceEqual(
992             GOST34112012256(bytes(eci["eContent"])).digest(),
993             bytes(dd["digest"]),
994         )
995
996     def test_digested512(self):
997         ci = ContentInfo().decod(b64decode("""
998 MIGfBgkqhkiG9w0BBwWggZEwgY4CAQAwCgYIKoUDBwEBAgMwOwYJKoZIhvcNAQcBoC4ELMru
999 7fLw7uv87fvpIO/w6Ozl8CDk6/8g8fLw8+ry8/D7IERpZ2VzdERhdGEuBEDe4VUvcKSRvU7R
1000 FVhFjajXY+nJSUkUsoi3oOeJBnru4PErt8RusPrCJs614ciHCM+ehrC4a+M1Nbq77F/Wsa/v
1001 """))
1002         _, dd = ci["content"].defined
1003         eci = dd["encapContentInfo"]
1004         self.assertSequenceEqual(
1005             GOST34112012512(bytes(eci["eContent"])).digest(),
1006             bytes(dd["digest"]),
1007         )
1008
1009     def test_encrypted_kuznechik(self):
1010         ci = ContentInfo().decod(b64decode("""
1011 MHEGCSqGSIb3DQEHBqBkMGICAQAwXQYJKoZIhvcNAQcBMB8GCSqFAwcBAQUCATASBBBSwX+z
1012 yOEPPuGyfpsRG4AigC/P8ftTdQMStfIThVkE/vpJlwaHgGv83m2bsPayeyuqpoTeEMOaqGcO
1013 0MxHWsC9hQ==
1014 """))
1015         _, ed = ci["content"].defined
1016         eci = ed["encryptedContentInfo"]
1017         self.assertEqual(
1018             eci["contentEncryptionAlgorithm"]["algorithm"],
1019             id_gostr3412_2015_kuznyechik_ctracpkm,
1020         )
1021         ukm = bytes(
1022             eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
1023         )
1024         content = ctr_acpkm(
1025             GOST3412Kuznechik,
1026             GOST3412Kuznechik(self.psk).encrypt,
1027             256 * 1024,
1028             GOST3412Kuznechik.blocksize,
1029             bytes(eci["encryptedContent"]),
1030             ukm[:GOST3412Kuznechik.blocksize // 2],
1031         )
1032         self.assertEqual(
1033             content.decode("cp1251"),
1034             text_type(u"Контрольный пример для структуры EncryptedData."),
1035         )
1036
1037     def test_encrypted_magma(self):
1038         ci = ContentInfo().decod(b64decode("""
1039 MIGIBgkqhkiG9w0BBwagezB5AgEAMFkGCSqGSIb3DQEHATAbBgkqhQMHAQEFAQIwDgQMuncO
1040 u3uYPbI30vFCgC9Nsws4R09yLp6jUtadncWUPZGmCGpPKnXGgNHvEmUArgKJvu4FPHtLkHuL
1041 eQXZg6EZMBcGCSqFAwcBAAYBATEKBAjCbQoH632oGA==
1042 """))
1043         _, ed = ci["content"].defined
1044         eci = ed["encryptedContentInfo"]
1045         self.assertEqual(
1046             eci["contentEncryptionAlgorithm"]["algorithm"],
1047             id_gostr3412_2015_magma_ctracpkm_omac,
1048         )
1049         ukm = bytes(
1050             eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
1051         )
1052         self.assertEqual(ed["unprotectedAttrs"][0]["attrType"], id_cms_mac_attr)
1053         encrypted_mac = bytes(ed["unprotectedAttrs"][0]["attrValues"][0].defined[1])
1054         cek_enc, cek_mac = kdf_tree_gostr3411_2012_256(
1055             self.psk, b"kdf tree", ukm[GOST3412Magma.blocksize // 2:], 2,
1056         )
1057         content_and_tag = ctr_acpkm(
1058             GOST3412Magma,
1059             GOST3412Magma(cek_enc).encrypt,
1060             8 * 1024,
1061             GOST3412Magma.blocksize,
1062             bytes(eci["encryptedContent"]) + encrypted_mac,
1063             ukm[:GOST3412Magma.blocksize // 2],
1064         )
1065         content = content_and_tag[:-GOST3412Magma.blocksize]
1066         tag_expected = content_and_tag[-GOST3412Magma.blocksize:]
1067         self.assertSequenceEqual(
1068             omac(
1069                 GOST3412Magma(cek_mac).encrypt,
1070                 GOST3412Magma.blocksize,
1071                 content,
1072             ),
1073             tag_expected,
1074         )
1075         self.assertEqual(
1076             content.decode("cp1251"),
1077             text_type(u"Контрольный пример для структуры EncryptedData."),
1078         )