Add project
Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
429
Hcs.Client/GostCryptography/Xml/GostEncryptedXmlImpl.cs
Normal file
429
Hcs.Client/GostCryptography/Xml/GostEncryptedXmlImpl.cs
Normal file
@ -0,0 +1,429 @@
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Config;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Properties;
|
||||
using GostCryptography.Reflection;
|
||||
using System;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Security.Policy;
|
||||
using System.Xml;
|
||||
|
||||
namespace GostCryptography.Xml
|
||||
{
|
||||
sealed class GostEncryptedXmlImpl : EncryptedXml
|
||||
{
|
||||
public GostEncryptedXmlImpl(ProviderType providerType)
|
||||
{
|
||||
ProviderType = providerType;
|
||||
}
|
||||
|
||||
public GostEncryptedXmlImpl(ProviderType providerType, XmlDocument document) : base(document)
|
||||
{
|
||||
ProviderType = providerType;
|
||||
}
|
||||
|
||||
public GostEncryptedXmlImpl(ProviderType providerType, XmlDocument document, Evidence evidence) : base(document, evidence)
|
||||
{
|
||||
ProviderType = providerType;
|
||||
}
|
||||
|
||||
public ProviderType ProviderType { get; }
|
||||
|
||||
public new void AddKeyNameMapping(string keyName, object keyObject)
|
||||
{
|
||||
if (string.IsNullOrEmpty(keyName))
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(keyName));
|
||||
}
|
||||
|
||||
if (keyObject == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(keyObject));
|
||||
}
|
||||
|
||||
if (keyObject is GostAsymmetricAlgorithm)
|
||||
{
|
||||
this.GetKeyNameMapping().Add(keyName, keyObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.AddKeyNameMapping(keyName, keyObject);
|
||||
}
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public new EncryptedData Encrypt(XmlElement element, X509Certificate2 certificate)
|
||||
{
|
||||
if (element == null || certificate == null || !certificate.IsGost())
|
||||
{
|
||||
return base.Encrypt(element, certificate);
|
||||
}
|
||||
|
||||
var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
var encryptionKey = new Gost_28147_89_SymmetricAlgorithm(publicKey.ProviderType);
|
||||
|
||||
var encryptedKey = new EncryptedKey();
|
||||
encryptedKey.KeyInfo.AddClause(new KeyInfoX509Data(certificate));
|
||||
encryptedKey.EncryptionMethod = new EncryptionMethod(publicKey.KeyExchangeAlgorithm);
|
||||
encryptedKey.CipherData.CipherValue = EncryptKey(encryptionKey, publicKey);
|
||||
|
||||
var encryptedData = new EncryptedData
|
||||
{
|
||||
Type = XmlEncElementUrl,
|
||||
EncryptionMethod = new EncryptionMethod(encryptionKey.AlgorithmName)
|
||||
};
|
||||
|
||||
encryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedKey));
|
||||
encryptedData.CipherData.CipherValue = EncryptData(element, encryptionKey, false);
|
||||
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
public static byte[] EncryptKey(Gost_28147_89_SymmetricAlgorithmBase sessionKey, GostAsymmetricAlgorithm publicKey)
|
||||
{
|
||||
if (sessionKey == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(sessionKey));
|
||||
}
|
||||
|
||||
if (publicKey == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(publicKey));
|
||||
}
|
||||
|
||||
var formatter = publicKey.CreateKeyExchangeFormatter();
|
||||
return formatter.CreateKeyExchangeData(sessionKey);
|
||||
}
|
||||
|
||||
public static byte[] EncryptKey(Gost_28147_89_SymmetricAlgorithmBase sessionKey, Gost_28147_89_SymmetricAlgorithmBase sharedKey, GostKeyExchangeExportMethod exportMethod)
|
||||
{
|
||||
if (sessionKey == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(sessionKey));
|
||||
}
|
||||
|
||||
if (sharedKey == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(sharedKey));
|
||||
}
|
||||
|
||||
return sharedKey.EncodePrivateKey(sessionKey, exportMethod);
|
||||
}
|
||||
|
||||
public override byte[] GetDecryptionIV(EncryptedData encryptedData, string symmetricAlgorithmUri)
|
||||
{
|
||||
if (encryptedData == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(encryptedData));
|
||||
}
|
||||
|
||||
if (symmetricAlgorithmUri == null)
|
||||
{
|
||||
if (encryptedData.EncryptionMethod == null)
|
||||
{
|
||||
return base.GetDecryptionIV(encryptedData, null);
|
||||
}
|
||||
|
||||
symmetricAlgorithmUri = encryptedData.EncryptionMethod.KeyAlgorithm;
|
||||
}
|
||||
|
||||
if (Gost_28147_89_SymmetricAlgorithm.AlgorithmNameValue.Equals(symmetricAlgorithmUri, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var iv = new byte[8];
|
||||
Buffer.BlockCopy(this.GetCipherValue(encryptedData.CipherData), 0, iv, 0, iv.Length);
|
||||
|
||||
return iv;
|
||||
}
|
||||
|
||||
return base.GetDecryptionIV(encryptedData, symmetricAlgorithmUri);
|
||||
}
|
||||
|
||||
public override SymmetricAlgorithm GetDecryptionKey(EncryptedData encryptedData, string symmetricAlgorithmUri)
|
||||
{
|
||||
if (encryptedData == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(encryptedData));
|
||||
}
|
||||
|
||||
SymmetricAlgorithm decryptionKey = null;
|
||||
|
||||
if (encryptedData.KeyInfo != null)
|
||||
{
|
||||
EncryptedKey encryptedKey = null;
|
||||
|
||||
foreach (var keyInfo in encryptedData.KeyInfo)
|
||||
{
|
||||
// Извлечение ключа по имени
|
||||
if (keyInfo is KeyInfoName)
|
||||
{
|
||||
var keyName = ((KeyInfoName)keyInfo).Value;
|
||||
var keyAlgorithm = this.GetKeyNameMapping()[keyName];
|
||||
|
||||
if (keyAlgorithm == null)
|
||||
{
|
||||
var nsManager = new XmlNamespaceManager(this.GetDocument().NameTable);
|
||||
nsManager.AddNamespace("enc", XmlEncNamespaceUrl);
|
||||
|
||||
var encryptedKeyNodes = this.GetDocument().SelectNodes("//enc:EncryptedKey", nsManager);
|
||||
|
||||
if (encryptedKeyNodes != null)
|
||||
{
|
||||
foreach (XmlElement encryptedKeyNode in encryptedKeyNodes)
|
||||
{
|
||||
var currentEncryptedKey = new EncryptedKey();
|
||||
currentEncryptedKey.LoadXml(encryptedKeyNode);
|
||||
|
||||
if ((currentEncryptedKey.CarriedKeyName == keyName) && (currentEncryptedKey.Recipient == Recipient))
|
||||
{
|
||||
encryptedKey = currentEncryptedKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
decryptionKey = (SymmetricAlgorithm)keyAlgorithm;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Извлечение ключа по ссылке
|
||||
if (keyInfo is KeyInfoRetrievalMethod)
|
||||
{
|
||||
var idValue = CryptographyXmlUtils.ExtractIdFromLocalUri(((KeyInfoRetrievalMethod)keyInfo).Uri);
|
||||
var idElement = GetIdElement(this.GetDocument(), idValue);
|
||||
|
||||
if (idElement != null)
|
||||
{
|
||||
encryptedKey = new EncryptedKey();
|
||||
encryptedKey.LoadXml(idElement);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Ключ в готовом виде
|
||||
if (keyInfo is KeyInfoEncryptedKey)
|
||||
{
|
||||
encryptedKey = ((KeyInfoEncryptedKey)keyInfo).EncryptedKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (decryptionKey == null && encryptedKey != null)
|
||||
{
|
||||
if (symmetricAlgorithmUri == null)
|
||||
{
|
||||
if (encryptedData.EncryptionMethod == null)
|
||||
{
|
||||
throw ExceptionUtility.CryptographicException(Resources.XmlMissingAlgorithm);
|
||||
}
|
||||
|
||||
symmetricAlgorithmUri = encryptedData.EncryptionMethod.KeyAlgorithm;
|
||||
}
|
||||
|
||||
decryptionKey = DecryptEncryptedKeyClass(encryptedKey, symmetricAlgorithmUri);
|
||||
}
|
||||
}
|
||||
|
||||
return decryptionKey;
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
private SymmetricAlgorithm DecryptEncryptedKeyClass(EncryptedKey encryptedKey, string symmetricAlgorithmUri)
|
||||
{
|
||||
if (encryptedKey == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(encryptedKey));
|
||||
}
|
||||
|
||||
SymmetricAlgorithm decryptionKey = null;
|
||||
|
||||
if (encryptedKey.KeyInfo != null)
|
||||
{
|
||||
foreach (var keyInfo in encryptedKey.KeyInfo)
|
||||
{
|
||||
// Извлечение ключа по имени
|
||||
if (keyInfo is KeyInfoName)
|
||||
{
|
||||
var keyName = ((KeyInfoName)keyInfo).Value;
|
||||
var keyAlgorithm = this.GetKeyNameMapping()[keyName];
|
||||
|
||||
if (keyAlgorithm != null)
|
||||
{
|
||||
if (keyAlgorithm is SymmetricAlgorithm)
|
||||
{
|
||||
decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (SymmetricAlgorithm)keyAlgorithm, symmetricAlgorithmUri, encryptedKey.EncryptionMethod.KeyAlgorithm);
|
||||
}
|
||||
else if (keyAlgorithm is RSA)
|
||||
{
|
||||
var useOaep = (encryptedKey.EncryptionMethod != null) && (encryptedKey.EncryptionMethod.KeyAlgorithm == XmlEncRSAOAEPUrl);
|
||||
decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (RSA)keyAlgorithm, useOaep, symmetricAlgorithmUri);
|
||||
}
|
||||
else if (keyAlgorithm is GostAsymmetricAlgorithm)
|
||||
{
|
||||
decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (GostAsymmetricAlgorithm)keyAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Извлечение ключа из сертификата
|
||||
if (keyInfo is KeyInfoX509Data)
|
||||
{
|
||||
var certificates = CryptographyXmlUtils.BuildBagOfCertsDecryption((KeyInfoX509Data)keyInfo);
|
||||
|
||||
foreach (var certificate in certificates)
|
||||
{
|
||||
var privateKey = certificate.GetPrivateKeyAlgorithm();
|
||||
|
||||
if (privateKey is RSA)
|
||||
{
|
||||
var useOaep = (encryptedKey.EncryptionMethod != null) && (encryptedKey.EncryptionMethod.KeyAlgorithm == XmlEncRSAOAEPUrl);
|
||||
decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (RSA)privateKey, useOaep, symmetricAlgorithmUri);
|
||||
}
|
||||
else if (privateKey is GostAsymmetricAlgorithm)
|
||||
{
|
||||
decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (GostAsymmetricAlgorithm)privateKey);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Извлечение ключа по ссылке
|
||||
if (keyInfo is KeyInfoRetrievalMethod)
|
||||
{
|
||||
var idValue = CryptographyXmlUtils.ExtractIdFromLocalUri(((KeyInfoRetrievalMethod)keyInfo).Uri);
|
||||
var idElement = GetIdElement(this.GetDocument(), idValue);
|
||||
|
||||
if (idElement != null)
|
||||
{
|
||||
var secondEncryptedKey = new EncryptedKey();
|
||||
secondEncryptedKey.LoadXml(idElement);
|
||||
|
||||
decryptionKey = DecryptEncryptedKeyClass(secondEncryptedKey, symmetricAlgorithmUri);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Ключ в готовом виде
|
||||
if (keyInfo is KeyInfoEncryptedKey)
|
||||
{
|
||||
var secondEncryptedKey = ((KeyInfoEncryptedKey)keyInfo).EncryptedKey;
|
||||
var symmetricAlgorithm = DecryptEncryptedKeyClass(secondEncryptedKey, symmetricAlgorithmUri);
|
||||
|
||||
if (symmetricAlgorithm != null)
|
||||
{
|
||||
decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, symmetricAlgorithm, symmetricAlgorithmUri, encryptedKey.EncryptionMethod.KeyAlgorithm);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return decryptionKey;
|
||||
}
|
||||
|
||||
private static SymmetricAlgorithm DecryptKeyClass(byte[] keyData, SymmetricAlgorithm algorithm, string symmetricAlgorithmUri, string encryptionKeyAlgorithm)
|
||||
{
|
||||
if (keyData == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(keyData));
|
||||
}
|
||||
|
||||
if (algorithm == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(algorithm));
|
||||
}
|
||||
|
||||
SymmetricAlgorithm decryptionKey = null;
|
||||
|
||||
if (algorithm is Gost_28147_89_SymmetricAlgorithmBase gost28147)
|
||||
{
|
||||
if (string.Equals(encryptionKeyAlgorithm, GostEncryptedXml.XmlEncGostKeyExportUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
decryptionKey = gost28147.DecodePrivateKey(keyData, GostKeyExchangeExportMethod.GostKeyExport);
|
||||
}
|
||||
|
||||
if (string.Equals(encryptionKeyAlgorithm, GostEncryptedXml.XmlEncGostCryptoProKeyExportUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
decryptionKey = gost28147.DecodePrivateKey(keyData, GostKeyExchangeExportMethod.CryptoProKeyExport);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var decryptionKeyBytes = DecryptKey(keyData, algorithm);
|
||||
|
||||
if (decryptionKeyBytes != null)
|
||||
{
|
||||
decryptionKey = (SymmetricAlgorithm)GostCryptoConfig.CreateFromName(symmetricAlgorithmUri);
|
||||
decryptionKey.Key = decryptionKeyBytes;
|
||||
}
|
||||
}
|
||||
|
||||
if (decryptionKey == null)
|
||||
{
|
||||
throw ExceptionUtility.CryptographicException(Resources.XmlMissingAlgorithm);
|
||||
}
|
||||
|
||||
return decryptionKey;
|
||||
}
|
||||
|
||||
private static SymmetricAlgorithm DecryptKeyClass(byte[] keyData, RSA algorithm, bool useOaep, string symmetricAlgorithmUri)
|
||||
{
|
||||
if (keyData == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(keyData));
|
||||
}
|
||||
|
||||
if (algorithm == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(algorithm));
|
||||
}
|
||||
|
||||
SymmetricAlgorithm decryptionKey = null;
|
||||
|
||||
var decryptionKeyBytes = DecryptKey(keyData, algorithm, useOaep);
|
||||
|
||||
if (decryptionKeyBytes != null)
|
||||
{
|
||||
decryptionKey = (SymmetricAlgorithm)GostCryptoConfig.CreateFromName(symmetricAlgorithmUri);
|
||||
decryptionKey.Key = decryptionKeyBytes;
|
||||
}
|
||||
|
||||
if (decryptionKey == null)
|
||||
{
|
||||
throw ExceptionUtility.CryptographicException(Resources.XmlMissingAlgorithm);
|
||||
}
|
||||
|
||||
return decryptionKey;
|
||||
}
|
||||
|
||||
public static SymmetricAlgorithm DecryptKeyClass(byte[] keyData, GostAsymmetricAlgorithm privateKey)
|
||||
{
|
||||
if (keyData == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(keyData));
|
||||
}
|
||||
|
||||
if (privateKey == null)
|
||||
{
|
||||
throw ExceptionUtility.ArgumentNull(nameof(privateKey));
|
||||
}
|
||||
|
||||
var deformatter = privateKey.CreateKeyExchangeDeformatter();
|
||||
var decryptionKey = deformatter.DecryptKeyExchangeAlgorithm(keyData);
|
||||
|
||||
return decryptionKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user