3 from base64 import b64decode
4 from unittest import skipIf
5 from unittest import TestCase
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
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
30 class CMSVersion(Integer):
33 class ContentType(ObjectIdentifier):
36 class RecipientIdentifier(Choice):
38 ("issuerAndSerialNumber", Any()),
39 # ("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
42 class AlgorithmIdentifier(Sequence):
44 ("algorithm", ObjectIdentifier()),
45 ("parameters", Any(optional=True)),
48 class KeyEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
51 class EncryptedKey(OctetString):
54 class KeyTransRecipientInfo(Sequence):
56 ("version", CMSVersion()),
57 ("rid", RecipientIdentifier()),
58 ("keyEncryptionAlgorithm", KeyEncryptionAlgorithmIdentifier()),
59 ("encryptedKey", EncryptedKey()),
62 class RecipientInfo(Choice):
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))),
71 class RecipientInfos(SetOf):
72 schema = RecipientInfo()
73 bounds = (1, float("+inf"))
75 class ContentEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
78 class EncryptedContent(OctetString):
81 class EncryptedContentInfo(Sequence):
83 ("contentType", ContentType()),
84 ("contentEncryptionAlgorithm", ContentEncryptionAlgorithmIdentifier()),
85 ("encryptedContent", EncryptedContent(impl=tag_ctxp(0), optional=True)),
88 class EnvelopedData(Sequence):
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)),
97 class ContentInfo(Sequence):
99 ("contentType", ContentType()),
100 ("content", Any(expl=tag_ctxc(0))),
103 class Gost2814789IV(OctetString):
106 class Gost2814789Parameters(Sequence):
108 ("iv", Gost2814789IV()),
109 ("encryptionParamSet", ObjectIdentifier()),
112 class Gost2814789Key(OctetString):
115 class Gost2814789MAC(OctetString):
118 class Gost2814789EncryptedKey(Sequence):
120 ("encryptedKey", Gost2814789Key()),
121 ("maskKey", Gost2814789Key(impl=tag_ctxp(0), optional=True)),
122 ("macKey", Gost2814789MAC()),
125 class SubjectPublicKeyInfo(Sequence):
127 ("algorithm", AlgorithmIdentifier()),
128 ("subjectPublicKey", BitString()),
131 class GostR34102001TransportParameters(Sequence):
133 ("encryptionParamSet", ObjectIdentifier()),
134 ("ephemeralPublicKey", SubjectPublicKeyInfo(
138 ("ukm", OctetString()),
141 class GostR3410KeyTransport(Sequence):
143 ("sessionEncryptedKey", Gost2814789EncryptedKey()),
144 ("transportParameters", GostR34102001TransportParameters(
151 pyderasn_exists = False
153 pyderasn_exists = True
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)
162 `PyDERASN <http://pyderasn.cypherpunks.ru/>`__ library is required
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"])
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"])
194 iv = bytes(encryption_params["iv"])
195 self.assertSequenceEqual(
196 cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
201 content_info_raw = b64decode("""
202 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
257 prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
259 def keker(curve, prv, pub, ukm):
260 return kek_34102012256(
271 "GostR3410_2001_CryptoPro_XchA_ParamSet",
273 b"Test data to encrypt.\n" * 100,
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=
289 prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
291 def keker(curve, prv, pub, ukm):
292 return kek_34102012256(
295 pub_unmarshal(pub, mode=2012),
302 "GostR3410_2012_TC26_ParamSetB",