-1

我正在尝试使用椭圆曲线密码图 ECDiffieHellman 解密消息,使用 KDFX963 作为密钥派生函数 (KDF)(在 ANSI-X9.63-KDF http://www.secg.org/sec1-v2.pdf中定义)

但我正在努力完成这项工作。我非常需要这样的方法:

DecryptMessage(string tokenFromPayload, string publicKeyStr, string privateKeyStr){
    // Generate an ephemeral key from the public and private key
    // Decrypt payload with the ephemeral key
}

有关解密消息的算法的一些额外信息:

  • 椭圆曲线:SECP384R1;命名为Curves.brainpoolP384r1
  • 密码:AES 模式:GCM
  • 密钥大小:32
  • Mac 尺寸 = 16
  • 密钥导出函数:ANSI-X9.63-KDF
  • 哈希:Sha256(长度 32)

我有下面的 Python 代码正在执行解密消息所需的操作,但我需要在 C# 中使用它。

import base64
import binascii
import json
import os

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
from cryptography import utils
from hashlib import sha256
from math import ceil


class BCAuthCrypto:
    """A class containing a number of handlers for the secp384r1 ECC algorithm in Python"""

    curve = ec.SECP384R1()
    cipher_key_size = 32
    mac_size = 16
    backend = default_backend()

    def ITOSP(self, longint, length):
        """ITOSP, short for Integer-to-Octet-String Primitive, converts a non-negative integer
        to an octet string of a specified length. This particular function is defined in the
        PKCS #1 v2.1: RSA Cryptography Standard (June 14, 2002)
        https://www.cryptrec.go.jp/cryptrec_03_spec_cypherlist_files/PDF/pkcs-1v2-12.pdf"""

        hex_string = "%X" % longint
        assert len(hex_string) <= 2 * length, "ITOSP function: Insufficient length for encoding"
        return binascii.a2b_hex(hex_string.zfill(2 * length))

    def KDFX963(self, inbyte_x, shared_data, key_length, hashfunct=sha256, hash_len=32):
        """KDFX963 is a key derivation function (KDF) that takes as input byte sequence inbyte_x
        and additional shared data shared_data and outputs a byte sequence key of length
        key_length. This function is defined in ANSI-X9.63-KDF, and this particular flavor of
        KDF is known as X9.63. You can read more about it from:
        http://www.secg.org/sec1-v2.pdf"""

        assert key_length >= 0, "KDFX963 function: key_length should be positive integer"
        k = key_length / float(hash_len)
        k = int(ceil(k))

        acc_str = ""
        for i in range(1, k+1):
            h = hashfunct()
            h.update(inbyte_x)
            h.update(self.ITOSP(i, 4))
            h.update(shared_data)
            acc_str = acc_str + h.hexdigest()

        return acc_str[:key_length * 2]

    def decrypt(self, cipher_text_b64, private_key):
        """Decrypt takes input base64-encoded data input cipher_text_b64 and private key
        private_key and outputs plain text data, throws exception on error"""
        cipher = base64.b64decode(cipher_text_b64)

        ephemeral_key_len = ((self.curve.key_size + 7) // 8) * 2 + 1
        ephemeral_key_numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(self.curve, cipher[:ephemeral_key_len])
        ephemeral_key = ephemeral_key_numbers.public_key(self.backend)

        shared_key = private_key.exchange(ec.ECDH(), ephemeral_key)

        V = cipher[:ephemeral_key_len]
        K = binascii.unhexlify(self.KDFX963(shared_key, V, self.cipher_key_size + self.mac_size))
        K1 = K[:self.cipher_key_size]
        K2 = K[self.cipher_key_size:]

        T = cipher[ephemeral_key_len:]
        enc_data = T[:len(T) - self.mac_size]
        tag = T[-self.mac_size:]

        decryptor = Cipher(algorithms.AES(K1), modes.GCM(K2, tag), backend=self.backend).decryptor()
        plain_text = decryptor.update(enc_data) + decryptor.finalize()
        return plain_text

def decrypt_auth_token(tokenFromPayload, public_key_str, private_key_str):
    """Retrive the auth token and decrypt it, in a way that does not specify the name of the service."""
    bc_crypto = BCAuthCrypto()

    public_number = ec.EllipticCurvePublicNumbers.from_encoded_point(bc_crypto.curve, base64.b64decode(public_key_str))
    private_number = ec.EllipticCurvePrivateNumbers(utils.int_from_bytes(base64.b64decode(private_key_str), "big"), public_number)

    private_key = private_number.private_key(bc_crypto.backend)
    token = bc_crypto.decrypt(tokenFromPayload, private_key)

    print "token (decrypted): %s" % token

    return token

希望有一个密码学天才可以帮助我,或者是“Python To C#”专家。谢谢。

4

1 回答 1

0

得到我的答案解密 Apple Business Chat auth token

namespace AppleBusinessChat45
{
    class Program
    {
        static void Main(string[] args)
        {
            var privateKey = "pX/BvdXXUdpC79mW/jWi10Z6PJb5SBY2+aqkR/qYOjqgakKsqZFKnl0kz10Ve+BP";
            var token = "BDiRKNnPiPUb5oala31nkmCaXMB0iyWy3Q93p6fN7vPxEQSUlFVsInkJzPBBqmW1FUIY1KBA3BQb3W3Qv4akZ8kblqbmvupE/EJzPKbROZFBNvxpvVOHHgO2qadmHAjHSmnxUuxrpKxopWnOgyhzUx+mBUTao0pcEgqZFw0Y/qZIJPf1KusCMlz5TAhpjsw=";

            // #####
            // ##### Step 1
            // #####
            var decodedToken = Convert.FromBase64String(token);
            var decodedEphemeralPublicKey = decodedToken.Take(97).ToArray();
            var encodedEphemeralPublicKeyCheck = Convert.ToBase64String(decodedEphemeralPublicKey);

            if (encodedEphemeralPublicKeyCheck != "BDiRKNnPiPUb5oala31nkmCaXMB0iyWy3Q93p6fN7vPxEQSUlFVsInkJzPBBqmW1FUIY1KBA3BQb3W3Qv4akZ8kblqbmvupE/EJzPKbROZFBNvxpvVOHHgO2qadmHAjHSg==")
                throw new Exception("Public key check failed");

            X9ECParameters curveParams = ECNamedCurveTable.GetByName("secp384r1");
            ECPoint decodePoint = curveParams.Curve.DecodePoint(decodedEphemeralPublicKey);
            ECDomainParameters domainParams = new ECDomainParameters(curveParams.Curve, curveParams.G, curveParams.N, curveParams.H, curveParams.GetSeed());
            ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(decodePoint, domainParams);

            var x = ecPublicKeyParameters.Q.AffineXCoord.ToBigInteger();
            var y = ecPublicKeyParameters.Q.AffineYCoord.ToBigInteger();

            if (!x.Equals(new BigInteger("8706462696031173094919866327685737145866436939551712382591956952075131891462487598200779332295613073905587629438229")))
                throw new Exception("X coord check failed");

            if (!y.Equals(new BigInteger("10173258529327482491525749925661342501140613951412040971418641469645769857676705559747557238888921287857458976966474")))
                throw new Exception("Y coord check failed");

            Console.WriteLine("Step 1 complete");

            // #####
            // ##### Step 2
            // #####
            var privateKeyBytes = Convert.FromBase64String(privateKey);
            var ecPrivateKeyParameters = new ECPrivateKeyParameters("ECDHC", new BigInteger(1, privateKeyBytes), domainParams);
            var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(ecPrivateKeyParameters);
            var ecPrivateKey = (ECPrivateKeyParameters) PrivateKeyFactory.CreateKey(privateKeyInfo);

            IBasicAgreement agree = AgreementUtilities.GetBasicAgreement("ECDHC");
            agree.Init(ecPrivateKey);
            BigInteger sharedKey = agree.CalculateAgreement(ecPublicKeyParameters);
            var sharedKeyBytes = sharedKey.ToByteArrayUnsigned();
            var sharedKeyBase64 = Convert.ToBase64String(sharedKeyBytes);

            if (sharedKeyBase64 != "2lvSJsBO2keUHRfvPG6C1RMUmGpuDbdgNrZ9YD7RYnvAcfgq/fjeYr1p0hWABeif")
                throw new Exception("Shared key check failed");

            Console.WriteLine("Step 2 complete");

            // #####
            // ##### Step 3
            // #####
            var kdf2Bytes = Kdf2(sharedKeyBytes, decodedEphemeralPublicKey);
            var kdf2Base64 = Convert.ToBase64String(kdf2Bytes);

            if (kdf2Base64 != "mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZOtXequzN3Q8w+B5GE2eU5g")
                throw new Exception("Kdf2 failed");

            Console.WriteLine("Step 3 complete");

            // #####
            // ##### Step 4
            // #####
            var decryptionKeyBytes = kdf2Bytes.Take(32).ToArray();
            var decryptionIvBytes = kdf2Bytes.Skip(32).ToArray();

            var decryptionKeyBase64 = Convert.ToBase64String(decryptionKeyBytes);
            var decryptionIvBase64 = Convert.ToBase64String(decryptionIvBytes);

            if (decryptionKeyBase64 != "mAzkYatDlz4SzrCyM23NhgL/+mE3eGgfUz9h1CFPhZM=")
                throw new Exception("Decryption key check failed");

            if (decryptionIvBase64 != "rV3qrszd0PMPgeRhNnlOYA==")
                throw new Exception("Decryption iv check failed");

            var encryptedDataBytes = decodedToken.Skip(97).Take(decodedToken.Length - 113).ToArray();
            var tagBytes = decodedToken.Skip(decodedToken.Length - 16).ToArray();

            var encryptedDataBase64 = Convert.ToBase64String(encryptedDataBytes);
            var tagBase64 = Convert.ToBase64String(tagBytes);

            if (encryptedDataBase64 != "afFS7GukrGilac6DKHNTH6YFRNqjSlwSCpkXDRj+")
                throw new Exception("Encrypted data check failed");

            if (tagBase64 != "pkgk9/Uq6wIyXPlMCGmOzA==")
                throw new Exception("Tag check failed");

            KeyParameter keyParam = ParameterUtilities.CreateKeyParameter("AES", decryptionKeyBytes);
            ParametersWithIV parameters = new ParametersWithIV(keyParam, decryptionIvBytes);
            IBufferedCipher cipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
            cipher.Init(false, parameters);
            var resultBytes = cipher.DoFinal(encryptedDataBytes.Concat(tagBytes).ToArray());
            var resultBase64 = Convert.ToBase64String(resultBytes);
            var resultString = Strings.FromByteArray(resultBytes);

            if (resultString != "xXTi32iZwrQ6O8Sy6r1isKwF6Ff1Py")
                throw new Exception("Decryption failed");

            Console.WriteLine("Step 4 complete");
            Console.WriteLine(resultString);

            Console.WriteLine();
            Console.WriteLine("Done... press any key to finish");
            Console.ReadLine();
        }

        static byte[] Kdf2(byte[] sharedKeyBytes, byte[] ephemeralKeyBytes)
        {
            var gen = new Kdf2BytesGenerator(new Sha256Digest());
            gen.Init(new KdfParameters(sharedKeyBytes, ephemeralKeyBytes));

            byte[] encryptionKeyBytes = new byte[48];
            gen.GenerateBytes(encryptionKeyBytes, 0, encryptionKeyBytes.Length);
            return encryptionKeyBytes;
        }
    }
}
于 2020-02-05T09:24:31.057 回答