Add project
Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
namespace GostCryptography.Gost_28147_89
|
||||
{
|
||||
enum Gost_28147_89_CryptoTransformMode
|
||||
{
|
||||
Encrypt,
|
||||
Decrypt
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user