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
41 from pygost.asn1schemas.cms import EncryptedData
42 from pygost.asn1schemas.cms import EnvelopedData
43 from pygost.asn1schemas.cms import SignedAttributes
44 from pygost.asn1schemas.cms import SignedData
45 from pygost.asn1schemas.oids import id_data
46 from pygost.asn1schemas.oids import id_envelopedData
47 from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
48 from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
49 from pygost.asn1schemas.oids import id_messageDigest
50 from pygost.asn1schemas.oids import id_pbes2
51 from pygost.asn1schemas.oids import id_pkcs12_bagtypes_certBag
52 from pygost.asn1schemas.oids import id_pkcs12_bagtypes_keyBag
53 from pygost.asn1schemas.oids import id_pkcs12_bagtypes_pkcs8ShroudedKeyBag
54 from pygost.asn1schemas.oids import id_pkcs9_certTypes_x509Certificate
55 from pygost.asn1schemas.oids import id_signedData
56 from pygost.asn1schemas.oids import id_tc26_agreement_gost3410_2012_256
57 from pygost.asn1schemas.oids import id_tc26_gost3411_2012_256
58 from pygost.asn1schemas.pfx import CertBag
59 from pygost.asn1schemas.pfx import KeyBag
60 from pygost.asn1schemas.pfx import OctetStringSafeContents
61 from pygost.asn1schemas.pfx import PBES2Params
62 from pygost.asn1schemas.pfx import PFX
63 from pygost.asn1schemas.pfx import PKCS8ShroudedKeyBag
64 from pygost.asn1schemas.pfx import SafeContents
65 from pygost.asn1schemas.x509 import Certificate
67 pyderasn_exists = False
69 pyderasn_exists = True
72 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
73 class TestPFX(TestCase):
74 """PFX test vectors from "Транспортный ключевой контейнер" (R50.1.112-2016.pdf)
76 pfx_raw = b64decode("""
77 MIIFqgIBAzCCBSsGCSqGSIb3DQEHAaCCBRwEggUYMIIFFDCCASIGCSqGSIb3DQEH
78 AaCCARMEggEPMIIBCzCCAQcGCyqGSIb3DQEMCgECoIHgMIHdMHEGCSqGSIb3DQEF
79 DTBkMEEGCSqGSIb3DQEFDDA0BCD5qZr0TTIsBvdgUoq/zFwOzdyJohj6/4Wiyccg
80 j9AK/QICB9AwDAYIKoUDBwEBBAIFADAfBgYqhQMCAhUwFQQI3Ip/Vp0IsyIGCSqF
81 AwcBAgUBAQRoSfLhgx9s/zn+BjnhT0ror07vS55Ys5hgvVpWDx4mXGWWyez/2sMc
82 aFgSr4H4UTGGwoMynGLpF1IOVo+bGJ0ePqHB+gS5OL9oV+PUmZ/ELrRENKlCDqfY
83 WvpSystX29CvCFrnTnDsbBYxFTATBgkqhkiG9w0BCRUxBgQEAQAAADCCA+oGCSqG
84 SIb3DQEHBqCCA9swggPXAgEAMIID0AYJKoZIhvcNAQcBMHEGCSqGSIb3DQEFDTBk
85 MEEGCSqGSIb3DQEFDDA0BCCJTJLZQRi1WIpQHzyjXbq7+Vw2+1280C45x8ff6kMS
86 VAICB9AwDAYIKoUDBwEBBAIFADAfBgYqhQMCAhUwFQQIxepowwvS11MGCSqFAwcB
87 AgUBAYCCA06n09P/o+eDEKoSWpvlpOLKs7dKmVquKzJ81nCngvLQ5fEWL1WkxwiI
88 rEhm53JKLD0wy4hekalEk011Bvc51XP9gkDkmaoBpnV/TyKIY35wl6ATfeGXno1M
89 KoA+Ktdhv4gLnz0k2SXdkUj11JwYskXue+REA0p4m2ZsoaTmvoODamh9JeY/5Qjy
90 Xe58CGnyXFzX3eU86qs4WfdWdS3NzYYOk9zzVl46le9u79O/LnW2j4n2of/Jpk/L
91 YjrRmz5oYeQOqKOKhEyhpO6e+ejr6laduEv7TwJQKRNiygogbVvkNn3VjHTSOUG4
92 W+3NRPhjb0jD9obdyx6MWa6O3B9bUzFMNav8/gYn0vTDxqXMLy/92oTngNrVx6Gc
93 cNl128ISrDS6+RxtAMiEBRK6xNkemqX5yNXG5GrLQQFGP6mbs2nNpjKlgj3pljmX
94 Eky2/G78XiJrv02OgGs6CKnI9nMpa6N7PBHV34MJ6EZzWOWDRQ420xk63mnicrs0
95 WDVJ0xjdu4FW3iEk02EaiRTvGBpa6GL7LBp6QlaXSSwONx725cyRsL9cTlukqXER
96 WHDlMpjYLbkGZRrCc1myWgEfsputfSIPNF/oLv9kJNWacP3uuDOfecg3us7eg2OA
97 xo5zrYfn39GcBMF1WHAYRO/+PnJb9jrDuLAE8+ONNqjNulWNK9CStEhb6Te+yE6q
98 oeP6hJjFLi+nFLE9ymIo0A7gLQD5vzFvl+7v1ZNVnQkwRUsWoRiEVVGnv3Z1iZU6
99 xStxgoHMl62V/P5cz4dr9vJM2adEWNZcVXl6mk1H8DRc1sRGnvs2l237oKWRVntJ
100 hoWnZ8qtD+3ZUqsX79QhVzUQBzKuBt6jwNhaHLGl5B+Or/zA9FezsOh6+Uc+fZaV
101 W7fFfeUyWwGy90XD3ybTrjzep9f3nt55Z2c+fu2iEwhoyImWLuC3+CVhf9Af59j9
102 8/BophMJuATDJEtgi8rt4vLnfxKu250Mv2ZpbfF69EGTgFYbwc55zRfaUG9zlyCu
103 1YwMJ6HC9FUVtJp9gObSrirbzTH7mVaMjQkBLotazWbegzI+be8V3yT06C+ehD+2
104 GdLWAVs9hp8gPHEUShb/XrgPpDSJmFlOiyeOFBO/j4edDACKqVcwdjBOMAoGCCqF
105 AwcBAQIDBEAIFX0fyZe20QKKhWm6WYX+S92Gt6zaXroXOvAmayzLfZ5Sd9C2t9zZ
106 JSg6M8RBUYpw/8ym5ou1o2nDa09M5zF3BCCpzyCQBI+rzfISeKvPV1ROfcXiYU93
109 password = u"Пароль для PFX"
111 def test_shrouded_key_bag(self):
112 private_key_info_expected = b64decode(b"""
113 MGYCAQAwHwYIKoUDBwEBAQEwEwYHKoUDAgIjAQYIKoUDBwEBAgIEQEYbRu86z+1JFKDcPDN9UbTG
114 G2ki9enTqos4KpUU0j9IDpl1UXiaA1YDIwUjlAp+81GkLmyt8Fw6Gt/X5JZySAY=
117 pfx, tail = PFX().decode(self.pfx_raw)
118 self.assertSequenceEqual(tail, b"")
119 _, outer_safe_contents = pfx["authSafe"]["content"].defined
120 safe_contents, tail = OctetStringSafeContents().decode(
121 bytes(outer_safe_contents[0]["bagValue"]),
123 self.assertSequenceEqual(tail, b"")
124 safe_bag = safe_contents[0]
125 shrouded_key_bag, tail = PKCS8ShroudedKeyBag().decode(
126 bytes(safe_bag["bagValue"]),
128 self.assertSequenceEqual(tail, b"")
129 _, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
130 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
131 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
133 key = gost34112012_pbkdf2(
134 password=self.password.encode("utf-8"),
135 salt=bytes(pbkdf2_params["salt"]["specified"]),
136 iterations=int(pbkdf2_params["iterationCount"]),
139 # key = hexdec("309dd0354c5603739403f2335e9e2055138f8b5c98b63009de0635eea1fd7ba8")
140 self.assertSequenceEqual(
143 bytes(shrouded_key_bag["encryptedData"]),
144 iv=bytes(enc_scheme_params["iv"]),
145 sbox="id-tc26-gost-28147-param-Z",
147 private_key_info_expected,
150 def test_encrypted_data(self):
151 cert_bag_expected = b64decode(b"""
152 MIIDSjCCA0YGCyqGSIb3DQEMCgEDoIIDHjCCAxoGCiqGSIb3DQEJFgGgggMKBIIDBjCCAwIwggKt
153 oAMCAQICEAHQaF8xH5bAAAAACycJAAEwDAYIKoUDBwEBAwIFADBgMQswCQYDVQQGEwJSVTEVMBMG
154 A1UEBwwM0JzQvtGB0LrQstCwMQ8wDQYDVQQKDAbQotCaMjYxKTAnBgNVBAMMIENBIGNlcnRpZmlj
155 YXRlIChQS0NTIzEyIGV4YW1wbGUpMB4XDTE1MDMyNzA3MjUwMFoXDTIwMDMyNzA3MjMwMFowZDEL
156 MAkGA1UEBhMCUlUxFTATBgNVBAcMDNCc0L7RgdC60LLQsDEPMA0GA1UECgwG0KLQmjI2MS0wKwYD
157 VQQDDCRUZXN0IGNlcnRpZmljYXRlIDEgKFBLQ1MjMTIgZXhhbXBsZSkwZjAfBggqhQMHAQEBATAT
158 BgcqhQMCAiMBBggqhQMHAQECAgNDAARA1xzymkpvr2dYJT8WTOX3Dt96/+hGsXNytUQpkWB5ImJM
159 4tg9AsC4RIUwV5H41MhG0uBRFweTzN6AsAdBvhTClYEJADI3MDkwMDAxo4IBKTCCASUwKwYDVR0Q
160 BCQwIoAPMjAxNTAzMjcwNzI1MDBagQ8yMDE2MDMyNzA3MjUwMFowDgYDVR0PAQH/BAQDAgTwMB0G
161 A1UdDgQWBBQhWOsRQ68yYN2Utg/owHoWcqsVbTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
162 AwQwDAYDVR0TAQH/BAIwADCBmQYDVR0jBIGRMIGOgBQmnc7Xh5ykb5t/BMwOkxA4drfEmqFkpGIw
163 YDELMAkGA1UEBhMCUlUxFTATBgNVBAcMDNCc0L7RgdC60LLQsDEPMA0GA1UECgwG0KLQmjI2MSkw
164 JwYDVQQDDCBDQSBjZXJ0aWZpY2F0ZSAoUEtDUyMxMiBleGFtcGxlKYIQAdBoXvL8TSAAAAALJwkA
165 ATAMBggqhQMHAQEDAgUAA0EA9oq0Vvk8kkgIwkp0x0J5eKtia4MNTiwKAm7jgnCZIx3O98BThaTX
166 3ZQhEo2RL9pTCPr6wFMheeJ+YdGMReXvsjEVMBMGCSqGSIb3DQEJFTEGBAQBAAAA
169 pfx, tail = PFX().decode(self.pfx_raw)
170 self.assertSequenceEqual(tail, b"")
171 _, outer_safe_contents = pfx["authSafe"]["content"].defined
172 _, encrypted_data = outer_safe_contents[1]["bagValue"].defined
173 _, pbes2_params = encrypted_data["encryptedContentInfo"]["contentEncryptionAlgorithm"]["parameters"].defined
174 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
175 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
176 key = gost34112012_pbkdf2(
177 password=self.password.encode("utf-8"),
178 salt=bytes(pbkdf2_params["salt"]["specified"]),
179 iterations=int(pbkdf2_params["iterationCount"]),
182 # key = hexdec("0e93d71339e7f53b79a0bc41f9109dd4fb60b30ae10736c1bb77b84c07681cfc")
183 self.assertSequenceEqual(
186 bytes(encrypted_data["encryptedContentInfo"]["encryptedContent"]),
187 iv=bytes(enc_scheme_params["iv"]),
188 sbox="id-tc26-gost-28147-param-Z",
194 pfx, tail = PFX().decode(self.pfx_raw)
195 self.assertSequenceEqual(tail, b"")
196 _, outer_safe_contents = pfx["authSafe"]["content"].defined
197 mac_data = pfx["macData"]
198 mac_key = gost34112012_pbkdf2(
199 password=self.password.encode("utf-8"),
200 salt=bytes(mac_data["macSalt"]),
201 iterations=int(mac_data["iterations"]),
204 # mac_key = hexdec("cadbfbf3bceaa9b79f651508fac5abbeb4a13d0bd0e1876bd3c3efb2112128a5")
205 self.assertSequenceEqual(
208 msg=SafeContents(outer_safe_contents).encode(),
209 digestmod=GOST34112012512,
211 bytes(mac_data["mac"]["digest"]),
215 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
216 class TestPFX2020(TestCase):
217 """PFX test vectors from newer PKCS#12 update
219 ca_prv_raw = hexdec("092F8D059E97E22B90B1AE99F0087FC4D26620B91550CBB437C191005A290810")
220 ca_curve = gost3410.CURVES["id-tc26-gost-3410-12-256-paramSetA"]
221 ca_cert = Certificate().decod(b64decode(b"""
222 MIIB+TCCAaagAwIBAgIEAYy6gTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
223 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
224 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA4MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx
225 5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwXjAXBggqhQMHAQEBATALBgkq
226 hQMHAQIBAQEDQwAEQBpKgpyPDnhQAJyLqy8Qs0XQhgxEhby6tSypqYimgbjpcKqtU6
227 4jpDXc3h3BxGxtl2oHJ/4YLZ/ll87dto3ltMqjgZgwgZUwYwYDVR0jBFwwWoAUrGwO
228 TERmokKW4p8JOyVm88ukUyqhPKQ6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHk
229 NBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQUrGwO
230 TERmokKW4p8JOyVm88ukUyowDwYDVR0TAQH/BAUwAwEB/zAKBggqhQMHAQEDAgNBAB
231 Gg3nhgQ5oCKbqlEdVaRxH+1WX4wVkawGXuTYkr1AC2OWw3ZC14Vvg3nazm8UMWUZtk
234 ca_pub = gost3410.pub_unmarshal(bytes(OctetString().decod(bytes(
235 ca_cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
237 password = u"Пароль для PFX".encode("utf-8")
238 cert_test = Certificate().decod(b64decode(b"""
239 MIICLjCCAdugAwIBAgIEAYy6hDAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
240 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
241 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYDVQQDEy
242 FPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDUxMi1iaXQwgaAwFwYIKoUDBwEBAQIw
243 CwYJKoUDBwECAQIBA4GEAASBgLSLt1q8KQ4YZVxioU+1LV9QhE7MHR9gBEh7S1yVNG
244 lqt7+rNG5VFqmrPM74rbUsOlhV8M+zZKprXdk35Oz8lSW/n2oIUHZxikXIH/SSHj4r
245 v3K/Puvz7hYTQSZl/xPdp78nUmjrEa6d5wfX8biEy2z0dgufFvAkMw1Ua4gdXqDOo4
246 GHMIGEMGMGA1UdIwRcMFqAFKxsDkxEZqJCluKfCTslZvPLpFMqoTykOjA4MQ0wCwYD
247 VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaX
248 SCBAGMuoEwHQYDVR0OBBYEFH4GVwmYDK1rCKhX7nkAWDrJ16CkMAoGCCqFAwcBAQMC
249 A0EACl6p8dAbpi9Hk+3mgMyI0WIh17IrlrSp/mB0F7ZzMt8XUD1Dwz3JrrnxeXnfMv
250 OA5BdUJ9hCyDgMVAGs/IcEEA==
252 prv_test_raw = b64decode("""
253 MIHiAgEBMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAQRAEWkl+eblsHWs86SNgRKq
254 SxMOgGhbvR/uZ5/WWfdNG1axvUwVhpcXIxDZUmzQuNzqJBkseI7f5/JjXyTFRF1a
255 +YGBgQG0i7davCkOGGVcYqFPtS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO
256 +K21LDpYVfDPs2Sqa13ZN+Ts/JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0Em
257 Zf8T3ae/J1Jo6xGunecH1/G4hMts9HYLnxbwJDMNVGuIHV6gzg==
260 def test_cert_and_encrypted_key(self):
261 pfx_raw = b64decode(b"""
262 MIIFKwIBAzCCBMQGCSqGSIb3DQEHAaCCBLUEggSxMIIErTCCAswGCSqGSIb3DQEH
263 AaCCAr0EggK5MIICtTCCArEGCyqGSIb3DQEMCgEDoIICSjCCAkYGCiqGSIb3DQEJ
264 FgGgggI2BIICMjCCAi4wggHboAMCAQICBAGMuoQwCgYIKoUDBwEBAwIwODENMAsG
265 A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
266 Yml0MB4XDTAxMDEwMTAwMDAwMFoXDTQ5MTIzMTAwMDAwMFowOzENMAsGA1UEChME
267 VEsyNjEqMCgGA1UEAxMhT1JJR0lOQVRPUjogR09TVCAzNC4xMC0xMiA1MTItYml0
268 MIGgMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAQOBhAAEgYC0i7davCkOGGVcYqFP
269 tS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO+K21LDpYVfDPs2Sqa13ZN+Ts
270 /JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0EmZf8T3ae/J1Jo6xGunecH1/G4
271 hMts9HYLnxbwJDMNVGuIHV6gzqOBhzCBhDBjBgNVHSMEXDBagBSsbA5MRGaiQpbi
272 nwk7JWbzy6RTKqE8pDowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsy
273 NjogR09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBR+BlcJmAyt
274 awioV+55AFg6ydegpDAKBggqhQMHAQEDAgNBAApeqfHQG6YvR5Pt5oDMiNFiIdey
275 K5a0qf5gdBe2czLfF1A9Q8M9ya658Xl53zLzgOQXVCfYQsg4DFQBrPyHBBAxVDAj
276 BgkqhkiG9w0BCRUxFgQUeVV0+dS25MICJChpmGc/8AoUwE0wLQYJKoZIhvcNAQkU
277 MSAeHgBwADEAMgBGAHIAaQBlAG4AZABsAHkATgBhAG0AZTCCAdkGCSqGSIb3DQEH
278 AaCCAcoEggHGMIIBwjCCAb4GCyqGSIb3DQEMCgECoIIBVzCCAVMwWQYJKoZIhvcN
279 AQUNMEwwKQYJKoZIhvcNAQUMMBwECKf4N7NMwugqAgIIADAMBggqhQMHAQEEAgUA
280 MB8GCSqFAwcBAQUCAjASBBAlmt2WDfaPJlsAs0mLKglzBIH1DMvEacbbWRNDVSnX
281 JLWygYrKoipdOjDA/2HEnBZ34uFOLNheUqiKpCPoFpbR2GBiVYVTVK9ibiczgaca
282 EQYzDXtcS0QCZOxpKWfteAlbdJLC/SqPurPYyKi0MVRUPROhbisFASDT38HDH1Dh
283 0dL5f6ga4aPWLrWbbgWERFOoOPyh4DotlPF37AQOwiEjsbyyRHq3HgbWiaxQRuAh
284 eqHOn4QVGY92/HFvJ7u3TcnQdLWhTe/lh1RHLNF3RnXtN9if9zC23laDZOiWZplU
285 yLrUiTCbHrtn1RppPDmLFNMt9dJ7KKgCkOi7Zm5nhqPChbywX13wcfYxVDAjBgkq
286 hkiG9w0BCRUxFgQUeVV0+dS25MICJChpmGc/8AoUwE0wLQYJKoZIhvcNAQkUMSAe
287 HgBwADEAMgBGAHIAaQBlAG4AZABsAHkATgBhAG0AZTBeME4wCgYIKoUDBwEBAgME
288 QAkBKw4ihn7pSIYTEhu0bcvTPZjI3WgVxCkUVlOsc80G69EKFEOTnObGJGSKJ51U
289 KkOsXF0a7+VBZf3BcVVQh9UECIVEtO+VpuskAgIIAA==
291 pfx = PFX().decod(pfx_raw)
292 _, outer_safe_contents = pfx["authSafe"]["content"].defined
294 safe_contents = OctetStringSafeContents().decod(bytes(
295 outer_safe_contents[0]["bagValue"]
297 safe_bag = safe_contents[0]
298 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
299 cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
300 self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
301 _, cert = cert_bag["certValue"].defined
302 self.assertEqual(Certificate(cert), self.cert_test)
304 safe_contents = OctetStringSafeContents().decod(bytes(
305 outer_safe_contents[1]["bagValue"]
307 safe_bag = safe_contents[0]
308 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_pkcs8ShroudedKeyBag)
309 shrouded_key_bag = PKCS8ShroudedKeyBag().decod(bytes(safe_bag["bagValue"]))
310 _, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
311 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
312 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
313 ukm = bytes(enc_scheme_params["ukm"])
314 key = gost34112012_pbkdf2(
315 password=self.password,
316 salt=bytes(pbkdf2_params["salt"]["specified"]),
317 iterations=int(pbkdf2_params["iterationCount"]),
320 # key = hexdec("4b7ae649ca31dd5fe3243a91a5188c03f1d7049bec8e0d241c0e1e8c39ea4c1f")
321 key_enc, key_mac = kdf_tree_gostr3411_2012_256(
322 key, b"kdf tree", ukm[GOST3412Kuznechik.blocksize // 2:], 2,
324 ciphertext = bytes(shrouded_key_bag["encryptedData"])
325 plaintext = ctr_acpkm(
327 GOST3412Kuznechik(key_enc).encrypt,
328 section_size=256 * 1024,
329 bs=GOST3412Kuznechik.blocksize,
331 iv=ukm[:GOST3412Kuznechik.blocksize // 2],
333 mac_expected = plaintext[-GOST3412Kuznechik.blocksize:]
334 plaintext = plaintext[:-GOST3412Kuznechik.blocksize]
336 GOST3412Kuznechik(key_mac).encrypt,
337 GOST3412Kuznechik.blocksize,
340 self.assertSequenceEqual(mac, mac_expected)
341 self.assertSequenceEqual(plaintext, self.prv_test_raw)
343 mac_data = pfx["macData"]
344 mac_key = gost34112012_pbkdf2(
345 password=self.password,
346 salt=bytes(mac_data["macSalt"]),
347 iterations=int(mac_data["iterations"]),
350 # mac_key = hexdec("a81d1bc91a4a5cf1fd7320f92dda7e5b285816c3b20826a382d7ed0cbf3a9bf4")
351 self.assertSequenceEqual(
354 msg=SafeContents(outer_safe_contents).encode(),
355 digestmod=GOST34112012512,
357 bytes(mac_data["mac"]["digest"]),
359 self.assertTrue(gost3410.verify(
362 GOST34112012256(cert["tbsCertificate"].encode()).digest()[::-1],
363 bytes(cert["signatureValue"]),
366 def test_encrypted_cert_and_key(self):
367 pfx_raw = b64decode(b"""
368 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
399 pfx = PFX().decod(pfx_raw)
400 _, outer_safe_contents = pfx["authSafe"]["content"].defined
402 encrypted_data = EncryptedData().decod(bytes(
403 outer_safe_contents[0]["bagValue"]
405 eci = encrypted_data["encryptedContentInfo"]
406 self.assertEqual(eci["contentEncryptionAlgorithm"]["algorithm"], id_pbes2)
407 pbes2_params = PBES2Params().decod(bytes(
408 eci["contentEncryptionAlgorithm"]["parameters"]
410 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
411 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
412 ukm = bytes(enc_scheme_params["ukm"])
413 key = gost34112012_pbkdf2(
414 password=self.password,
415 salt=bytes(pbkdf2_params["salt"]["specified"]),
416 iterations=int(pbkdf2_params["iterationCount"]),
419 # key = hexdec("d066a96fb326ba896a2352d3f40240a4ded6e7e7bd5b4db6b5241d631c8c381c")
420 key_enc, key_mac = kdf_tree_gostr3411_2012_256(
421 key, b"kdf tree", ukm[GOST3412Magma.blocksize // 2:], 2,
423 ciphertext = bytes(eci["encryptedContent"])
424 plaintext = ctr_acpkm(
426 GOST3412Magma(key_enc).encrypt,
427 section_size=8 * 1024,
428 bs=GOST3412Magma.blocksize,
430 iv=ukm[:GOST3412Magma.blocksize // 2],
432 mac_expected = plaintext[-GOST3412Magma.blocksize:]
433 plaintext = plaintext[:-GOST3412Magma.blocksize]
435 GOST3412Magma(key_mac).encrypt,
436 GOST3412Magma.blocksize,
439 self.assertSequenceEqual(mac, mac_expected)
441 safe_contents = SafeContents().decod(plaintext)
442 safe_bag = safe_contents[0]
443 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
444 cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
445 self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
446 _, cert = cert_bag["certValue"].defined
447 self.assertEqual(Certificate(cert), self.cert_test)
449 safe_contents = OctetStringSafeContents().decod(bytes(
450 outer_safe_contents[1]["bagValue"]
452 safe_bag = safe_contents[0]
453 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_pkcs8ShroudedKeyBag)
454 shrouded_key_bag = PKCS8ShroudedKeyBag().decod(bytes(safe_bag["bagValue"]))
455 _, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
456 _, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
457 _, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
458 ukm = bytes(enc_scheme_params["ukm"])
459 key = gost34112012_pbkdf2(
460 password=self.password,
461 salt=bytes(pbkdf2_params["salt"]["specified"]),
462 iterations=int(pbkdf2_params["iterationCount"]),
465 # key = hexdec("f840d001fd11441e0fb7ccf48f471915e5bf35275309dbe7ade9da4fe460ba7e")
466 ciphertext = bytes(shrouded_key_bag["encryptedData"])
467 plaintext = ctr_acpkm(
469 GOST3412Magma(key).encrypt,
470 section_size=8 * 1024,
471 bs=GOST3412Magma.blocksize,
473 iv=ukm[:GOST3412Magma.blocksize // 2],
475 self.assertSequenceEqual(plaintext, self.prv_test_raw)
477 mac_data = pfx["macData"]
478 mac_key = gost34112012_pbkdf2(
479 password=self.password,
480 salt=bytes(mac_data["macSalt"]),
481 iterations=int(mac_data["iterations"]),
484 # mac_key = hexdec("084f81782af1534ffd67e3c579c14cb45d7a6f659f46fdbb51a552e874e66fb2")
485 self.assertSequenceEqual(
488 msg=SafeContents(outer_safe_contents).encode(),
489 digestmod=GOST34112012512,
491 bytes(mac_data["mac"]["digest"]),
495 curve = gost3410.CURVES["id-tc26-gost-3410-12-256-paramSetA"]
496 # sender_prv_raw = hexdec("0B20810E449978C7C3B76C6FF77A16C532421139344A058EF56310B6B6F377E8")
497 sender_cert = Certificate().decod(b64decode("""
498 MIIB6zCCAZigAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
499 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
500 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYDVQQDEy
501 FPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwXjAXBggqhQMHAQEBATAL
502 BgkqhQMHAQIBAQEDQwAEQJYpDRNiWWqDgaZje0EmLLOldQ35o5X1ZuZNSKequYQc/s
503 oI3OgDMWD7ThJJCk01IelCeb6MsBmG4lol+pnpVtOjgYcwgYQwYwYDVR0jBFwwWoAU
504 rGwOTERmokKW4p8JOyVm88ukUyqhPKQ6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBA
505 MTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQU
506 Px5RgcjkifhlJm4/jQdkbm30rVQwCgYIKoUDBwEBAwIDQQA68x7Vk6PvP/8xOGHhf8
507 PuqaXAYskSyJPuBu+3Bo/PEj10devwc1J9uYWIDCGdKKPybSlnQHqUPBBPM30YX1YN
509 recipient_prv_raw = hexdec("0DC8DC1FF2BC114BABC3F1CA8C51E4F58610427E197B1C2FBDBA4AE58CBFB7CE")[::-1]
510 recipient_prv = gost3410.prv_unmarshal(recipient_prv_raw)
511 recipient_cert = Certificate().decod(b64decode("""
512 MIIB6jCCAZegAwIBAgIEAYy6gzAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
513 cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
514 MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA6MQ0wCwYDVQQKEwRUSzI2MSkwJwYDVQQDEy
515 BSRUNJUElFTlQ6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdDBeMBcGCCqFAwcBAQEBMAsG
516 CSqFAwcBAgEBAQNDAARAvyeCGXMsYwpYe5aE0w8w3m4vpKQapGInqpnFlv7h08psFP
517 0s1W80q3BR534F4TmR+o5+iU+AW6ycvWuc73JEQ6OBhzCBhDBjBgNVHSMEXDBagBSs
518 bA5MRGaiQpbinwk7JWbzy6RTKqE8pDowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAx
519 MeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBQ3
520 5gHPN1bx8l2eEMTbrtIg+5MU0TAKBggqhQMHAQEDAgNBABF2RHDaRqQuBS2yu7yGIG
521 FgA6c/LG4GKjSOwYsRVmXJNNkQ4TB7PB8j3q7gx2koPsVBm90WfMWSL6SNSh3muuM=
523 self.assertTrue(gost3410.verify(
526 GOST34112012256(sender_cert["tbsCertificate"].encode()).digest()[::-1],
527 bytes(sender_cert["signatureValue"]),
529 self.assertTrue(gost3410.verify(
532 GOST34112012256(recipient_cert["tbsCertificate"].encode()).digest()[::-1],
533 bytes(recipient_cert["signatureValue"]),
536 pfx_raw = b64decode("""
537 MIIKZwIBAzCCCmAGCSqGSIb3DQEHAqCCClEwggpNAgEBMQwwCgYIKoUDBwEBAgIw
538 ggcrBgkqhkiG9w0BBwGgggccBIIHGDCCBxQwggKdBgkqhkiG9w0BBwGgggKOBIIC
539 ijCCAoYwggKCBgsqhkiG9w0BDAoBA6CCAkowggJGBgoqhkiG9w0BCRYBoIICNgSC
540 AjIwggIuMIIB26ADAgECAgQBjLqEMAoGCCqFAwcBAQMCMDgxDTALBgNVBAoTBFRL
541 MjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdDAeFw0w
542 MTAxMDEwMDAwMDBaFw00OTEyMzEwMDAwMDBaMDsxDTALBgNVBAoTBFRLMjYxKjAo
543 BgNVBAMTIU9SSUdJTkFUT1I6IEdPU1QgMzQuMTAtMTIgNTEyLWJpdDCBoDAXBggq
544 hQMHAQEBAjALBgkqhQMHAQIBAgEDgYQABIGAtIu3WrwpDhhlXGKhT7UtX1CETswd
545 H2AESHtLXJU0aWq3v6s0blUWqas8zvittSw6WFXwz7Nkqmtd2Tfk7PyVJb+faghQ
546 dnGKRcgf9JIePiu/cr8+6/PuFhNBJmX/E92nvydSaOsRrp3nB9fxuITLbPR2C58W
547 8CQzDVRriB1eoM6jgYcwgYQwYwYDVR0jBFwwWoAUrGwOTERmokKW4p8JOyVm88uk
548 UyqhPKQ6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1Qg
549 MzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQUfgZXCZgMrWsIqFfueQBY
550 OsnXoKQwCgYIKoUDBwEBAwIDQQAKXqnx0BumL0eT7eaAzIjRYiHXsiuWtKn+YHQX
551 tnMy3xdQPUPDPcmuufF5ed8y84DkF1Qn2ELIOAxUAaz8hwQQMSUwIwYJKoZIhvcN
552 AQkVMRYEFHlVdPnUtuTCAiQoaZhnP/AKFMBNMIIEbwYJKoZIhvcNAQcDoIIEYDCC
553 BFwCAQKgggH7oIIB9zCCAfMwggGgoAMCAQICBAGMuoIwCgYIKoUDBwEBAwIwODEN
554 MAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAy
555 NTYtYml0MB4XDTAxMDEwMTAwMDAwMFoXDTQ5MTIzMTAwMDAwMFowOzENMAsGA1UE
556 ChMEVEsyNjEqMCgGA1UEAxMhT1JJR0lOQVRPUjogR09TVCAzNC4xMC0xMiAyNTYt
557 Yml0MGgwIQYIKoUDBwEBAQEwFQYJKoUDBwECAQEBBggqhQMHAQECAgNDAARAlikN
558 E2JZaoOBpmN7QSYss6V1DfmjlfVm5k1Ip6q5hBz+ygjc6AMxYPtOEkkKTTUh6UJ5
559 voywGYbiWiX6melW06OBhTCBgjBhBgNVHQEEWjBYgBSA2Qz3mfhmTZNTiY7AnnEt
560 p6cxEqE6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1Qg
561 MzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQU0ZwoR0lm0GMJyQutp9s7
562 uTY3dN8wCgYIKoUDBwEBAwIDQQAeNaIo2l0hJ+fJe/Mtq4cWN+f5ShKuF1me9Bbb
563 DZVcVgE8s4DuVpYsJ7dTuBqGbMcfK+k/4u1RuuVDZkJcHTikMYH/oYH8AgEDoEIw
564 QDA4MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEw
565 LTEyIDI1Ni1iaXQCBAGMuoKhIgQgVyXLHEfPiRZOVrAtgmddYSS+MjuKuWWA2fC7
566 TlhQ7/wwFwYJKoUDBwEBBwIBMAoGCCqFAwcBAQYBMHYwdDBAMDgxDTALBgNVBAoT
567 BFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdAIE
568 AYy6gwQwSqUJbuUEakskO0Ks2l4YIRo3aUnzluRiy17S7jXmupoIYWUMo44iYXs3
569 05wL+iU1MIIBVAYJKoZIhvcNAQcBMB8GCSqFAwcBAQUCATASBBCdur5wO9c8vgAA
570 AAAAAAAAgIIBJLIXYiLziJdz/VDbl+tEd3lItfQWvLy+P1my1ZRZ3FFnQvuDHHo/
571 i9pB2/8xaaWJhhfXMORJR7DdvwAMvzcwwgX5KIbbjrrK1EFADult5D2MMiRNBa9d
572 jM6w+pgKsZhi+id+v+Hx83xGimM5qUf/oe40TolQKM6uMq9XG/efRYKJ67Bht4s6
573 bKKy2+Uswv91m5uNNyrjSsA5UAW5PSMKovjwnVC/wIWs7Zlk8SVzlK4bdUppJF6F
574 Hca1knFlzvyi5mRnoIqcVe11bDM7GROSBtp4Po23+GGSGIBCMgP2I2ePoarQNYG3
575 jY5W6zoxGuH+xA8D+XrCbWJToNHekfYUlXkGSkEnHc5ZywK3tvvIBXu6z0ebvEKP
576 3VVkBvu1rhZY8/DBXaegggH3MIIB8zCCAaCgAwIBAgIEAYy6gjAKBggqhQMHAQED
577 AjA4MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEw
578 LTEyIDI1Ni1iaXQwHhcNMDEwMTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0w
579 CwYDVQQKEwRUSzI2MSowKAYDVQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEy
580 IDI1Ni1iaXQwaDAhBggqhQMHAQEBATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MA
581 BECWKQ0TYllqg4GmY3tBJiyzpXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpN
582 NSHpQnm+jLAZhuJaJfqZ6VbTo4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJ
583 jsCecS2npzESoTowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjog
584 R09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBTRnChHSWbQYwnJ
585 C62n2zu5Njd03zAKBggqhQMHAQEDAgNBAB41oijaXSEn58l78y2rhxY35/lKEq4X
586 WZ70FtsNlVxWATyzgO5Wliwnt1O4GoZsxx8r6T/i7VG65UNmQlwdOKQxggEOMIIB
587 CgIBATBAMDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1Qg
588 MzQuMTAtMTIgMjU2LWJpdAIEAYy6gjAKBggqhQMHAQECAqBpMBgGCSqGSIb3DQEJ
589 AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIwMTIyODIxNTcxNVowLwYJ
590 KoZIhvcNAQkEMSIEIDpxzO/5T2vf3BSYXhSaNCL9kMTRIVG6UVv0h1sRa+6tMAoG
591 CCqFAwcBAQEBBEA9mo045ap4k03ZdSacyoZlbvSqNZMHsGUciqE7aWGc5h7U23H8
592 e6qgRVHn9b+Mq3sp57LxHk4Sny0zV8TRwCr8
594 pfx = PFX().decod(pfx_raw)
595 self.assertEqual(pfx["authSafe"]["contentType"], id_signedData)
597 sd = SignedData().decod(bytes(pfx["authSafe"]["content"]))
598 # self.assertEqual(sd["certificates"][0]["certificate"], sender_cert)
599 si = sd["signerInfos"][0]
601 si["digestAlgorithm"]["algorithm"],
602 id_tc26_gost3411_2012_256,
605 bytes(attr["attrValues"][0].defined[1]) for attr in si["signedAttrs"]
606 if attr["attrType"] == id_messageDigest
608 sender_pub = gost3410.pub_unmarshal(bytes(OctetString().decod(bytes(
609 sender_cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
611 content = bytes(sd["encapContentInfo"]["eContent"])
612 self.assertSequenceEqual(digest, GOST34112012256(content).digest())
613 self.assertTrue(gost3410.verify(
617 SignedAttributes(si["signedAttrs"]).encode()
619 bytes(si["signature"]),
622 outer_safe_contents = SafeContents().decod(content)
624 safe_bag = outer_safe_contents[0]
625 self.assertEqual(safe_bag["bagId"], id_data)
626 safe_contents = OctetStringSafeContents().decod(bytes(safe_bag["bagValue"]))
627 safe_bag = safe_contents[0]
628 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
629 cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
630 self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
631 _, cert = cert_bag["certValue"].defined
632 self.assertEqual(Certificate(cert), self.cert_test)
634 safe_bag = outer_safe_contents[1]
635 self.assertEqual(safe_bag["bagId"], id_envelopedData)
636 ed = EnvelopedData().decod(bytes(safe_bag["bagValue"]))
637 kari = ed["recipientInfos"][0]["kari"]
638 ukm = bytes(kari["ukm"])
640 kari["keyEncryptionAlgorithm"]["algorithm"],
641 id_gostr3412_2015_kuznyechik_wrap_kexp15,
644 kari["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
645 id_tc26_agreement_gost3410_2012_256,
647 kexp = bytes(kari["recipientEncryptedKeys"][0]["encryptedKey"])
648 keymat = keg(curve, recipient_prv, sender_pub, ukm)
649 kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
651 GOST3412Kuznechik(kek).encrypt,
652 GOST3412Kuznechik(kim).encrypt,
653 GOST3412Kuznechik.blocksize,
655 ukm[24:24 + GOST3412Kuznechik.blocksize // 2],
657 eci = ed["encryptedContentInfo"]
659 eci["contentEncryptionAlgorithm"]["algorithm"],
660 id_gostr3412_2015_kuznyechik_ctracpkm,
663 eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
667 GOST3412Kuznechik(cek).encrypt,
669 GOST3412Kuznechik.blocksize,
670 bytes(eci["encryptedContent"]),
671 eci_ukm[:GOST3412Kuznechik.blocksize // 2],
674 safe_contents = SafeContents().decod(content)
675 safe_bag = safe_contents[0]
676 self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_keyBag)
677 KeyBag().decod(bytes(safe_bag["bagValue"]))
678 self.assertSequenceEqual(bytes(safe_bag["bagValue"]), self.prv_test_raw)