Алгоритм шифрования Blowfish

 

 

Содержание

 

  • 1 Введение
  • 2 Описание алгоритма
    • 2.1 Параметры
    • 2.2 Функция F(x)
    • 2.3 Алгоритм шифрования 64-битного блока с известным массивом P и F(x)
    • 2.4 Алгоритм Blowfish
    • 2.5 Выбор начального значения P-массива и таблицы замен
  • 3 Криптостойкость
  • 4 Пример работы алгоритма
  • 5 Применения
  • 6 Заключение
  • 7 Список литературы
  • 8 Приложение

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ВВЕДЕНИЕ

 

Blowfish (произносится [бло́уфиш]) — криптографический алгоритм, реализующий блочное симметричное шифрование.

Разработан Брюсом Шнайером в 1993 году. Представляет собой сеть Фейстеля. Выполнен на простых и быстрых операциях: XOR, подстановка, сложение. Является не запатентованным и свободно распространяемым.

До появления Blowfish существовавшие алгоритмы были либо запатентованными, либо ненадёжными, а некоторые и  вовсе держались в секрете (например, Skipjack). Алгоритм был разработан в 1993 году Брюсом Шнайером в качестве быстрой и свободной альтернативы устаревшему DES и запатентованному IDEA. По заявлению автора, критерии проектирования Blowfish были:

  • скорость (шифрование на 32-битных процессорах происходит за 26 тактов);
  • простота (за счёт использования простых операций, уменьшающих вероятность ошибки реализации алгоритма);
  • компактность;
  • настраиваемая стойкость.

 


ОПИСАНИЕ АЛГОРИТМА

Параметры

  • секретный ключ K (от 32 до 448 бит)
  • 32-битные ключи шифрования P1-P18
  • 32-битные таблицы замен S1-S4:

S1[0] S1[1] .. S1[255]

S2[0] S2[1] .. S2[255]

S3[0] S3[1] .. S3[255]

S4[0] S4[1] .. S4[255]

 

Функция F(x)

Функция F(x) в Blowfish

  1. 32-битный блок делится на четыре 8-битных блока (X1, X2, X3, X4), каждый из которых является индексом массива таблицы замен S1-S4
  2. значения S1[X1] и S2[X2] складываются по модулю 232, после "XOR"ятся с S3[X3] и, наконец, складываются с S4[X4] по модулю 232.
  3. Результат этих операций — значение F(x).


 

Алгоритм шифрования 64-битного блока с известным  массивом P и F(x)

 

Сеть Фейстеля при зашифровании

  • разделение на 32-битные блоки :
  •  и   «XOR»-ся c ключами  , 
  • вычисления в i-том раунде:

  • после 16 раунда   меняются местами:

 

Алгоритм Blowfish

Разделён на 2 этапа:

  1. Подготовительный — формирование ключей шифрования по секретному ключу.
    • Инициализация массивов P и S при помощи секретного ключа K
      1. Инициализация P1-P18 фиксированной строкой, состоящей из шестнадцатеричных цифр мантиссы числа пи.
      2. Производится операция XOR над P1 с первыми 32 битами ключа K, над P2 со вторыми 32-битами и так далее. 
        Если ключ K короче, то он накладывается циклически.
    • Шифрование ключей и таблиц замен
      1. Алгоритм шифрования 64-битного блока, используя инициализированные ключи P1-P18 и таблицу замен S1-S4, шифрует 64 битную нулевую (0x0000000000000000) строку. Результат записывается в P1, P2.
      2. P1 и P2 шифруются изменёнными значениями ключей и таблиц замен. Результат записывается в P3 и P4.
      3. Шифрование продолжается до изменения всех ключей P1-P18 и таблиц замен S1-S4.
  2. Шифрование текста полученными ключами и F(x), с предварительным разбиением на блоки по 64 бита. Если невозможно разбить начальный текст точно на блоки по 64 бита, используются различные режимы шифрования для построения сообщения, состоящего из целого числа блоков. Cуммарная требуемая память 4168 байт: P1-P18:18 переменных по 32 бита; S1-S4: 4x256 переменных по 32 бита.

Дешифрование происходит аналогично, только P1-P18 применяются  в обратном порядке.

Выбор начального значения P-массива и таблицы замен

Нет ничего особенного в  цифрах числа пи. Данный выбор заключается  в инициализации последовательности, не связанной с алгоритмом, которая  могла бы быть сохранена как часть  алгоритма или получена при необходимости (Пи (число)). В принципе подойдёт любая строка из случайных битов цифр числа e, RAND-таблицы, или случайные сгенерированные цифры.

 

КРИПТОСТОЙКОСТЬ


  • слабый S-box (и порождающий его слабый ключ) означает, что существует такие i, j, N={1,2,3,4} : SN[i]==SN[j]

Криптостойкость главным  образом зависит от F(x). На это  указал Serge Vaudenay, говоря о наличии  небольшого класса слабых ключей (генерирующих слабые S-box): вероятность появления  слабого S-box равна 2 − 15. Он также рассмотрел упрощенный вариант Blowfish, с известной функцией F(x) и слабым ключом. Для этого варианта требуется   выбранных открытых текстов (t — число раундов, а символы [] означают операцию получения целой части числа). Эта атака может быть использована только для алгоритма с  . Для t = 7 требуется 224 открытых текстов, причём для варианта с известным F(x) и случайным ключом требуется 248 открытых текстов. Но данная атака не эффективна для Blowfish с 16 раундами.

John Kelsey разработал атаку,  которая позволяла взломать 3-итерационный Blowfish. Она опирается на факт, что  операции сложения по модулю 23и XOR не коммутативны.

Невозможно заранее определить является ли ключ слабым. Проводить  проверку можно только после генерации  ключа.

Криптостойкость можно настраивать  за счёт изменения количества раундов  шифрования (увеличивая длину массива P) и количества используемых S-box. При  уменьшении используемых S-box возрастает вероятность появления слабых ключей, но уменьшается используемая память. Адаптируя Blowfish на 64-битной архитектуру, можно увеличить количество и  размер S-box (а следовательно и  память для массивов P и S), а также  усложнить F(x), причём для алгоритма  с такой функцией F(x) невозможны вышеуказанные  атаки.

Модификация F(x): на вход подается 64-битный блок который делится на восемь 8-битных блоков (X1-X8). Результат  вычисляется по формуле 

 

, где 

 
На сегодняшний день (ноябрь 2008) не существует атак, выполняемых за разумное время. Успешные атаки возможны только из-за ошибок реализации.

ПРИМЕР  РАБОТЫ  АЛГОРИТМА


Пример работы свободно распространяемой версии алгоритма Blowfish. 
Параметры: Размер ключа: 448 бит Размер блока: 64 бит Число раундов: 16 режим: ECB

Исходное изображение


 

 

Зашифрованное изображение


ПРИМЕНЕНИЯ


Blowfish зарекомендовал себя, как надёжный алгоритм, поэтому  реализован во многих программах, где не требуется частая смена  ключа и необходима высокая  скорость шифрования/расшифрования.

  • хэширование паролей
  • защита электронной почты и файлов
    • GnuPG (безопасное хранение и передача)
  • в линиях связи: связка ElGamal (не запатентован) или RSA (действие патента закончилось в 2000 году) и Blowfish вместо IDEA
    • в маршрутизаторе Intel Express 8100 с ключом длиной 144 бита
  • обеспечение безопасности в протоколах сетевого и транспортного уровня
    • PuTTY (сетевой уровень)
    • SSH (транспортный уровень)
    • OpenVPN (создание зашифрованных каналов)

 

 

 

 

 

 

 

 

 

 

 

 

ЗАКЛЮЧЕНИЕ


Скорость шифрования алгоритма  во многом зависит от используемой техники и системы команд. На различных  архитектурах один алгоритм может значительно  опережать по скорости его конкурентов, а на другом ситуация может сравняться или даже измениться прямо в противоположную  сторону. Более того, программная  реализация значительно зависит  от используемого компилятора. Использование  ассемблерного кода может повысить скорость шифрования. На скорость шифрования влияет время выполнения операций mov, add, xor, причём время выполнения операций увеличивается при обращении  к оперативной памяти (для процессоров  серии Pentium примерно в 5 раз). Blowfish показывает более высокие результаты при использовании кэша для хранения всех подключей. В этом случае он опережает алгоритмы DES, IDEA. На отставание IDEA влияет операция умножения по модулю 232 + 1. Скорость Twofishможет быть близка по значению с Blowfish за счёт большего шифруемого блока.

Хотя Blowfish по скорости опережает  его аналоги, но при увеличении частоты  смены ключа основное время его  работы будет уходить на подготовительный этап, что в сотни раз уменьшает  его эффективность.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

СПИСОК  ЛИТЕРАТУРЫ

  1. А.П. Алферов, А.Ю. Зубов, А.С. Кузьмин, А.В. Черемушкин, «Основы криптографии», Гелиос АРВ, М., 2001.
  2. Брюс Шнайер. Прикладная криптография. Изд-во «Триумф», М., 2004г.
  3. Национальный стандарт РФ «Методы и средства обеспечения безопасности. Часть 1. Концепция и модели менеджмента безопасности информационных и телекоммуникационных технологий» (ГОСТ Р ИСО/МЭК 13335-1 — 2006).
  4. Методы и средства защиты компьютерной информации Р.Р. Хамидуллин. Учеб. Пособие СПб.: Изд-во СЗТУ, 2006 г.
  5. ГОСТ Р 34.11-94. Информационная технология. Криптографическая защита информации. Функция хеширования.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ПРИЛОЖЕНИЕ

Листинг

//USAGE:

//BlowFish b = new BlowFish("04B915BA43FEB5B6");

//string plainText = "The quick brown fox jumped over the lazy dog.";

//string cipherText = b.Encrypt_CBC(plainText);

//MessageBox.Show(cipherText);

//plainText = b.Decrypt_CBC(cipherText);

//MessageBox.Show(plainText);

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Security.Cryptography;

 

namespace BlowFishCS

{

    class BlowFish

    {

        RNGCryptoServiceProvider randomSource;

 

        //SBLOCKS

        private uint[] bf_s0;

        private uint[] bf_s1;

        private uint[] bf_s2;

        private uint[] bf_s3;

 

        private uint[] bf_P;

 

        //KEY

        private byte[] key;

 

        //HALF-BLOCKS

        private uint xl_par;

        private uint xr_par;

 

        private byte[] InitVector;

        private bool IVSet;

 

        //COMPATIBILITY WITH javascript CRYPTO LIBRARY

        private bool nonStandardMethod;

 

        /// <summary>

        /// Constructor for hex key

        /// </summary>

        /// <param name="hexKey">Cipher key as a hex string</param>

public BlowFish(string hexKey)

        {

            randomSource = new RNGCryptoServiceProvider();

            SetupKey(HexToByte(hexKey));

        }

 

        /// <summary>

        /// Constructor for byte key

        /// </summary>

        /// <param name="cipherKey">Cipher key as a byte array</param>

public BlowFish(byte[] cipherKey)

        {

            randomSource = new RNGCryptoServiceProvider();

            SetupKey(cipherKey);

        }

 

        /// <summary>

        /// Encrypts a string in CBC mode

        /// </summary>

        /// <param name="pt">Plaintext data to encrypt</param>

        /// <returns>Ciphertext with IV appended to front</returns>

public string Encrypt_CBC(string pt)

        {

            if (!IVSet)

                SetRandomIV();

            return ByteToHex(InitVector) + ByteToHex(Encrypt_CBC(

            Encoding.ASCII.GetBytes(pt)));

        }

 

        /// <summary>

        /// Decrypts a string in CBC mode

        /// </summary>

        /// <param name="ct">Ciphertext with IV appended to front</param>

        /// <returns>Plaintext</returns>

public string Decrypt_CBC(string ct)

        {

            IV = HexToByte(ct.Substring(0, 16));

            return Encoding.ASCII.GetString(Decrypt_CBC(HexToByte(

            ct.Substring(16)))).Replace("\0", "");

        }

 

        /// <summary>

        /// Decrypts a byte array in CBC mode.

        /// IV must be created and saved manually.

        /// </summary>

        /// <param name="ct">Ciphertext data to decrypt</param>

        /// <returns>Plaintext</returns>

public byte[] Decrypt_CBC(byte[] ct)

        {

            return Crypt_CBC(ct, true);

        }

 

        /// <summary>

        /// Encrypts a byte array in CBC mode.

        /// IV must be created and saved manually.

        /// </summary>

        /// <param name="pt">Plaintext data to encrypt</param>

        /// <returns>Ciphertext</returns>

public byte[] Encrypt_CBC(byte[] pt)

        {

            return Crypt_CBC(pt, false);

        }

       

        /// <summary>

        /// Encrypt a string in ECB mode

        /// </summary>

        /// <param name="pt">Plaintext to encrypt as ascii string</param>

        /// <returns>hex value of encrypted data</returns>

public string Encrypt_ECB(string pt)

        {

            return ByteToHex(Encrypt_ECB(Encoding.ASCII.GetBytes(pt)));

        }

 

        /// <summary>

        /// Decrypts a string (ECB)

        /// </summary>

        /// <param name="ct">hHex string of the ciphertext</param>

        /// <returns>Plaintext ascii string</returns>

public string Decrypt_ECB(string ct)

        {

            return Encoding.ASCII.GetString(Decrypt_ECB(

            HexToByte(ct))).Replace("\0","");

        }

 

        /// <summary>

        /// Encrypts a byte array in ECB mode

        /// </summary>

        /// <param name="pt">Plaintext data</param>

        /// <returns>Ciphertext bytes</returns>

        public byte[] Encrypt_ECB(byte[] pt)

        {

            return Crypt_ECB(pt, false);

        }

 

        /// <summary>

        /// Decrypts a byte array (ECB)

        /// </summary>

        /// <param name="ct">Ciphertext byte array</param>

        /// <returns>Plaintext</returns>

        public byte[] Decrypt_ECB(byte[] ct)

        {

            return Crypt_ECB(ct, true);

        }

 

        /// <summary>

        /// Initialization vector for CBC mode.

        /// </summary>

        public byte[] IV

        {

            get { return InitVector; }

            set

            {

                if (value.Length == 8)

                {

                    InitVector = value;

                    IVSet = true;

                }

                else

                {

                    throw new Exception("Invalid IV size.");

                }

            }

        }

 

        public bool NonStandard

        {

            get { return nonStandardMethod; }

            set { nonStandardMethod = value; }

        }

 

        /// <summary>

        /// Creates and sets a random initialization vector.

        /// </summary>

        /// <returns>The random IV</returns>

public byte[] SetRandomIV()

        {

            InitVector = new byte[8];

            randomSource.GetBytes(InitVector);

            IVSet = true;

            return InitVector;

        }

 

        #region Cryptography

            

        /// <summary>

        /// Sets up the S-blocks and the key

        /// </summary>

        /// <param name="cipherKey">Block cipher key (1-448

bits)</param>

        private void SetupKey(byte[] cipherKey)

        {

            bf_P = SetupP();

            //set up the S blocks

            bf_s0 = SetupS0();

            bf_s1 = SetupS1();

            bf_s2 = SetupS2();

            bf_s3 = SetupS3();

 

            key = new byte[cipherKey.Length]; // 448 bits

            if (cipherKey.Length > 56)

            {

                throw new Exception("Key too long. 56 bytes required.");

            }

 

            Buffer.BlockCopy(cipherKey, 0, key, 0, cipherKey.Length);

            int j = 0;

            for (int i = 0; i < 18; i++)

            {

                uint d = (uint)(((key[j % cipherKey.Length] * 256 +

key[(j + 1) % cipherKey.Length]) * 256 + key[(j + 2) %

cipherKey.Length]) * 256 + key[(j + 3) % cipherKey.Length]);

                bf_P[i] ^= d;

                j = (j + 4) % cipherKey.Length;

            }

 

            xl_par = 0;

            xr_par = 0;

            for (int i = 0; i < 18; i += 2)

            {

                encipher();

                bf_P[i] = xl_par;

                bf_P[i + 1] = xr_par;

            }

 

            for (int i = 0; i < 256; i += 2)

            {

                encipher();

                bf_s0[i] = xl_par;

                bf_s0[i + 1] = xr_par;

            }

            for (int i = 0; i < 256; i += 2)

            {

                encipher();

                bf_s1[i] = xl_par;

                bf_s1[i + 1] = xr_par;

            }

            for (int i = 0; i < 256; i += 2)

            {

                encipher();

                bf_s2[i] = xl_par;

                bf_s2[i + 1] = xr_par;

            }

            for (int i = 0; i < 256; i += 2)

            {

                encipher();

                bf_s3[i] = xl_par;

                bf_s3[i + 1] = xr_par;

            }

        }

 

        /// <summary>

        /// Encrypts or decrypts data in ECB mode

        /// </summary>

        /// <param name="text">plain/ciphertext</param>

        /// <param name="decrypt">true to decrypt, false to encrypt</param>

        /// <returns>(En/De)crypted data</returns>

        private byte[] Crypt_ECB(byte[] text, bool decrypt)

        {

            int paddedLen = (text.Length % 8 == 0 ? text.Length : text.Length

+ 8 - (text.Length % 8));

            byte[] plainText = new byte[paddedLen];

            Buffer.BlockCopy(text, 0, plainText, 0, text.Length);

            byte[] block = new byte[8];

            for (int i = 0; i < plainText.Length; i += 8)

            {

                Buffer.BlockCopy(plainText,i, block, 0, 8);

                if (decrypt)

                {

                    BlockDecrypt(ref block);

                }

                else

                {

                    BlockEncrypt(ref block);

                }

                Buffer.BlockCopy(block, 0, plainText, i, 8);

            }

            return plainText;

        }

 

        /// <summary>

        /// Encrypts or decrypts data in CBC mode

        /// </summary>

        /// <param name="text">plain/ciphertext</param>

        /// <param name="decrypt">true to decrypt, false to encrypt</param>

        /// <returns>(En/De)crypted data</returns>

        private byte[] Crypt_CBC(byte[] text, bool decrypt)

        {

            if (!IVSet)

            {

                throw new Exception("IV not set.");

            }

            int paddedLen = (text.Length % 8 == 0 ? text.Length : text.Length

+ 8 - (text.Length % 8));

            byte[] plainText = new byte[paddedLen];

            Buffer.BlockCopy(text, 0, plainText, 0, text.Length);

            byte[] block = new byte[8];

            byte[] preblock = new byte[8];

            byte[] iv = new byte[8];

            Buffer.BlockCopy(InitVector,0,iv,0,8);

            if (!decrypt)

            {

                for (int i = 0; i < plainText.Length; i += 8)

                {

                    Buffer.BlockCopy(plainText, i, block, 0, 8);

                    XorBlock(ref block, iv);

                    BlockEncrypt(ref block);

                    Buffer.BlockCopy(block, 0, iv, 0, 8);

                    Buffer.BlockCopy(block, 0, plainText, i, 8);

                }

            }

            else

            {

                for (int i = 0; i < plainText.Length; i += 8)

                {

                    Buffer.BlockCopy(plainText, i, block, 0, 8);

 

                    Buffer.BlockCopy(block, 0, preblock, 0, 8);

                    BlockDecrypt(ref block);

                    XorBlock(ref block, iv);

                    Buffer.BlockCopy(preblock, 0, iv, 0, 8);

 

                    Buffer.BlockCopy(block, 0, plainText, i, 8);

                }

            }

            return plainText;

        }

 

        /// <summary>

        /// XoR encrypts two 8 bit blocks

        /// </summary>

        /// <param name="block">8 bit block 1</param>

        /// <param name="iv">8 bit block 2</param>

        private void XorBlock(ref byte[] block, byte[] iv)

        {

            for (int i = 0; i < block.Length; i++)

            {

                block[i] ^= iv[i];

            }

        }

 

        /// <summary>

        /// Encrypts a 64 bit block

        /// </summary>

        /// <param name="block">The 64 bit block to encrypt</param>

        private void BlockEncrypt(ref byte[] block)

        {

            SetBlock(block);

            encipher();

            GetBlock(ref block);

        }

 

        /// <summary>

        /// Decrypts a 64 bit block

        /// </summary>

        /// <param name="block">The 64 bit block to decrypt</param>

        private void BlockDecrypt(ref byte[] block)

        {

            SetBlock(block);

            decipher();

            GetBlock(ref block);

        }

 

        /// <summary>

        /// Splits the block into the two uint values

        /// </summary>

        /// <param name="block">the 64 bit block to setup</param>

        private void SetBlock(byte[] block)

        {

            byte[] block1 = new byte[4];

            byte[] block2 = new byte[4];

            Buffer.BlockCopy(block, 0, block1, 0, 4);

            Buffer.BlockCopy(block, 4, block2, 0, 4);

            //split the block

            if (nonStandardMethod)

            {

                xr_par = BitConverter.ToUInt32(block1, 0);

                xl_par = BitConverter.ToUInt32(block2, 0);

            }

            else

            {

                //ToUInt32 requires the bytes in reverse order

                Array.Reverse(block1);

                Array.Reverse(block2);

                xl_par = BitConverter.ToUInt32(block1, 0);

                xr_par = BitConverter.ToUInt32(block2, 0);

            }

        }

 

        /// <summary>

        /// Converts the two uint values into a 64 bit block

        /// </summary>

        /// <param name="block">64 bit buffer to receive the block</param>

        private void GetBlock(ref byte[] block)

        {

            byte[] block1 = new byte[4];

            byte[] block2 = new byte[4];

            if (nonStandardMethod)

            {

                block1 = BitConverter.GetBytes(xr_par);

                block2 = BitConverter.GetBytes(xl_par);

            }

            else

            {

                block1 = BitConverter.GetBytes(xl_par);

                block2 = BitConverter.GetBytes(xr_par);

 

                //GetBytes returns the bytes in reverse order

                Array.Reverse(block1);

                Array.Reverse(block2);

            }

            //join the block

            Buffer.BlockCopy(block1, 0, block, 0, 4);

            Buffer.BlockCopy(block2, 0, block, 4, 4);

        }

 

        /// <summary>

        /// Runs the blowfish algorithm (standard 16 rounds)

        /// </summary>

        private void encipher()

        {

            xl_par ^= bf_P[0];

            for (uint i = 0; i < 16; i+= 2)

            {

                xr_par = round(xr_par, xl_par, i + 1);

                xl_par = round(xl_par, xr_par, i + 2);

            }

            xr_par = xr_par ^ bf_P[17];

 

            //swap the blocks

            uint swap = xl_par;

            xl_par = xr_par;

            xr_par = swap;

        }

 

        /// <summary>

        /// Runs the blowfish algorithm in reverse (standard 16 rounds)

        /// </summary>

        private void decipher()

        {

            xl_par ^= bf_P[17];

            for (uint i = 16; i > 0; i -= 2)

            {

                xr_par = round(xr_par, xl_par, i );

                xl_par = round(xl_par, xr_par, i-1);

            }

            xr_par = xr_par ^ bf_P[0];

 

            //swap the blocks

            uint swap = xl_par;

            xl_par = xr_par;

            xr_par = swap;

        }

 

        /// <summary>

        /// one round of the blowfish algorithm

        /// </summary>

        /// <param name="a">See spec</param>

        /// <param name="b">See spec</param>

        /// <param name="n">See spec</param>

        /// <returns></returns>

        private uint round(uint a, uint b, uint n)

        {

            uint x1 = (bf_s0[wordByte0( B) ] + bf_s1[wordByte1( B) ]) ^

bf_s2[wordByte2( B) ];

            uint x2 = x1 + bf_s3[this.wordByte3( B) ];

            uint x3 = x2 ^ bf_P[n];

            return x3 ^ a;

        }

 

        #endregion

 

        #region SBLOCKS

        //SBLOCKS ARE THE HEX DIGITS OF PI.

        //The amount of hex digits can be increased if you want to experiment with

more rounds and longer key lengths

        private uint[] SetupP()

        {

            return new uint[] {

                0x243f6a88,0x85a308d3,0x13198a2e,0x03707344,0xa4093822,0x299f31d0,

                    0x082efa98,0xec4e6c89,0x452821e6,0x38d01377,0xbe5466cf,0x34e90c6c,

                    0xc0ac29b7,0xc97c50dd,0x3f84d5b5,0xb5470917,0x9216d5d9,0x8979fb1b

            };

        }

 

        private uint[] SetupS0()

        {

            return new uint[] {

                    0xd1310ba6,0x98dfb5ac,0x2ffd72db,0xd01adfb7,0xb8e1afed,0x6a267e96,

                    0xba7c9045,0xf12c7f99,0x24a19947,0xb3916cf7,0x0801f2e2,0x858efc16,

                    0x636920d8,0x71574e69,0xa458fea3,0xf4933d7e,0x0d95748f,0x728eb658,

                    0x718bcd58,0x82154aee,0x7b54a41d,0xc25a59b5,0x9c30d539,0x2af26013,

                    0xc5d1b023,0x286085f0,0xca417918,0xb8db38ef,0x8e79dcb0,0x603a180e,

                    0x6c9e0e8b,0xb01e8a3e,0xd71577c1,0xbd314b27,0x78af2fda,0x55605c60,

                    0xe65525f3,0xaa55ab94,0x57489862,0x63e81440,0x55ca396a,0x2aab10b6,

                    0xb4cc5c34,0x1141e8ce,0xa15486af,0x7c72e993,0xb3ee1411,0x636fbc2a,

                    0x2ba9c55d,0x741831f6,0xce5c3e16,0x9b87931e,0xafd6ba33,0x6c24cf5c,

                    0x7a325381,0x28958677,0x3b8f4898,0x6b4bb9af,0xc4bfe81b,0x66282193,

                    0x61d809cc,0xfb21a991,0x487cac60,0x5dec8032,0xef845d5d,0xe98575b1,

                    0xdc262302,0xeb651b88,0x23893e81,0xd396acc5,0x0f6d6ff3,0x83f44239,

                    0x2e0b4482,0xa4842004,0x69c8f04a,0x9e1f9b5e,0x21c66842,0xf6e96c9a,

                    0x670c9c61,0xabd388f0,0x6a51a0d2,0xd8542f68,0x960fa728,0xab5133a3,

                    0x6eef0b6c,0x137a3be4,0xba3bf050,0x7efb2a98,0xa1f1651d,0x39af0176,

                    0x66ca593e,0x82430e88,0x8cee8619,0x456f9fb4,0x7d84a5c3,0x3b8b5ebe,

                    0xe06f75d8,0x85c12073,0x401a449f,0x56c16aa6,0x4ed3aa62,0x363f7706,

                    0x1bfedf72,0x429b023d,0x37d0d724,0xd00a1248,0xdb0fead3,0x49f1c09b,

                    0x075372c9,0x80991b7b,0x25d479d8,0xf6e8def7,0xe3fe501a,0xb6794c3b,

                    0x976ce0bd,0x04c006ba,0xc1a94fb6,0x409f60c4,0x5e5c9ec2,0x196a2463,

                    0x68fb6faf,0x3e6c53b5,0x1339b2eb,0x3b52ec6f,0x6dfc511f,0x9b30952c,

                    0xcc814544,0xaf5ebd09,0xbee3d004,0xde334afd,0x660f2807,0x192e4bb3,

                    0xc0cba857,0x45c8740f,0xd20b5f39,0xb9d3fbdb,0x5579c0bd,0x1a60320a,

                    0xd6a100c6,0x402c7279,0x679f25fe,0xfb1fa3cc,0x8ea5e9f8,0xdb3222f8,

                    0x3c7516df,0xfd616b15,0x2f501ec8,0xad0552ab,0x323db5fa,0xfd238760,

                    0x53317b48,0x3e00df82,0x9e5c57bb,0xca6f8ca0,0x1a87562e,0xdf1769db,

                    0xd542a8f6,0x287effc3,0xac6732c6,0x8c4f5573,0x695b27b0,0xbbca58c8,

                    0xe1ffa35d,0xb8f011a0,0x10fa3d98,0xfd2183b8,0x4afcb56c,0x2dd1d35b,

                    0x9a53e479,0xb6f84565,0xd28e49bc,0x4bfb9790,0xe1ddf2da,0xa4cb7e33,

                    0x62fb1341,0xcee4c6e8,0xef20cada,0x36774c01,0xd07e9efe,0x2bf11fb4,

                    0x95dbda4d,0xae909198,0xeaad8e71,0x6b93d5a0,0xd08ed1d0,0xafc725e0,

                    0x8e3c5b2f,0x8e7594b7,0x8ff6e2fb,0xf2122b64,0x8888b812,0x900df01c,

                    0x4fad5ea0,0x688fc31c,0xd1cff191,0xb3a8c1ad,0x2f2f2218,0xbe0e1777,

                    0xea752dfe,0x8b021fa1,0xe5a0cc0f,0xb56f74e8,0x18acf3d6,0xce89e299,

                    0xb4a84fe0,0xfd13e0b7,0x7cc43b81,0xd2ada8d9,0x165fa266,0x80957705,

                    0x93cc7314,0x211a1477,0xe6ad2065,0x77b5fa86,0xc75442f5,0xfb9d35cf,

                    0xebcdaf0c,0x7b3e89a0,0xd6411bd3,0xae1e7e49,0x00250e2d,0x2071b35e,

                    0x226800bb,0x57b8e0af,0x2464369b,0xf009b91e,0x5563911d,0x59dfa6aa,

                    0x78c14389,0xd95a537f,0x207d5ba2,0x02e5b9c5,0x83260376,0x6295cfa9,

                    0x11c81968,0x4e734a41,0xb3472dca,0x7b14a94a,0x1b510052,0x9a532915,

                    0xd60f573f,0xbc9bc6e4,0x2b60a476,0x81e67400,0x08ba6fb5,0x571be91f,

                    0xf296ec6b,0x2a0dd915,0xb6636521,0xe7b9f9b6,0xff34052e,0xc5855664,

                    0x53b02d5d,0xa99f8fa1,0x08ba4799,0x6e85076a

            };

        }

 

        private uint[] SetupS1()

        {

            return new uint[] {

                0x4b7a70e9,0xb5b32944,0xdb75092e,0xc4192623,0xad6ea6b0,0x49a7df7d,

Алгоритм шифрования Blowfish