]> Cypherpunks.ru repositories - pygost.git/blob - pygost/test_cms_enveloped.py
Less pylint-related comments
[pygost.git] / pygost / test_cms_enveloped.py
1 # coding: utf-8
2
3 from base64 import b64decode
4 from unittest import skipIf
5 from unittest import TestCase
6
7 from pygost.gost28147 import cfb_decrypt
8 from pygost.gost3410 import CURVE_PARAMS
9 from pygost.gost3410 import GOST3410Curve
10 from pygost.gost3410 import prv_unmarshal
11 from pygost.gost3410 import pub_unmarshal
12 from pygost.gost3410_vko import kek_34102012256
13 from pygost.gost3410_vko import ukm_unmarshal
14 from pygost.utils import hexdec
15 from pygost.wrap import unwrap_cryptopro
16
17 try:
18
19     from pyderasn import Any
20     from pyderasn import BitString
21     from pyderasn import Choice
22     from pyderasn import Integer
23     from pyderasn import ObjectIdentifier
24     from pyderasn import OctetString
25     from pyderasn import Sequence
26     from pyderasn import SetOf
27     from pyderasn import tag_ctxc
28     from pyderasn import tag_ctxp
29
30     class CMSVersion(Integer):
31         pass
32
33     class ContentType(ObjectIdentifier):
34         pass
35
36     class RecipientIdentifier(Choice):
37         schema = (
38             ("issuerAndSerialNumber", Any()),
39             # ("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
40         )
41
42     class AlgorithmIdentifier(Sequence):
43         schema = (
44             ("algorithm", ObjectIdentifier()),
45             ("parameters", Any(optional=True)),
46         )
47
48     class KeyEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
49         pass
50
51     class EncryptedKey(OctetString):
52         pass
53
54     class KeyTransRecipientInfo(Sequence):
55         schema = (
56             ("version", CMSVersion()),
57             ("rid", RecipientIdentifier()),
58             ("keyEncryptionAlgorithm", KeyEncryptionAlgorithmIdentifier()),
59             ("encryptedKey", EncryptedKey()),
60         )
61
62     class RecipientInfo(Choice):
63         schema = (
64             ("ktri", KeyTransRecipientInfo()),
65             # ("kari", KeyAgreeRecipientInfo(impl=tag_ctxc(1))),
66             # ("kekri", KEKRecipientInfo(impl=tag_ctxc(2))),
67             # ("pwri", PasswordRecipientInfo(impl=tag_ctxc(3))),
68             # ("ori", OtherRecipientInfo(impl=tag_ctxc(4))),
69         )
70
71     class RecipientInfos(SetOf):
72         schema = RecipientInfo()
73         bounds = (1, float("+inf"))
74
75     class ContentEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
76         pass
77
78     class EncryptedContent(OctetString):
79         pass
80
81     class EncryptedContentInfo(Sequence):
82         schema = (
83             ("contentType", ContentType()),
84             ("contentEncryptionAlgorithm", ContentEncryptionAlgorithmIdentifier()),
85             ("encryptedContent", EncryptedContent(impl=tag_ctxp(0), optional=True)),
86         )
87
88     class EnvelopedData(Sequence):
89         schema = (
90             ("version", CMSVersion()),
91             # ("originatorInfo", OriginatorInfo(impl=tag_ctxc(0), optional=True)),
92             ("recipientInfos", RecipientInfos()),
93             ("encryptedContentInfo", EncryptedContentInfo()),
94             # ("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
95         )
96
97     class ContentInfo(Sequence):
98         schema = (
99             ("contentType", ContentType()),
100             ("content", Any(expl=tag_ctxc(0))),
101         )
102
103     class Gost2814789IV(OctetString):
104         bounds = (8, 8)
105
106     class Gost2814789Parameters(Sequence):
107         schema = (
108             ("iv", Gost2814789IV()),
109             ("encryptionParamSet", ObjectIdentifier()),
110         )
111
112     class Gost2814789Key(OctetString):
113         bounds = (32, 32)
114
115     class Gost2814789MAC(OctetString):
116         bounds = (4, 4)
117
118     class Gost2814789EncryptedKey(Sequence):
119         schema = (
120             ("encryptedKey", Gost2814789Key()),
121             ("maskKey", Gost2814789Key(impl=tag_ctxp(0), optional=True)),
122             ("macKey", Gost2814789MAC()),
123         )
124
125     class SubjectPublicKeyInfo(Sequence):
126         schema = (
127             ("algorithm", AlgorithmIdentifier()),
128             ("subjectPublicKey", BitString()),
129         )
130
131     class GostR34102001TransportParameters(Sequence):
132         schema = (
133             ("encryptionParamSet", ObjectIdentifier()),
134             ("ephemeralPublicKey", SubjectPublicKeyInfo(
135                 impl=tag_ctxc(0),
136                 optional=True,
137             )),
138             ("ukm", OctetString()),
139         )
140
141     class GostR3410KeyTransport(Sequence):
142         schema = (
143             ("sessionEncryptedKey", Gost2814789EncryptedKey()),
144             ("transportParameters", GostR34102001TransportParameters(
145                 impl=tag_ctxc(0),
146                 optional=True,
147             )),
148         )
149
150 except ImportError:
151     pyderasn_exists = False
152 else:
153     pyderasn_exists = True
154
155
156 @skipIf(not pyderasn_exists, "PyDERASN dependency is required")
157 class TestCMSEnveloped(TestCase):
158     """KeyTransRecipientInfo-based test vectors from "Использование
159     алгоритмов ГОСТ 28147-89, ГОСТ Р 34.11 и ГОСТ Р 34.10 в
160     криптографических сообщениях формата CMS" (TK26CMS.pdf)
161
162     `PyDERASN <http://pyderasn.cypherpunks.ru/>`__ library is required
163     for CMS parsing.
164     """
165
166     def process_cms(
167             self,
168             content_info_raw,
169             prv_key_our,
170             curve_name,
171             keker,
172             plaintext_expected,
173     ):
174         sbox = "Gost28147_tc26_ParamZ"
175         content_info, _ = ContentInfo().decode(content_info_raw)
176         enveloped_data, _ = EnvelopedData().decode(bytes(content_info["content"]))
177         eci = enveloped_data["encryptedContentInfo"]
178         ri = enveloped_data["recipientInfos"][0]
179         encrypted_key, _ = GostR3410KeyTransport().decode(
180             bytes(ri["ktri"]["encryptedKey"])
181         )
182         ukm = bytes(encrypted_key["transportParameters"]["ukm"])
183         spk = bytes(encrypted_key["transportParameters"]["ephemeralPublicKey"]["subjectPublicKey"])
184         pub_key_their, _ = OctetString().decode(spk)
185         curve = GOST3410Curve(*CURVE_PARAMS[curve_name])
186         kek = keker(curve, prv_key_our, bytes(pub_key_their), ukm)
187         key_wrapped = bytes(encrypted_key["sessionEncryptedKey"]["encryptedKey"])
188         mac = bytes(encrypted_key["sessionEncryptedKey"]["macKey"])
189         cek = unwrap_cryptopro(kek, ukm + key_wrapped + mac, sbox=sbox)
190         ciphertext = bytes(eci["encryptedContent"])
191         encryption_params, _ = Gost2814789Parameters().decode(
192             bytes(eci["contentEncryptionAlgorithm"]["parameters"])
193         )
194         iv = bytes(encryption_params["iv"])
195         self.assertSequenceEqual(
196             cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
197             plaintext_expected,
198         )
199
200     def test_256(self):
201         content_info_raw = b64decode("""
202 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
256         """)
257         prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
258
259         def keker(curve, prv, pub, ukm):
260             return kek_34102012256(
261                 curve,
262                 prv_unmarshal(prv),
263                 pub_unmarshal(pub),
264                 ukm_unmarshal(ukm),
265                 mode=2001,
266             )
267
268         self.process_cms(
269             content_info_raw,
270             prv_key_our,
271             "GostR3410_2001_CryptoPro_XchA_ParamSet",
272             keker,
273             b"Test data to encrypt.\n" * 100,
274         )
275
276     def test_512(self):
277         content_info_raw = b64decode("""
278 MIIB0gYJKoZIhvcNAQcDoIIBwzCCAb8CAQAxggF8MIIBeAIBADBbMFYxKTAnBgkq
279 hkiG9w0BCQEWGkdvc3RSMzQxMC0yMDEyQGV4YW1wbGUuY29tMSkwJwYDVQQDEyBH
280 b3N0UjM0MTAtMjAxMiA1MTIgYml0cyBleGNoYW5nZQIBATAhBggqhQMHAQEBAjAV
281 BgkqhQMHAQIBAgIGCCqFAwcBAQIDBIHyMIHvMCgEIIsYzbVLn33aLinQ7SLNA7y+
282 Lrm02khqDCfXrNS9iiMhBATerS8zoIHCBgkqhQMHAQIFAQGggaowIQYIKoUDBwEB
283 AQIwFQYJKoUDBwECAQICBggqhQMHAQECAwOBhAAEgYAYiTVLKpSGaAvjJEDQ0hdK
284 qR/jek5Q9Q2pXC+NkOimQh7dpCi+wcaHlPcBk96hmpnOFvLaiokX8V6jqtBl5gdk
285 M40kOXv8kcDdTzEVKA/ZLxA8xanL+gTD6ZjaPsUu06nsA2MoMBWcHLUzueaP3bGT
286 /yHTV+Za5xdcQehag/lNBgQIvCw4uUl0XC4wOgYJKoZIhvcNAQcBMB8GBiqFAwIC
287 FTAVBAj+1QzaXaN9FwYJKoUDBwECBQEBgAyK54euw0sHhEVEkA0=
288         """)
289         prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
290
291         def keker(curve, prv, pub, ukm):
292             return kek_34102012256(
293                 curve,
294                 prv_unmarshal(prv),
295                 pub_unmarshal(pub, mode=2012),
296                 ukm_unmarshal(ukm),
297             )
298
299         self.process_cms(
300             content_info_raw,
301             prv_key_our,
302             "GostR3410_2012_TC26_ParamSetB",
303             keker,
304             b"Test message",
305         )