163 lines
6.5 KiB
C#
163 lines
6.5 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using Org.BouncyCastle.Asn1;
|
|
using Org.BouncyCastle.Asn1.Cms;
|
|
using Org.BouncyCastle.Asn1.Cms.Ecc;
|
|
using Org.BouncyCastle.Asn1.Pkcs;
|
|
using Org.BouncyCastle.Asn1.X509;
|
|
using Org.BouncyCastle.Asn1.X9;
|
|
using Org.BouncyCastle.Crypto;
|
|
using Org.BouncyCastle.Crypto.Parameters;
|
|
using Org.BouncyCastle.Math;
|
|
using Org.BouncyCastle.Pkcs;
|
|
using Org.BouncyCastle.Security;
|
|
|
|
namespace Org.BouncyCastle.Cms;
|
|
|
|
public class KeyAgreeRecipientInformation : RecipientInformation
|
|
{
|
|
private KeyAgreeRecipientInfo info;
|
|
|
|
private Asn1OctetString encryptedKey;
|
|
|
|
internal static void ReadRecipientInfo(IList infos, KeyAgreeRecipientInfo info, CmsSecureReadable secureReadable)
|
|
{
|
|
try
|
|
{
|
|
foreach (Asn1Encodable recipientEncryptedKey in info.RecipientEncryptedKeys)
|
|
{
|
|
RecipientEncryptedKey instance = RecipientEncryptedKey.GetInstance(recipientEncryptedKey.ToAsn1Object());
|
|
RecipientID recipientID = new RecipientID();
|
|
KeyAgreeRecipientIdentifier identifier = instance.Identifier;
|
|
Org.BouncyCastle.Asn1.Cms.IssuerAndSerialNumber issuerAndSerialNumber = identifier.IssuerAndSerialNumber;
|
|
if (issuerAndSerialNumber != null)
|
|
{
|
|
recipientID.Issuer = issuerAndSerialNumber.Name;
|
|
recipientID.SerialNumber = issuerAndSerialNumber.SerialNumber.Value;
|
|
}
|
|
else
|
|
{
|
|
RecipientKeyIdentifier rKeyID = identifier.RKeyID;
|
|
recipientID.SubjectKeyIdentifier = rKeyID.SubjectKeyIdentifier.GetOctets();
|
|
}
|
|
infos.Add(new KeyAgreeRecipientInformation(info, recipientID, instance.EncryptedKey, secureReadable));
|
|
}
|
|
}
|
|
catch (IOException innerException)
|
|
{
|
|
throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", innerException);
|
|
}
|
|
}
|
|
|
|
internal KeyAgreeRecipientInformation(KeyAgreeRecipientInfo info, RecipientID rid, Asn1OctetString encryptedKey, CmsSecureReadable secureReadable)
|
|
: base(info.KeyEncryptionAlgorithm, secureReadable)
|
|
{
|
|
this.info = info;
|
|
base.rid = rid;
|
|
this.encryptedKey = encryptedKey;
|
|
}
|
|
|
|
private AsymmetricKeyParameter GetSenderPublicKey(AsymmetricKeyParameter receiverPrivateKey, OriginatorIdentifierOrKey originator)
|
|
{
|
|
OriginatorPublicKey originatorPublicKey = originator.OriginatorPublicKey;
|
|
if (originatorPublicKey != null)
|
|
{
|
|
return GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, originatorPublicKey);
|
|
}
|
|
OriginatorID originatorID = new OriginatorID();
|
|
Org.BouncyCastle.Asn1.Cms.IssuerAndSerialNumber issuerAndSerialNumber = originator.IssuerAndSerialNumber;
|
|
if (issuerAndSerialNumber != null)
|
|
{
|
|
originatorID.Issuer = issuerAndSerialNumber.Name;
|
|
originatorID.SerialNumber = issuerAndSerialNumber.SerialNumber.Value;
|
|
}
|
|
else
|
|
{
|
|
SubjectKeyIdentifier subjectKeyIdentifier = originator.SubjectKeyIdentifier;
|
|
originatorID.SubjectKeyIdentifier = subjectKeyIdentifier.GetKeyIdentifier();
|
|
}
|
|
return GetPublicKeyFromOriginatorID(originatorID);
|
|
}
|
|
|
|
private AsymmetricKeyParameter GetPublicKeyFromOriginatorPublicKey(AsymmetricKeyParameter receiverPrivateKey, OriginatorPublicKey originatorPublicKey)
|
|
{
|
|
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(receiverPrivateKey);
|
|
SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo(privateKeyInfo.PrivateKeyAlgorithm, originatorPublicKey.PublicKey.GetBytes());
|
|
return PublicKeyFactory.CreateKey(keyInfo);
|
|
}
|
|
|
|
private AsymmetricKeyParameter GetPublicKeyFromOriginatorID(OriginatorID origID)
|
|
{
|
|
throw new CmsException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
|
|
}
|
|
|
|
private KeyParameter CalculateAgreedWrapKey(string wrapAlg, AsymmetricKeyParameter senderPublicKey, AsymmetricKeyParameter receiverPrivateKey)
|
|
{
|
|
DerObjectIdentifier algorithm = keyEncAlg.Algorithm;
|
|
ICipherParameters cipherParameters = senderPublicKey;
|
|
ICipherParameters cipherParameters2 = receiverPrivateKey;
|
|
if (algorithm.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
|
|
{
|
|
byte[] octets = info.UserKeyingMaterial.GetOctets();
|
|
MQVuserKeyingMaterial instance = MQVuserKeyingMaterial.GetInstance(Asn1Object.FromByteArray(octets));
|
|
AsymmetricKeyParameter publicKeyFromOriginatorPublicKey = GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, instance.EphemeralPublicKey);
|
|
cipherParameters = new MqvPublicParameters((ECPublicKeyParameters)cipherParameters, (ECPublicKeyParameters)publicKeyFromOriginatorPublicKey);
|
|
cipherParameters2 = new MqvPrivateParameters((ECPrivateKeyParameters)cipherParameters2, (ECPrivateKeyParameters)cipherParameters2);
|
|
}
|
|
IBasicAgreement basicAgreementWithKdf = AgreementUtilities.GetBasicAgreementWithKdf(algorithm, wrapAlg);
|
|
basicAgreementWithKdf.Init(cipherParameters2);
|
|
BigInteger s = basicAgreementWithKdf.CalculateAgreement(cipherParameters);
|
|
int qLength = GeneratorUtilities.GetDefaultKeySize(wrapAlg) / 8;
|
|
byte[] keyBytes = X9IntegerConverter.IntegerToBytes(s, qLength);
|
|
return ParameterUtilities.CreateKeyParameter(wrapAlg, keyBytes);
|
|
}
|
|
|
|
private KeyParameter UnwrapSessionKey(string wrapAlg, KeyParameter agreedKey)
|
|
{
|
|
byte[] octets = encryptedKey.GetOctets();
|
|
IWrapper wrapper = WrapperUtilities.GetWrapper(wrapAlg);
|
|
wrapper.Init(forWrapping: false, agreedKey);
|
|
byte[] keyBytes = wrapper.Unwrap(octets, 0, octets.Length);
|
|
return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), keyBytes);
|
|
}
|
|
|
|
internal KeyParameter GetSessionKey(AsymmetricKeyParameter receiverPrivateKey)
|
|
{
|
|
try
|
|
{
|
|
string id = DerObjectIdentifier.GetInstance(Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id;
|
|
AsymmetricKeyParameter senderPublicKey = GetSenderPublicKey(receiverPrivateKey, info.Originator);
|
|
KeyParameter agreedKey = CalculateAgreedWrapKey(id, senderPublicKey, receiverPrivateKey);
|
|
return UnwrapSessionKey(id, agreedKey);
|
|
}
|
|
catch (SecurityUtilityException e)
|
|
{
|
|
throw new CmsException("couldn't create cipher.", e);
|
|
}
|
|
catch (InvalidKeyException e2)
|
|
{
|
|
throw new CmsException("key invalid in message.", e2);
|
|
}
|
|
catch (Exception e3)
|
|
{
|
|
throw new CmsException("originator key invalid.", e3);
|
|
}
|
|
}
|
|
|
|
public override CmsTypedStream GetContentStream(ICipherParameters key)
|
|
{
|
|
if (!(key is AsymmetricKeyParameter))
|
|
{
|
|
throw new ArgumentException("KeyAgreement requires asymmetric key", "key");
|
|
}
|
|
AsymmetricKeyParameter asymmetricKeyParameter = (AsymmetricKeyParameter)key;
|
|
if (!asymmetricKeyParameter.IsPrivate)
|
|
{
|
|
throw new ArgumentException("Expected private key", "key");
|
|
}
|
|
KeyParameter sessionKey = GetSessionKey(asymmetricKeyParameter);
|
|
return GetContentFromSessionKey(sessionKey);
|
|
}
|
|
}
|