Files
hcs/Hcs.ClientNet/GostCryptography/Gost_R3410/Gost_R3410_KeyExchangeXmlSerializer.cs

202 lines
7.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}