You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
6.0 KiB
176 lines
6.0 KiB
1 year ago
|
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||
|
#pragma warning disable
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.IO;
|
||
|
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cms;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cms.Ecc;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X9;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
|
||
|
|
||
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Cms
|
||
|
{
|
||
|
internal class KeyAgreeRecipientInfoGenerator : RecipientInfoGenerator
|
||
|
{
|
||
|
private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
|
||
|
|
||
|
private DerObjectIdentifier keyAgreementOID;
|
||
|
private DerObjectIdentifier keyEncryptionOID;
|
||
|
private IList recipientCerts;
|
||
|
private AsymmetricCipherKeyPair senderKeyPair;
|
||
|
|
||
|
internal KeyAgreeRecipientInfoGenerator()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
internal DerObjectIdentifier KeyAgreementOID
|
||
|
{
|
||
|
set { this.keyAgreementOID = value; }
|
||
|
}
|
||
|
|
||
|
internal DerObjectIdentifier KeyEncryptionOID
|
||
|
{
|
||
|
set { this.keyEncryptionOID = value; }
|
||
|
}
|
||
|
|
||
|
internal ICollection RecipientCerts
|
||
|
{
|
||
|
set { this.recipientCerts = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(value); }
|
||
|
}
|
||
|
|
||
|
internal AsymmetricCipherKeyPair SenderKeyPair
|
||
|
{
|
||
|
set { this.senderKeyPair = value; }
|
||
|
}
|
||
|
|
||
|
public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
|
||
|
{
|
||
|
byte[] keyBytes = contentEncryptionKey.GetKey();
|
||
|
|
||
|
AsymmetricKeyParameter senderPublicKey = senderKeyPair.Public;
|
||
|
ICipherParameters senderPrivateParams = senderKeyPair.Private;
|
||
|
|
||
|
|
||
|
OriginatorIdentifierOrKey originator;
|
||
|
try
|
||
|
{
|
||
|
originator = new OriginatorIdentifierOrKey(
|
||
|
CreateOriginatorPublicKey(senderPublicKey));
|
||
|
}
|
||
|
catch (IOException e)
|
||
|
{
|
||
|
throw new InvalidKeyException("cannot extract originator public key: " + e);
|
||
|
}
|
||
|
|
||
|
|
||
|
Asn1OctetString ukm = null;
|
||
|
if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
IAsymmetricCipherKeyPairGenerator ephemKPG =
|
||
|
GeneratorUtilities.GetKeyPairGenerator(keyAgreementOID);
|
||
|
ephemKPG.Init(
|
||
|
((ECPublicKeyParameters)senderPublicKey).CreateKeyGenerationParameters(random));
|
||
|
|
||
|
AsymmetricCipherKeyPair ephemKP = ephemKPG.GenerateKeyPair();
|
||
|
|
||
|
ukm = new DerOctetString(
|
||
|
new MQVuserKeyingMaterial(
|
||
|
CreateOriginatorPublicKey(ephemKP.Public), null));
|
||
|
|
||
|
senderPrivateParams = new MqvPrivateParameters(
|
||
|
(ECPrivateKeyParameters)senderPrivateParams,
|
||
|
(ECPrivateKeyParameters)ephemKP.Private,
|
||
|
(ECPublicKeyParameters)ephemKP.Public);
|
||
|
}
|
||
|
catch (IOException e)
|
||
|
{
|
||
|
throw new InvalidKeyException("cannot extract MQV ephemeral public key: " + e);
|
||
|
}
|
||
|
catch (SecurityUtilityException e)
|
||
|
{
|
||
|
throw new InvalidKeyException("cannot determine MQV ephemeral key pair parameters from public key: " + e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
DerSequence paramSeq = new DerSequence(
|
||
|
keyEncryptionOID,
|
||
|
DerNull.Instance);
|
||
|
AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyAgreementOID, paramSeq);
|
||
|
|
||
|
|
||
|
Asn1EncodableVector recipientEncryptedKeys = new Asn1EncodableVector();
|
||
|
foreach (X509Certificate recipientCert in recipientCerts)
|
||
|
{
|
||
|
TbsCertificateStructure tbsCert;
|
||
|
try
|
||
|
{
|
||
|
tbsCert = TbsCertificateStructure.GetInstance(
|
||
|
Asn1Object.FromByteArray(recipientCert.GetTbsCertificate()));
|
||
|
}
|
||
|
catch (Exception)
|
||
|
{
|
||
|
throw new ArgumentException("can't extract TBS structure from certificate");
|
||
|
}
|
||
|
|
||
|
// TODO Should there be a SubjectKeyIdentifier-based alternative?
|
||
|
IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(
|
||
|
tbsCert.Issuer, tbsCert.SerialNumber.Value);
|
||
|
KeyAgreeRecipientIdentifier karid = new KeyAgreeRecipientIdentifier(issuerSerial);
|
||
|
|
||
|
ICipherParameters recipientPublicParams = recipientCert.GetPublicKey();
|
||
|
if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
|
||
|
{
|
||
|
recipientPublicParams = new MqvPublicParameters(
|
||
|
(ECPublicKeyParameters)recipientPublicParams,
|
||
|
(ECPublicKeyParameters)recipientPublicParams);
|
||
|
}
|
||
|
|
||
|
// Use key agreement to choose a wrap key for this recipient
|
||
|
IBasicAgreement keyAgreement = AgreementUtilities.GetBasicAgreementWithKdf(
|
||
|
keyAgreementOID, keyEncryptionOID.Id);
|
||
|
keyAgreement.Init(new ParametersWithRandom(senderPrivateParams, random));
|
||
|
BigInteger agreedValue = keyAgreement.CalculateAgreement(recipientPublicParams);
|
||
|
|
||
|
int keyEncryptionKeySize = GeneratorUtilities.GetDefaultKeySize(keyEncryptionOID) / 8;
|
||
|
byte[] keyEncryptionKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, keyEncryptionKeySize);
|
||
|
KeyParameter keyEncryptionKey = ParameterUtilities.CreateKeyParameter(
|
||
|
keyEncryptionOID, keyEncryptionKeyBytes);
|
||
|
|
||
|
// Wrap the content encryption key with the agreement key
|
||
|
IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionOID.Id);
|
||
|
keyWrapper.Init(true, new ParametersWithRandom(keyEncryptionKey, random));
|
||
|
byte[] encryptedKeyBytes = keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);
|
||
|
|
||
|
Asn1OctetString encryptedKey = new DerOctetString(encryptedKeyBytes);
|
||
|
|
||
|
recipientEncryptedKeys.Add(new RecipientEncryptedKey(karid, encryptedKey));
|
||
|
}
|
||
|
|
||
|
return new RecipientInfo(new KeyAgreeRecipientInfo(originator, ukm, keyEncAlg,
|
||
|
new DerSequence(recipientEncryptedKeys)));
|
||
|
}
|
||
|
|
||
|
private static OriginatorPublicKey CreateOriginatorPublicKey(
|
||
|
AsymmetricKeyParameter publicKey)
|
||
|
{
|
||
|
SubjectPublicKeyInfo spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
|
||
|
return new OriginatorPublicKey(
|
||
|
new AlgorithmIdentifier(spki.AlgorithmID.Algorithm, DerNull.Instance),
|
||
|
spki.PublicKeyData.GetBytes());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#pragma warning restore
|
||
|
#endif
|