From fd28fdc0abb235b8a6244b9cc3b3456dffae70f6 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 30 Jul 2020 17:56:39 +0300 Subject: [PATCH] =?utf8?q?=D0=A0=201323565.1.025-2019=20test=20vectors?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- pygost/asn1schemas/cms.py | 131 +++++++- pygost/asn1schemas/oids.py | 21 +- pygost/asn1schemas/pkcs10.py | 18 +- pygost/test_cms.py | 627 +++++++++++++++++++++++++++++++++++ 4 files changed, 762 insertions(+), 35 deletions(-) diff --git a/pygost/asn1schemas/cms.py b/pygost/asn1schemas/cms.py index 2309935..a39b10b 100644 --- a/pygost/asn1schemas/cms.py +++ b/pygost/asn1schemas/cms.py @@ -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(), }), diff --git a/pygost/asn1schemas/oids.py b/pygost/asn1schemas/oids.py index 0cb3b8d..c40319a 100644 --- a/pygost/asn1schemas/oids.py +++ b/pygost/asn1schemas/oids.py @@ -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") diff --git a/pygost/asn1schemas/pkcs10.py b/pygost/asn1schemas/pkcs10.py index f1f684a..1665f8a 100644 --- a/pygost/asn1schemas/pkcs10.py +++ b/pygost/asn1schemas/pkcs10.py @@ -16,34 +16,18 @@ """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() diff --git a/pygost/test_cms.py b/pygost/test_cms.py index b289fa5..9cc8b58 100644 --- a/pygost/test_cms.py +++ b/pygost/test_cms.py @@ -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."), + ) -- 2.44.0