202 lines
7.7 KiB
C#
202 lines
7.7 KiB
C#
using GostCryptography.Asn1.Gost.Gost_R3410;
|
||
using GostCryptography.Properties;
|
||
using System;
|
||
using System.Security;
|
||
using System.Text;
|
||
|
||
namespace GostCryptography.Gost_R3410
|
||
{
|
||
/// <summary>
|
||
/// Базовый класс XML-сериализатора параметров ключа цифровой подписи ГОСТ Р 34.10
|
||
/// </summary>
|
||
/// <typeparam name="TKeyParams">Параметры ключа цифровой подписи ГОСТ Р 34.10</typeparam>
|
||
public abstract class Gost_R3410_KeyExchangeXmlSerializer<TKeyParams> where TKeyParams : Gost_R3410_KeyExchangeParams
|
||
{
|
||
private const string OidPrefix = "urn:oid:";
|
||
private const string PublicKeyParametersTag = "PublicKeyParameters";
|
||
private const string PublicKeyParamSetTag = "publicKeyParamSet";
|
||
private const string DigestParamSetTag = "digestParamSet";
|
||
private const string EncryptionParamSetTag = "encryptionParamSet";
|
||
private const string PublicKeyTag = "PublicKey";
|
||
private const string PrivateKeyTag = "PrivateKey";
|
||
|
||
private readonly string _keyValueTag;
|
||
|
||
/// <summary>
|
||
/// Создает новый экземпляр данного класса
|
||
/// </summary>
|
||
/// <param name="keyValueTag">Имя тега с информацией о параметрах ключа</param>
|
||
protected Gost_R3410_KeyExchangeXmlSerializer(string keyValueTag)
|
||
{
|
||
_keyValueTag = keyValueTag;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Возвращает XML с параметрами ключа
|
||
/// </summary>
|
||
public string Serialize(TKeyParams parameters)
|
||
{
|
||
var builder = new StringBuilder().AppendFormat("<{0}>", _keyValueTag);
|
||
|
||
if ((parameters.DigestParamSet != null) || (parameters.EncryptionParamSet != null) || (parameters.PublicKeyParamSet != null))
|
||
{
|
||
builder.AppendFormat("<{0}>", PublicKeyParametersTag);
|
||
builder.AppendFormat("<{0}>{1}{2}</{0}>", PublicKeyParamSetTag, OidPrefix, parameters.PublicKeyParamSet);
|
||
builder.AppendFormat("<{0}>{1}{2}</{0}>", DigestParamSetTag, OidPrefix, parameters.DigestParamSet);
|
||
|
||
if (parameters.EncryptionParamSet != null)
|
||
{
|
||
builder.AppendFormat("<{0}>{1}{2}</{0}>", EncryptionParamSetTag, OidPrefix, parameters.EncryptionParamSet);
|
||
}
|
||
|
||
builder.AppendFormat("</{0}>", PublicKeyParametersTag);
|
||
}
|
||
|
||
builder.AppendFormat("<{0}>{1}</{0}>", PublicKeyTag, Convert.ToBase64String(parameters.PublicKey));
|
||
|
||
if (parameters.PrivateKey != null)
|
||
{
|
||
builder.AppendFormat("<{0}>{1}</{0}>", PrivateKeyTag, Convert.ToBase64String(parameters.PublicKey));
|
||
}
|
||
|
||
builder.AppendFormat("</{0}>", _keyValueTag);
|
||
|
||
return builder.ToString();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Возвращает параметры ключа на основе XML
|
||
/// </summary>
|
||
public TKeyParams Deserialize(string keyParametersXml, TKeyParams parameters)
|
||
{
|
||
if (string.IsNullOrEmpty(keyParametersXml))
|
||
{
|
||
throw ExceptionUtility.ArgumentNull(nameof(keyParametersXml));
|
||
}
|
||
|
||
var keyValue = SecurityElement.FromString(keyParametersXml);
|
||
|
||
if (keyValue == null)
|
||
{
|
||
throw ExceptionUtility.CryptographicException(Resources.InvalidFromXmlString, _keyValueTag);
|
||
}
|
||
|
||
keyValue = SelectChildElement(keyValue, _keyValueTag) ?? keyValue;
|
||
|
||
var publicKeyParameters = SelectChildElement(keyValue, PublicKeyParametersTag);
|
||
|
||
if (publicKeyParameters != null)
|
||
{
|
||
var publicKeyParamSet = RemoveWhiteSpaces(SelectChildElementText(publicKeyParameters, PublicKeyParamSetTag, false));
|
||
|
||
if (!publicKeyParamSet.StartsWith(OidPrefix, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
throw ExceptionUtility.CryptographicException(Resources.InvalidFromXmlString, PublicKeyParamSetTag);
|
||
}
|
||
|
||
parameters.PublicKeyParamSet = publicKeyParamSet.Substring(OidPrefix.Length);
|
||
|
||
var digestParamSet = RemoveWhiteSpaces(SelectChildElementText(publicKeyParameters, DigestParamSetTag, false));
|
||
|
||
if (!digestParamSet.StartsWith(OidPrefix, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
throw ExceptionUtility.CryptographicException(Resources.InvalidFromXmlString, DigestParamSetTag);
|
||
}
|
||
|
||
parameters.DigestParamSet = digestParamSet.Substring(OidPrefix.Length);
|
||
|
||
var encryptionParamSet = SelectChildElementText(publicKeyParameters, EncryptionParamSetTag, true);
|
||
|
||
if (!string.IsNullOrEmpty(encryptionParamSet))
|
||
{
|
||
encryptionParamSet = RemoveWhiteSpaces(encryptionParamSet);
|
||
|
||
if (!encryptionParamSet.StartsWith(OidPrefix, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
throw ExceptionUtility.CryptographicException(Resources.InvalidFromXmlString, EncryptionParamSetTag);
|
||
}
|
||
|
||
parameters.EncryptionParamSet = encryptionParamSet.Substring(OidPrefix.Length);
|
||
}
|
||
}
|
||
|
||
var publicKey = SelectChildElementText(keyValue, PublicKeyTag, false);
|
||
parameters.PublicKey = Convert.FromBase64String(RemoveWhiteSpaces(publicKey));
|
||
|
||
var privateKey = SelectChildElementText(keyValue, PrivateKeyTag, true);
|
||
|
||
if (privateKey != null)
|
||
{
|
||
parameters.PrivateKey = Convert.FromBase64String(RemoveWhiteSpaces(privateKey));
|
||
}
|
||
|
||
return parameters;
|
||
}
|
||
|
||
private static string SelectChildElementText(SecurityElement element, string childName, bool canNull)
|
||
{
|
||
string text = null;
|
||
|
||
var child = SelectChildElement(element, childName);
|
||
|
||
if (child != null && (child.Children == null || child.Children.Count == 0))
|
||
{
|
||
text = child.Text;
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(text) && !canNull)
|
||
{
|
||
throw ExceptionUtility.CryptographicException(Resources.InvalidFromXmlString, childName);
|
||
}
|
||
|
||
return text;
|
||
}
|
||
|
||
private static SecurityElement SelectChildElement(SecurityElement element, string childName)
|
||
{
|
||
var children = element.Children;
|
||
|
||
if (children != null)
|
||
{
|
||
foreach (SecurityElement child in children)
|
||
{
|
||
if (string.Equals(child.Tag, childName, StringComparison.OrdinalIgnoreCase)
|
||
|| child.Tag.EndsWith(":" + childName, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return child;
|
||
}
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
private static string RemoveWhiteSpaces(string value)
|
||
{
|
||
var length = value.Length;
|
||
|
||
var countWhiteSpace = 0;
|
||
|
||
for (var i = 0; i < length; ++i)
|
||
{
|
||
if (char.IsWhiteSpace(value[i]))
|
||
{
|
||
++countWhiteSpace;
|
||
}
|
||
}
|
||
|
||
var valueWithoutWhiteSpace = new char[length - countWhiteSpace];
|
||
|
||
for (int i = 0, j = 0; i < length; ++i)
|
||
{
|
||
if (!char.IsWhiteSpace(value[i]))
|
||
{
|
||
valueWithoutWhiteSpace[j++] = value[i];
|
||
}
|
||
}
|
||
|
||
return new string(valueWithoutWhiteSpace);
|
||
}
|
||
}
|
||
}
|