Add migrated to .NET 8.0 variant of Hcs.Client

This commit is contained in:
2025-09-26 19:48:32 +09:00
parent da127df8f6
commit 6cd2fb82e9
503 changed files with 223796 additions and 0 deletions

View File

@ -0,0 +1,281 @@
using GostCryptography.Base;
using GostCryptography.Native;
using GostCryptography.Properties;
using System;
using System.Collections.Generic;
using System.Security;
using System.Security.Cryptography;
namespace GostCryptography.Gost_28147_89
{
/// <summary>
/// Реализует криптографическое преобразование с использованием алгоритма симметричного шифрования ГОСТ 28147-89
/// </summary>
sealed class Gost_28147_89_CryptoTransform : ICryptoTransform
{
[SecurityCritical]
public Gost_28147_89_CryptoTransform(
ProviderType providerType,
SafeKeyHandleImpl keyHandle,
Dictionary<int, object> keyParameters,
PaddingMode paddingValue,
CipherMode modeValue,
int blockSizeValue,
Gost_28147_89_CryptoTransformMode transformMode)
{
_providerType = providerType;
_keyHandle = keyHandle;
_paddingValue = paddingValue;
_isStreamModeValue = (modeValue == CipherMode.OFB) || (modeValue == CipherMode.CFB);
_blockSizeValue = blockSizeValue;
_transformMode = transformMode;
// Установка параметров ключа
foreach (var keyParameter in keyParameters)
{
var keyParameterId = keyParameter.Key;
var keyParameterValue = keyParameter.Value;
// Копирование значения параметра
if (keyParameterValue is byte[])
{
var keyParamValueBytes = (byte[])keyParameterValue;
var copyKeyParamValueBytes = new byte[keyParamValueBytes.Length];
Array.Copy(keyParamValueBytes, copyKeyParamValueBytes, keyParamValueBytes.Length);
keyParameterValue = copyKeyParamValueBytes;
}
else if (keyParameterValue is int)
{
keyParameterValue = (int)keyParameterValue;
}
else if (keyParameterValue is CipherMode)
{
keyParameterValue = Convert.ToInt32(keyParameterValue);
}
else if (keyParameterValue is PaddingMode)
{
keyParameterValue = Convert.ToInt32(keyParameterValue);
}
// Установка значения параметра
switch (keyParameterId)
{
case Constants.KP_IV:
{
_ivValue = (byte[])keyParameterValue;
var iv = _ivValue;
CryptoApiHelper.SetKeyParameter(_keyHandle, keyParameterId, iv);
}
break;
case Constants.KP_MODE:
{
CryptoApiHelper.SetKeyParameterInt32(_keyHandle, keyParameterId, (int)keyParameterValue);
}
break;
case Constants.KP_PADDING:
{
if (!providerType.IsVipNet())
{
CryptoApiHelper.SetKeyParameterInt32(_keyHandle, keyParameterId, (int)keyParameterValue);
}
}
break;
}
}
}
private readonly ProviderType _providerType;
[SecurityCritical]
private readonly SafeKeyHandleImpl _keyHandle;
private readonly PaddingMode _paddingValue;
private readonly bool _isStreamModeValue;
private readonly int _blockSizeValue;
private readonly Gost_28147_89_CryptoTransformMode _transformMode;
private byte[] _dataBuffer;
private byte[] _ivValue;
public bool CanReuseTransform => true;
public bool CanTransformMultipleBlocks => true;
public int InputBlockSize => (_blockSizeValue / 8);
public int OutputBlockSize => (_blockSizeValue / 8);
[SecuritySafeCritical]
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer == null)
{
throw ExceptionUtility.ArgumentNull(nameof(inputBuffer));
}
if (outputBuffer == null)
{
throw ExceptionUtility.ArgumentNull(nameof(outputBuffer));
}
if (inputOffset < 0)
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(inputOffset));
}
if ((inputCount <= 0) || ((inputCount % InputBlockSize) != 0) || (inputCount > inputBuffer.Length))
{
throw ExceptionUtility.Argument(nameof(inputOffset), Resources.InvalidDataOffset);
}
if ((inputBuffer.Length - inputCount) < inputOffset)
{
throw ExceptionUtility.Argument(nameof(inputOffset), Resources.InvalidDataOffset);
}
if (_transformMode == Gost_28147_89_CryptoTransformMode.Encrypt)
{
return CryptoApiHelper.EncryptData(_providerType, _keyHandle, inputBuffer, inputOffset, inputCount, ref outputBuffer, outputOffset, _paddingValue, false, _isStreamModeValue);
}
if ((_paddingValue == PaddingMode.Zeros) || (_paddingValue == PaddingMode.None))
{
return CryptoApiHelper.DecryptData(_keyHandle, inputBuffer, inputOffset, inputCount, ref outputBuffer, outputOffset, _paddingValue, false);
}
int dectyptDataLength;
if (_dataBuffer == null)
{
_dataBuffer = new byte[InputBlockSize];
var length = inputCount - InputBlockSize;
Array.Copy(inputBuffer, inputOffset + length, _dataBuffer, 0, InputBlockSize);
dectyptDataLength = CryptoApiHelper.DecryptData(_keyHandle, inputBuffer, inputOffset, length, ref outputBuffer, outputOffset, _paddingValue, false);
}
else
{
CryptoApiHelper.DecryptData(_keyHandle, _dataBuffer, 0, _dataBuffer.Length, ref outputBuffer, outputOffset, _paddingValue, false);
outputOffset += OutputBlockSize;
var length = inputCount - InputBlockSize;
Array.Copy(inputBuffer, inputOffset + length, _dataBuffer, 0, InputBlockSize);
dectyptDataLength = OutputBlockSize + CryptoApiHelper.DecryptData(_keyHandle, inputBuffer, inputOffset, length, ref outputBuffer, outputOffset, _paddingValue, false);
}
return dectyptDataLength;
}
[SecuritySafeCritical]
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputBuffer == null)
{
throw ExceptionUtility.ArgumentNull(nameof(inputBuffer));
}
if (inputOffset < 0)
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(inputOffset));
}
if ((inputCount < 0) || (inputCount > inputBuffer.Length))
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(inputOffset), Resources.InvalidDataOffset);
}
if ((inputBuffer.Length - inputCount) < inputOffset)
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(inputOffset), Resources.InvalidDataOffset);
}
byte[] buffer = null;
if (_transformMode == Gost_28147_89_CryptoTransformMode.Encrypt)
{
CryptoApiHelper.EncryptData(_providerType, _keyHandle, inputBuffer, inputOffset, inputCount, ref buffer, 0, _paddingValue, true, _isStreamModeValue);
Reset();
return buffer;
}
if (_isStreamModeValue)
{
CryptoApiHelper.DecryptData(_keyHandle, inputBuffer, inputOffset, inputCount, ref buffer, 0, _paddingValue, true);
Reset();
return buffer;
}
if ((inputCount % InputBlockSize) != 0)
{
throw ExceptionUtility.CryptographicException(Resources.DecryptInvalidDataSize);
}
if (_dataBuffer == null)
{
CryptoApiHelper.DecryptData(_keyHandle, inputBuffer, inputOffset, inputCount, ref buffer, 0, _paddingValue, true);
Reset();
return buffer;
}
var destinationArray = new byte[_dataBuffer.Length + inputCount];
Array.Copy(_dataBuffer, 0, destinationArray, 0, _dataBuffer.Length);
Array.Copy(inputBuffer, inputOffset, destinationArray, _dataBuffer.Length, inputCount);
CryptoApiHelper.DecryptData(_keyHandle, destinationArray, 0, destinationArray.Length, ref buffer, 0, _paddingValue, true);
Reset();
return buffer;
}
[SecuritySafeCritical]
private void Reset()
{
_dataBuffer = null;
if (_transformMode == Gost_28147_89_CryptoTransformMode.Encrypt)
{
CryptoApiHelper.EndEncrypt(_providerType, _keyHandle);
}
else
{
CryptoApiHelper.EndDecrypt(_providerType, _keyHandle);
}
}
[SecuritySafeCritical]
private void Dispose(bool disposing)
{
if (disposing)
{
if (_ivValue != null)
{
Array.Clear(_ivValue, 0, _ivValue.Length);
_ivValue = null;
}
if (_dataBuffer != null)
{
Array.Clear(_dataBuffer, 0, _dataBuffer.Length);
_dataBuffer = null;
}
}
_keyHandle.TryDispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Gost_28147_89_CryptoTransform()
{
Dispose(false);
}
}
}

View File

@ -0,0 +1,8 @@
namespace GostCryptography.Gost_28147_89
{
enum Gost_28147_89_CryptoTransformMode
{
Encrypt,
Decrypt
}
}

View File

@ -0,0 +1,148 @@
using GostCryptography.Base;
using GostCryptography.Native;
using System;
using System.Security;
namespace GostCryptography.Gost_28147_89
{
/// <summary>
/// Реализация функции вычисления имитовставки по ГОСТ 28147-89
/// </summary>
public sealed class Gost_28147_89_ImitHashAlgorithm : Gost_28147_89_ImitHashAlgorithmBase, ISafeHandleProvider<SafeHashHandleImpl>
{
/// <summary>
/// Размер имитовставки ГОСТ 28147-89
/// </summary>
public const int DefaultHashSize = 32;
/// <summary>
/// Наименование алгоритма вычисления имитовставки ГОСТ 28147-89
/// </summary>
public const string AlgorithmNameValue = "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gost28147imit";
/// <summary>
/// Известные наименования алгоритма вычисления имитовставки ГОСТ 28147-89
/// </summary>
public static readonly string[] KnownAlgorithmNames = { AlgorithmNameValue };
/// <inheritdoc />
[SecuritySafeCritical]
public Gost_28147_89_ImitHashAlgorithm() : base(DefaultHashSize)
{
_keyAlgorithm = new Gost_28147_89_SymmetricAlgorithm(ProviderType);
}
/// <inheritdoc />
[SecuritySafeCritical]
public Gost_28147_89_ImitHashAlgorithm(ProviderType providerType) : base(providerType, DefaultHashSize)
{
_keyAlgorithm = new Gost_28147_89_SymmetricAlgorithm(ProviderType);
}
/// <summary>
/// Конструктор
/// </summary>
/// <param name="key">Ключ симметричного шифрования для подсчета имитовставки</param>
/// <exception cref="ArgumentNullException"></exception>
[SecuritySafeCritical]
public Gost_28147_89_ImitHashAlgorithm(Gost_28147_89_SymmetricAlgorithmBase key) : base(key.ProviderType, DefaultHashSize)
{
if (key == null)
{
throw ExceptionUtility.ArgumentNull(nameof(key));
}
KeyValue = null;
_keyAlgorithm = Gost_28147_89_SymmetricAlgorithm.CreateFromKey(key);
}
[SecurityCritical]
private Gost_28147_89_SymmetricAlgorithm _keyAlgorithm;
[SecurityCritical]
private SafeHashHandleImpl _hashHandle;
/// <inheritdoc />
public override string AlgorithmName => AlgorithmNameValue;
/// <inheritdoc />
SafeHashHandleImpl ISafeHandleProvider<SafeHashHandleImpl>.SafeHandle
{
[SecurityCritical]
get { return _hashHandle; }
}
/// <inheritdoc />
public override byte[] Key
{
[SecuritySafeCritical]
get => _keyAlgorithm.Key;
[SecuritySafeCritical]
set => _keyAlgorithm.Key = value;
}
/// <inheritdoc />
public override Gost_28147_89_SymmetricAlgorithmBase KeyAlgorithm
{
[SecuritySafeCritical]
get => Gost_28147_89_SymmetricAlgorithm.CreateFromKey(_keyAlgorithm);
[SecuritySafeCritical]
set => _keyAlgorithm = Gost_28147_89_SymmetricAlgorithm.CreateFromKey(value);
}
/// <inheritdoc />
[SecuritySafeCritical]
protected override void HashCore(byte[] data, int dataOffset, int dataLength)
{
if (_hashHandle == null)
{
InitHash();
}
CryptoApiHelper.HashData(_hashHandle, data, dataOffset, dataLength);
}
/// <inheritdoc />
[SecuritySafeCritical]
protected override byte[] HashFinal()
{
if (_hashHandle == null)
{
InitHash();
}
return CryptoApiHelper.EndHashData(_hashHandle);
}
[SecurityCritical]
private void InitHash()
{
var providerHandle = CryptoApiHelper.GetProviderHandle(ProviderType);
var hashHandle = CryptoApiHelper.CreateHashImit(providerHandle, _keyAlgorithm.GetSafeHandle());
_hashHandle = hashHandle;
}
/// <inheritdoc />
[SecuritySafeCritical]
public override void Initialize()
{
_hashHandle.TryDispose();
_hashHandle = null;
}
/// <inheritdoc />
[SecuritySafeCritical]
protected override void Dispose(bool disposing)
{
if (disposing)
{
_keyAlgorithm?.Clear();
_hashHandle.TryDispose();
}
base.Dispose(disposing);
}
}
}

View File

@ -0,0 +1,25 @@
using GostCryptography.Base;
namespace GostCryptography.Gost_28147_89
{
/// <summary>
/// Базовый класс для всех реализаций функции вычисления имитовставки по ГОСТ 28147-89
/// </summary>
public abstract class Gost_28147_89_ImitHashAlgorithmBase : GostKeyedHashAlgorithm
{
/// <inheritdoc />
protected Gost_28147_89_ImitHashAlgorithmBase(int hashSize) : base(hashSize)
{
}
/// <inheritdoc />
protected Gost_28147_89_ImitHashAlgorithmBase(ProviderType providerType, int hashSize) : base(providerType, hashSize)
{
}
/// <summary>
/// Алгоритм симметричного шифрования ключа
/// </summary>
public virtual Gost_28147_89_SymmetricAlgorithmBase KeyAlgorithm { get; set; }
}
}

View File

@ -0,0 +1,433 @@
using GostCryptography.Asn1.Gost.Gost_28147_89;
using GostCryptography.Base;
using GostCryptography.Native;
using GostCryptography.Properties;
using System.Collections.Generic;
using System.Security;
using System.Security.Cryptography;
namespace GostCryptography.Gost_28147_89
{
/// <summary>
/// Реализация алгоритма симметричного шифрования по ГОСТ 28147-89
/// </summary>
public sealed class Gost_28147_89_SymmetricAlgorithm : Gost_28147_89_SymmetricAlgorithmBase, ISafeHandleProvider<SafeKeyHandleImpl>
{
/// <summary>
/// Наименование алгоритма шифрования ГОСТ 28147-89
/// </summary>
public const string AlgorithmNameValue = "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gost28147";
/// <summary>
/// Известные наименования алгоритма шифрования ГОСТ 28147-89
/// </summary>
public static readonly string[] KnownAlgorithmNames = { AlgorithmNameValue };
/// <inheritdoc />
[SecuritySafeCritical]
public Gost_28147_89_SymmetricAlgorithm()
{
InitDefaults();
_providerHandle = CryptoApiHelper.GetProviderHandle(ProviderType).DangerousAddRef();
_keyHandle = SafeKeyHandleImpl.InvalidHandle;
}
/// <inheritdoc />
[SecuritySafeCritical]
public Gost_28147_89_SymmetricAlgorithm(ProviderType providerType) : base(providerType)
{
InitDefaults();
_providerHandle = CryptoApiHelper.GetProviderHandle(ProviderType).DangerousAddRef();
_keyHandle = SafeKeyHandleImpl.InvalidHandle;
}
[SecurityCritical]
internal Gost_28147_89_SymmetricAlgorithm(ProviderType providerType, SafeProvHandleImpl providerHandle, SafeKeyHandleImpl keyHandle) : base(providerType)
{
InitDefaults();
_providerHandle = providerHandle.DangerousAddRef();
_keyHandle = CryptoApiHelper.DuplicateKey(keyHandle);
if (CryptoApiHelper.GetKeyParameterInt32(_keyHandle, Constants.KP_ALGID) != Constants.CALG_G28147)
{
throw ExceptionUtility.Argument(nameof(keyHandle), Resources.RequiredGost28147);
}
}
[SecurityCritical]
private void InitDefaults()
{
Mode = CipherMode.CFB;
Padding = PaddingMode.None;
}
/// <inheritdoc />
public override string AlgorithmName => AlgorithmNameValue;
/// <summary>
/// Создает экземпляр <see cref="Gost_28147_89_SymmetricAlgorithm"/> на основе указанного алгоритма шифрования
/// </summary>
/// <param name="keyAlgorithm">Алгоритм симметричного шифрования ключа</param>
[SecurityCritical]
public static Gost_28147_89_SymmetricAlgorithm CreateFromKey(Gost_28147_89_SymmetricAlgorithmBase keyAlgorithm)
{
if (keyAlgorithm == null)
{
throw ExceptionUtility.ArgumentNull(nameof(keyAlgorithm));
}
return (keyAlgorithm is Gost_28147_89_SymmetricAlgorithm sessionKey)
? new Gost_28147_89_SymmetricAlgorithm(keyAlgorithm.ProviderType, sessionKey._providerHandle, sessionKey.GetSafeHandle())
: new Gost_28147_89_SymmetricAlgorithm(keyAlgorithm.ProviderType) { Key = keyAlgorithm.Key };
}
/// <summary>
/// Создает экземпляр <see cref="Gost_28147_89_SymmetricAlgorithm"/> на основе указанного пароля
/// </summary>
[SecuritySafeCritical]
public static Gost_28147_89_SymmetricAlgorithm CreateFromPassword(HashAlgorithm hashAlgorithm, byte[] password)
{
if (hashAlgorithm == null)
{
throw ExceptionUtility.ArgumentNull(nameof(hashAlgorithm));
}
if (!(hashAlgorithm is IGostAlgorithm gostHashAlgorithm))
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(hashAlgorithm));
}
if (!(hashAlgorithm is ISafeHandleProvider<SafeHashHandleImpl> hashHandleProvider))
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(hashAlgorithm));
}
if (password == null)
{
throw ExceptionUtility.ArgumentNull(nameof(password));
}
hashAlgorithm.TransformBlock(password, 0, password.Length, password, 0);
var providerType = gostHashAlgorithm.ProviderType;
var providerHandle = CryptoApiHelper.GetProviderHandle(providerType);
var symKeyHandle = CryptoApiHelper.DeriveSymKey(providerHandle, hashHandleProvider.SafeHandle);
return new Gost_28147_89_SymmetricAlgorithm(providerType, providerHandle, symKeyHandle);
}
/// <summary>
/// Создает экземпляр <see cref="Gost_28147_89_SymmetricAlgorithm"/> на основе сессионного ключа
/// </summary>
[SecuritySafeCritical]
public static Gost_28147_89_SymmetricAlgorithm CreateFromSessionKey(ProviderType providerType, byte[] sessionKey)
{
if (sessionKey == null)
{
throw ExceptionUtility.ArgumentNull(nameof(sessionKey));
}
if (sessionKey.Length != 32)
{
throw ExceptionUtility.Argument(nameof(sessionKey), Resources.InvalidHashSize, 32);
}
var providerHandle = CryptoApiHelper.GetProviderHandle(providerType);
var randomNumberGenerator = CryptoApiHelper.GetRandomNumberGenerator(providerType);
using (var keyHandle = CryptoApiHelper.ImportBulkSessionKey(providerType, providerHandle, sessionKey, randomNumberGenerator))
{
return new Gost_28147_89_SymmetricAlgorithm(providerType, providerHandle, keyHandle);
}
}
[SecurityCritical]
private SafeProvHandleImpl _providerHandle;
[SecurityCritical]
private SafeKeyHandleImpl _keyHandle;
/// <inheritdoc />
SafeKeyHandleImpl ISafeHandleProvider<SafeKeyHandleImpl>.SafeHandle
{
[SecurityCritical]
get
{
if (_keyHandle.IsInvalid)
{
GenerateKey();
}
return _keyHandle;
}
}
/// <inheritdoc />
public override byte[] Key
{
[SecuritySafeCritical]
get { throw ExceptionUtility.NotSupported(Resources.SymmetryExportBulkKeyNotSupported); }
[SecuritySafeCritical]
set { throw ExceptionUtility.NotSupported(Resources.SymmetryImportBulkKeyNotSupported); }
}
/// <inheritdoc />
public override int KeySize
{
[SecuritySafeCritical]
get { return base.KeySize; }
[SecuritySafeCritical]
set
{
base.KeySize = value;
_keyHandle.TryDispose();
_providerHandle.TryDispose();
_keyHandle = SafeKeyHandleImpl.InvalidHandle;
_providerHandle = SafeProvHandleImpl.InvalidHandle;
}
}
/// <summary>
/// Создает симметричный ключ на основе пароля
/// </summary>
[SecuritySafeCritical]
public void DeriveFromPassword(GostHashAlgorithm hashAlgorithm, byte[] password)
{
var provider = CreateFromPassword(hashAlgorithm, password);
_keyHandle.TryDispose();
_providerHandle.TryDispose();
_keyHandle = provider._keyHandle;
_providerHandle = provider._providerHandle;
provider._keyHandle = SafeKeyHandleImpl.InvalidHandle;
provider._providerHandle = SafeProvHandleImpl.InvalidHandle;
}
/// <inheritdoc />
[SecuritySafeCritical]
public override byte[] ComputeHash(HashAlgorithm hash)
{
if (!(hash is ISafeHandleProvider<SafeHashHandleImpl> hashHadnleProvider))
{
throw ExceptionUtility.Argument(nameof(hash), Resources.RequiredGostHash);
}
var hashHandle = hashHadnleProvider.SafeHandle;
CryptoApiHelper.HashKeyExchange(hashHandle, this.GetSafeHandle());
return CryptoApiHelper.EndHashData(hashHandle);
}
/// <inheritdoc />
[SecuritySafeCritical]
public override void GenerateIV()
{
IVValue = new byte[DefaultIvSize];
CryptoApiHelper.GetRandomNumberGenerator(ProviderType).GetBytes(IVValue);
}
/// <inheritdoc />
[SecuritySafeCritical]
public override void GenerateKey()
{
_keyHandle = CryptoApiHelper.GenerateKey(_providerHandle, Constants.CALG_G28147, CspProviderFlags.NoFlags);
KeyValue = null;
KeySizeValue = DefaultKeySize;
}
/// <inheritdoc />
[SecuritySafeCritical]
public override ICryptoTransform CreateEncryptor()
{
var hKey = CryptoApiHelper.DuplicateKey(this.GetSafeHandle());
return CreateCryptoTransform(hKey, IV, Gost_28147_89_CryptoTransformMode.Encrypt);
}
/// <inheritdoc />
[SecuritySafeCritical]
public override ICryptoTransform CreateEncryptor(byte[] key, byte[] iv)
{
throw ExceptionUtility.NotSupported(Resources.Gost28147UnsafeCreateDecryptorNotSupported);
}
/// <inheritdoc />
[SecuritySafeCritical]
public override ICryptoTransform CreateDecryptor()
{
var hKey = CryptoApiHelper.DuplicateKey(this.GetSafeHandle());
return CreateCryptoTransform(hKey, IV, Gost_28147_89_CryptoTransformMode.Decrypt);
}
/// <inheritdoc />
[SecuritySafeCritical]
public override ICryptoTransform CreateDecryptor(byte[] key, byte[] iv)
{
throw ExceptionUtility.NotSupported(Resources.Gost28147UnsafeCreateDecryptorNotSupported);
}
[SecurityCritical]
private ICryptoTransform CreateCryptoTransform(SafeKeyHandleImpl hKey, byte[] iv, Gost_28147_89_CryptoTransformMode transformMode)
{
// TODO: Нужен рефактор! Порядок параметров важен!
if (hKey == null)
{
hKey = CryptoApiHelper.GenerateKey(CryptoApiHelper.GetProviderHandle(ProviderType), Constants.CALG_G28147, CspProviderFlags.NoFlags);
}
var keyParameters = new Dictionary<int, object>();
if (ModeValue == CipherMode.CTS)
{
throw ExceptionUtility.CryptographicException(Resources.CipherTextSteamingNotSupported);
}
if ((Padding != PaddingMode.None) && ((ModeValue == CipherMode.OFB) || (ModeValue == CipherMode.CFB)))
{
throw ExceptionUtility.CryptographicException(Resources.InvalidPaddingMode);
}
// Установка KP_MODE
keyParameters.Add(Constants.KP_MODE, ModeValue);
// Установка KP_PADDING
keyParameters.Add(Constants.KP_PADDING, Constants.ZERO_PADDING);
if ((ModeValue == CipherMode.CFB) && (FeedbackSizeValue != DefaultFeedbackSize))
{
throw ExceptionUtility.CryptographicException(Resources.IncorrectFeedbackSize);
}
// Установка KP_IV
if (ModeValue != CipherMode.ECB)
{
if (iv == null)
{
iv = new byte[DefaultIvSize];
CryptoApiHelper.GetRandomNumberGenerator(ProviderType).GetBytes(iv);
}
if (iv.Length < DefaultIvSize)
{
throw ExceptionUtility.CryptographicException(Resources.InvalidIvSize);
}
keyParameters.Add(Constants.KP_IV, iv);
}
return new Gost_28147_89_CryptoTransform(ProviderType, hKey, keyParameters, PaddingValue, ModeValue, BlockSizeValue, transformMode);
}
/// <inheritdoc />
[SecuritySafeCritical]
public override SymmetricAlgorithm DecodePrivateKey(byte[] encodedKeyExchangeData, GostKeyExchangeExportMethod keyExchangeExportMethod)
{
if (encodedKeyExchangeData == null)
{
throw ExceptionUtility.ArgumentNull(nameof(encodedKeyExchangeData));
}
int keyExchangeExportAlgId;
if (keyExchangeExportMethod == GostKeyExchangeExportMethod.GostKeyExport)
{
keyExchangeExportAlgId = Constants.CALG_SIMPLE_EXPORT;
}
else if (keyExchangeExportMethod == GostKeyExchangeExportMethod.CryptoProKeyExport)
{
keyExchangeExportAlgId = Constants.CALG_PRO_EXPORT;
}
else
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(keyExchangeExportMethod));
}
var providerHandle = CryptoApiHelper.GetProviderHandle(ProviderType);
var keyExchangeInfo = new Gost_28147_89_KeyExchangeInfo();
keyExchangeInfo.Decode(encodedKeyExchangeData);
using (var keyHandle = CryptoApiHelper.DuplicateKey(this.GetSafeHandle()))
{
CryptoApiHelper.SetKeyExchangeExportAlgId(ProviderType, keyHandle, keyExchangeExportAlgId);
var keyExchangeHandle = CryptoApiHelper.ImportKeyExchange(providerHandle, keyExchangeInfo, keyHandle);
return new Gost_28147_89_SymmetricAlgorithm(ProviderType, providerHandle, keyExchangeHandle);
}
}
/// <inheritdoc />
[SecuritySafeCritical]
public override byte[] EncodePrivateKey(Gost_28147_89_SymmetricAlgorithmBase keyExchangeAlgorithm, GostKeyExchangeExportMethod keyExchangeExportMethod)
{
if (keyExchangeAlgorithm == null)
{
throw ExceptionUtility.ArgumentNull(nameof(keyExchangeAlgorithm));
}
int keyExchangeExportAlgId;
if (keyExchangeExportMethod == GostKeyExchangeExportMethod.GostKeyExport)
{
keyExchangeExportAlgId = Constants.CALG_SIMPLE_EXPORT;
}
else if (keyExchangeExportMethod == GostKeyExchangeExportMethod.CryptoProKeyExport)
{
keyExchangeExportAlgId = Constants.CALG_PRO_EXPORT;
}
else
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(keyExchangeExportMethod));
}
var currentSessionKey = keyExchangeAlgorithm as Gost_28147_89_SymmetricAlgorithm;
if (currentSessionKey == null)
{
using (var derivedSessionKey = new Gost_28147_89_SymmetricAlgorithm(ProviderType))
{
derivedSessionKey.Key = keyExchangeAlgorithm.Key;
return EncodePrivateKeyInternal(derivedSessionKey, keyExchangeExportAlgId);
}
}
return EncodePrivateKeyInternal(currentSessionKey, keyExchangeExportAlgId);
}
[SecurityCritical]
private byte[] EncodePrivateKeyInternal(Gost_28147_89_SymmetricAlgorithm sessionKey, int keyExchangeExportAlgId)
{
var hSessionKey = sessionKey.GetSafeHandle();
using (var keyHandle = CryptoApiHelper.DuplicateKey(this.GetSafeHandle()))
{
CryptoApiHelper.SetKeyExchangeExportAlgId(ProviderType, keyHandle, keyExchangeExportAlgId);
CryptoApiHelper.SetKeyParameter(keyHandle, Constants.KP_IV, IV);
var keyExchangeInfo = CryptoApiHelper.ExportKeyExchange(hSessionKey, keyHandle);
return keyExchangeInfo.Encode();
}
}
/// <inheritdoc />
[SecuritySafeCritical]
protected override void Dispose(bool disposing)
{
_keyHandle.TryDispose();
_providerHandle.TryDispose();
base.Dispose(disposing);
}
}
}

View File

@ -0,0 +1,58 @@
using GostCryptography.Base;
using System.Security.Cryptography;
namespace GostCryptography.Gost_28147_89
{
/// <summary>
/// Базовый класс для всех реализаций симметричного шифрования по ГОСТ 28147-89
/// </summary>
public abstract class Gost_28147_89_SymmetricAlgorithmBase : GostSymmetricAlgorithm
{
public const int DefaultIvSize = 8;
public const int DefaultKeySize = 256;
public const int DefaultBlockSize = 64;
public const int DefaultFeedbackSize = 64;
public static readonly KeySizes[] DefaultLegalKeySizes = { new KeySizes(DefaultKeySize, DefaultKeySize, 0) };
public static readonly KeySizes[] DefaultLegalBlockSizes = { new KeySizes(DefaultBlockSize, DefaultBlockSize, 0) };
/// <inheritdoc />
protected Gost_28147_89_SymmetricAlgorithmBase()
{
InitDefaults();
}
/// <inheritdoc />
protected Gost_28147_89_SymmetricAlgorithmBase(ProviderType providerType) : base(providerType)
{
InitDefaults();
}
private void InitDefaults()
{
KeySizeValue = DefaultKeySize;
BlockSizeValue = DefaultBlockSize;
FeedbackSizeValue = DefaultFeedbackSize;
LegalBlockSizesValue = DefaultLegalBlockSizes;
LegalKeySizesValue = DefaultLegalKeySizes;
}
/// <summary>
/// Хэширует секретный ключ
/// </summary>
public abstract byte[] ComputeHash(HashAlgorithm hash);
/// <summary>
/// Экспортирует (шифрует) секретный ключ
/// </summary>
/// <param name="keyExchangeAlgorithm">Общий секретный ключ</param>
/// <param name="keyExchangeExportMethod">Алгоритм экспорта общего секретного ключа</param>
public abstract byte[] EncodePrivateKey(Gost_28147_89_SymmetricAlgorithmBase keyExchangeAlgorithm, GostKeyExchangeExportMethod keyExchangeExportMethod);
/// <summary>
/// Импортирует (дешифрует) секретный ключ
/// </summary>
/// <param name="encodedKeyExchangeData">Зашифрованный общий секретный ключ</param>
/// <param name="keyExchangeExportMethod">Алгоритм экспорта общего секретного ключа</param>
public abstract SymmetricAlgorithm DecodePrivateKey(byte[] encodedKeyExchangeData, GostKeyExchangeExportMethod keyExchangeExportMethod);
}
}