Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
430 lines
16 KiB
C#
430 lines
16 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|