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

📄 twofish.cpp

📁 一款密码保险箱源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    if( key_len < 0 || key_len > 32 )
        {
        /* 
         * This can only happen if a programmer didn't read the limitations
         * on the key size. 
         */
        Twofish_fatal( "Twofish_prepare_key: illegal key length" );
        /* 
         * A return statement just in case the fatal macro returns.
         * The rest of the code assumes that key_len is in range, and would
         * buffer-overflow if it wasn't. 
         *
         * Why do we still use a programming language that has problems like
         * buffer overflows, when these problems were solved in 1960 with
         * the development of Algol? Have we not leared anything?
         */
        return;
        }

    /* Pad the key with zeroes to the next suitable key length. */
    memcpy( K, key, key_len );
    memset( K+key_len, 0, sizeof(K)-key_len );

    /* 
     * Compute kCycles: the number of key cycles used in the cipher. 
     * 2 for 128-bit keys, 3 for 192-bit keys, and 4 for 256-bit keys.
     */
    kCycles = (key_len + 7) >> 3;
    /* Handle the special case of very short keys: minimum 2 cycles. */
    if( kCycles < 2 )
        {
        kCycles = 2;
        }

    /* 
     * From now on we just pretend to have 8*kCycles bytes of 
     * key material in K. This handles all the key size cases. 
     */

    /* 
     * We first compute the 40 expanded key words, 
     * formulas straight from the Twofish specifications.
     */
    for( i=0; i<40; i+=2 )
        {
        /* 
         * Due to the byte spacing expected by the h() function 
         * we can pick the bytes directly from the key K.
         * As we use bytes, we never have the little/big endian
         * problem.
         *
         * Note that we apply the rotation function only to simple
         * variables, as the rotation macro might evaluate its argument
         * more than once.
         */
        A = h( i  , K  , kCycles );
        B = h( i+1, K+4, kCycles );
        B = ROL32( B, 8 );

        /* Compute and store the round keys. */
        A += B;
        B += A;
        xkey->K[i]   = A;
        xkey->K[i+1] = ROL32( B, 9 );
        }

    /* Wipe variables that contained key material. */
    A=B=0;

    /* 
     * And now the dreaded RS multiplication that few seem to understand.
     * The RS matrix is not random, and is specially designed to compute the
     * RS matrix multiplication in a simple way.
     *
     * We work in the field GF(2)[x]/x^8+x^6+x^3+x^2+1. Note that this is a
     * different field than used for the MDS matrix. 
     * (At least, it is a different representation because all GF(2^8) 
     * representations are equivalent in some form.)
     * 
     * We take 8 consecutive bytes of the key and interpret them as 
     * a polynomial k_0 + k_1 y + k_2 y^2 + ... + k_7 y^7 where 
     * the k_i bytes are the key bytes and are elements of the finite field.
     * We multiply this polynomial by y^4 and reduce it modulo
     *     y^4 + (x + 1/x)y^3 + (x)y^2 + (x + 1/x)y + 1. 
     * using straightforward polynomial modulo reduction.
     * The coefficients of the result are the result of the RS
     * matrix multiplication. When we wrote the Twofish specification, 
     * the original RS definition used the polynomials, 
     * but that requires much more mathematical knowledge. 
     * We were already using matrix multiplication in a finite field for 
     * the MDS matrix, so I re-wrote the RS operation as a matrix 
     * multiplication to reduce the difficulty of understanding it. 
     * Some implementors have not picked up on this simpler method of
     * computing the RS operation, even though it is mentioned in the
     * specifications.
     *
     * It is possible to perform these computations faster by using 32-bit 
     * word operations, but that is not portable and this is not a speed-
     * critical area.
     *
     * We explained the 1/x computation when we did the MDS matrix. 
     *
     * The S vector is stored in K[32..64].
     * The S vector has to be reversed, so we loop cross-wise.
     *
     * Note the weird byte spacing of the S-vector, to match the even 
     * or odd key words arrays. See the discussion at the Hxx macros for
     * details.
     */
    kptr = K + 8*kCycles;           /* Start at end of key */
    sptr = K + 32;                  /* Start at start of S */

    /* Loop over all key material */
    while( kptr > K ) 
        {
        kptr -= 8;
        /* 
         * Initialise the polynimial in sptr[0..12]
         * The first four coefficients are 0 as we have to multiply by y^4.
         * The next 8 coefficients are from the key material.
         */
        memset( sptr, 0, 4 );
        memcpy( sptr+4, kptr, 8 );

        /* 
         * The 12 bytes starting at sptr are now the coefficients of
         * the polynomial we need to reduce.
         */

        /* Loop over the polynomial coefficients from high to low */
        t = sptr+11;
        /* Keep looping until polynomial is degree 3; */
        while( t > sptr+3 )
            {
            /* Pick up the highest coefficient of the poly. */
            b = *t;

            /* 
             * Compute x and (x+1/x) times this coefficient. 
             * See the MDS matrix implementation for a discussion of 
             * multiplication by x and 1/x. We just use different 
             * constants here as we are in a 
             * different finite field representation.
             *
             * These two statements set 
             * bx = (x) * b 
             * bxx= (x + 1/x) * b
             */
            bx = (Twofish_Byte)((b<<1) ^ rs_poly_const[ b>>7 ]);
            bxx= (Twofish_Byte)((b>>1) ^ rs_poly_div_const[ b&1 ] ^ bx);

            /*
             * Subtract suitable multiple of 
             * y^4 + (x + 1/x)y^3 + (x)y^2 + (x + 1/x)y + 1 
             * from the polynomial, except that we don't bother
             * updating t[0] as it will become zero anyway.
             */
            t[-1] ^= bxx;
            t[-2] ^= bx;
            t[-3] ^= bxx;
            t[-4] ^= b;
            
            /* Go to the next coefficient. */
            t--;
            }

        /* Go to next S-vector word, obeying the weird spacing rules. */
        sptr += 8;
        }

    /* Wipe variables that contained key material. */
    b = bx = bxx = 0;

    /* And finally, we can compute the key-dependent S-boxes. */
    fill_keyed_sboxes( &K[32], kCycles, xkey );

    /* Wipe array that contained key material. */
    memset( K, 0, sizeof( K ) );
    }


/*
 * We can now start on the actual encryption and decryption code.
 * As these are often speed-critical we will use a lot of macros.
 */

/*
 * The g() function is the heart of the round function.
 * We have two versions of the g() function, one without an input
 * rotation and one with.
 * The pre-computed S-boxes make this pretty simple.
 */
#define g0(X,xkey) \
 (xkey->s[0][b0(X)]^xkey->s[1][b1(X)]^xkey->s[2][b2(X)]^xkey->s[3][b3(X)])

#define g1(X,xkey) \
 (xkey->s[0][b3(X)]^xkey->s[1][b0(X)]^xkey->s[2][b1(X)]^xkey->s[3][b2(X)])

/*
 * A single round of Twofish. The A,B,C,D are the four state variables,
 * T0 and T1 are temporaries, xkey is the expanded key, and r the 
 * round number.
 *
 * Note that this macro does not implement the swap at the end of the round.
 */
#define ENCRYPT_RND( A,B,C,D, T0, T1, xkey, r ) \
    T0 = g0(A,xkey); T1 = g1(B,xkey);\
    C ^= T0+T1+xkey->K[8+2*(r)]; C = ROR32(C,1);\
    D = ROL32(D,1); D ^= T0+2*T1+xkey->K[8+2*(r)+1]

/*
 * Encrypt a single cycle, consisting of two rounds.
 * This avoids the swapping of the two halves. 
 * Parameter r is now the cycle number.
 */
#define ENCRYPT_CYCLE( A, B, C, D, T0, T1, xkey, r ) \
    ENCRYPT_RND( A,B,C,D,T0,T1,xkey,2*(r)   );\
    ENCRYPT_RND( C,D,A,B,T0,T1,xkey,2*(r)+1 )

/* Full 16-round encryption */
#define ENCRYPT( A,B,C,D,T0,T1,xkey ) \
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 0 );\
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 1 );\
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 2 );\
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 3 );\
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 4 );\
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 5 );\
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 6 );\
    ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 7 )

/*
 * A single round of Twofish for decryption. It differs from
 * ENCRYTP_RND only because of the 1-bit rotations.
 */
#define DECRYPT_RND( A,B,C,D, T0, T1, xkey, r ) \
    T0 = g0(A,xkey); T1 = g1(B,xkey);\
    C = ROL32(C,1); C ^= T0+T1+xkey->K[8+2*(r)];\
    D ^= T0+2*T1+xkey->K[8+2*(r)+1]; D = ROR32(D,1)

/*
 * Decrypt a single cycle, consisting of two rounds. 
 * This avoids the swapping of the two halves. 
 * Parameter r is now the cycle number.
 */
#define DECRYPT_CYCLE( A, B, C, D, T0, T1, xkey, r ) \
    DECRYPT_RND( A,B,C,D,T0,T1,xkey,2*(r)+1 );\
    DECRYPT_RND( C,D,A,B,T0,T1,xkey,2*(r)   )

/* Full 16-round decryption. */
#define DECRYPT( A,B,C,D,T0,T1, xkey ) \
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 7 );\
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 6 );\
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 5 );\
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 4 );\
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 3 );\
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 2 );\
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 1 );\
    DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 0 )

/*
 * A macro to read the state from the plaintext and do the initial key xors.
 * The koff argument allows us to use the same macro 
 * for the decryption which uses different key words at the start.
 */
#define GET_INPUT( src, A,B,C,D, xkey, koff ) \
    A = GET32(src   )^xkey->K[  koff]; B = GET32(src+ 4)^xkey->K[1+koff]; \
    C = GET32(src+ 8)^xkey->K[2+koff]; D = GET32(src+12)^xkey->K[3+koff]

/*
 * Similar macro to put the ciphertext in the output buffer.
 * We xor the keys into the state variables before we use the PUT32 
 * macro as the macro might use its argument multiple times.
 */
#define PUT_OUTPUT( A,B,C,D, dst, xkey, koff ) \
    A ^= xkey->K[  koff]; B ^= xkey->K[1+koff]; \
    C ^= xkey->K[2+koff]; D ^= xkey->K[3+koff]; \
    PUT32( A, dst   ); PUT32( B, dst+ 4 ); \
    PUT32( C, dst+8 ); PUT32( D, dst+12 )


/*
 * Twofish block encryption
 *
 * Arguments:
 * xkey         expanded key array
 * p            16 bytes of plaintext
 * c            16 bytes in which to store the ciphertext
 */
void Twofish_encrypt( Twofish_key * xkey, Twofish_Byte p[16], Twofish_Byte c[16])
    {
    Twofish_UInt32 A,B,C,D,T0,T1;       /* Working variables */

    /* Get the four plaintext words xorred with the key */
    GET_INPUT( p, A,B,C,D, xkey, 0 );

    /* Do 8 cycles (= 16 rounds) */
    ENCRYPT( A,B,C,D,T0,T1,xkey );

    /* Store them with the final swap and the output whitening. */
    PUT_OUTPUT( C,D,A,B, c, xkey, 4 );
    }


/*
 * Twofish block decryption.
 *
 * Arguments:
 * xkey         expanded key array
 * p            16 bytes of plaintext
 * c            16 bytes in which to store the ciphertext
 */
void Twofish_decrypt( Twofish_key * xkey, Twofish_Byte c[16], Twofish_Byte p[16])
    {
    Twofish_UInt32 A,B,C,D,T0,T1;       /* Working variables */

    /* Get the four plaintext words xorred with the key */
    GET_INPUT( c, A,B,C,D, xkey, 4 );

    /* Do 8 cycles (= 16 rounds) */
    DECRYPT( A,B,C,D,T0,T1,xkey );

    /* Store them with the final swap and the output whitening. */
    PUT_OUTPUT( C,D,A,B, p, xkey, 0 );
    }

/*
 * Using the macros it is easy to make special routines for
 * CBC mode, CTR mode etc. The only thing you might want to
 * add is a XOR_PUT_OUTPUT which xors the outputs into the
 * destinationa instead of overwriting the data. This requires
 * a XOR_PUT32 macro as well, but that should all be trivial.
 *
 * I thought about including routines for the separate cipher
 * modes here, but it is unclear which modes should be included,
 * and each encryption or decryption routine takes up a lot of code space.
 * Also, I don't have any test vectors for 

⌨️ 快捷键说明

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