⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 blowfishecb.cs

📁 source for advanced algorithm
💻 CS
📖 第 1 页 / 共 3 页
字号:
/* 
  Copyright 2001-2007 Markus Hahn 
  All rights reserved. See documentation for license details.  
*/

using System;

namespace BlowfishNET
{
    /// <summary>Blowfish ECB implementation.</summary>
    /// <remarks>Use this class to encrypt or decrypt byte arrays or a single
    /// block with Blowfish in the ECB (Electronic Code Book) mode. The key
    /// length can be flexible from zero up to 56 bytes.</remarks>
    public class BlowfishECB : ICloneable
    {
        /// <summary>The maximum and recommended key size in bytes.</summary>
        public const int MAX_KEY_LENGTH = 56;

        /// <summary>The block size in bytes.</summary>
        public const int BLOCK_SIZE = 8;

        const int PBOX_ENTRIES = 18;
        const int SBOX_ENTRIES = 256;

        #region Cipher State
        
        /// <summary>Runtime p-box.</summary>
        protected uint[] pbox = new uint[PBOX_ENTRIES];
        /// <summary>Runtime s-box #1.</summary>
        protected uint[] sbox1 = new uint[SBOX_ENTRIES];
        /// <summary>Runtime s-box #2.</summary>
        protected uint[] sbox2 = new uint[SBOX_ENTRIES];
        /// <summary>Runtime s-box #3.</summary>
        protected uint[] sbox3 = new uint[SBOX_ENTRIES];
        /// <summary>Runtime s-box #4.</summary>
        protected uint[] sbox4 = new uint[SBOX_ENTRIES];
        /// <summary>Single block cache.</summary>
        protected byte[] block = new byte[BLOCK_SIZE];
        /// <summary>1 if a weak key was detected, 0 if not and -1 if it hasn't
        /// been determined yet.</summary>
        protected int isWeakKey;

        #endregion

        /// <summary>To check if the key used is weak.</summary>
        /// <remarks>If a key is weak it means that eventually an attack is easier to apply than
        /// just a simple brute force on keys. Due to the randomness in the key setup process
        /// such a case however is unlikely to happen, yet checking after each setup might still
        /// be the preferred way. In the case of a weak key detected a simple recreation with a
        /// different key (or just a different salt value) is the recommended solution. For
        /// performance reasons we don't do the weak key check during the initialization, but on
        /// demand only, and then only once to determine the flag.</remarks>
        public bool IsWeakKey
        {
            get
            {
                if (-1 == this.isWeakKey)
                {
                    this.isWeakKey = 0;

                    int i, j;
                    for (i = 0; i < SBOX_ENTRIES - 1; i++) 
                    {
                        j = i + 1;
                        while (j < SBOX_ENTRIES) 
                        {
                            if ((this.sbox1[i] == this.sbox1[j]) |
                                (this.sbox2[i] == this.sbox2[j]) | 
                                (this.sbox3[i] == this.sbox3[j]) |
                                (this.sbox4[i] == this.sbox4[j])) break;
                            else j++;
                        }
                        if (j < SBOX_ENTRIES)
                        {
                            this.isWeakKey = 1;
                            break;
                        }
                    }
                }

                return (1 == this.isWeakKey);
            }
        }

        /// <summary>Resets the instance with new or initial key material. Allows the switch of
        /// keys at runtime without any new internal object allocation.</summary>
        /// <param name="key">The buffer with the key material.</param>
        /// <param name="ofs">Position at which the key material starts in the buffer.</param>
        /// <param name="len">Size of the key material, up to MAX_KEY_LENGTH bytes.</param>
        public void Initialize(byte[] key, int ofs, int len) 
        {
            int i, j, keyPos, keyEnd;
            uint build, hi, lo;
            uint[] box;

            this.isWeakKey = -1;

            Array.Copy(PBOX_INIT  , 0, this.pbox , 0, PBOX_INIT.Length); 
            Array.Copy(SBOX_INIT_1, 0, this.sbox1, 0, SBOX_INIT_1.Length); 
            Array.Copy(SBOX_INIT_2, 0, this.sbox2, 0, SBOX_INIT_2.Length); 
            Array.Copy(SBOX_INIT_3, 0, this.sbox3, 0, SBOX_INIT_3.Length); 
            Array.Copy(SBOX_INIT_4, 0, this.sbox4, 0, SBOX_INIT_4.Length); 

            if (0 == len)
            {
                return;
            }
            
            keyPos = ofs;
            keyEnd = ofs + len;
            build = 0;

            for (i = 0; i < PBOX_ENTRIES; i++)
            {
                for (j = 0; j < 4; j++) 
                {
                    build = (build << 8) | key[keyPos];
      
                    if (++keyPos == keyEnd) 
                    { 
                        keyPos = ofs;
                    }
                }
                this.pbox[i] ^= build;
            }

            hi = lo = 0;

            box = this.pbox;
            for (i = 0; i < PBOX_ENTRIES;) 
            {
                EncryptBlock(hi, lo, out hi, out lo);
                box[i++] = hi;
                box[i++] = lo;
            }
            box = this.sbox1;
            for (i = 0; i < SBOX_ENTRIES;) 
            {
                EncryptBlock(hi, lo, out hi, out lo);
                box[i++] = hi;
                box[i++] = lo;
            }
            box = this.sbox2;
            for (i = 0; i < SBOX_ENTRIES;) 
            {
                EncryptBlock(hi, lo, out hi, out lo);
                box[i++] = hi;
                box[i++] = lo;
            }
            box = this.sbox3;
            for (i = 0; i < SBOX_ENTRIES;) 
            {
                EncryptBlock(hi, lo, out hi, out lo);
                box[i++] = hi;
                box[i++] = lo;
            }
            box = this.sbox4;
            for (i = 0; i < SBOX_ENTRIES;) 
            {
                EncryptBlock(hi, lo, out hi, out lo);
                box[i++] = hi;
                box[i++] = lo;
            }
        }

        /// <summary>Zero constructor, properly initializes an instance. Initialize afterwards
        /// to set up a valid key!</summary>
        public BlowfishECB()
        {
            Initialize(null, 0, 0);     
        }

        /// <see cref="BlowfishECB.Initialize"/>
        public BlowfishECB(byte[] key, int ofs, int len) 
        {
            Initialize(key, ofs, len);
        }

        /// <summary> Deletes all internal data structures and invalidates this instance.</summary>
        /// <remarks>Call this method as soon as the work with a particular instance is done,
        /// so no sensitive translated key material remains. The instance is invalid after this
        /// call and usage can lead to unexpected results!</remarks> 
        public void Invalidate() 
        {
            Array.Clear(this.pbox, 0, this.pbox.Length);
            
            Array.Clear(this.sbox1, 0, this.sbox1.Length);
            Array.Clear(this.sbox2, 0, this.sbox2.Length);
            Array.Clear(this.sbox3, 0, this.sbox3.Length);
            Array.Clear(this.sbox4, 0, this.sbox4.Length);

            Array.Clear(this.block, 0, this.block.Length);
        }

        static readonly byte[] TEST_KEY = { 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef };
        static readonly uint[] TEST_VECTOR_PLAIN  = { 0x30553228, 0x6d6f295a };
        static readonly uint[] TEST_VECTOR_CIPHER = { 0x55cb3774, 0xd13ef201 };

        /// <summary>To execute a selftest.</summary>
        /// <remarks>Call this method to make sure that the implemenation is able to produce
        /// valid output according to the specification. This should usually be done at process
        /// startup time, before the usage of this class and its inherited variants.</remarks>
        /// <returns>True if the selftest passed or false is it failed. In such a case you must
        /// not use the cipher to avoid data corruption!</returns>
        public static bool RunSelfTest()
        {
            uint hi, lo;
            BlowfishECB bfe;


            hi = TEST_VECTOR_PLAIN[0];
            lo = TEST_VECTOR_PLAIN[1];

            bfe = new BlowfishECB(TEST_KEY, 0, TEST_KEY.Length);

            bfe.EncryptBlock(hi, lo, out hi, out lo);

            if ((TEST_VECTOR_CIPHER[0] != hi) ||
                (TEST_VECTOR_CIPHER[1] != lo))
            {
                return false;
            }

            bfe.DecryptBlock(hi, lo, out hi, out lo);

            if ((TEST_VECTOR_PLAIN[0] != hi) ||
                (TEST_VECTOR_PLAIN[1] != lo))
            {
                return false;
            }

            return true;
        }
        
        /// <summary>Encrypts a single block.</summary>
        /// <param name="hi">The high 32bit word of the block.</param>
        /// <param name="lo">The low 32bit word of the block.</param>
        /// <param name="outHi">Where to put the encrypted high word.</param>
        /// <param name="outLo">Where to put the encrypted low word.</param>
        public void EncryptBlock(
            uint hi,
            uint lo,
            out uint outHi,
            out uint outLo)
        {
            byte[] block;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -