]> Cypherpunks.ru repositories - pygost.git/blobdiff - pygost/test_cms.py
Р 1323565.1.025-2019 test vectors
[pygost.git] / pygost / test_cms.py
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."),
+        )