]> Cypherpunks.ru repositories - pygost.git/blob - pygost/test_cms_enveloped.py
pygost.wrap.* Sbox specifying
[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
163     def process_cms(
164             self,
165             content_info_raw,
166             prv_key_our,
167             curve_name,
168             keker,
169             plaintext_expected,
170     ):
171         sbox = "Gost28147_tc26_ParamZ"
172         content_info, _ = ContentInfo().decode(content_info_raw)
173         enveloped_data, _ = EnvelopedData().decode(bytes(content_info["content"]))
174         eci = enveloped_data["encryptedContentInfo"]
175         ri = enveloped_data["recipientInfos"][0]
176         encrypted_key, _ = GostR3410KeyTransport().decode(
177             bytes(ri["ktri"]["encryptedKey"])
178         )
179         ukm = bytes(encrypted_key["transportParameters"]["ukm"])
180         spk = bytes(encrypted_key["transportParameters"]["ephemeralPublicKey"]["subjectPublicKey"])
181         pub_key_their, _ = OctetString().decode(spk)
182         curve = GOST3410Curve(*CURVE_PARAMS[curve_name])
183         kek = keker(curve, prv_key_our, bytes(pub_key_their), ukm)
184         key_wrapped = bytes(encrypted_key["sessionEncryptedKey"]["encryptedKey"])
185         mac = bytes(encrypted_key["sessionEncryptedKey"]["macKey"])
186         cek = unwrap_cryptopro(kek, ukm + key_wrapped + mac, sbox=sbox)
187         ciphertext = bytes(eci["encryptedContent"])
188         encryption_params, _ = Gost2814789Parameters().decode(
189             bytes(eci["contentEncryptionAlgorithm"]["parameters"])
190         )
191         iv = bytes(encryption_params["iv"])
192         self.assertSequenceEqual(
193             cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
194             plaintext_expected,
195         )
196
197     def test_256(self):
198         content_info_raw = b64decode("""
199 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
253         """)
254         prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
255
256         def keker(curve, prv, pub, ukm):
257             return kek_34102012256(
258                 curve,
259                 prv_unmarshal(prv),
260                 pub_unmarshal(pub),
261                 ukm_unmarshal(ukm),
262                 mode=2001,
263             )
264
265         self.process_cms(
266             content_info_raw,
267             prv_key_our,
268             "GostR3410_2001_CryptoPro_XchA_ParamSet",
269             keker,
270             b"Test data to encrypt.\n" * 100,
271         )
272
273     def test_512(self):
274         content_info_raw = b64decode("""
275 MIIB0gYJKoZIhvcNAQcDoIIBwzCCAb8CAQAxggF8MIIBeAIBADBbMFYxKTAnBgkq
276 hkiG9w0BCQEWGkdvc3RSMzQxMC0yMDEyQGV4YW1wbGUuY29tMSkwJwYDVQQDEyBH
277 b3N0UjM0MTAtMjAxMiA1MTIgYml0cyBleGNoYW5nZQIBATAhBggqhQMHAQEBAjAV
278 BgkqhQMHAQIBAgIGCCqFAwcBAQIDBIHyMIHvMCgEIIsYzbVLn33aLinQ7SLNA7y+
279 Lrm02khqDCfXrNS9iiMhBATerS8zoIHCBgkqhQMHAQIFAQGggaowIQYIKoUDBwEB
280 AQIwFQYJKoUDBwECAQICBggqhQMHAQECAwOBhAAEgYAYiTVLKpSGaAvjJEDQ0hdK
281 qR/jek5Q9Q2pXC+NkOimQh7dpCi+wcaHlPcBk96hmpnOFvLaiokX8V6jqtBl5gdk
282 M40kOXv8kcDdTzEVKA/ZLxA8xanL+gTD6ZjaPsUu06nsA2MoMBWcHLUzueaP3bGT
283 /yHTV+Za5xdcQehag/lNBgQIvCw4uUl0XC4wOgYJKoZIhvcNAQcBMB8GBiqFAwIC
284 FTAVBAj+1QzaXaN9FwYJKoUDBwECBQEBgAyK54euw0sHhEVEkA0=
285         """)
286         prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
287
288         def keker(curve, prv, pub, ukm):
289             return kek_34102012256(
290                 curve,
291                 prv_unmarshal(prv),
292                 pub_unmarshal(pub, mode=2012),
293                 ukm_unmarshal(ukm),
294             )
295
296         self.process_cms(
297             content_info_raw,
298             prv_key_our,
299             "GostR3410_2012_TC26_ParamSetB",
300             keker,
301             b"Test message",
302         )