2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2021 Sergey Matveev <stargrave@stargrave.org>
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.
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.
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/>.
17 from base64 import b64decode
18 from hmac import new as hmac_new
19 from unittest import skipIf
20 from unittest import TestCase
22 from pygost import gost3410
23 from pygost.gost28147 import cfb_decrypt
24 from pygost.gost34112012256 import GOST34112012256
25 from pygost.gost34112012512 import GOST34112012512
26 from pygost.gost34112012512 import pbkdf2 as gost34112012_pbkdf2
27 from pygost.gost3412 import GOST3412Kuznechik
28 from pygost.gost3412 import GOST3412Magma
29 from pygost.gost3412 import KEYSIZE
30 from pygost.gost3413 import ctr_acpkm
31 from pygost.gost3413 import mac as omac
32 from pygost.kdf import kdf_tree_gostr3411_2012_256
33 from pygost.kdf import keg
34 from pygost.utils import hexdec
35 from pygost.wrap import kimp15
39 from pyderasn import OctetString
40 from pygost.asn1schemas.cms import EncryptedData
41 from pygost.asn1schemas.cms import EnvelopedData
42 from pygost.asn1schemas.cms import SignedAttributes
43 from pygost.asn1schemas.cms import SignedData
44 from pygost.asn1schemas.oids import id_data
45 from pygost.asn1schemas.oids import id_envelopedData
46 from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
47 from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
48 from pygost.asn1schemas.oids import id_messageDigest
49 from pygost.asn1schemas.oids import id_pbes2
50 from pygost.asn1schemas.oids import id_pkcs12_bagtypes_certBag
51 from pygost.asn1schemas.oids import id_pkcs12_bagtypes_keyBag
52 from pygost.asn1schemas.oids import id_pkcs12_bagtypes_pkcs8ShroudedKeyBag
53 from pygost.asn1schemas.oids import id_pkcs9_certTypes_x509Certificate
54 from pygost.asn1schemas.oids import id_signedData
55 from pygost.asn1schemas.oids import id_tc26_agreement_gost3410_2012_256
56 from pygost.asn1schemas.oids import id_tc26_gost3411_2012_256
57 from pygost.asn1schemas.pfx import CertBag
58 from pygost.asn1schemas.pfx import KeyBag
59 from pygost.asn1schemas.pfx import OctetStringSafeContents
60 from pygost.asn1schemas.pfx import PBES2Params
61 from pygost.asn1schemas.pfx import PFX
62 from pygost.asn1schemas.pfx import PKCS8ShroudedKeyBag
63 from pygost.asn1schemas.pfx import SafeContents
64 from pygost.asn1schemas.x509 import Certificate
66 pyderasn_exists = False
68 pyderasn_exists = True
71 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
72 class TestPFX(TestCase):
73 """PFX test vectors from "Транспортный ключевой контейнер" (R50.1.112-2016.pdf)
75 pfx_raw = b64decode("""
76 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
108 password = u"Пароль для PFX"
110 def test_shrouded_key_bag(self):
111 private_key_info_expected = b64decode(b"""
112 MGYCAQAwHwYIKoUDBwEBAQEwEwYHKoUDAgIjAQYIKoUDBwEBAgIEQEYbRu86z+1JFKDcPDN9UbTG
113 G2ki9enTqos4KpUU0j9IDpl1UXiaA1YDIwUjlAp+81GkLmyt8Fw6Gt/X5JZySAY=
116 pfx, tail = PFX().decode(self.pfx_raw)
117 self.assertSequenceEqual(tail, b"")
118 _, outer_safe_contents = pfx["authSafe"]["content"].defined
119 safe_contents, tail = OctetStringSafeContents().decode(
120 bytes(outer_safe_contents[0]["bagValue"]),
122 self.assertSequenceEqual(tail, b"")
123 safe_bag = safe_contents[0]
124 shrouded_key_bag, tail = PKCS8ShroudedKeyBag().decode(
125 bytes(safe_bag["bagValue"]),
127 self.assertSequenceEqual(tail, b"")
128 _, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
129 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
130 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
132 key = gost34112012_pbkdf2(
133 password=self.password.encode("utf-8"),
134 salt=bytes(pbkdf2_params["salt"]["specified"]),
135 iterations=int(pbkdf2_params["iterationCount"]),
138 # key = hexdec("309dd0354c5603739403f2335e9e2055138f8b5c98b63009de0635eea1fd7ba8")
139 self.assertSequenceEqual(
142 bytes(shrouded_key_bag["encryptedData"]),
143 iv=bytes(enc_scheme_params["iv"]),
144 sbox="id-tc26-gost-28147-param-Z",
146 private_key_info_expected,
149 def test_encrypted_data(self):
150 cert_bag_expected = b64decode(b"""
151 MIIDSjCCA0YGCyqGSIb3DQEMCgEDoIIDHjCCAxoGCiqGSIb3DQEJFgGgggMKBIIDBjCCAwIwggKt
152 oAMCAQICEAHQaF8xH5bAAAAACycJAAEwDAYIKoUDBwEBAwIFADBgMQswCQYDVQQGEwJSVTEVMBMG
153 A1UEBwwM0JzQvtGB0LrQstCwMQ8wDQYDVQQKDAbQotCaMjYxKTAnBgNVBAMMIENBIGNlcnRpZmlj
154 YXRlIChQS0NTIzEyIGV4YW1wbGUpMB4XDTE1MDMyNzA3MjUwMFoXDTIwMDMyNzA3MjMwMFowZDEL
155 MAkGA1UEBhMCUlUxFTATBgNVBAcMDNCc0L7RgdC60LLQsDEPMA0GA1UECgwG0KLQmjI2MS0wKwYD
156 VQQDDCRUZXN0IGNlcnRpZmljYXRlIDEgKFBLQ1MjMTIgZXhhbXBsZSkwZjAfBggqhQMHAQEBATAT
157 BgcqhQMCAiMBBggqhQMHAQECAgNDAARA1xzymkpvr2dYJT8WTOX3Dt96/+hGsXNytUQpkWB5ImJM
158 4tg9AsC4RIUwV5H41MhG0uBRFweTzN6AsAdBvhTClYEJADI3MDkwMDAxo4IBKTCCASUwKwYDVR0Q
159 BCQwIoAPMjAxNTAzMjcwNzI1MDBagQ8yMDE2MDMyNzA3MjUwMFowDgYDVR0PAQH/BAQDAgTwMB0G
160 A1UdDgQWBBQhWOsRQ68yYN2Utg/owHoWcqsVbTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
161 AwQwDAYDVR0TAQH/BAIwADCBmQYDVR0jBIGRMIGOgBQmnc7Xh5ykb5t/BMwOkxA4drfEmqFkpGIw
162 YDELMAkGA1UEBhMCUlUxFTATBgNVBAcMDNCc0L7RgdC60LLQsDEPMA0GA1UECgwG0KLQmjI2MSkw
163 JwYDVQQDDCBDQSBjZXJ0aWZpY2F0ZSAoUEtDUyMxMiBleGFtcGxlKYIQAdBoXvL8TSAAAAALJwkA
164 ATAMBggqhQMHAQEDAgUAA0EA9oq0Vvk8kkgIwkp0x0J5eKtia4MNTiwKAm7jgnCZIx3O98BThaTX
165 3ZQhEo2RL9pTCPr6wFMheeJ+YdGMReXvsjEVMBMGCSqGSIb3DQEJFTEGBAQBAAAA
168 pfx, tail = PFX().decode(self.pfx_raw)
169 self.assertSequenceEqual(tail, b"")
170 _, outer_safe_contents = pfx["authSafe"]["content"].defined
171 _, encrypted_data = outer_safe_contents[1]["bagValue"].defined
172 _, pbes2_params = encrypted_data["encryptedContentInfo"]["contentEncryptionAlgorithm"]["parameters"].defined
173 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
174 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
175 key = gost34112012_pbkdf2(
176 password=self.password.encode("utf-8"),
177 salt=bytes(pbkdf2_params["salt"]["specified"]),
178 iterations=int(pbkdf2_params["iterationCount"]),
181 # key = hexdec("0e93d71339e7f53b79a0bc41f9109dd4fb60b30ae10736c1bb77b84c07681cfc")
182 self.assertSequenceEqual(
185 bytes(encrypted_data["encryptedContentInfo"]["encryptedContent"]),
186 iv=bytes(enc_scheme_params["iv"]),
187 sbox="id-tc26-gost-28147-param-Z",
193 pfx, tail = PFX().decode(self.pfx_raw)
194 self.assertSequenceEqual(tail, b"")
195 _, outer_safe_contents = pfx["authSafe"]["content"].defined
196 mac_data = pfx["macData"]
197 mac_key = gost34112012_pbkdf2(
198 password=self.password.encode("utf-8"),
199 salt=bytes(mac_data["macSalt"]),
200 iterations=int(mac_data["iterations"]),
203 # mac_key = hexdec("cadbfbf3bceaa9b79f651508fac5abbeb4a13d0bd0e1876bd3c3efb2112128a5")
204 self.assertSequenceEqual(
207 msg=SafeContents(outer_safe_contents).encode(),
208 digestmod=GOST34112012512,
210 bytes(mac_data["mac"]["digest"]),
214 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
215 class TestPFX2020(TestCase):
216 """PFX test vectors from newer PKCS#12 update
218 ca_prv_raw = hexdec("092F8D059E97E22B90B1AE99F0087FC4D26620B91550CBB437C191005A290810")
219 ca_curve = gost3410.CURVES["id-tc26-gost-3410-12-256-paramSetA"]
220 ca_cert = Certificate().decod(b64decode(b"""
221 MIIB+TCCAaagAwIBAgIEAYy6gTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
222 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
223 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA4MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx
224 5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwXjAXBggqhQMHAQEBATALBgkq
225 hQMHAQIBAQEDQwAEQBpKgpyPDnhQAJyLqy8Qs0XQhgxEhby6tSypqYimgbjpcKqtU6
226 4jpDXc3h3BxGxtl2oHJ/4YLZ/ll87dto3ltMqjgZgwgZUwYwYDVR0jBFwwWoAUrGwO
227 TERmokKW4p8JOyVm88ukUyqhPKQ6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHk
228 NBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQUrGwO
229 TERmokKW4p8JOyVm88ukUyowDwYDVR0TAQH/BAUwAwEB/zAKBggqhQMHAQEDAgNBAB
230 Gg3nhgQ5oCKbqlEdVaRxH+1WX4wVkawGXuTYkr1AC2OWw3ZC14Vvg3nazm8UMWUZtk
233 ca_pub = gost3410.pub_unmarshal(bytes(OctetString().decod(bytes(
234 ca_cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
236 password = "Пароль для PFX".encode("utf-8")
237 cert_test = Certificate().decod(b64decode(b"""
238 MIICLjCCAdugAwIBAgIEAYy6hDAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
239 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
240 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYDVQQDEy
241 FPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDUxMi1iaXQwgaAwFwYIKoUDBwEBAQIw
242 CwYJKoUDBwECAQIBA4GEAASBgLSLt1q8KQ4YZVxioU+1LV9QhE7MHR9gBEh7S1yVNG
243 lqt7+rNG5VFqmrPM74rbUsOlhV8M+zZKprXdk35Oz8lSW/n2oIUHZxikXIH/SSHj4r
244 v3K/Puvz7hYTQSZl/xPdp78nUmjrEa6d5wfX8biEy2z0dgufFvAkMw1Ua4gdXqDOo4
245 GHMIGEMGMGA1UdIwRcMFqAFKxsDkxEZqJCluKfCTslZvPLpFMqoTykOjA4MQ0wCwYD
246 VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaX
247 SCBAGMuoEwHQYDVR0OBBYEFH4GVwmYDK1rCKhX7nkAWDrJ16CkMAoGCCqFAwcBAQMC
248 A0EACl6p8dAbpi9Hk+3mgMyI0WIh17IrlrSp/mB0F7ZzMt8XUD1Dwz3JrrnxeXnfMv
249 OA5BdUJ9hCyDgMVAGs/IcEEA==
251 prv_test_raw = b64decode("""
252 MIHiAgEBMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAQRAEWkl+eblsHWs86SNgRKq
253 SxMOgGhbvR/uZ5/WWfdNG1axvUwVhpcXIxDZUmzQuNzqJBkseI7f5/JjXyTFRF1a
254 +YGBgQG0i7davCkOGGVcYqFPtS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO
255 +K21LDpYVfDPs2Sqa13ZN+Ts/JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0Em
256 Zf8T3ae/J1Jo6xGunecH1/G4hMts9HYLnxbwJDMNVGuIHV6gzg==
259 def test_cert_and_encrypted_key(self):
260 pfx_raw = b64decode(b"""
261 MIIFKwIBAzCCBMQGCSqGSIb3DQEHAaCCBLUEggSxMIIErTCCAswGCSqGSIb3DQEH
262 AaCCAr0EggK5MIICtTCCArEGCyqGSIb3DQEMCgEDoIICSjCCAkYGCiqGSIb3DQEJ
263 FgGgggI2BIICMjCCAi4wggHboAMCAQICBAGMuoQwCgYIKoUDBwEBAwIwODENMAsG
264 A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
265 Yml0MB4XDTAxMDEwMTAwMDAwMFoXDTQ5MTIzMTAwMDAwMFowOzENMAsGA1UEChME
266 VEsyNjEqMCgGA1UEAxMhT1JJR0lOQVRPUjogR09TVCAzNC4xMC0xMiA1MTItYml0
267 MIGgMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAQOBhAAEgYC0i7davCkOGGVcYqFP
268 tS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO+K21LDpYVfDPs2Sqa13ZN+Ts
269 /JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0EmZf8T3ae/J1Jo6xGunecH1/G4
270 hMts9HYLnxbwJDMNVGuIHV6gzqOBhzCBhDBjBgNVHSMEXDBagBSsbA5MRGaiQpbi
271 nwk7JWbzy6RTKqE8pDowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsy
272 NjogR09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBR+BlcJmAyt
273 awioV+55AFg6ydegpDAKBggqhQMHAQEDAgNBAApeqfHQG6YvR5Pt5oDMiNFiIdey
274 K5a0qf5gdBe2czLfF1A9Q8M9ya658Xl53zLzgOQXVCfYQsg4DFQBrPyHBBAxVDAj
275 BgkqhkiG9w0BCRUxFgQUeVV0+dS25MICJChpmGc/8AoUwE0wLQYJKoZIhvcNAQkU
276 MSAeHgBwADEAMgBGAHIAaQBlAG4AZABsAHkATgBhAG0AZTCCAdkGCSqGSIb3DQEH
277 AaCCAcoEggHGMIIBwjCCAb4GCyqGSIb3DQEMCgECoIIBVzCCAVMwWQYJKoZIhvcN
278 AQUNMEwwKQYJKoZIhvcNAQUMMBwECKf4N7NMwugqAgIIADAMBggqhQMHAQEEAgUA
279 MB8GCSqFAwcBAQUCAjASBBAlmt2WDfaPJlsAs0mLKglzBIH1DMvEacbbWRNDVSnX
280 JLWygYrKoipdOjDA/2HEnBZ34uFOLNheUqiKpCPoFpbR2GBiVYVTVK9ibiczgaca
281 EQYzDXtcS0QCZOxpKWfteAlbdJLC/SqPurPYyKi0MVRUPROhbisFASDT38HDH1Dh
282 0dL5f6ga4aPWLrWbbgWERFOoOPyh4DotlPF37AQOwiEjsbyyRHq3HgbWiaxQRuAh
283 eqHOn4QVGY92/HFvJ7u3TcnQdLWhTe/lh1RHLNF3RnXtN9if9zC23laDZOiWZplU
284 yLrUiTCbHrtn1RppPDmLFNMt9dJ7KKgCkOi7Zm5nhqPChbywX13wcfYxVDAjBgkq
285 hkiG9w0BCRUxFgQUeVV0+dS25MICJChpmGc/8AoUwE0wLQYJKoZIhvcNAQkUMSAe
286 HgBwADEAMgBGAHIAaQBlAG4AZABsAHkATgBhAG0AZTBeME4wCgYIKoUDBwEBAgME
287 QAkBKw4ihn7pSIYTEhu0bcvTPZjI3WgVxCkUVlOsc80G69EKFEOTnObGJGSKJ51U
288 KkOsXF0a7+VBZf3BcVVQh9UECIVEtO+VpuskAgIIAA==
290 pfx = PFX().decod(pfx_raw)
291 _, outer_safe_contents = pfx["authSafe"]["content"].defined
293 safe_contents = OctetStringSafeContents().decod(bytes(
294 outer_safe_contents[0]["bagValue"]
296 safe_bag = safe_contents[0]
297 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
298 cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
299 self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
300 _, cert = cert_bag["certValue"].defined
301 self.assertEqual(Certificate(cert), self.cert_test)
303 safe_contents = OctetStringSafeContents().decod(bytes(
304 outer_safe_contents[1]["bagValue"]
306 safe_bag = safe_contents[0]
307 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_pkcs8ShroudedKeyBag)
308 shrouded_key_bag = PKCS8ShroudedKeyBag().decod(bytes(safe_bag["bagValue"]))
309 _, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
310 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
311 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
312 ukm = bytes(enc_scheme_params["ukm"])
313 key = gost34112012_pbkdf2(
314 password=self.password,
315 salt=bytes(pbkdf2_params["salt"]["specified"]),
316 iterations=int(pbkdf2_params["iterationCount"]),
319 # key = hexdec("4b7ae649ca31dd5fe3243a91a5188c03f1d7049bec8e0d241c0e1e8c39ea4c1f")
320 key_enc, key_mac = kdf_tree_gostr3411_2012_256(
321 key, b"kdf tree", ukm[GOST3412Kuznechik.blocksize // 2:], 2,
323 ciphertext = bytes(shrouded_key_bag["encryptedData"])
324 plaintext = ctr_acpkm(
326 GOST3412Kuznechik(key_enc).encrypt,
327 section_size=256 * 1024,
328 bs=GOST3412Kuznechik.blocksize,
330 iv=ukm[:GOST3412Kuznechik.blocksize // 2],
332 mac_expected = plaintext[-GOST3412Kuznechik.blocksize:]
333 plaintext = plaintext[:-GOST3412Kuznechik.blocksize]
335 GOST3412Kuznechik(key_mac).encrypt,
336 GOST3412Kuznechik.blocksize,
339 self.assertSequenceEqual(mac, mac_expected)
340 self.assertSequenceEqual(plaintext, self.prv_test_raw)
342 mac_data = pfx["macData"]
343 mac_key = gost34112012_pbkdf2(
344 password=self.password,
345 salt=bytes(mac_data["macSalt"]),
346 iterations=int(mac_data["iterations"]),
349 # mac_key = hexdec("a81d1bc91a4a5cf1fd7320f92dda7e5b285816c3b20826a382d7ed0cbf3a9bf4")
350 self.assertSequenceEqual(
353 msg=SafeContents(outer_safe_contents).encode(),
354 digestmod=GOST34112012512,
356 bytes(mac_data["mac"]["digest"]),
358 self.assertTrue(gost3410.verify(
361 GOST34112012256(cert["tbsCertificate"].encode()).digest()[::-1],
362 bytes(cert["signatureValue"]),
365 def test_encrypted_cert_and_key(self):
366 pfx_raw = b64decode(b"""
367 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
398 pfx = PFX().decod(pfx_raw)
399 _, outer_safe_contents = pfx["authSafe"]["content"].defined
401 encrypted_data = EncryptedData().decod(bytes(
402 outer_safe_contents[0]["bagValue"]
404 eci = encrypted_data["encryptedContentInfo"]
405 self.assertEqual(eci["contentEncryptionAlgorithm"]["algorithm"], id_pbes2)
406 pbes2_params = PBES2Params().decod(bytes(
407 eci["contentEncryptionAlgorithm"]["parameters"]
409 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
410 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
411 ukm = bytes(enc_scheme_params["ukm"])
412 key = gost34112012_pbkdf2(
413 password=self.password,
414 salt=bytes(pbkdf2_params["salt"]["specified"]),
415 iterations=int(pbkdf2_params["iterationCount"]),
418 # key = hexdec("d066a96fb326ba896a2352d3f40240a4ded6e7e7bd5b4db6b5241d631c8c381c")
419 key_enc, key_mac = kdf_tree_gostr3411_2012_256(
420 key, b"kdf tree", ukm[GOST3412Magma.blocksize // 2:], 2,
422 ciphertext = bytes(eci["encryptedContent"])
423 plaintext = ctr_acpkm(
425 GOST3412Magma(key_enc).encrypt,
426 section_size=8 * 1024,
427 bs=GOST3412Magma.blocksize,
429 iv=ukm[:GOST3412Magma.blocksize // 2],
431 mac_expected = plaintext[-GOST3412Magma.blocksize:]
432 plaintext = plaintext[:-GOST3412Magma.blocksize]
434 GOST3412Magma(key_mac).encrypt,
435 GOST3412Magma.blocksize,
438 self.assertSequenceEqual(mac, mac_expected)
440 safe_contents = SafeContents().decod(plaintext)
441 safe_bag = safe_contents[0]
442 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
443 cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
444 self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
445 _, cert = cert_bag["certValue"].defined
446 self.assertEqual(Certificate(cert), self.cert_test)
448 safe_contents = OctetStringSafeContents().decod(bytes(
449 outer_safe_contents[1]["bagValue"]
451 safe_bag = safe_contents[0]
452 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_pkcs8ShroudedKeyBag)
453 shrouded_key_bag = PKCS8ShroudedKeyBag().decod(bytes(safe_bag["bagValue"]))
454 _, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
455 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
456 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
457 ukm = bytes(enc_scheme_params["ukm"])
458 key = gost34112012_pbkdf2(
459 password=self.password,
460 salt=bytes(pbkdf2_params["salt"]["specified"]),
461 iterations=int(pbkdf2_params["iterationCount"]),
464 # key = hexdec("f840d001fd11441e0fb7ccf48f471915e5bf35275309dbe7ade9da4fe460ba7e")
465 ciphertext = bytes(shrouded_key_bag["encryptedData"])
466 plaintext = ctr_acpkm(
468 GOST3412Magma(key).encrypt,
469 section_size=8 * 1024,
470 bs=GOST3412Magma.blocksize,
472 iv=ukm[:GOST3412Magma.blocksize // 2],
474 self.assertSequenceEqual(plaintext, self.prv_test_raw)
476 mac_data = pfx["macData"]
477 mac_key = gost34112012_pbkdf2(
478 password=self.password,
479 salt=bytes(mac_data["macSalt"]),
480 iterations=int(mac_data["iterations"]),
483 # mac_key = hexdec("084f81782af1534ffd67e3c579c14cb45d7a6f659f46fdbb51a552e874e66fb2")
484 self.assertSequenceEqual(
487 msg=SafeContents(outer_safe_contents).encode(),
488 digestmod=GOST34112012512,
490 bytes(mac_data["mac"]["digest"]),
494 curve = gost3410.CURVES["id-tc26-gost-3410-12-256-paramSetA"]
495 # sender_prv_raw = hexdec("0B20810E449978C7C3B76C6FF77A16C532421139344A058EF56310B6B6F377E8")
496 sender_cert = Certificate().decod(b64decode("""
497 MIIB6zCCAZigAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
498 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
499 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYDVQQDEy
500 FPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwXjAXBggqhQMHAQEBATAL
501 BgkqhQMHAQIBAQEDQwAEQJYpDRNiWWqDgaZje0EmLLOldQ35o5X1ZuZNSKequYQc/s
502 oI3OgDMWD7ThJJCk01IelCeb6MsBmG4lol+pnpVtOjgYcwgYQwYwYDVR0jBFwwWoAU
503 rGwOTERmokKW4p8JOyVm88ukUyqhPKQ6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBA
504 MTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQU
505 Px5RgcjkifhlJm4/jQdkbm30rVQwCgYIKoUDBwEBAwIDQQA68x7Vk6PvP/8xOGHhf8
506 PuqaXAYskSyJPuBu+3Bo/PEj10devwc1J9uYWIDCGdKKPybSlnQHqUPBBPM30YX1YN
508 recipient_prv_raw = hexdec("0DC8DC1FF2BC114BABC3F1CA8C51E4F58610427E197B1C2FBDBA4AE58CBFB7CE")[::-1]
509 recipient_prv = gost3410.prv_unmarshal(recipient_prv_raw)
510 recipient_cert = Certificate().decod(b64decode("""
511 MIIB6jCCAZegAwIBAgIEAYy6gzAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
512 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
513 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA6MQ0wCwYDVQQKEwRUSzI2MSkwJwYDVQQDEy
514 BSRUNJUElFTlQ6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdDBeMBcGCCqFAwcBAQEBMAsG
515 CSqFAwcBAgEBAQNDAARAvyeCGXMsYwpYe5aE0w8w3m4vpKQapGInqpnFlv7h08psFP
516 0s1W80q3BR534F4TmR+o5+iU+AW6ycvWuc73JEQ6OBhzCBhDBjBgNVHSMEXDBagBSs
517 bA5MRGaiQpbinwk7JWbzy6RTKqE8pDowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAx
518 MeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBQ3
519 5gHPN1bx8l2eEMTbrtIg+5MU0TAKBggqhQMHAQEDAgNBABF2RHDaRqQuBS2yu7yGIG
520 FgA6c/LG4GKjSOwYsRVmXJNNkQ4TB7PB8j3q7gx2koPsVBm90WfMWSL6SNSh3muuM=
522 self.assertTrue(gost3410.verify(
525 GOST34112012256(sender_cert["tbsCertificate"].encode()).digest()[::-1],
526 bytes(sender_cert["signatureValue"]),
528 self.assertTrue(gost3410.verify(
531 GOST34112012256(recipient_cert["tbsCertificate"].encode()).digest()[::-1],
532 bytes(recipient_cert["signatureValue"]),
535 pfx_raw = b64decode("""
536 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
591 e6qgRVHn9b+Mq3sp57LxHk4Sny0zV8TRwCr8
593 pfx = PFX().decod(pfx_raw)
594 self.assertEqual(pfx["authSafe"]["contentType"], id_signedData)
596 sd = SignedData().decod(bytes(pfx["authSafe"]["content"]))
597 # self.assertEqual(sd["certificates"][0]["certificate"], sender_cert)
598 si = sd["signerInfos"][0]
600 si["digestAlgorithm"]["algorithm"],
601 id_tc26_gost3411_2012_256,
604 bytes(attr["attrValues"][0].defined[1]) for attr in si["signedAttrs"]
605 if attr["attrType"] == id_messageDigest
607 sender_pub = gost3410.pub_unmarshal(bytes(OctetString().decod(bytes(
608 sender_cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
610 content = bytes(sd["encapContentInfo"]["eContent"])
611 self.assertSequenceEqual(digest, GOST34112012256(content).digest())
612 self.assertTrue(gost3410.verify(
616 SignedAttributes(si["signedAttrs"]).encode()
618 bytes(si["signature"]),
621 outer_safe_contents = SafeContents().decod(content)
623 safe_bag = outer_safe_contents[0]
624 self.assertEqual(safe_bag["bagId"], id_data)
625 safe_contents = OctetStringSafeContents().decod(bytes(safe_bag["bagValue"]))
626 safe_bag = safe_contents[0]
627 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
628 cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
629 self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
630 _, cert = cert_bag["certValue"].defined
631 self.assertEqual(Certificate(cert), self.cert_test)
633 safe_bag = outer_safe_contents[1]
634 self.assertEqual(safe_bag["bagId"], id_envelopedData)
635 ed = EnvelopedData().decod(bytes(safe_bag["bagValue"]))
636 kari = ed["recipientInfos"][0]["kari"]
637 ukm = bytes(kari["ukm"])
639 kari["keyEncryptionAlgorithm"]["algorithm"],
640 id_gostr3412_2015_kuznyechik_wrap_kexp15,
643 kari["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
644 id_tc26_agreement_gost3410_2012_256,
646 kexp = bytes(kari["recipientEncryptedKeys"][0]["encryptedKey"])
647 keymat = keg(curve, recipient_prv, sender_pub, ukm)
648 kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
650 GOST3412Kuznechik(kek).encrypt,
651 GOST3412Kuznechik(kim).encrypt,
652 GOST3412Kuznechik.blocksize,
654 ukm[24:24 + GOST3412Kuznechik.blocksize // 2],
656 eci = ed["encryptedContentInfo"]
658 eci["contentEncryptionAlgorithm"]["algorithm"],
659 id_gostr3412_2015_kuznyechik_ctracpkm,
662 eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
666 GOST3412Kuznechik(cek).encrypt,
668 GOST3412Kuznechik.blocksize,
669 bytes(eci["encryptedContent"]),
670 eci_ukm[:GOST3412Kuznechik.blocksize // 2],
673 safe_contents = SafeContents().decod(content)
674 safe_bag = safe_contents[0]
675 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_keyBag)
676 KeyBag().decod(bytes(safe_bag["bagValue"]))
677 self.assertSequenceEqual(bytes(safe_bag["bagValue"]), self.prv_test_raw)