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)
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"])
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"])
191 iv = bytes(encryption_params["iv"])
192 self.assertSequenceEqual(
193 cfb_decrypt(cek, ciphertext, iv, sbox=sbox, mesh=True),
198 content_info_raw = b64decode("""
199 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
254 prv_key_our = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
256 def keker(curve, prv, pub, ukm):
257 return kek_34102012256(
268 "GostR3410_2001_CryptoPro_XchA_ParamSet",
270 b"Test data to encrypt.\n" * 100,
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=
286 prv_key_our = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
288 def keker(curve, prv, pub, ukm):
289 return kek_34102012256(
292 pub_unmarshal(pub, mode=2012),
299 "GostR3410_2012_TC26_ParamSetB",