📄 aes.h
字号:
#ifndef __AES_H
#define __AES_H
// I retain copyright in this code but I encourage its free use provided
// that I don't carry any responsibility for the results. I am especially
// happy to see it used in free and open source software. If you do use
// it I would appreciate an acknowledgement of its origin in the code or
// the product that results and I would also appreciate knowing a liitle
// about the use to which it is being put.
//
// Dr B. R. Gladman <brg@gladman.uk.net> 23rd January 2001.
// This is an implementation of the AES encryption algorithm (Rijndael)
// designed by Joan Daemen and Vincent Rijmen. This version is designed
// to provide both fixed and dynamic block and key lengths and can also
// run with either big or little endian internal byte order (see aes.h).
// It inputs block and key lengths in bytes with the legal values being
// 16, 24 and 32.
// A. THE CIPHER INTERFACE
//
// byte (an unsigned 8-bit type)
// word (an unsigned 32-bit type)
// rval: (a signed 16 bit type for function return values)
// aes_good (value != 0, a good return)
// aes_bad (value == 0, an error return)
// enum aes_key: (encryption direction)
// enc (set key for encryption)
// dec (set key for decryption)
// both (set key for both)
// class or struct aes (structure for context)
//
// C subroutine calls:
//
// rval set_blk(const word n_bytes, aes *cx) (if block size is variable)
// rval set_key(const byte key[], const word n_bytes, const enum aes_key f, aes *cx)
// rval encrypt(const byte in_blk[], byte out_blk[], const aes *cx)
// rval decrypt(const byte in_blk[], byte out_blk[], const aes *cx)
//
// C++ aes class subroutines:
//
// rval set_blk(const word n_bytes) (if block size is variable)
// rval set_key(const byte key[], const word n_bytes, const aes_key f)
// rval encrypt(const byte in_blk[], byte out_blk[]) const
// rval decrypt(const byte in_blk[], byte out_blk[]) const
//
// The block length inputs to set_block and set_key are in numbers of
// BYTES, not bits. The calls to subroutines must be made in the above
// order but multiple calls can be made without repeating earlier calls
// if their parameters have not changed. If the cipher block length is
// variable but set_blk has not been called before cipher operations a
// value of 16 is assumed (that is, the AES block size). In contrast to
// earlier versions the block and key length parameters are now checked
// for correctness and the encryption and decryption routines test to
// ensure that an appropriate key has been set before their use.
// B. COMPILATION
//
// To compile AES (Rijndael) in C
// a. Rename aes.cpp to aes.c (if necessary) and compile as a C file
// b. Exclude the AES_DLL define in aes.h
// c. Disable the AES_IN_CPP define in aes.h
//
// To compile AES (Rijndael) in C++
// a. Rename aes.c to aes.cpp (if necessary) and compile as a C++ file
// b. Exclude the AES_DLL define in aes.h
// c. Enable the AES_IN_CPP define in aes.h
//
// To compile AES (Rijndael) in C as a Dynamic Link Library
// a. Rename aes.cpp to aes.c (if necessary) and compile as a C file
// c. Include the AES_DLL define in aes.h
// c. Disable the AES_IN_CPP define in aes.h
// d. Compile the DLL. If using the test files, exclude aes.c and
// aes.cpp from the test build project and compile it with same
// defines used for the DLL. Ensure that the DLL path section G
// below points to correct DLL directory.
//
// Note that parts of this header file can be removed if the testing code
// is not being used or if only the C or the C++ implementation is used.
#define BIG_ENDIAN 1 // do not change
#define LITTLE_ENDIAN 2 // do not change
// C. CONFIGURATION OPTIONS (see also aes.c and/or aes.cpp)
// 1. define BLOCK_SIZE_R to set the cipher block size (16, 24 or 32) or
// leave this undefined for dynamically variable block size (this will
// result in much slower code).
// 2. set AES_IN_CPP to compile in C++ rather than C (this define may
// also occur in aes.c and aes.cpp).
// 3. set AES_DLL if AES (Rijndael) is to be compiled to a DLL
// 4. set INTERNAL_BYTE_ORDER to one of the above constants to set the
// internal byte order (the order used within the algorithm code)
// 5. set EXTERNAL_BYTE_ORDER to one of the above constants to set the byte
// order used at the external interfaces for the input, output and key
// byte arrays.
// IMPORTANT NOTE: BLOCK_SIZE_R is in BYTES (16, 24, 32 or undefined). If left
// undefined a slower version providing variable block length is compiled
#define BLOCK_SIZE_R 16
//#define AES_IN_CPP
//#define AES_DLL
#define INTERNAL_BYTE_ORDER LITTLE_ENDIAN
#define EXTERNAL_BYTE_ORDER LITTLE_ENDIAN
// End of configuration options, but see also aes.c, aes.cpp and sections G.
// D, COMMON C AND C++ DEFINITIONS
typedef unsigned char byte; // must be an 8-bit storage unit
typedef unsigned int word; // must be a 32-bit storage unit
typedef short int rval; // function return type
#define aes_good 1 // return value after success
#define aes_bad 0 // return value after failure
// rot1 changes [b0,b1,b2,b3] to [b3,b0,b1,b2]
// rot2 changes [b0,b1,b2,b3] to [b2,b3,b0,b1]
// rot3 changes [b0,b1,b2,b3] to [b1,b2,b3,b0]
#if(INTERNAL_BYTE_ORDER == LITTLE_ENDIAN)
// Circular byte rotates of 32-bit words
#if defined(_MSC_VER) // non-portable but gives a small gain in speed
#include <stdlib.h>
#pragma intrinsic(_lrotr,_lrotl)
#define rot1(x) _lrotl(x, 8)
#define rot2(x) _lrotl(x,16)
#define rot3(x) _lrotl(x,24)
#else
#define rot1(x) (((x) << 8) | ((x) >> 24))
#define rot2(x) (((x) << 16) | ((x) >> 16))
#define rot3(x) (((x) << 24) | ((x) >> 8))
#endif
// Extract bytes from a 32-bit words
#define byte0(x) ((byte) (x))
#define byte1(x) ((byte)((x) >> 8))
#define byte2(x) ((byte)((x) >> 16))
#define byte3(x) ((byte)((x) >> 24))
#define bytes2word(b0, b1, b2, b3) ((word)(b3) << 24 | (word)(b2) << 16 | (word)(b1) << 8 | (b0))
// Invert byte order in a 32 bit variable
#define byte_swap(x) (rot1(x) & 0x00ff00ff | rot3(x) & 0xff00ff00)
#else
// Circular byte rotates of 32-bit words
#define rot3(x) (((x) << 8) | ((x) >> 24))
#define rot2(x) (((x) << 16) | ((x) >> 16))
#define rot1(x) (((x) << 24) | ((x) >> 8))
// Extract bytes from a 32-bit words
#define byte3(x) ((byte) (x))
#define byte2(x) ((byte)((x) >> 8))
#define byte1(x) ((byte)((x) >> 16))
#define byte0(x) ((byte)((x) >> 24))
#define bytes2word(b0, b1, b2, b3) \
((word)(b0) << 24 | (word)(b1) << 16 | (word)(b2) << 8 | (b3))
// Invert byte order in a 32 bit variable
#define byte_swap(x) (rot3(x) & 0x00ff00ff | rot1(x) & 0xff00ff00)
#endif
#if(INTERNAL_BYTE_ORDER == EXTERNAL_BYTE_ORDER)
#define word_in(x) *(word*)(x)
#define word_out(x,v) *(word*)(x) = (v)
#else
#define word_in(x) byte_swap(*(word*)(x))
#define word_out(x,v) *(word*)(x) = byte_swap(v)
#endif
enum aes_const
{
Nrow = 4, // the number of rows in the cipher state
Mcol = 8, // maximum number of columns in the state
Mkbl = 15, // maximum number of key schedule blocks
#if defined(BLOCK_SIZE_R) // set up a statically defined block size
Ncol = BLOCK_SIZE_R / 4,
Shr1 = 1, // the cyclic shift values for rows 1, 2 & 3
Shr2 = BLOCK_SIZE_R == 32 ? 3 : 2,
Shr3 = BLOCK_SIZE_R == 32 ? 4 : 3
#endif
};
enum aes_key
{
enc = 1, // set if encryption is needed
dec = 2, // set if decryption is needed
both = 3, // set if both are needed
};
#if defined(AES_IN_CPP) // AES (Rijndael) compiled in C++
// E. DEFINITIONS FOR C++ IMPLEMENTATION
class aes
{
private:
word Nkey; // the number of words in the key input block
word Nrnd; // the number of cipher rounds
#if !defined(BLOCK_SIZE_R)
word Ncol; // the number of columns in the cipher state
byte shf1[8]; // row 1 forward shift table
byte shf2[8]; // row 2 forward shift table
byte shf3[8]; // row 3 forward shift table
byte shr1[8]; // row 1 reverse shift table
byte shr2[8]; // row 2 reverse shift table
byte shr3[8]; // row 3 reverse shift table
word e_key[128]; // the encryption key schedule
word d_key[128]; // the decryption key schedule
#else
word e_key[4 * BLOCK_SIZE_R]; // the encryption key schedule
word d_key[4 * BLOCK_SIZE_R]; // the decryption key schedule
#endif
byte mode; // encrypt, decrypt or both
public:
#if !defined(BLOCK_SIZE_R)
aes(word n_bytes = 4) : mode(0)
{
set_blk(n_bytes);
};
rval set_blk(const word n_bytes);
#endif
rval set_key(const byte key[], const word n_bytes, const aes_key f);
rval _encrypt(const byte in_blk[], byte out_blk[]) const;
rval _decrypt(const byte in_blk[], byte out_blk[]) const;
};
#else
// F. DEFINITIONS FOR C IMPLEMENTATION
#if defined(__cplusplus)
extern "C"
{
#endif
typedef struct // note that Nkey = key_len_in_bits / 32
{
word Nkey; // the number of words in the key input block
word Nrnd; // the number of cipher rounds
#if !defined(BLOCK_SIZE_R)
word Ncol; // the number of columns in the cipher state
byte shf1[8]; // row 1 forward shift table
byte shf2[8]; // row 2 forward shift table
byte shf3[8]; // row 3 forward shift table
byte shr1[8]; // row 1 reverse shift table
byte shr2[8]; // row 2 reverse shift table
byte shr3[8]; // row 3 reverse shift table
word e_key[128]; // the encryption key schedule
word d_key[128]; // the decryption key schedule
#else
word e_key[4 * BLOCK_SIZE_R]; // the encryption key schedule
word d_key[4 * BLOCK_SIZE_R]; // the decryption key schedule
#endif
byte mode; // encrypt, decrypt or both
} aes;
// _stdcall is needed for Visual Basic DLLs but is not necessary for C/C++
#if defined(AES_DLL)
#define cf_dec rval __declspec(dllexport) _stdcall
#else
#define cf_dec rval
#endif
cf_dec set_key(const byte key[], const word n_bytes, const enum aes_key f, aes *cx);
cf_dec _encrypt(const byte in_blk[], byte out_blk[], const aes *cx);
cf_dec _decrypt(const byte in_blk[], byte out_blk[], const aes *cx);
cf_dec set_blk(const word n_bytes, aes *cx);
#if defined(__cplusplus)
};
#endif
#endif // defined(AES_IN_CPP)
// G. DEFINITIONS FOR TESTING ONLY
// The following definitions are required for testing only, They are not needed
// for AES (Rijndael) implementation. They are used to allow C, C++ and DLL
// data acesses and subroutine calls to be expressed in the same form in the
// testing code.
#define ref_path "..\\testvals\\" // path for test vector files
#define out_path "..\\outvals\\" // path for output files
#define dll_path "..\\aes_dll\\release\\aes" // path for DLL
#if defined(AES_IN_CPP)
#define f_dat(a,b) (b)
#define f_set_key(a,b,c,d) (a)->set_key((b),(c),(d))
#define f_encrypt(a,b,c) (a)->encrypt((b),(c))
#define f_decrypt(a,b,c) (a)->decrypt((b),(c))
#define f_set_blk(a,b) (a)->set_blk((b))
#elif !defined(AES_DLL)
#define f_dat(a,b) (a->b)
#define f_set_key(a,b,c,d) set_key((b),(c),(d),(a))
#define f_encrypt(a,b,c) _encrypt((b),(c),(a))
#define f_decrypt(a,b,c) _decrypt((b),(c),(a))
#define f_set_blk(a,b) set_blk((b),(a))
#else
typedef cf_dec f_ky(const byte key[], const word klen, const enum aes_key mode, aes *ctx);
typedef cf_dec f_ed(const byte in_blk[], byte out_blk[], const aes *ctx);
typedef cf_dec f_bl(const word blen, aes *ctx);
typedef struct // initialised with subroutine addresses when the DLL is loaded
{
f_ky *fn_set_key;
f_ed *fn_encrypt;
f_ed *fn_decrypt;
f_bl *fn_set_blk;
} fn_ptrs;
#define f_dat(a,b) (a->b)
#define f_set_key(a,b,c,d) (fn.fn_set_key)((b),(c),(d),(a))
#define f_encrypt(a,b,c) (fn.fn_encrypt)((b),(c),(a))
#define f_decrypt(a,b,c) (fn.fn_decrypt)((b),(c),(a))
#define f_set_blk(a,b) (fn.fn_set_blk)((b),(a))
#endif
#endif //__AES_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -