Beispiel #1
0
        private string NextToken(char[] delimiters)
        {
            var str        = "";
            var currentPos = _currentPos;

            while (Array.IndexOf(delimiters, _chars[(int)((IntPtr)_currentPos)], 0, delimiters.Length) != -1)
            {
                if ((_currentPos += 1L) == _chars.Length)
                {
                    _currentPos = currentPos;

                    throw ExceptionUtility.ArgumentOutOfRange("delimiters");
                }
            }

            while (Array.IndexOf(delimiters, _chars[(int)((IntPtr)_currentPos)], 0, delimiters.Length) == -1)
            {
                str = str + _chars[(int)((IntPtr)_currentPos)];

                if ((_currentPos += 1L) == _chars.Length)
                {
                    return(str);
                }
            }

            return(str);
        }
Beispiel #2
0
        private bool VerifyHash(byte[] hash, byte[] signature)
        {
            if (hash == null)
            {
                throw ExceptionUtility.ArgumentNull("hash");
            }

            if (signature == null)
            {
                throw ExceptionUtility.ArgumentNull("signature");
            }

            if (hash.Length != 64)
            {
                throw ExceptionUtility.ArgumentOutOfRange("InvalidHashSize");
            }

            bool res = false;

            UsingKey(h =>
            {
                res = CryptoApiHelper.VerifySign(_providerHandle, h, hash, signature, GostAlgorithmType.Gost2012_512);
            });
            return(res);
        }
Beispiel #3
0
        private byte[] SignHash(byte[] hash)
        {
            if (hash == null)
            {
                throw ExceptionUtility.ArgumentNull("hash");
            }

            if (hash.Length != 32)
            {
                throw ExceptionUtility.ArgumentOutOfRange("hash", Resources.InvalidHashSize);
            }

            if (IsPublicKeyOnly)
            {
                throw ExceptionUtility.CryptographicException(Resources.NoPrivateKey);
            }

            GetKeyPair();

            if (!CspKeyContainerInfo.RandomlyGenerated)
            {
                var keyContainerPermission  = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
                var keyContainerAccessEntry = new KeyContainerPermissionAccessEntry(_providerParameters, KeyContainerPermissionFlags.Sign);
                keyContainerPermission.AccessEntries.Add(keyContainerAccessEntry);
                keyContainerPermission.Demand();
            }

            return(CryptoApiHelper.SignValue(_providerHandle, _providerParameters.KeyNumber, hash));
        }
        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));
        }
Beispiel #5
0
        public static unsafe void HashData(SafeHashHandleImpl hashHandle, byte[] data, int dataOffset, int dataLength)
        {
            if (data == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(data));
            }

            if (dataOffset < 0)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataOffset));
            }

            if (dataLength < 0)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataLength));
            }

            if (data.Length < dataOffset + dataLength)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataLength));
            }

            if (dataLength > 0)
            {
                fixed(byte *dataRef = data)
                {
                    var dataOffsetRef = dataRef + dataOffset;

                    if (!CryptoApi.CryptHashData(hashHandle, dataOffsetRef, (uint)dataLength, 0))
                    {
                        throw CreateWin32Error();
                    }
                }
            }
        }
        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);
        }
Beispiel #7
0
        /// <inheritdoc />
        protected override void ValidateHashParameter(byte[] hash)
        {
            if (hash == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(hash));
            }

            if (hash.Length != Gost_R3411_2012_256_HashAlgorithm.DefaultHashSizeValue / 8)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(hash), Resources.InvalidHashSize, Gost_R3411_2012_256_HashAlgorithm.DefaultHashSizeValue / 8);
            }
        }
Beispiel #8
0
        private byte[] EncodeKeyExchangeInternal(Gost28147SymmetricAlgorithm keyExchangeAlgorithm, GostKeyExchangeExportMethod keyExchangeExportMethod)
        {
            switch (keyExchangeExportMethod)
            {
            case GostKeyExchangeExportMethod.GostKeyExport:
                return(EncodeKeyExchangeInternal(keyExchangeAlgorithm, Constants.CALG_SIMPLE_EXPORT));

            case GostKeyExchangeExportMethod.CryptoProKeyExport:
                return(EncodeKeyExchangeInternal(keyExchangeAlgorithm, Constants.CALG_PRO_EXPORT));
            }

            throw ExceptionUtility.ArgumentOutOfRange("keyExchangeExportMethod");
        }
Beispiel #9
0
        protected static int ParseInt(string str, IntHolder off, int len)
        {
            if ((off.Value + len) > str.Length)
            {
                throw ExceptionUtility.ArgumentOutOfRange("off");
            }

            var mValue = off.Value;

            off.Value += len;

            return(int.Parse(str.Substring(mValue, len)));
        }
        public override SymmetricAlgorithm DecodeKeyExchange(byte[] encodedKeyExchangeData, GostKeyExchangeExportMethod keyExchangeExportMethod)
        {
            switch (keyExchangeExportMethod)
            {
            case GostKeyExchangeExportMethod.GostKeyExport:
                return(DecodeKeyExchangeInternal(encodedKeyExchangeData, Constants.CALG_SIMPLE_EXPORT));

            case GostKeyExchangeExportMethod.CryptoProKeyExport:
                return(DecodeKeyExchangeInternal(encodedKeyExchangeData, Constants.CALG_PRO_EXPORT));
            }

            throw ExceptionUtility.ArgumentOutOfRange(nameof(keyExchangeExportMethod));
        }
        /// <inheritdoc />
        public override void SetKey(AsymmetricAlgorithm privateKey)
        {
            if (privateKey == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(privateKey));
            }

            if (!(privateKey is GostAsymmetricAlgorithm gostPrivateKey))
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(privateKey), Resources.ShouldSupportGost3410);
            }

            _privateKey = gostPrivateKey;
        }
        /// <inheritdoc />
        public override void SetKey(AsymmetricAlgorithm publicKey)
        {
            if (publicKey == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(publicKey));
            }

            if (!(publicKey is Gost_R3410_AsymmetricAlgorithmBase <TKeyParams, TKeyAlgorithm> gostPublicKey))
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(publicKey), Resources.ShouldSupportGost3410);
            }

            _publicKey = gostPublicKey;
        }
Beispiel #13
0
        /// <summary>
        /// Устанавливает открытый ключ для проверки цифрововй подписи.
        /// </summary>
        /// <param name="publicKey">Открытый ключ для проверки цифровой подписи.</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        public override void SetKey(AsymmetricAlgorithm publicKey)
        {
            if (publicKey == null)
            {
                throw ExceptionUtility.ArgumentNull("publicKey");
            }

            if (!(publicKey is Gost3410AsymmetricAlgorithmBase))
            {
                throw ExceptionUtility.ArgumentOutOfRange("publicKey", Resources.ShouldSupportGost3410);
            }

            _publicKey = (Gost3410AsymmetricAlgorithmBase)publicKey;
        }
Beispiel #14
0
        private byte[] SignHash(byte[] hash)
        {
            if (hash == null)
            {
                throw ExceptionUtility.ArgumentNull("hash");
            }

            if (hash.Length != 64)
            {
                throw ExceptionUtility.ArgumentOutOfRange("hash", "InvalidHashSize");
            }

            var res = CryptoApiHelper.SignValue(_providerHandle, _providerParameters.KeyNumber, hash, GostAlgorithmType.Gost2012_512);

            return(res);
        }
Beispiel #15
0
        /// <inheritdoc />
        public override void SetKey(AsymmetricAlgorithm publicKey)
        {
            if (publicKey == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(publicKey));
            }

            if (!(publicKey is GostAsymmetricAlgorithm gostPublicKey))
            {
                if (publicKey.SignatureAlgorithm.IndexOf("gost", StringComparison.OrdinalIgnoreCase) < 0)
                {
                    throw ExceptionUtility.ArgumentOutOfRange(nameof(publicKey), Resources.ShouldSupportGost3410);
                }

                gostPublicKey = new GostExternalAsymmetricAlgorithm(publicKey);
            }

            _publicKey = gostPublicKey;
        }
        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());
        }
Beispiel #17
0
        public Gost28147 DeriveKey(int position)
        {
            if ((position % 256) != 0)
            {
                throw ExceptionUtility.ArgumentOutOfRange("position");
            }

            var keyIndex = position / 256;

            if (keyIndex < _keyIndex)
            {
                throw ExceptionUtility.ArgumentOutOfRange("position");
            }

            while (keyIndex > _keyIndex)
            {
                DeriveKey().Clear();
            }

            return(DeriveKey());
        }
Beispiel #18
0
        public string NextToken(string delimiters)
        {
            _delimiters = delimiters;

            var array = delimiters.ToCharArray();

            if (_currentPos == _chars.Length)
            {
                throw ExceptionUtility.ArgumentOutOfRange("delimiters");
            }

            if ((Array.IndexOf(array, _chars[(int)((IntPtr)_currentPos)], 0, array.Length) != -1) && _includeDelims)
            {
                long num;
                _currentPos = (num = _currentPos) + 1L;

                return("" + _chars[(int)((IntPtr)num)]);
            }

            return(NextToken(delimiters.ToCharArray()));
        }
Beispiel #19
0
        private bool VerifyHash(byte[] hash, byte[] signature)
        {
            if (hash == null)
            {
                throw ExceptionUtility.ArgumentNull("hash");
            }

            if (signature == null)
            {
                throw ExceptionUtility.ArgumentNull("signature");
            }

            if (hash.Length != 32)
            {
                throw ExceptionUtility.ArgumentOutOfRange(Resources.InvalidHashSize);
            }

            GetKeyPair();

            return(CryptoApiHelper.VerifySign(_providerHandle, _keyHandle, hash, signature));
        }
        public override SymmetricAlgorithm DecodePrivateKey(byte[] encodedKeyExchangeData, GostKeyExchangeExportMethod keyExchangeExportMethod)
        {
            if (encodedKeyExchangeData == null)
            {
                throw ExceptionUtility.ArgumentNull("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("keyExchangeExportMethod");
            }

            var providerHandle = CryptoApiHelper.ProviderHandle;

            var keyExchangeInfo = new GostKeyExchangeInfo();

            keyExchangeInfo.Decode(encodedKeyExchangeData);

            using (var keyHandle = CryptoApiHelper.DuplicateKey(InternalKeyHandle))
            {
                CryptoApiHelper.SetKeyParameterInt32(keyHandle, Constants.KP_ALGID, keyExchangeExportAlgId);

                var keyExchangeHandle = CryptoApiHelper.ImportKeyExchange(providerHandle, keyExchangeInfo, keyHandle);

                return(new Gost28147SymmetricAlgorithm(providerHandle, keyExchangeHandle));
            }
        }
        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));
            }
        }
        public override byte[] EncodePrivateKey(Gost28147 keyExchangeAlgorithm, GostKeyExchangeExportMethod keyExchangeExportMethod)
        {
            if (keyExchangeAlgorithm == null)
            {
                throw ExceptionUtility.ArgumentNull("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("keyExchangeExportMethod");
            }

            var currentSessionKey = keyExchangeAlgorithm as Gost28147SymmetricAlgorithm;

            if (currentSessionKey == null)
            {
                using (var derivedSessinKey = new Gost28147SymmetricAlgorithm())
                {
                    derivedSessinKey.Key = keyExchangeAlgorithm.Key;

                    return(EncodePrivateKeyInternal(derivedSessinKey, keyExchangeExportAlgId));
                }
            }

            return(EncodePrivateKeyInternal(currentSessionKey, keyExchangeExportAlgId));
        }
        /// <inheritdoc />
        public override byte[] CreateKeyExchange(byte[] keyExchangeData, Type keyExchangeAlgorithmType)
        {
            if (keyExchangeData == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(keyExchangeData));
            }

            if (keyExchangeAlgorithmType == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(keyExchangeAlgorithmType));
            }

            if (!typeof(GostSymmetricAlgorithm).IsAssignableFrom(keyExchangeAlgorithmType))
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(keyExchangeAlgorithmType));
            }

            GostSymmetricAlgorithm keyExchangeAlgorithm;

            if (_publicKey != null)
            {
                var constructorInfo = keyExchangeAlgorithmType.GetConstructor(new[] { typeof(ProviderType) });
                keyExchangeAlgorithm = (GostSymmetricAlgorithm)constructorInfo.Invoke(new object[] { _publicKey.ProviderType });
            }
            else
            {
                keyExchangeAlgorithm = (GostSymmetricAlgorithm)Activator.CreateInstance(keyExchangeAlgorithmType);
            }

            using (keyExchangeAlgorithm)
            {
                keyExchangeAlgorithm.Key = keyExchangeData;

                return(CreateKeyExchangeData(keyExchangeAlgorithm));
            }
        }
Beispiel #24
0
        public static int EncryptData(ProviderType providerType, SafeKeyHandleImpl symKeyHandle, byte[] data, int dataOffset, int dataLength, ref byte[] encryptedData, int encryptedDataOffset, PaddingMode paddingMode, bool isDone, bool isStream)
        {
            if (dataOffset < 0)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataOffset));
            }

            if (dataLength < 0)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataLength));
            }

            if (dataOffset > data.Length)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataOffset), Resources.InvalidDataOffset);
            }

            var length = dataLength;

            if (isDone)
            {
                length += 8;
            }

            // Выровненные данные
            var dataAlignLength = (uint)dataLength;
            var dataAlignArray  = new byte[length];

            Array.Clear(dataAlignArray, 0, length);
            Array.Copy(data, dataOffset, dataAlignArray, 0, dataLength);

            if (isDone)
            {
                var dataPadding     = dataLength & 7;
                var dataPaddingSize = (byte)(8 - dataPadding);

                // Добпаление дополнения данных в зависимости от настроек
                switch (paddingMode)
                {
                case PaddingMode.None:
                    if ((dataPadding != 0) && !isStream)
                    {
                        throw ExceptionUtility.CryptographicException(Resources.EncryptInvalidDataSize);
                    }

                    break;

                case PaddingMode.Zeros:
                    if (dataPadding != 0)
                    {
                        dataAlignLength += dataPaddingSize;

                        // Дополнение заполняется нулевыми байтами
                    }

                    break;

                case PaddingMode.PKCS7:
                {
                    dataAlignLength += dataPaddingSize;

                    var paddingIndex = dataLength;

                    // Дополнение заполняется байтами, в каждый из которых записывается размер дополнения
                    while (paddingIndex < dataAlignLength)
                    {
                        dataAlignArray[paddingIndex++] = dataPaddingSize;
                    }
                }
                break;

                case PaddingMode.ANSIX923:
                {
                    dataAlignLength += dataPaddingSize;

                    // Дополнение заполняется нулевыми, кроме последнего - в него записывается размер дополнения
                    dataAlignArray[(int)((IntPtr)(dataAlignLength - 1))] = dataPaddingSize;
                }
                break;

                case PaddingMode.ISO10126:
                {
                    dataAlignLength += dataPaddingSize;

                    // Дополнение заполняется случайными байтами, кроме последнего - в него записывается размер дополнения
                    var randomPadding = new byte[dataPaddingSize - 1];
                    GetRandomNumberGenerator(providerType).GetBytes(randomPadding);
                    randomPadding.CopyTo(dataAlignArray, dataLength);
                    dataAlignArray[(int)((IntPtr)(dataAlignLength - 1))] = dataPaddingSize;
                }
                break;

                default:
                    throw ExceptionUtility.Argument(nameof(paddingMode), Resources.InvalidPaddingMode);
                }
            }

            // Шифрование данных
            if (!CryptoApi.CryptEncrypt(symKeyHandle, SafeHashHandleImpl.InvalidHandle, false, 0, dataAlignArray, ref dataAlignLength, (uint)length))
            {
                throw CreateWin32Error();
            }

            // Копирование результата шифрования данных

            if (encryptedData == null)
            {
                encryptedData = new byte[dataAlignLength];

                Array.Copy(dataAlignArray, 0L, encryptedData, 0L, dataAlignLength);
            }
            else
            {
                if (encryptedDataOffset < 0)
                {
                    throw ExceptionUtility.ArgumentOutOfRange(nameof(encryptedDataOffset));
                }

                if ((encryptedData.Length < dataAlignLength) || ((encryptedData.Length - dataAlignLength) < encryptedDataOffset))
                {
                    throw ExceptionUtility.ArgumentOutOfRange(nameof(encryptedDataOffset), Resources.InvalidDataOffset);
                }

                Array.Copy(dataAlignArray, 0L, encryptedData, encryptedDataOffset, dataAlignLength);
            }

            return((int)dataAlignLength);
        }
Beispiel #25
0
        public static int DecryptData(SafeKeyHandleImpl symKeyHandle, byte[] data, int dataOffset, int dataLength, ref byte[] decryptedData, int decryptedDataOffset, PaddingMode paddingMode, bool isDone)
        {
            if (dataOffset < 0)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataOffset));
            }

            if (dataLength < 0)
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataLength));
            }

            if ((dataOffset > data.Length) || ((dataOffset + dataLength) > data.Length))
            {
                throw ExceptionUtility.ArgumentOutOfRange(nameof(dataOffset), Resources.InvalidDataOffset);
            }

            // Выровненные данные
            var dataAlignLength = (uint)dataLength;
            var dataAlign       = new byte[dataAlignLength];

            Array.Copy(data, dataOffset, dataAlign, 0L, dataAlignLength);

            // Расшифровка данных
            if (!CryptoApi.CryptDecrypt(symKeyHandle, SafeHashHandleImpl.InvalidHandle, false, 0, dataAlign, ref dataAlignLength))
            {
                throw CreateWin32Error();
            }

            var length = (int)dataAlignLength;

            if (isDone)
            {
                byte dataPaddingSize = 0;

                // Удаление дополнения данных в зависимости от настроек
                if (((paddingMode == PaddingMode.PKCS7) || (paddingMode == PaddingMode.ANSIX923)) || (paddingMode == PaddingMode.ISO10126))
                {
                    if (dataAlignLength < 8)
                    {
                        throw ExceptionUtility.CryptographicException(Constants.NTE_BAD_DATA);
                    }

                    // Размер дополнения находится в последнем байте
                    dataPaddingSize = dataAlign[(int)((IntPtr)(dataAlignLength - 1))];

                    if (dataPaddingSize > 8)
                    {
                        throw ExceptionUtility.CryptographicException(Constants.NTE_BAD_DATA);
                    }

                    // Проверка корректности дополнения данных
                    if (paddingMode == PaddingMode.PKCS7)
                    {
                        for (var paddingIndex = dataAlignLength - dataPaddingSize; paddingIndex < (dataAlignLength - 1); paddingIndex++)
                        {
                            if (dataAlign[paddingIndex] != dataPaddingSize)
                            {
                                throw ExceptionUtility.CryptographicException(Constants.NTE_BAD_DATA);
                            }
                        }
                    }
                    else if (paddingMode == PaddingMode.ANSIX923)
                    {
                        for (var paddingIndex = dataAlignLength - dataPaddingSize; paddingIndex < (dataAlignLength - 1); paddingIndex++)
                        {
                            if (dataAlign[paddingIndex] != 0)
                            {
                                throw ExceptionUtility.CryptographicException(Constants.NTE_BAD_DATA);
                            }
                        }
                    }
                }
                else if ((paddingMode != PaddingMode.None) && (paddingMode != PaddingMode.Zeros))
                {
                    throw ExceptionUtility.Argument(nameof(paddingMode), Resources.InvalidPaddingMode);
                }

                length -= dataPaddingSize;
            }

            if (decryptedData == null)
            {
                decryptedData = new byte[length];

                Array.Copy(dataAlign, 0, decryptedData, 0, length);
            }
            else
            {
                if (decryptedDataOffset < 0)
                {
                    throw ExceptionUtility.ArgumentOutOfRange(nameof(decryptedDataOffset));
                }

                if ((decryptedData.Length < length) || ((decryptedData.Length - length) < decryptedDataOffset))
                {
                    throw ExceptionUtility.ArgumentOutOfRange(nameof(decryptedData), Resources.InvalidDataOffset);
                }

                Array.Copy(dataAlign, 0, decryptedData, decryptedDataOffset, length);
            }

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