using GostCryptography.Base;
using GostCryptography.Gost_28147_89;
using System;
using System.Security;
namespace GostCryptography.Gost_R3411
{
///
/// Базовый класс для всех реализаций генератора псевдослучайной последовательности (Pseudorandom Function, PRF) на базе алгоритма хэширования ГОСТ Р 34.11
///
/// Тип HMAC
public abstract class Gost_R3411_PRF : GostPRF where THMAC : GostHMAC
{
///
/// Конструктор
///
/// Симметричный ключ ГОСТ 28147 для вычисления HMAC на основе алгоритма ГОСТ Р 34.11
/// Метка для порождения ключей (аргумент label функции PRF)
/// Начальное число для порождения ключей (аргумент seed функции PRF)
///
///
[SecuritySafeCritical]
protected Gost_R3411_PRF(Gost_28147_89_SymmetricAlgorithmBase key, byte[] label, byte[] seed)
: this(key.ProviderType, Gost_28147_89_SymmetricAlgorithm.CreateFromKey(key), label, seed)
{
}
///
/// Конструктор
///
/// Тип криптографического провайдера
/// Симметричный ключ ГОСТ 28147 для вычисления HMAC на основе алгоритма ГОСТ Р 34.11
/// Метка для порождения ключей (аргумент label функции PRF)
/// Начальное число для порождения ключей (аргумент seed функции PRF)
///
///
[SecuritySafeCritical]
protected Gost_R3411_PRF(ProviderType providerType, byte[] key, byte[] label, byte[] seed)
: this(providerType, Gost_28147_89_SymmetricAlgorithm.CreateFromSessionKey(providerType, key), label, seed)
{
}
///
/// Конструктор
///
/// Тип криптографического провайдера
/// Симметричный ключ ГОСТ 28147 для вычисления HMAC на основе алгоритма ГОСТ Р 34.11
/// Метка для порождения ключей (аргумент label функции PRF)
/// Начальное число для порождения ключей (аргумент seed функции PRF)
///
///
[SecuritySafeCritical]
private Gost_R3411_PRF(ProviderType providerType, Gost_28147_89_SymmetricAlgorithm key, byte[] label, byte[] seed) : base(providerType)
{
if (label == null)
{
throw ExceptionUtility.ArgumentNull(nameof(label));
}
if (seed == null)
{
throw ExceptionUtility.ArgumentNull(nameof(seed));
}
_key = key;
_hmac = CreateHMAC(key);
var labelAndSeed = new byte[label.Length + seed.Length];
label.CopyTo(labelAndSeed, 0);
seed.CopyTo(labelAndSeed, label.Length);
_labelAndSeed = labelAndSeed;
_buffer = new byte[labelAndSeed.Length + (_hmac.HashSize / 8)];
_value = labelAndSeed;
_keyIndex = 0;
}
private readonly Gost_28147_89_SymmetricAlgorithm _key;
private readonly GostHMAC _hmac;
private readonly byte[] _labelAndSeed;
private readonly byte[] _buffer;
private byte[] _value;
private int _keyIndex;
///
/// Создает экземпляр на основе заданного ключа
///
[SecuritySafeCritical]
protected abstract THMAC CreateHMAC(Gost_28147_89_SymmetricAlgorithm key);
///
/// Возвращает очередной набор псевдослучайной последовательности
///
///
/// Размер последовательности зависит от алгоритма хэширования
///
[SecurityCritical]
public byte[] DeriveBytes()
{
var randomBuffer = GenerateNextBytes();
return _hmac.ComputeHash(randomBuffer);
}
///
/// Возвращает псевдослучайный симметричный ключ ГОСТ 28147
///
[SecuritySafeCritical]
public Gost_28147_89_SymmetricAlgorithmBase DeriveKey()
{
var randomPassword = GenerateNextBytes();
using (var hmac = CreateHMAC(_key))
{
return Gost_28147_89_SymmetricAlgorithm.CreateFromPassword(hmac, randomPassword);
}
}
///
/// Возвращает псевдослучайный симметричный ключ ГОСТ 28147
///
/// Позиция ключа в псевдослучайной последовательности
/// Если позиция ключа не кратна размеру ключа в байтах или ключ с данной позицией уже был создан
[SecurityCritical]
public Gost_28147_89_SymmetricAlgorithmBase DeriveKey(int position)
{
if ((position % _hmac.HashSize) != 0)
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(position));
}
var keyIndex = position / _hmac.HashSize;
if (keyIndex < _keyIndex)
{
throw ExceptionUtility.ArgumentOutOfRange(nameof(position));
}
while (keyIndex > _keyIndex)
{
DeriveKey().Clear();
}
return DeriveKey();
}
[SecurityCritical]
private byte[] GenerateNextBytes()
{
_value = _hmac.ComputeHash(_value);
_value.CopyTo(_buffer, 0);
_labelAndSeed.CopyTo(_buffer, _value.Length);
_keyIndex++;
return _buffer;
}
///
protected override void Dispose(bool disposing)
{
_key.Clear();
_hmac.Dispose();
}
}
}