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