]> Cypherpunks.ru repositories - pygost.git/commitdiff
Р 1323565.1.025-2019 test vectors
authorSergey Matveev <stargrave@stargrave.org>
Thu, 30 Jul 2020 14:56:39 +0000 (17:56 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Thu, 30 Jul 2020 16:10:28 +0000 (19:10 +0300)
pygost/asn1schemas/cms.py
pygost/asn1schemas/oids.py
pygost/asn1schemas/pkcs10.py
pygost/test_cms.py

index 23099353217a6b683167212371fe534b12088b5b..a39b10be978f2f2e1b8ad0d27a671ec6bf1a6c9a 100644 (file)
@@ -28,14 +28,26 @@ from pyderasn import SetOf
 from pyderasn import tag_ctxc
 from pyderasn import tag_ctxp
 
+from pygost.asn1schemas.oids import id_cms_mac_attr
+from pygost.asn1schemas.oids import id_contentType
 from pygost.asn1schemas.oids import id_digestedData
+from pygost.asn1schemas.oids import id_encryptedData
 from pygost.asn1schemas.oids import id_envelopedData
 from pygost.asn1schemas.oids import id_Gost28147_89
+from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
+from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm_omac
+from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
+from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm
+from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm_omac
+from pygost.asn1schemas.oids import id_gostr3412_2015_magma_wrap_kexp15
+from pygost.asn1schemas.oids import id_messageDigest
 from pygost.asn1schemas.oids import id_signedData
 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
 from pygost.asn1schemas.x509 import AlgorithmIdentifier
 from pygost.asn1schemas.x509 import Certificate
+from pygost.asn1schemas.x509 import CertificateSerialNumber
+from pygost.asn1schemas.x509 import Name
 from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
 
 
@@ -91,12 +103,32 @@ class GostR3410KeyTransport(Sequence):
     )
 
 
+class GostR3410KeyTransport2019(Sequence):
+    schema = (
+        ("encryptedKey", OctetString()),
+        ("ephemeralPublicKey", SubjectPublicKeyInfo()),
+        ("ukm", OctetString()),
+    )
+
+
+class GostR341012KEGParameters(Sequence):
+    schema = (
+        ("algorithm", ObjectIdentifier()),
+    )
+
+
 class KeyEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
     schema = (
         ("algorithm", ObjectIdentifier(defines=(
+            (("parameters",), {
+                id_gostr3412_2015_magma_wrap_kexp15: GostR341012KEGParameters(),
+                id_gostr3412_2015_kuznyechik_wrap_kexp15: GostR341012KEGParameters(),
+            }),
             (("..", "encryptedKey"), {
                 id_tc26_gost3410_2012_256: GostR3410KeyTransport(),
                 id_tc26_gost3410_2012_512: GostR3410KeyTransport(),
+                id_gostr3412_2015_magma_wrap_kexp15: GostR3410KeyTransport2019(),
+                id_gostr3412_2015_kuznyechik_wrap_kexp15: GostR3410KeyTransport2019(),
             }),
             (("..", "recipientEncryptedKeys", any, "encryptedKey"), {
                 id_tc26_gost3410_2012_256: Gost2814789EncryptedKey(),
@@ -127,10 +159,25 @@ class OriginatorPublicKey(Sequence):
     )
 
 
+class IssuerAndSerialNumber(Sequence):
+    schema = (
+        ("issuer", Name()),
+        ("serialNumber", CertificateSerialNumber()),
+    )
+
+
+class KeyIdentifier(OctetString):
+    pass
+
+
+class SubjectKeyIdentifier(KeyIdentifier):
+    pass
+
+
 class OriginatorIdentifierOrKey(Choice):
     schema = (
-        ("issuerAndSerialNumber", IssuerAndSerialNumber()),
-        ("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
+        ("issuerAndSerialNumber", IssuerAndSerialNumber()),
+        ("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
         ("originatorKey", OriginatorPublicKey(impl=tag_ctxc(1))),
     )
 
@@ -193,10 +240,22 @@ class Gost2814789Parameters(Sequence):
     )
 
 
+class Gost341215EncryptionParameters(Sequence):
+    schema = (
+        ("ukm", OctetString()),
+    )
+
+
 class ContentEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
     schema = (
         ("algorithm", ObjectIdentifier(defines=(
-            (("parameters",), {id_Gost28147_89: Gost2814789Parameters()}),
+            (("parameters",), {
+                id_Gost28147_89: Gost2814789Parameters(),
+                id_gostr3412_2015_magma_ctracpkm: Gost341215EncryptionParameters(),
+                id_gostr3412_2015_kuznyechik_ctracpkm: Gost341215EncryptionParameters(),
+                id_gostr3412_2015_magma_ctracpkm_omac: Gost341215EncryptionParameters(),
+                id_gostr3412_2015_kuznyechik_ctracpkm_omac: Gost341215EncryptionParameters(),
+            }),
         ))),
         ("parameters", Any(optional=True)),
     )
@@ -214,13 +273,47 @@ class EncryptedContentInfo(Sequence):
     )
 
 
+class Digest(OctetString):
+    pass
+
+
+class AttributeValue(Any):
+    pass
+
+
+class AttributeValues(SetOf):
+    schema = AttributeValue()
+
+
+class EncryptedMac(OctetString):
+    pass
+
+
+class Attribute(Sequence):
+    schema = (
+        ("attrType", ObjectIdentifier(defines=(
+            (("attrValues",), {
+                id_contentType: ObjectIdentifier(),
+                id_messageDigest: Digest(),
+                id_cms_mac_attr: EncryptedMac(),
+            },),
+        ))),
+        ("attrValues", AttributeValues()),
+    )
+
+
+class UnprotectedAttributes(SetOf):
+    schema = Attribute()
+    bounds = (1, float("+inf"))
+
+
 class EnvelopedData(Sequence):
     schema = (
         ("version", CMSVersion()),
         # ("originatorInfo", OriginatorInfo(impl=tag_ctxc(0), optional=True)),
         ("recipientInfos", RecipientInfos()),
         ("encryptedContentInfo", EncryptedContentInfo()),
-        ("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
+        ("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
     )
 
 
@@ -254,12 +347,17 @@ class SignatureValue(OctetString):
     pass
 
 
+class SignedAttributes(SetOf):
+    schema = Attribute()
+    bounds = (1, float("+inf"))
+
+
 class SignerInfo(Sequence):
     schema = (
         ("version", CMSVersion()),
         ("sid", SignerIdentifier()),
         ("digestAlgorithm", DigestAlgorithmIdentifier()),
-        ("signedAttrs", SignedAttributes(impl=tag_ctxc(0), optional=True)),
+        ("signedAttrs", SignedAttributes(impl=tag_ctxc(0), optional=True)),
         ("signatureAlgorithm", SignatureAlgorithmIdentifier()),
         ("signature", SignatureValue()),
         # ("unsignedAttrs", UnsignedAttributes(impl=tag_ctxc(1), optional=True)),
@@ -272,11 +370,11 @@ class SignerInfos(SetOf):
 
 class CertificateChoices(Choice):
     schema = (
-        ('certificate', Certificate()),
-        # ('extendedCertificate', ExtendedCertificate(impl=tag_ctxp(0))),
-        # ('v1AttrCert', AttributeCertificateV1(impl=tag_ctxc(1))),  # V1 is osbolete
-        # ('v2AttrCert', AttributeCertificateV2(impl=tag_ctxc(2))),
-        # ('other', OtherCertificateFormat(impl=tag_ctxc(3))),
+        ("certificate", Certificate()),
+        # ("extendedCertificate", ExtendedCertificate(impl=tag_ctxp(0))),
+        # ("v1AttrCert", AttributeCertificateV1(impl=tag_ctxc(1))),  # V1 is osbolete
+        # ("v2AttrCert", AttributeCertificateV2(impl=tag_ctxc(2))),
+        # ("other", OtherCertificateFormat(impl=tag_ctxc(3))),
     )
 
 
@@ -295,10 +393,6 @@ class SignedData(Sequence):
     )
 
 
-class Digest(OctetString):
-    pass
-
-
 class DigestedData(Sequence):
     schema = (
         ("version", CMSVersion()),
@@ -308,11 +402,20 @@ class DigestedData(Sequence):
     )
 
 
+class EncryptedData(Sequence):
+    schema = (
+        ("version", CMSVersion()),
+        ("encryptedContentInfo", EncryptedContentInfo()),
+        ("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
+    )
+
+
 class ContentInfo(Sequence):
     schema = (
         ("contentType", ContentType(defines=(
             (("content",), {
                 id_digestedData: DigestedData(),
+                id_encryptedData: EncryptedData(),
                 id_envelopedData: EnvelopedData(),
                 id_signedData: SignedData(),
             }),
index 0cb3b8dca41e6da7e74457d1e353df29261005db..c40319ab81ac4f93d92e488de18ce2b054bfda30 100644 (file)
@@ -8,10 +8,27 @@ id_envelopedData = id_pkcs7 + (3,)
 id_digestedData = id_pkcs7 + (5,)
 id_encryptedData = id_pkcs7 + (6,)
 
+id_pkcs9 = ObjectIdentifier("1.2.840.113549.1.9")
+id_contentType = id_pkcs9 + (3,)
+id_messageDigest = id_pkcs9 + (4,)
+
+id_Gost28147_89 = ObjectIdentifier("1.2.643.2.2.21")
+id_GostR3410_2001_TestParamSet = ObjectIdentifier("1.2.643.2.2.35.0")
+id_cms_mac_attr = ObjectIdentifier("1.2.643.7.1.0.6.1.1")
 id_tc26_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.1.1")
 id_tc26_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.1.2")
 id_tc26_gost3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.2.2")
 id_tc26_gost3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.2.3")
+id_tc26_signwithdigest_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2")
+id_tc26_signwithdigest_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3")
+id_gostr3412_2015_magma_ctracpkm = ObjectIdentifier("1.2.643.7.1.1.5.1.1")
+id_gostr3412_2015_magma_ctracpkm_omac = ObjectIdentifier("1.2.643.7.1.1.5.1.2")
+id_gostr3412_2015_kuznyechik_ctracpkm = ObjectIdentifier("1.2.643.7.1.1.5.2.1")
+id_gostr3412_2015_kuznyechik_ctracpkm_omac = ObjectIdentifier("1.2.643.7.1.1.5.2.2")
+id_tc26_agreement_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.6.1")
+id_tc26_agreement_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.6.2")
+id_gostr3412_2015_magma_wrap_kexp15 = ObjectIdentifier("1.2.643.7.1.1.7.1.1")
+id_gostr3412_2015_kuznyechik_wrap_kexp15 = ObjectIdentifier("1.2.643.7.1.1.7.2.1")
 id_tc26_gost3410_2012_256_paramSetA = ObjectIdentifier("1.2.643.7.1.2.1.1.1")
 id_tc26_gost3410_2012_256_paramSetB = ObjectIdentifier("1.2.643.7.1.2.1.1.2")
 id_tc26_gost3410_2012_256_paramSetC = ObjectIdentifier("1.2.643.7.1.2.1.1.3")
@@ -20,11 +37,7 @@ id_tc26_gost3410_2012_512_paramSetTest = ObjectIdentifier("1.2.643.7.1.2.1.2.0")
 id_tc26_gost3410_2012_512_paramSetA = ObjectIdentifier("1.2.643.7.1.2.1.2.1")
 id_tc26_gost3410_2012_512_paramSetB = ObjectIdentifier("1.2.643.7.1.2.1.2.2")
 id_tc26_gost3410_2012_512_paramSetC = ObjectIdentifier("1.2.643.7.1.2.1.2.3")
-id_tc26_signwithdigest_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2")
-id_tc26_signwithdigest_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3")
 id_tc26_gost_28147_param_Z = ObjectIdentifier("1.2.643.7.1.2.5.1.1")
-id_Gost28147_89 = ObjectIdentifier("1.2.643.2.2.21")
-id_GostR3410_2001_TestParamSet = ObjectIdentifier("1.2.643.2.2.35.0")
 
 id_pbes2 = ObjectIdentifier("1.2.840.113549.1.5.13")
 id_pbkdf2 = ObjectIdentifier("1.2.840.113549.1.5.12")
index f1f684aca0be418155ef85132376b05e6c76b6dc..1665f8ae21786aee8cfd3fb1735e0e3d19ecb6bf 100644 (file)
 """PKCS #10 related structures (**NOT COMPLETE**)
 """
 
-from pyderasn import Any
 from pyderasn import BitString
 from pyderasn import Integer
-from pyderasn import ObjectIdentifier
 from pyderasn import Sequence
 from pyderasn import SetOf
 from pyderasn import tag_ctxc
 
+from pygost.asn1schemas.cms import Attribute
 from pygost.asn1schemas.x509 import AlgorithmIdentifier
 from pygost.asn1schemas.x509 import Name
 from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
 
 
-class AttributeValue(Any):
-    pass
-
-
-class AttributeValues(SetOf):
-    schema = AttributeValue()
-
-
-class Attribute(Sequence):
-    schema = (
-        ("type", ObjectIdentifier()),
-        ("values", AttributeValues()),
-    )
-
-
 class Attributes(SetOf):
     schema = Attribute()
 
index b289fa5595afb469e158646b8b3bc6343301ecc1..9cc8b584913516c618f004cafe9b3bbcb7dc7b3d 100644 (file)
@@ -18,9 +18,12 @@ from base64 import b64decode
 from unittest import skipIf
 from unittest import TestCase
 
+from six import text_type
+
 from pygost.gost28147 import cfb_decrypt
 from pygost.gost3410 import CURVES
 from pygost.gost3410 import prv_unmarshal
+from pygost.gost3410 import pub_marshal
 from pygost.gost3410 import pub_unmarshal
 from pygost.gost3410 import public_key
 from pygost.gost3410 import verify
@@ -28,7 +31,15 @@ from pygost.gost3410_vko import kek_34102012256
 from pygost.gost3410_vko import ukm_unmarshal
 from pygost.gost34112012256 import GOST34112012256
 from pygost.gost34112012512 import GOST34112012512
+from pygost.gost3412 import GOST3412Kuznechik
+from pygost.gost3412 import GOST3412Magma
+from pygost.gost3413 import ctr_acpkm
+from pygost.gost3413 import KEYSIZE
+from pygost.gost3413 import mac as omac
+from pygost.kdf import kdf_tree_gostr3411_2012_256
+from pygost.kdf import keg
 from pygost.utils import hexdec
+from pygost.wrap import kimp15
 from pygost.wrap import unwrap_cryptopro
 from pygost.wrap import unwrap_gost
 
@@ -37,9 +48,25 @@ try:
     from pyderasn import OctetString
 
     from pygost.asn1schemas.cms import ContentInfo
+    from pygost.asn1schemas.cms import SignedAttributes
+    from pygost.asn1schemas.oids import id_cms_mac_attr
     from pygost.asn1schemas.oids import id_envelopedData
+    from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
+    from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm_omac
+    from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
+    from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm
+    from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm_omac
+    from pygost.asn1schemas.oids import id_gostr3412_2015_magma_wrap_kexp15
+    from pygost.asn1schemas.oids import id_messageDigest
+    from pygost.asn1schemas.oids import id_tc26_agreement_gost3410_2012_256
+    from pygost.asn1schemas.oids import id_tc26_agreement_gost3410_2012_512
     from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
     from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
+    from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetA
+    from pygost.asn1schemas.oids import id_tc26_gost3411_2012_256
+    from pygost.asn1schemas.oids import id_tc26_gost3411_2012_512
+    from pygost.asn1schemas.x509 import Certificate
+    from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
 except ImportError:
     pyderasn_exists = False
 else:
@@ -460,3 +487,603 @@ WFUZEnEuAKcuG6dTOawEBLhi9hIwOgYJKoZIhvcNAQcBMB8GBiqFAwICFTAVBAiD
             keker,
             b"Test message",
         )
+
+
+@skipIf(not pyderasn_exists, "PyDERASN dependency is required")
+class TestR132356510252019(TestCase):
+    """Test vectors from Р 1323565.1.025-2019
+    """
+    curve256 = CURVES["id-tc26-gost-3410-2012-256-paramSetA"]
+    curve512 = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
+    psk = hexdec("8F5EEF8814D228FB2BBC5612323730CFA33DB7263CC2C0A01A6C6953F33D61D5")[::-1]
+
+    ca_prv = prv_unmarshal(hexdec("092F8D059E97E22B90B1AE99F0087FC4D26620B91550CBB437C191005A290810")[::-1])
+    ca_pub = public_key(curve256, ca_prv)
+    ca_cert = Certificate().decod(b64decode("""
+MIIB8DCCAZ2gAwIBAgIEAYy6gTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
+MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
+MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA4MQ0wCwYDVQQKEwRUSzI2MScwJQYD
+VQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwaDAhBggqhQMHAQEB
+ATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABEAaSoKcjw54UACci6svELNF0IYM
+RIW8urUsqamIpoG46XCqrVOuI6Q13N4dwcRsbZdqByf+GC2f5ZfO3baN5bTKo4GF
+MIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzESoTowODENMAsGA1UE
+ChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0
+ggQBjLqBMB0GA1UdDgQWBBSA2Qz3mfhmTZNTiY7AnnEtp6cxEjAKBggqhQMHAQED
+AgNBAAgv248F4OeNCkhlzJWec0evHYnMBlSzk1lDm0F875B7CqMrKh2MtJHXenbj
+Gc2uRn2IwgmSf/LZDrYsKKqZSxk=
+"""))
+
+    sender256_prv = prv_unmarshal(hexdec("0B20810E449978C7C3B76C6FF77A16C532421139344A058EF56310B6B6F377E8")[::-1])
+    sender256_pub = public_key(curve256, sender256_prv)
+    sender256_cert = Certificate().decod(b64decode("""
+MIIB8zCCAaCgAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
+MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
+MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYD
+VQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwaDAhBggqhQMH
+AQEBATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABECWKQ0TYllqg4GmY3tBJiyz
+pXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpNNSHpQnm+jLAZhuJaJfqZ6VbT
+o4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzESoTowODENMAsG
+A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
+Yml0ggQBjLqBMB0GA1UdDgQWBBTRnChHSWbQYwnJC62n2zu5Njd03zAKBggqhQMH
+AQEDAgNBAB41oijaXSEn58l78y2rhxY35/lKEq4XWZ70FtsNlVxWATyzgO5Wliwn
+t1O4GoZsxx8r6T/i7VG65UNmQlwdOKQ=
+"""))
+
+    recipient256_prv = prv_unmarshal(hexdec("0DC8DC1FF2BC114BABC3F1CA8C51E4F58610427E197B1C2FBDBA4AE58CBFB7CE")[::-1])
+    recipient256_pub = public_key(curve256, recipient256_prv)
+    recipient256_cert = Certificate().decod(b64decode("""
+MIIB8jCCAZ+gAwIBAgIEAYy6gzAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
+MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
+MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA6MQ0wCwYDVQQKEwRUSzI2MSkwJwYD
+VQQDEyBSRUNJUElFTlQ6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdDBoMCEGCCqFAwcB
+AQEBMBUGCSqFAwcBAgEBAQYIKoUDBwEBAgIDQwAEQL8nghlzLGMKWHuWhNMPMN5u
+L6SkGqRiJ6qZxZb+4dPKbBT9LNVvNKtwUed+BeE5kfqOfolPgFusnL1rnO9yREOj
+gYUwgYIwYQYDVR0BBFowWIAUgNkM95n4Zk2TU4mOwJ5xLaenMRKhOjA4MQ0wCwYD
+VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1i
+aXSCBAGMuoEwHQYDVR0OBBYEFLue+PUb9Oe+pziBU+MvNejjgrzFMAoGCCqFAwcB
+AQMCA0EAPP9Oad1/5jwokSjPpccsQ0xCdVYM+mGQ0IbpiZxQj8gnkt8sq4jR6Ya+
+I/BDkbZNDNE27TU1p3t5rE9NMEeViA==
+"""))
+
+    sender512_prv = prv_unmarshal(hexdec("F95A5D44C5245F63F2E7DF8E782C1924EADCB8D06C52D91023179786154CBDB1561B4DF759D69F67EE1FBD5B68800E134BAA12818DA4F3AC75B0E5E6F9256911")[::-1])
+    sender512_pub = public_key(curve512, sender512_prv)
+    sender512_cert = Certificate().decod(b64decode("""
+MIICNjCCAeOgAwIBAgIEAYy6hDAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
+MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
+MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYD
+VQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDUxMi1iaXQwgaowIQYIKoUD
+BwEBAQIwFQYJKoUDBwECAQIBBggqhQMHAQECAwOBhAAEgYC0i7davCkOGGVcYqFP
+tS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO+K21LDpYVfDPs2Sqa13ZN+Ts
+/JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0EmZf8T3ae/J1Jo6xGunecH1/G4
+hMts9HYLnxbwJDMNVGuIHV6gzqOBhTCBgjBhBgNVHQEEWjBYgBSA2Qz3mfhmTZNT
+iY7AnnEtp6cxEqE6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6
+IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQUK+l9HAscONGx
+zCcRpxRAmFHvlXowCgYIKoUDBwEBAwIDQQAbjA0Q41/rIKOOvjHKsAsoEJM+WJf6
+/PKXg2JaStthmw99bdtwwkU/qDbcje2tF6mt+XWyQBXwvfeES1GFY9fJ
+"""))
+
+    recipient512_prv = prv_unmarshal(hexdec("A50315981F0A7C7FC05B4EB9591A62B1F84BD6FD518ACFCEDF0A7C9CF388D1F18757C056ADA5B38CBF24CDDB0F1519EF72DB1712CEF1920952E94AF1F9C575DC")[::-1])
+    recipient512_pub = public_key(curve512, recipient512_prv)
+    recipient512_cert = Certificate().decod(b64decode("""
+MIICNTCCAeKgAwIBAgIEAYy6hTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
+MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
+MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA6MQ0wCwYDVQQKEwRUSzI2MSkwJwYD
+VQQDEyBSRUNJUElFTlQ6IEdPU1QgMzQuMTAtMTIgNTEyLWJpdDCBqjAhBggqhQMH
+AQEBAjAVBgkqhQMHAQIBAgEGCCqFAwcBAQIDA4GEAASBgKauwGYvUkzz19g0LP/p
+zeRdmwy1m+QSy9W5ZrL/AGuJofm2ARjz40ozNbW6bp9hkHu8x66LX7u5zz+QeS2+
+X5om18UXriComgO0+qhZbc+Hzu0eQ8FjOd8LpLk3TzzfBltfLOX5IiPLjeum+pSP
+0QjoXAVcrop//B4yvZIukvROo4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJ
+jsCecS2npzESoTowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjog
+R09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBSrXT5VKhm/5uff
+kwW0XpG19k6AajAKBggqhQMHAQEDAgNBAAJBpsHRrQKZGb22LOzaReEB8rl2MbIR
+ja64NaM5h+cAFoHm6t/k+ziLh2A11rTakR+5of4NQ3EjEhuPtomP2tc=
+"""))
+
+    def test_certs(self):
+        """Certificates signatures
+        """
+        for prv, pub, curve, mode, cert in (
+                (self.ca_prv, self.ca_pub, self.curve256, 2001, self.ca_cert),
+                (self.sender256_prv, self.sender256_pub, self.curve256, 2001, self.sender256_cert),
+                (self.recipient256_prv, self.recipient256_pub, self.curve256, 2001, self.recipient256_cert),
+                (self.sender512_prv, self.sender512_pub, self.curve512, 2012, self.sender512_cert),
+                (self.recipient512_prv, self.recipient512_pub, self.curve512, 2012, self.recipient512_cert),
+        ):
+            pub_our = public_key(curve, prv)
+            self.assertEqual(pub_our, pub)
+            self.assertSequenceEqual(
+                pub_marshal(pub_our, mode=mode),
+                bytes(OctetString().decod(bytes(
+                    cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
+                ))),
+            )
+
+        for cert in (
+                self.ca_cert,
+                self.sender256_cert,
+                self.recipient256_cert,
+                self.sender512_cert,
+                self.recipient512_cert,
+        ):
+            self.assertTrue(verify(
+                self.curve256,
+                self.ca_pub,
+                GOST34112012256(cert["tbsCertificate"].encode()).digest()[::-1],
+                bytes(cert["signatureValue"]),
+                mode=2001,
+            ))
+
+    def test_signed_with_attrs(self):
+        ci = ContentInfo().decod(b64decode("""
+MIIENwYJKoZIhvcNAQcCoIIEKDCCBCQCAQExDDAKBggqhQMHAQECAzA7BgkqhkiG
+9w0BBwGgLgQsyu7t8vDu6/zt++kg7/Do7OXwIOTr/yDx8vDz6vLz8PsgU2lnbmVk
+RGF0YS6gggI6MIICNjCCAeOgAwIBAgIEAYy6hDAKBggqhQMHAQEDAjA4MQ0wCwYD
+VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1i
+aXQwHhcNMDEwMTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRU
+SzI2MSowKAYDVQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDUxMi1iaXQw
+gaowIQYIKoUDBwEBAQIwFQYJKoUDBwECAQIBBggqhQMHAQECAwOBhAAEgYC0i7da
+vCkOGGVcYqFPtS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO+K21LDpYVfDP
+s2Sqa13ZN+Ts/JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0EmZf8T3ae/J1Jo
+6xGunecH1/G4hMts9HYLnxbwJDMNVGuIHV6gzqOBhTCBgjBhBgNVHQEEWjBYgBSA
+2Qz3mfhmTZNTiY7AnnEtp6cxEqE6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMT
+HkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQU
+K+l9HAscONGxzCcRpxRAmFHvlXowCgYIKoUDBwEBAwIDQQAbjA0Q41/rIKOOvjHK
+sAsoEJM+WJf6/PKXg2JaStthmw99bdtwwkU/qDbcje2tF6mt+XWyQBXwvfeES1GF
+Y9fJMYIBlDCCAZACAQEwQDA4MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBU
+SzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQCBAGMuoQwCgYIKoUDBwEBAgOgga0w
+GAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkwMzIw
+MTk1NTIyWjAiBgkqhkiG9w0BCWIxFQQTU2lnbmVkIGF0dHIncyB2YWx1ZTBPBgkq
+hkiG9w0BCQQxQgRAUdPHEukF5BIfo9DoQIMdnB0ZLkzq0RueEUZSNv07A7C+GKWi
+G62fueArg8uPCHPTUN6d/42p33fgMkEwH7f7cDAKBggqhQMHAQEBAgSBgGUnVka8
+FvTlClmOtj/FUUacBdE/nEBeMLOO/535VDYrXlftPE6zQf/4ghS7TQG2VRGQ3GWD
++L3+W09A7d5uyyTEbvgtdllUG0OyqFwKmJEaYsMin87SFVs0cn1PGV1fOKeLluZa
+bLx5whxd+mzlpekL5i6ImRX+TpERxrA/xSe5
+"""))
+        _, sd = ci["content"].defined
+        content = bytes(sd["encapContentInfo"]["eContent"])
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры SignedData."),
+        )
+        si = sd["signerInfos"][0]
+        self.assertEqual(
+            si["digestAlgorithm"]["algorithm"],
+            id_tc26_gost3411_2012_512,
+        )
+        digest = [
+            bytes(attr["attrValues"][0].defined[1]) for attr in si["signedAttrs"]
+            if attr["attrType"] == id_messageDigest
+        ][0]
+        self.assertSequenceEqual(digest, GOST34112012512(content).digest())
+        self.assertTrue(verify(
+            self.curve512,
+            self.sender512_pub,
+            GOST34112012512(
+                SignedAttributes(si["signedAttrs"]).encode()
+            ).digest()[::-1],
+            bytes(si["signature"]),
+            mode=2012,
+        ))
+
+    def test_signed_without_attrs(self):
+        ci = ContentInfo().decod(b64decode("""
+MIIDAQYJKoZIhvcNAQcCoIIC8jCCAu4CAQExDDAKBggqhQMHAQECAjA7BgkqhkiG
+9w0BBwGgLgQsyu7t8vDu6/zt++kg7/Do7OXwIOTr/yDx8vDz6vLz8PsgU2lnbmVk
+RGF0YS6gggH3MIIB8zCCAaCgAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYD
+VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1i
+aXQwHhcNMDEwMTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRU
+SzI2MSowKAYDVQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQw
+aDAhBggqhQMHAQEBATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABECWKQ0TYllq
+g4GmY3tBJiyzpXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpNNSHpQnm+jLAZ
+huJaJfqZ6VbTo4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzES
+oTowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4x
+MC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBTRnChHSWbQYwnJC62n2zu5Njd0
+3zAKBggqhQMHAQEDAgNBAB41oijaXSEn58l78y2rhxY35/lKEq4XWZ70FtsNlVxW
+ATyzgO5Wliwnt1O4GoZsxx8r6T/i7VG65UNmQlwdOKQxgaIwgZ8CAQEwQDA4MQ0w
+CwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1
+Ni1iaXQCBAGMuoIwCgYIKoUDBwEBAgIwCgYIKoUDBwEBAQEEQC6jZPA59szL9FiA
+0wC71EBE42ap6gKxklT800cu2FvbLu972GJYNSI7+UeanVU37OVWyenEXi2E5HkU
+94kBe8Q=
+"""))
+        _, sd = ci["content"].defined
+        content = bytes(sd["encapContentInfo"]["eContent"])
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры SignedData."),
+        )
+        si = sd["signerInfos"][0]
+        self.assertEqual(
+            si["digestAlgorithm"]["algorithm"],
+            id_tc26_gost3411_2012_256,
+        )
+        self.assertTrue(verify(
+            self.curve256,
+            self.sender256_pub,
+            GOST34112012256(content).digest()[::-1],
+            bytes(si["signature"]),
+            mode=2001,
+        ))
+
+    def test_kari_ephemeral(self):
+        ci = ContentInfo().decod(b64decode("""
+MIIB/gYJKoZIhvcNAQcDoIIB7zCCAesCAQIxggFioYIBXgIBA6CBo6GBoDAXBggq
+hQMHAQEBAjALBgkqhQMHAQIBAgEDgYQABIGAe+itJVNbHM35RHfzuwFJPYdPXqtW
+8hNEF7Z/XFEE2T71SRkhFX7ozYKQNh/TkVY9D4vG0LnD9Znr/pJyOjpsNb+dPcKX
+Kbk/0JQxoPGHxFzASVAFq0ov/yBe2XGFWMeKUqtaAr7SvoYS0oEhT5EuT8BXmecd
+nRe7NqOzESpb15ahIgQgsqHxOcdOp03l11S7k3OH1k1HNa5F8m9ctrOzH2846FMw
+FwYJKoUDBwEBBwIBMAoGCCqFAwcBAQYCMHYwdDBAMDgxDTALBgNVBAoTBFRLMjYx
+JzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdAIEAYy6hQQw
+SxLc18zMwzLwXbcKqYhV/VzsdBgVArOHsSBIbaThJWE7zI37VGPMQJM5VXJ7GVcL
+MF0GCSqGSIb3DQEHATAfBgkqhQMHAQEFAgIwEgQQ6EeVlADDCz2cdEWKy+tM94Av
+yIFl/Ie4VeFFuczTsMsIaOUEe3Jn9GeVp8hZSj3O2q4hslQ/u/+Gj4QkSHm/M0ih
+ITAfBgkqhQMHAQAGAQExEgQQs1t6D3J3WCEvxunnEE15NQ==
+"""))
+        _, ed = ci["content"].defined
+        kari = ed["recipientInfos"][0]["kari"]
+        orig_key = kari["originator"]["originatorKey"]
+        self.assertEqual(orig_key["algorithm"]["algorithm"], id_tc26_gost3410_2012_512)
+        self.assertEqual(
+            GostR34102012PublicKeyParameters().decod(
+                bytes(orig_key["algorithm"]["parameters"])
+            )["publicKeyParamSet"],
+            id_tc26_gost3410_2012_512_paramSetA,
+        )
+        orig_pub = pub_unmarshal(
+            bytes(OctetString().decod(bytes(orig_key["publicKey"]))),
+            mode=2012,
+        )
+        ukm = bytes(kari["ukm"])
+        self.assertEqual(
+            kari["keyEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_kuznyechik_wrap_kexp15,
+        )
+        self.assertEqual(
+            kari["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
+            id_tc26_agreement_gost3410_2012_512,
+        )
+        kexp = bytes(kari["recipientEncryptedKeys"][0]["encryptedKey"])
+        keymat = keg(self.curve512, self.recipient512_prv, orig_pub, ukm, mode=2012)
+        kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
+        cek = kimp15(
+            GOST3412Kuznechik(kek).encrypt,
+            GOST3412Kuznechik(kim).encrypt,
+            GOST3412Kuznechik.blocksize,
+            kexp,
+            ukm[24:24 + GOST3412Kuznechik.blocksize // 2],
+        )
+        eci = ed["encryptedContentInfo"]
+        self.assertEqual(
+            eci["contentEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_kuznyechik_ctracpkm_omac,
+        )
+        eci_ukm = bytes(
+            eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
+        )
+        self.assertEqual(ed["unprotectedAttrs"][0]["attrType"], id_cms_mac_attr)
+        encrypted_mac = bytes(ed["unprotectedAttrs"][0]["attrValues"][0].defined[1])
+        encrypted_content = bytes(eci["encryptedContent"])
+        cek_enc, cek_mac = kdf_tree_gostr3411_2012_256(
+            cek, b"kdf tree", eci_ukm[GOST3412Kuznechik.blocksize // 2:], 2,
+        )
+        content_and_tag = ctr_acpkm(
+            GOST3412Kuznechik,
+            GOST3412Kuznechik(cek_enc).encrypt,
+            256 * 1024,
+            GOST3412Kuznechik.blocksize,
+            encrypted_content + encrypted_mac,
+            eci_ukm[:GOST3412Kuznechik.blocksize // 2],
+        )
+        content = content_and_tag[:-GOST3412Kuznechik.blocksize]
+        tag_expected = content_and_tag[-GOST3412Kuznechik.blocksize:]
+        self.assertSequenceEqual(
+            omac(
+                GOST3412Kuznechik(cek_mac).encrypt,
+                GOST3412Kuznechik.blocksize,
+                content,
+            ),
+            tag_expected,
+        )
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры EnvelopedData."),
+        )
+
+    def test_kari_static(self):
+        ci = ContentInfo().decod(b64decode("""
+MIIBawYJKoZIhvcNAQcDoIIBXDCCAVgCAQIxgfehgfQCAQOgQjBAMDgxDTALBgNV
+BAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJp
+dAIEAYy6gqEiBCBvcfyuSF57y8vVyaw8Z0ch3wjC4lPKTrpVRXty4Rhk5DAXBgkq
+hQMHAQEHAQEwCgYIKoUDBwEBBgEwbjBsMEAwODENMAsGA1UEChMEVEsyNjEnMCUG
+A1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0AgQBjLqDBChPbi6B
+krXuLPexPAL2oUGCFWDGQHqINL5ExuMBG7/5XQRqriKARVa0MFkGCSqGSIb3DQEH
+ATAbBgkqhQMHAQEFAQEwDgQMdNdCKnYAAAAwqTEDgC9O2bYyTGQJ8WUQGq0zHwzX
+L0jFhWHTF1tcAxYmd9pX5i89UwIxhtYqyjX1QHju2g==
+"""))
+        _, ed = ci["content"].defined
+        kari = ed["recipientInfos"][0]["kari"]
+        ukm = bytes(kari["ukm"])
+        self.assertEqual(
+            kari["keyEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_magma_wrap_kexp15,
+        )
+        self.assertEqual(
+            kari["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
+            id_tc26_agreement_gost3410_2012_256,
+        )
+        kexp = bytes(kari["recipientEncryptedKeys"][0]["encryptedKey"])
+        keymat = keg(
+            self.curve256,
+            self.recipient256_prv,
+            self.sender256_pub,
+            ukm,
+            mode=2001,
+        )
+        kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
+        cek = kimp15(
+            GOST3412Magma(kek).encrypt,
+            GOST3412Magma(kim).encrypt,
+            GOST3412Magma.blocksize,
+            kexp,
+            ukm[24:24 + GOST3412Magma.blocksize // 2],
+        )
+        eci = ed["encryptedContentInfo"]
+        self.assertEqual(
+            eci["contentEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_magma_ctracpkm,
+        )
+        eci_ukm = bytes(
+            eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
+        )
+        content = ctr_acpkm(
+            GOST3412Magma,
+            GOST3412Magma(cek).encrypt,
+            8 * 1024,
+            GOST3412Magma.blocksize,
+            bytes(eci["encryptedContent"]),
+            eci_ukm[:GOST3412Magma.blocksize // 2],
+        )
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры EnvelopedData."),
+        )
+
+    def test_ktri_256(self):
+        ci = ContentInfo().decod(b64decode("""
+MIIBlQYJKoZIhvcNAQcDoIIBhjCCAYICAQAxggEcMIIBGAIBADBAMDgxDTALBgNV
+BAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJp
+dAIEAYy6gzAXBgkqhQMHAQEHAgEwCgYIKoUDBwEBBgEEgbcwgbQEMFiMredFR3Mv
+3g2wqyVXRnrhYEBMNFaqqgBpHwPQh3bF98tt9HZPxRDCww0OPfxeuTBeMBcGCCqF
+AwcBAQEBMAsGCSqFAwcBAgEBAQNDAARAdFJ9ww+3ptvQiaQpizCldNYhl4DB1rl8
+Fx/2FIgnwssCbYRQ+UuRsTk9dfLLTGJG3JIEXKFxXWBgOrK965A5pAQg9f2/EHxG
+DfetwCe1a6uUDCWD+wp5dYOpfkry8YRDEJgwXQYJKoZIhvcNAQcBMB8GCSqFAwcB
+AQUCATASBBDUHNxmVclO/v3OaY9P7jxOgC+sD9CHGlEMRUpfGn6yfFDMExmYeby8
+LzdPJe1MkYV0qQgdC1zI3nQ7/4taf+4zRA==
+"""))
+        _, ed = ci["content"].defined
+        ktri = ed["recipientInfos"][0]["ktri"]
+        self.assertEqual(
+            ktri["keyEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_kuznyechik_wrap_kexp15,
+        )
+        self.assertEqual(
+            ktri["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
+            id_tc26_agreement_gost3410_2012_256,
+        )
+        _, encrypted_key = ktri["encryptedKey"].defined
+        self.assertEqual(
+            encrypted_key["ephemeralPublicKey"]["algorithm"]["algorithm"],
+            id_tc26_gost3410_2012_256,
+        )
+        pub = pub_unmarshal(bytes(OctetString().decod(
+            bytes(encrypted_key["ephemeralPublicKey"]["subjectPublicKey"])
+        )), mode=2001)
+        ukm = bytes(encrypted_key["ukm"])
+        kexp = bytes(encrypted_key["encryptedKey"])
+        keymat = keg(self.curve256, self.recipient256_prv, pub, ukm, mode=2001)
+        kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
+        cek = kimp15(
+            GOST3412Kuznechik(kek).encrypt,
+            GOST3412Kuznechik(kim).encrypt,
+            GOST3412Kuznechik.blocksize,
+            kexp,
+            ukm[24:24 + GOST3412Kuznechik.blocksize // 2],
+        )
+        eci = ed["encryptedContentInfo"]
+        self.assertEqual(
+            eci["contentEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_kuznyechik_ctracpkm,
+        )
+        eci_ukm = bytes(
+            eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
+        )
+        content = ctr_acpkm(
+            GOST3412Kuznechik,
+            GOST3412Kuznechik(cek).encrypt,
+            256 * 1024,
+            GOST3412Kuznechik.blocksize,
+            bytes(eci["encryptedContent"]),
+            eci_ukm[:GOST3412Kuznechik.blocksize // 2],
+        )
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры EnvelopedData."),
+        )
+
+    def test_ktri_ephemeral512(self):
+        ci = ContentInfo().decod(b64decode("""
+MIIB5wYJKoZIhvcNAQcDoIIB2DCCAdQCAQAxggFXMIIBUwIBADBAMDgxDTALBgNVBAoTBFRL
+MjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdAIEAYy6hTAXBgkq
+hQMHAQEHAQEwCgYIKoUDBwEBBgIEgfIwge8EKDof9JLTJVuIfP+c+imDCGyOLtAYENkoXpeU
+CdiGn0Lt65t3TN9G0bUwgaAwFwYIKoUDBwEBAQIwCwYJKoUDBwECAQIBA4GEAASBgDD9XXHn
+0j4EwY3DGB1wzHeThPRDlCwIvpmqWy00QDhS3fLRWiETSe9uMLeg27zI/EiserKMasNZum/i
+d09cmP8aTNIDNRtI5H9M0mH7LpEtY8L901MszvOKHLDYdemvz0JUqOvBtvoeQ6sV4Gl45zXx
+HTzBWlBw1FLX/ITWLapaBCAa09foTeA+PObBznGuCOPoKy+xz/9IIVmZidI6EYkIrzBZBgkq
+hkiG9w0BBwEwGwYJKoUDBwEBBQECMA4EDA4z1UwRL4WYzKFX/oAv8eEX3fWt6hxDpjO0rI7/
+CiJ/CwYGCKODJ9h63vAwlsWwcPwAjxcsLvCNlv6i4NqhGTAXBgkqhQMHAQAGAQExCgQIs2DT
+LuZ22Yw=
+"""))
+        _, ed = ci["content"].defined
+        ktri = ed["recipientInfos"][0]["ktri"]
+        self.assertEqual(
+            ktri["keyEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_magma_wrap_kexp15,
+        )
+        self.assertEqual(
+            ktri["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
+            id_tc26_agreement_gost3410_2012_512,
+        )
+        _, encrypted_key = ktri["encryptedKey"].defined
+        self.assertEqual(
+            encrypted_key["ephemeralPublicKey"]["algorithm"]["algorithm"],
+            id_tc26_gost3410_2012_512,
+        )
+        pub = pub_unmarshal(
+            bytes(OctetString().decod(
+                bytes(encrypted_key["ephemeralPublicKey"]["subjectPublicKey"])
+            )),
+            mode=2012,
+        )
+        ukm = bytes(encrypted_key["ukm"])
+        kexp = bytes(encrypted_key["encryptedKey"])
+        keymat = keg(self.curve512, self.recipient512_prv, pub, ukm, mode=2012)
+        kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
+        cek = kimp15(
+            GOST3412Magma(kek).encrypt,
+            GOST3412Magma(kim).encrypt,
+            GOST3412Magma.blocksize,
+            kexp,
+            ukm[24:24 + GOST3412Magma.blocksize // 2],
+        )
+        eci = ed["encryptedContentInfo"]
+        self.assertEqual(
+            eci["contentEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_magma_ctracpkm_omac,
+        )
+        eci_ukm = bytes(
+            eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
+        )
+        self.assertEqual(ed["unprotectedAttrs"][0]["attrType"], id_cms_mac_attr)
+        encrypted_mac = bytes(ed["unprotectedAttrs"][0]["attrValues"][0].defined[1])
+        encrypted_content = bytes(eci["encryptedContent"])
+        cek_enc, cek_mac = kdf_tree_gostr3411_2012_256(
+            cek, b"kdf tree", eci_ukm[GOST3412Magma.blocksize // 2:], 2,
+        )
+        content_and_tag = ctr_acpkm(
+            GOST3412Magma,
+            GOST3412Magma(cek_enc).encrypt,
+            8 * 1024,
+            GOST3412Magma.blocksize,
+            encrypted_content + encrypted_mac,
+            eci_ukm[:GOST3412Magma.blocksize // 2],
+        )
+        content = content_and_tag[:-GOST3412Magma.blocksize]
+        tag_expected = content_and_tag[-GOST3412Magma.blocksize:]
+        self.assertSequenceEqual(
+            omac(
+                GOST3412Magma(cek_mac).encrypt,
+                GOST3412Magma.blocksize,
+                content,
+            ),
+            tag_expected,
+        )
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры EnvelopedData."),
+        )
+
+    def test_digested256(self):
+        ci = ContentInfo().decod(b64decode("""
+MH0GCSqGSIb3DQEHBaBwMG4CAQAwCgYIKoUDBwEBAgIwOwYJKoZIhvcNAQcBoC4ELMru7fLw
+7uv87fvpIO/w6Ozl8CDk6/8g8fLw8+ry8/D7IERpZ2VzdERhdGEuBCD/esPQYsGkzxZV8uUM
+IAWt6SI8KtxBP8NyG8AGbJ8i/Q==
+"""))
+        _, dd = ci["content"].defined
+        eci = dd["encapContentInfo"]
+        self.assertSequenceEqual(
+            GOST34112012256(bytes(eci["eContent"])).digest(),
+            bytes(dd["digest"]),
+        )
+
+    def test_digested512(self):
+        ci = ContentInfo().decod(b64decode("""
+MIGfBgkqhkiG9w0BBwWggZEwgY4CAQAwCgYIKoUDBwEBAgMwOwYJKoZIhvcNAQcBoC4ELMru
+7fLw7uv87fvpIO/w6Ozl8CDk6/8g8fLw8+ry8/D7IERpZ2VzdERhdGEuBEDe4VUvcKSRvU7R
+FVhFjajXY+nJSUkUsoi3oOeJBnru4PErt8RusPrCJs614ciHCM+ehrC4a+M1Nbq77F/Wsa/v
+"""))
+        _, dd = ci["content"].defined
+        eci = dd["encapContentInfo"]
+        self.assertSequenceEqual(
+            GOST34112012512(bytes(eci["eContent"])).digest(),
+            bytes(dd["digest"]),
+        )
+
+    def test_encrypted_kuznechik(self):
+        ci = ContentInfo().decod(b64decode("""
+MHEGCSqGSIb3DQEHBqBkMGICAQAwXQYJKoZIhvcNAQcBMB8GCSqFAwcBAQUCATASBBBSwX+z
+yOEPPuGyfpsRG4AigC/P8ftTdQMStfIThVkE/vpJlwaHgGv83m2bsPayeyuqpoTeEMOaqGcO
+0MxHWsC9hQ==
+"""))
+        _, ed = ci["content"].defined
+        eci = ed["encryptedContentInfo"]
+        self.assertEqual(
+            eci["contentEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_kuznyechik_ctracpkm,
+        )
+        ukm = bytes(
+            eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
+        )
+        content = ctr_acpkm(
+            GOST3412Kuznechik,
+            GOST3412Kuznechik(self.psk).encrypt,
+            256 * 1024,
+            GOST3412Kuznechik.blocksize,
+            bytes(eci["encryptedContent"]),
+            ukm[:GOST3412Kuznechik.blocksize // 2],
+        )
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры EncryptedData."),
+        )
+
+    def test_encrypted_magma(self):
+        ci = ContentInfo().decod(b64decode("""
+MIGIBgkqhkiG9w0BBwagezB5AgEAMFkGCSqGSIb3DQEHATAbBgkqhQMHAQEFAQIwDgQMuncO
+u3uYPbI30vFCgC9Nsws4R09yLp6jUtadncWUPZGmCGpPKnXGgNHvEmUArgKJvu4FPHtLkHuL
+eQXZg6EZMBcGCSqFAwcBAAYBATEKBAjCbQoH632oGA==
+"""))
+        _, ed = ci["content"].defined
+        eci = ed["encryptedContentInfo"]
+        self.assertEqual(
+            eci["contentEncryptionAlgorithm"]["algorithm"],
+            id_gostr3412_2015_magma_ctracpkm_omac,
+        )
+        ukm = bytes(
+            eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
+        )
+        self.assertEqual(ed["unprotectedAttrs"][0]["attrType"], id_cms_mac_attr)
+        encrypted_mac = bytes(ed["unprotectedAttrs"][0]["attrValues"][0].defined[1])
+        cek_enc, cek_mac = kdf_tree_gostr3411_2012_256(
+            self.psk, b"kdf tree", ukm[GOST3412Magma.blocksize // 2:], 2,
+        )
+        content_and_tag = ctr_acpkm(
+            GOST3412Magma,
+            GOST3412Magma(cek_enc).encrypt,
+            8 * 1024,
+            GOST3412Magma.blocksize,
+            bytes(eci["encryptedContent"]) + encrypted_mac,
+            ukm[:GOST3412Magma.blocksize // 2],
+        )
+        content = content_and_tag[:-GOST3412Magma.blocksize]
+        tag_expected = content_and_tag[-GOST3412Magma.blocksize:]
+        self.assertSequenceEqual(
+            omac(
+                GOST3412Magma(cek_mac).encrypt,
+                GOST3412Magma.blocksize,
+                content,
+            ),
+            tag_expected,
+        )
+        self.assertEqual(
+            content.decode("cp1251"),
+            text_type(u"Контрольный пример для структуры EncryptedData."),
+        )