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.
175 lines
6.0 KiB
175 lines
6.0 KiB
#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
|
|
|