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.
231 lines
8.9 KiB
231 lines
8.9 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.Pkcs;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Utilities;
|
||
|
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.Pkcs;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
|
||
|
|
||
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Cms
|
||
|
{
|
||
|
/**
|
||
|
* the RecipientInfo class for a recipient who has been sent a message
|
||
|
* encrypted using key agreement.
|
||
|
*/
|
||
|
public class KeyAgreeRecipientInformation
|
||
|
: RecipientInformation
|
||
|
{
|
||
|
private KeyAgreeRecipientInfo info;
|
||
|
private Asn1OctetString encryptedKey;
|
||
|
|
||
|
internal static void ReadRecipientInfo(IList infos, KeyAgreeRecipientInfo info,
|
||
|
CmsSecureReadable secureReadable)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
foreach (Asn1Encodable rek in info.RecipientEncryptedKeys)
|
||
|
{
|
||
|
RecipientEncryptedKey id = RecipientEncryptedKey.GetInstance(rek.ToAsn1Object());
|
||
|
|
||
|
RecipientID rid = new RecipientID();
|
||
|
|
||
|
Asn1.Cms.KeyAgreeRecipientIdentifier karid = id.Identifier;
|
||
|
|
||
|
Asn1.Cms.IssuerAndSerialNumber iAndSN = karid.IssuerAndSerialNumber;
|
||
|
if (iAndSN != null)
|
||
|
{
|
||
|
rid.Issuer = iAndSN.Name;
|
||
|
rid.SerialNumber = iAndSN.SerialNumber.Value;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Asn1.Cms.RecipientKeyIdentifier rKeyID = karid.RKeyID;
|
||
|
|
||
|
// Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational
|
||
|
|
||
|
rid.SubjectKeyIdentifier = rKeyID.SubjectKeyIdentifier.GetOctets();
|
||
|
}
|
||
|
|
||
|
infos.Add(new KeyAgreeRecipientInformation(info, rid, id.EncryptedKey,
|
||
|
secureReadable));
|
||
|
}
|
||
|
}
|
||
|
catch (IOException e)
|
||
|
{
|
||
|
throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal KeyAgreeRecipientInformation(
|
||
|
KeyAgreeRecipientInfo info,
|
||
|
RecipientID rid,
|
||
|
Asn1OctetString encryptedKey,
|
||
|
CmsSecureReadable secureReadable)
|
||
|
: base(info.KeyEncryptionAlgorithm, secureReadable)
|
||
|
{
|
||
|
this.info = info;
|
||
|
this.rid = rid;
|
||
|
this.encryptedKey = encryptedKey;
|
||
|
}
|
||
|
|
||
|
private AsymmetricKeyParameter GetSenderPublicKey(
|
||
|
AsymmetricKeyParameter receiverPrivateKey,
|
||
|
OriginatorIdentifierOrKey originator)
|
||
|
{
|
||
|
OriginatorPublicKey opk = originator.OriginatorPublicKey;
|
||
|
if (opk != null)
|
||
|
{
|
||
|
return GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, opk);
|
||
|
}
|
||
|
|
||
|
OriginatorID origID = new OriginatorID();
|
||
|
|
||
|
Asn1.Cms.IssuerAndSerialNumber iAndSN = originator.IssuerAndSerialNumber;
|
||
|
if (iAndSN != null)
|
||
|
{
|
||
|
origID.Issuer = iAndSN.Name;
|
||
|
origID.SerialNumber = iAndSN.SerialNumber.Value;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SubjectKeyIdentifier ski = originator.SubjectKeyIdentifier;
|
||
|
|
||
|
origID.SubjectKeyIdentifier = ski.GetKeyIdentifier();
|
||
|
}
|
||
|
|
||
|
return GetPublicKeyFromOriginatorID(origID);
|
||
|
}
|
||
|
|
||
|
private AsymmetricKeyParameter GetPublicKeyFromOriginatorPublicKey(
|
||
|
AsymmetricKeyParameter receiverPrivateKey,
|
||
|
OriginatorPublicKey originatorPublicKey)
|
||
|
{
|
||
|
PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(receiverPrivateKey);
|
||
|
SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
|
||
|
privInfo.PrivateKeyAlgorithm,
|
||
|
originatorPublicKey.PublicKey.GetBytes());
|
||
|
return PublicKeyFactory.CreateKey(pubInfo);
|
||
|
}
|
||
|
|
||
|
private AsymmetricKeyParameter GetPublicKeyFromOriginatorID(
|
||
|
OriginatorID origID)
|
||
|
{
|
||
|
// TODO Support all alternatives for OriginatorIdentifierOrKey
|
||
|
// see RFC 3852 6.2.2
|
||
|
throw new CmsException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
|
||
|
}
|
||
|
|
||
|
private KeyParameter CalculateAgreedWrapKey(
|
||
|
string wrapAlg,
|
||
|
AsymmetricKeyParameter senderPublicKey,
|
||
|
AsymmetricKeyParameter receiverPrivateKey)
|
||
|
{
|
||
|
DerObjectIdentifier agreeAlgID = keyEncAlg.Algorithm;
|
||
|
|
||
|
ICipherParameters senderPublicParams = senderPublicKey;
|
||
|
ICipherParameters receiverPrivateParams = receiverPrivateKey;
|
||
|
|
||
|
if (agreeAlgID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
|
||
|
{
|
||
|
byte[] ukmEncoding = info.UserKeyingMaterial.GetOctets();
|
||
|
MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.GetInstance(
|
||
|
Asn1Object.FromByteArray(ukmEncoding));
|
||
|
|
||
|
AsymmetricKeyParameter ephemeralKey = GetPublicKeyFromOriginatorPublicKey(
|
||
|
receiverPrivateKey, ukm.EphemeralPublicKey);
|
||
|
|
||
|
senderPublicParams = new MqvPublicParameters(
|
||
|
(ECPublicKeyParameters)senderPublicParams,
|
||
|
(ECPublicKeyParameters)ephemeralKey);
|
||
|
receiverPrivateParams = new MqvPrivateParameters(
|
||
|
(ECPrivateKeyParameters)receiverPrivateParams,
|
||
|
(ECPrivateKeyParameters)receiverPrivateParams);
|
||
|
}
|
||
|
|
||
|
IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf(
|
||
|
agreeAlgID, wrapAlg);
|
||
|
agreement.Init(receiverPrivateParams);
|
||
|
BigInteger agreedValue = agreement.CalculateAgreement(senderPublicParams);
|
||
|
|
||
|
int wrapKeySize = GeneratorUtilities.GetDefaultKeySize(wrapAlg) / 8;
|
||
|
byte[] wrapKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, wrapKeySize);
|
||
|
return ParameterUtilities.CreateKeyParameter(wrapAlg, wrapKeyBytes);
|
||
|
}
|
||
|
|
||
|
private KeyParameter UnwrapSessionKey(
|
||
|
string wrapAlg,
|
||
|
KeyParameter agreedKey)
|
||
|
{
|
||
|
byte[] encKeyOctets = encryptedKey.GetOctets();
|
||
|
|
||
|
IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg);
|
||
|
keyCipher.Init(false, agreedKey);
|
||
|
byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
|
||
|
return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), sKeyBytes);
|
||
|
}
|
||
|
|
||
|
internal KeyParameter GetSessionKey(
|
||
|
AsymmetricKeyParameter receiverPrivateKey)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
string wrapAlg = DerObjectIdentifier.GetInstance(
|
||
|
Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id;
|
||
|
|
||
|
AsymmetricKeyParameter senderPublicKey = GetSenderPublicKey(
|
||
|
receiverPrivateKey, info.Originator);
|
||
|
|
||
|
KeyParameter agreedWrapKey = CalculateAgreedWrapKey(wrapAlg,
|
||
|
senderPublicKey, receiverPrivateKey);
|
||
|
|
||
|
return UnwrapSessionKey(wrapAlg, agreedWrapKey);
|
||
|
}
|
||
|
catch (SecurityUtilityException e)
|
||
|
{
|
||
|
throw new CmsException("couldn't create cipher.", e);
|
||
|
}
|
||
|
catch (InvalidKeyException e)
|
||
|
{
|
||
|
throw new CmsException("key invalid in message.", e);
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
throw new CmsException("originator key invalid.", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* decrypt the content and return an input stream.
|
||
|
*/
|
||
|
public override CmsTypedStream GetContentStream(
|
||
|
ICipherParameters key)
|
||
|
{
|
||
|
if (!(key is AsymmetricKeyParameter))
|
||
|
throw new ArgumentException("KeyAgreement requires asymmetric key", "key");
|
||
|
|
||
|
AsymmetricKeyParameter receiverPrivateKey = (AsymmetricKeyParameter) key;
|
||
|
|
||
|
if (!receiverPrivateKey.IsPrivate)
|
||
|
throw new ArgumentException("Expected private key", "key");
|
||
|
|
||
|
KeyParameter sKey = GetSessionKey(receiverPrivateKey);
|
||
|
|
||
|
return GetContentFromSessionKey(sKey);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#pragma warning restore
|
||
|
#endif
|