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