📄 twofish.cpp
字号:
* Only relevant if SELECT_BYTE_FROM_UINT32_IN_MEMORY or
* CONVERT_USING_CASTS is set.
*
* Set to 1 on a big-endian machine, and to 0 on a little-endian machine.
* Twofish uses the little-endian convention (least significant byte first)
* and big-endian machines (using most significant byte first)
* have to do a few conversions.
*
* CAUTION: This code has never been tested on a big-endian machine,
* because I don't have access to one. Feedback appreciated.
*/
#define CPU_IS_BIG_ENDIAN 0
/*
* Macro to reverse the order of the bytes in a UInt32.
* Used to convert to little-endian on big-endian machines.
* This macro is always tested, but only used in the encryption and
* decryption if CONVERT_USING_CASTS, and CPU_IS_BIG_ENDIAN
* are both set. In other words: this macro is only speed-critical if
* both these flags have been set.
*
* This default definition of SWAP works, but on many platforms there is a
* more efficient implementation.
*/
#define BSWAP(x) (ROL32((x),8)&0x00ff00ff | ROR32((x),8) & 0xff00ff00)
/*
* END OF PLATFORM FIXES
* =====================
*
* You should not have to touch the rest of this file.
*/
/*
* Convert the external type names to some that are easier to use inside
* this file. I didn't want to use the names Byte and UInt32 in the
* header file, because many programs already define them and using two
* conventions at once can be very difficult.
* Don't change these definitions! Change the originals
* in twofish.h instead.
*/
/* A Byte must be an unsigned integer, 8 bits long. */
// typedef Twofish_Byte Byte;
/* A UInt32 must be an unsigned integer at least 32 bits long. */
// typedef Twofish_UInt32 UInt32;
/*
* Define a macro ENDIAN_CONVERT.
*
* We define a macro ENDIAN_CONVERT that performs a BSWAP on big-endian
* machines, and is the identity function on little-endian machines.
* The code then uses this macro without considering the endianness.
*/
#if CPU_IS_BIG_ENDIAN
#define ENDIAN_CONVERT(x) BSWAP(x)
#else
#define ENDIAN_CONVERT(x) (x)
#endif
/*
* Compute byte offset within a UInt32 stored in memory.
*
* This is only used when SELECT_BYTE_FROM_UINT32_IN_MEMORY is set.
*
* The input is the byte number 0..3, 0 for least significant.
* Note the use of sizeof() to support UInt32 types that are larger
* than 4 bytes.
*/
#if CPU_IS_BIG_ENDIAN
#define BYTE_OFFSET( n ) (sizeof(Twofish_UInt32) - 1 - (n) )
#else
#define BYTE_OFFSET( n ) (n)
#endif
/*
* Macro to get Byte no. b from UInt32 value X.
* We use two different definition, depending on the settings.
*/
#if SELECT_BYTE_FROM_UINT32_IN_MEMORY
/* Pick the byte from the memory in which X is stored. */
#define SELECT_BYTE( X, b ) (((Twofish_Byte *)(&(X)))[BYTE_OFFSET(b)])
#else
/* Portable solution: Pick the byte directly from the X value. */
#define SELECT_BYTE( X, b ) (((X) >> (8*(b))) & 0xff)
#endif
/* Some shorthands because we use byte selection in large formulae. */
#define b0(X) SELECT_BYTE((X),0)
#define b1(X) SELECT_BYTE((X),1)
#define b2(X) SELECT_BYTE((X),2)
#define b3(X) SELECT_BYTE((X),3)
/*
* We need macros to load and store UInt32 from/to byte arrays
* using the least-significant-byte-first convention.
*
* GET32( p ) gets a UInt32 in lsb-first form from four bytes pointed to
* by p.
* PUT32( v, p ) writes the UInt32 value v at address p in lsb-first form.
*/
#if CONVERT_USING_CASTS
/* Get UInt32 from four bytes pointed to by p. */
#define GET32( p ) ENDIAN_CONVERT( *((Twofish_UInt32 *)(p)) )
/* Put UInt32 into four bytes pointed to by p */
#define PUT32( v, p ) *((Twofish_UInt32 *)(p)) = ENDIAN_CONVERT(v)
#else
/* Get UInt32 from four bytes pointed to by p. */
#define GET32( p ) \
( \
(Twofish_UInt32)((p)[0]) \
| (Twofish_UInt32)((p)[1])<< 8 \
| (Twofish_UInt32)((p)[2])<<16 \
| (Twofish_UInt32)((p)[3])<<24 \
)
/* Put UInt32 into four bytes pointed to by p */
#define PUT32( v, p ) \
(p)[0] = (Twofish_Byte)(((v) ) & 0xff); \
(p)[1] = (Twofish_Byte)(((v) >> 8) & 0xff); \
(p)[2] = (Twofish_Byte)(((v) >> 16) & 0xff); \
(p)[3] = (Twofish_Byte)(((v) >> 24) & 0xff)
#endif
/*
* Test the platform-specific macros.
* This function tests the macros defined so far to make sure the
* definitions are appropriate for this platform.
* If you make any mistake in the platform configuration, this should detect
* that and inform you what went wrong.
* Somewhere, someday, this is going to save somebody a lot of time,
* because misbehaving macros are hard to debug.
*/
static void test_platform()
{
/* Buffer with test values. */
Twofish_Byte buf[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0};
Twofish_UInt32 C;
Twofish_UInt32 x,y;
int i;
/*
* Some sanity checks on the types that can't be done in compile time.
* A smart compiler will just optimise these tests away.
* The pre-processor doesn't understand different types, so we cannot
* do these checks in compile-time.
*
* I hate C.
*
* The first check in each case is to make sure the size is correct.
* The second check is to ensure that it is an unsigned type.
*/
if( ((Twofish_UInt32)((Twofish_UInt32)1 << 31) == 0) || ((Twofish_UInt32)-1 < 0 ))
{
Twofish_fatal( "Twofish code: Twofish_UInt32 type not suitable" );
}
if( (sizeof( Twofish_Byte ) != 1) || (((Twofish_Byte)-1) < 0) )
{
Twofish_fatal( "Twofish code: Twofish_Byte type not suitable" );
}
/*
* Sanity-check the endianness conversions.
* This is just an aid to find problems. If you do the endianness
* conversion macros wrong you will fail the full cipher test,
* but that does not help you find the error.
* Always make it easy to find the bugs!
*
* Detail: There is no fully portable way of writing UInt32 constants,
* as you don't know whether to use the U or UL suffix. Using only U you
* might only be allowed 16-bit constants. Using UL you might get 64-bit
* constants which cannot be stored in a UInt32 without warnings, and
* which generally behave subtly different from a true UInt32.
* As long as we're just comparing with the constant,
* we can always use the UL suffix and at worst lose some efficiency.
* I use a separate '32-bit constant' macro in most of my other code.
*
* I hate C.
*
* Start with testing GET32. We test it on all positions modulo 4
* to make sure we can handly any position of inputs. (Some CPUs
* do not allow non-aligned accesses which we would do if you used
* the CONVERT_USING_CASTS option.
*/
if( (GET32( buf ) != 0x78563412UL) || (GET32(buf+1) != 0x9a785634UL)
|| (GET32( buf+2 ) != 0xbc9a7856UL) || (GET32(buf+3) != 0xdebc9a78UL) )
{
Twofish_fatal( "Twofish code: GET32 not implemented properly" );
}
/*
* We can now use GET32 to test PUT32.
* We don't test the shifted versions. If GET32 can do that then
* so should PUT32.
*/
C = GET32( buf );
PUT32( 3*C, buf );
if( GET32( buf ) != 0x69029c36UL )
{
Twofish_fatal( "Twofish code: PUT32 not implemented properly" );
}
/* Test ROL and ROR */
for( i=1; i<32; i++ )
{
/* Just a simple test. */
x = ROR32( C, i );
y = ROL32( C, i );
x ^= (C>>i) ^ (C<<(32-i));
y ^= (C<<i) ^ (C>>(32-i));
x |= y;
/*
* Now all we check is that x is zero in the least significant
* 32 bits. Using the UL suffix is safe here, as it doesn't matter
* if we get a larger type.
*/
if( (x & 0xffffffffUL) != 0 )
{
Twofish_fatal( "Twofish ROL or ROR not properly defined." );
}
}
/* Test the BSWAP macro */
if( BSWAP(C) != 0x12345678UL )
{
/*
* The BSWAP macro should always work, even if you are not using it.
* A smart optimising compiler will just remove this entire test.
*/
Twofish_fatal( "BSWAP not properly defined." );
}
/* And we can test the b<i> macros which use SELECT_BYTE. */
if( (b0(C)!=0x12) || (b1(C) != 0x34) || (b2(C) != 0x56) || (b3(C) != 0x78) )
{
/*
* There are many reasons why this could fail.
* Most likely is that CPU_IS_BIG_ENDIAN has the wrong value.
*/
Twofish_fatal( "Twofish code: SELECT_BYTE not implemented properly" );
}
}
/*
* Finally, we can start on the Twofish-related code.
* You really need the Twofish specifications to understand this code. The
* best source is the Twofish book:
* "The Twofish Encryption Algorithm", by Bruce Schneier, John Kelsey,
* Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson.
* you can also use the AES submission document of Twofish, which is
* available from my list of publications on my personal web site at
* http://niels.ferguson.net/.
*
* The first thing we do is write the testing routines. This is what the
* implementation has to satisfy in the end. We only test the external
* behaviour of the implementation of course.
*/
/*
* Perform a single self test on a (plaintext,ciphertext,key) triple.
* Arguments:
* key array of key bytes
* key_len length of key in bytes
* p plaintext
* c ciphertext
*/
static void test_vector( Twofish_Byte key[], int key_len, Twofish_Byte p[16], Twofish_Byte c[16] )
{
Twofish_Byte tmp[16]; /* scratch pad. */
Twofish_key xkey; /* The expanded key */
int i;
/* Prepare the key */
Twofish_prepare_key( key, key_len, &xkey );
/*
* We run the test twice to ensure that the xkey structure
* is not damaged by the first encryption.
* Those are hideous bugs to find if you get them in an application.
*/
for( i=0; i<2; i++ )
{
/* Encrypt and test */
Twofish_encrypt( &xkey, p, tmp );
if( memcmp( c, tmp, 16 ) != 0 )
{
Twofish_fatal( "Twofish encryption failure" );
}
/* Decrypt and test */
Twofish_decrypt( &xkey, c, tmp );
if( memcmp( p, tmp, 16 ) != 0 )
{
Twofish_fatal( "Twofish decryption failure" );
}
}
/* The test keys are not secret, so we don't need to wipe xkey. */
}
/*
* Check implementation using three (key,plaintext,ciphertext)
* test vectors, one for each major key length.
*
* This is an absolutely minimal self-test.
* This routine does not test odd-sized keys.
*/
static void test_vectors()
{
/*
* We run three tests, one for each major key length.
* These test vectors come from the Twofish specification.
* One encryption and one decryption using randomish data and key
* will detect almost any error, especially since we generate the
* tables ourselves, so we don't have the problem of a single
* damaged table entry in the source.
*/
/* 128-bit test is the I=3 case of section B.2 of the Twofish book. */
static Twofish_Byte k128[] = {
0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32,
0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A,
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -