# coding: utf-8
# PyGOST -- Pure Python GOST cryptographic functions library
-# Copyright (C) 2015-2019 Sergey Matveev <stargrave@stargrave.org>
+# Copyright (C) 2015-2020 Sergey Matveev <stargrave@stargrave.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
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
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
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:
prv_key_raw,
curve_name,
hasher,
- mode,
):
content_info, tail = ContentInfo().decode(content_info_raw)
self.assertSequenceEqual(tail, b"")
public_key(curve, prv_unmarshal(prv_key_raw)),
hasher(bytes(signed_data["encapContentInfo"]["eContent"])).digest()[::-1],
bytes(signed_data["signerInfos"][0]["signature"]),
- mode=mode,
))
def test_256(self):
prv_key_raw,
"id-GostR3410-2001-CryptoPro-XchA-ParamSet",
GOST34112012256,
- 2001,
)
def test_512(self):
prv_key_raw,
"id-tc26-gost-3410-12-512-paramSetB",
GOST34112012512,
- 2012,
)
prv_unmarshal(prv),
pub_unmarshal(pub),
ukm_unmarshal(ukm),
- mode=2001,
)
self.process_cms(
return kek_34102012256(
curve,
prv_unmarshal(prv),
- pub_unmarshal(pub, mode=2012),
+ pub_unmarshal(pub),
ukm_unmarshal(ukm),
)
},
),
),
- ) for spki_algorithm in (
+ ) for _ in (
id_tc26_gost3410_2012_256,
id_tc26_gost3410_2012_512,
)
prv_unmarshal(prv),
pub_unmarshal(pub),
ukm_unmarshal(ukm),
- mode=2001,
)
self.process_cms(
return kek_34102012256(
curve,
prv_unmarshal(prv),
- pub_unmarshal(pub, mode=2012),
+ pub_unmarshal(pub),
ukm_unmarshal(ukm),
)
keker,
b"Test message",
)
+
+
+@skipIf(not pyderasn_exists, "PyDERASN dependency is required")
+class TestR132356510252019(TestCase):
+ """Test vectors from Р 1323565.1.025-2019
+ """
+ def setUp(self):
+ self.curve256 = CURVES["id-tc26-gost-3410-2012-256-paramSetA"]
+ self.curve512 = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
+ self.psk = hexdec("8F5EEF8814D228FB2BBC5612323730CFA33DB7263CC2C0A01A6C6953F33D61D5")[::-1]
+
+ self.ca_prv = prv_unmarshal(hexdec("092F8D059E97E22B90B1AE99F0087FC4D26620B91550CBB437C191005A290810")[::-1])
+ self.ca_pub = public_key(self.curve256, self.ca_prv)
+ self.ca_cert = Certificate().decod(b64decode("""
+MIIB8DCCAZ2gAwIBAgIEAYy6gTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
+MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
+MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA4MQ0wCwYDVQQKEwRUSzI2MScwJQYD
+VQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwaDAhBggqhQMHAQEB
+ATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABEAaSoKcjw54UACci6svELNF0IYM
+RIW8urUsqamIpoG46XCqrVOuI6Q13N4dwcRsbZdqByf+GC2f5ZfO3baN5bTKo4GF
+MIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzESoTowODENMAsGA1UE
+ChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0
+ggQBjLqBMB0GA1UdDgQWBBSA2Qz3mfhmTZNTiY7AnnEtp6cxEjAKBggqhQMHAQED
+AgNBAAgv248F4OeNCkhlzJWec0evHYnMBlSzk1lDm0F875B7CqMrKh2MtJHXenbj
+Gc2uRn2IwgmSf/LZDrYsKKqZSxk=
+"""))
+
+ self.sender256_prv = prv_unmarshal(hexdec("0B20810E449978C7C3B76C6FF77A16C532421139344A058EF56310B6B6F377E8")[::-1])
+ self.sender256_pub = public_key(self.curve256, self.sender256_prv)
+ self.sender256_cert = Certificate().decod(b64decode("""
+MIIB8zCCAaCgAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
+MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
+MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYD
+VQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwaDAhBggqhQMH
+AQEBATAVBgkqhQMHAQIBAQEGCCqFAwcBAQICA0MABECWKQ0TYllqg4GmY3tBJiyz
+pXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpNNSHpQnm+jLAZhuJaJfqZ6VbT
+o4GFMIGCMGEGA1UdAQRaMFiAFIDZDPeZ+GZNk1OJjsCecS2npzESoTowODENMAsG
+A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
+Yml0ggQBjLqBMB0GA1UdDgQWBBTRnChHSWbQYwnJC62n2zu5Njd03zAKBggqhQMH
+AQEDAgNBAB41oijaXSEn58l78y2rhxY35/lKEq4XWZ70FtsNlVxWATyzgO5Wliwn
+t1O4GoZsxx8r6T/i7VG65UNmQlwdOKQ=
+"""))
+
+ self.recipient256_prv = prv_unmarshal(hexdec("0DC8DC1FF2BC114BABC3F1CA8C51E4F58610427E197B1C2FBDBA4AE58CBFB7CE")[::-1])
+ self.recipient256_pub = public_key(self.curve256, self.recipient256_prv)
+ self.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==
+"""))
+
+ self.sender512_prv = prv_unmarshal(hexdec("F95A5D44C5245F63F2E7DF8E782C1924EADCB8D06C52D91023179786154CBDB1561B4DF759D69F67EE1FBD5B68800E134BAA12818DA4F3AC75B0E5E6F9256911")[::-1])
+ self.sender512_pub = public_key(self.curve512, self.sender512_prv)
+ self.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
+"""))
+
+ self.recipient512_prv = prv_unmarshal(hexdec("A50315981F0A7C7FC05B4EB9591A62B1F84BD6FD518ACFCEDF0A7C9CF388D1F18757C056ADA5B38CBF24CDDB0F1519EF72DB1712CEF1920952E94AF1F9C575DC")[::-1])
+ self.recipient512_pub = public_key(self.curve512, self.recipient512_prv)
+ self.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, cert in (
+ (self.ca_prv, self.ca_pub, self.curve256, self.ca_cert),
+ (self.sender256_prv, self.sender256_pub, self.curve256, self.sender256_cert),
+ (self.recipient256_prv, self.recipient256_pub, self.curve256, self.recipient256_cert),
+ (self.sender512_prv, self.sender512_pub, self.curve512, self.sender512_cert),
+ (self.recipient512_prv, self.recipient512_pub, self.curve512, self.recipient512_cert),
+ ):
+ pub_our = public_key(curve, prv)
+ self.assertEqual(pub_our, pub)
+ self.assertSequenceEqual(
+ pub_marshal(pub_our),
+ 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"]),
+ ))
+
+ 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"]),
+ ))
+
+ 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"]),
+ ))
+
+ 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"]))),
+ )
+ 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)
+ 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,
+ )
+ 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"])
+ )))
+ ukm = bytes(encrypted_key["ukm"])
+ kexp = bytes(encrypted_key["encryptedKey"])
+ keymat = keg(self.curve256, self.recipient256_prv, pub, ukm)
+ 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_512(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"])
+ )),
+ )
+ ukm = bytes(encrypted_key["ukm"])
+ kexp = bytes(encrypted_key["encryptedKey"])
+ keymat = keg(self.curve512, self.recipient512_prv, pub, ukm)
+ 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."),
+ )