Unified interface of symmetric encryption algorithms in OpenSSL Copyleft of this document is owned by yfydz. It can be freely copied and reproduced when published using GPL. ensure the integrity of the document during reprinting. It is strictly prohibited for any commercial purposes.
MSN:
Yfydz_no1@hotmail.com
Source:
Http://yfydz.cublog.cn1. Preface OpenSSL is an open-source SSL implementation, which integrates multiple encryption algorithms. OpenSSL encapsulates the uniqueness of each algorithm internally and uses a unified algorithm interface externally. Therefore, external applications only need to specify which algorithm to use, you can call the encryption and decryption functions in the same way without considering the differences. This algorithm is encapsulated in a unified manner in many other software and also provides convenience for algorithm expansion. The following code comes from OpenSSL-0.9.7b. 2. the EVP interface 2.1 Data Structure OpenSSL/crypto/EVP directory defines the Interface source files of various algorithms. All these files need to be done is to fill in the evp_cipher structure that describes the algorithm, each algorithm has an evp_cipher structure to describe: OpenSSL/crypto/EVP. hstruct evp_cipher_st
{
Int NID;
Int block_size;
Int key_len;/* default value for Variable Length ciphers */
Int iv_len;
Unsigned long flags;/* various flags */
INT (* init) (evp_cipher_ctx * CTX, const unsigned char * key,
Const unsigned char * iv, int ENC);/* init key */
INT (* do_cipher) (evp_cipher_ctx * CTX, unsigned char * Out,
Const unsigned char * In, unsigned int INL);/* encrypt/decrypt data */
INT (* cleanup) (evp_cipher_ctx *);/* cleanup CTX */
Int ctx_size;/* How big CTX-> cipher_data needs to be */
INT (* set_asn1_parameters) (evp_cipher_ctx *, asn1_type *);/* populate a asn1_type with parameters */
INT (* get_asn1_parameters) (evp_cipher_ctx *, asn1_type *);/* GET parameters from a asn1_type */
INT (* CTRL) (evp_cipher_ctx *, int type, int Arg, void * PTR);/* miscellaneous operations */
Void * app_data;/* Application Data */
}/* Evp_cipher */; typedef struct evp_cipher_st evp_cipher; NID: ID of the algorithm, which is defined in include/OpenSSL/object. h;
Block_size: the length of the decryption group.
Key_len: Key Length
Iv_len: initial vector Length
Flags: Flag
(* Init): the initialization function that provides keys, IV vectors, algorithm context CTX, encryption or decryption.
(* Do_cipher): encryption and decryption function, which provides the algorithm context CTX, output data, input data, and input data length.
(* Clean_up): Resource release
Ctx_size: The data size of each algorithm, which is actually the key data of each algorithm.
(* Set_asn1_parameters): sets the ASN1 parameter.
(* Get_asn1_parameters): obtains the ASN1 parameter.
(* CTRL): Other control operations
App_data: Another important data structure of algorithm-related data is to describe the context structure evp_cipher_ctx of the encryption algorithm. This structure is provided by the system according to the specified algorithm before entering the algorithm: struct evp_cipher_ctx_st
{
Const evp_cipher * cipher;
Engine * engine;/* functional reference if 'cipher' is engine-provided */
Int encrypt;/* encrypt or decrypt */
Int buf_len;/* number we have left */unsigned char OIV [evp_max_iv_length];/* Original IV */
Unsigned char IV [evp_max_iv_length];/* Working IV */
Unsigned char Buf [evp_max_block_length];/* saved partial block */
Int num;/* used by CFB/ofB mode */void * app_data;/* Application stuff */
Int key_len;/* may change for Variable Length cipher */
Unsigned long flags;/* various flags */
Void * cipher_data;/* per EVP data */
Int final_used;
Int block_mask;
Unsigned char final [evp_max_block_length];/* possible final block */
}/* Evp_cipher_ctx */; typedef struct evp_cipher_ctx_st evp_cipher_ctx; parameter:
Cipher: algorithm pointer
Engine: encryption/Decryption Engine
Encrypt: encryption or decryption
Buf_len: available space
OIV: original initial vector
IV: current initial vector
Buf: Part of the stored block data
Num: the amount of data in the CFB/ofB mode.
App_data: Application-related data
Key_len: Key Length
Flags: Flag
Cipher_data: the Key of each algorithm.
Final_used:
Block_mask: block mask
Final: The last grouping block 1.2.2 algorithm interface each algorithm is to fill in its own evp_cipher structure. Taking RC4 as an example, two evp_cipher structures of RC4 are defined, but the key length is different, one is a 128-bit (16-byte Key), the other is a 40-bit (5-byte Key), and the algorithms are the same: # ifndef openssl_no_rc4 # include <stdio. h>
# Include "cryptlib. H"
# Include <OpenSSL/EVP. h>
# Include <OpenSSL/objects. h>
# Include <OpenSSL/rc4.h>/* fixme: surely this is available elsewhere? */
# Define evp_rc4_key_size 16 // This structure is unique to each encryption algorithm, and each algorithm has its own
// That is, the cipher_data in the evp_cipher_ctx Structure
Typedef struct
{
Rc4_key KS;/* Working key */
} Evp_rc4_key; # define data (CTX) (evp_rc4_key *) (CTX)-> cipher_data) Static int rc4_init_key (evp_cipher_ctx * CTX, const unsigned char * key,
Const unsigned char * iv, int ENC );
Static int rc4_cipher (evp_cipher_ctx * CTX, unsigned char * Out,
Const unsigned char * In, unsigned int INL );
Static const evp_cipher r4_cipher =
{
Nid_rc4,
1, evp_rc4_key_size, 0,
Evp_ciph_variable_length,
Rc4_init_key,
Rc4_cipher,
Null,
Sizeof (evp_rc4_key ),
Null,
Null,
Null
}; Static const evp_cipher r4_40_cipher =
{
Nid_rc4_40,
1, 5/* 40 bit */, 0,
Evp_ciph_variable_length,
Rc4_init_key,
Rc4_cipher,
Null,
Sizeof (evp_rc4_key ),
Null,
Null,
Null
}; // Returns the algorithm structure pointer
Const evp_cipher * evp_rc4 (void)
{
Return (& r4_cipher );
} Const evp_cipher * evp_rc4_40 (void)
{
Return (& r4_40_cipher );
} // Key initialization Function
// CTX: encryption and decryption context; key: key string; IV: initialization vector; ENC: encryption or decryption
Static int rc4_init_key (evp_cipher_ctx * CTX, const unsigned char * key,
Const unsigned char * iv, int ENC)
{
// Key function set by RC4 algorithm
// In general, the key used in the algorithm for encryption and decryption is not the password string entered by the user, because the algorithm
// The key length must be fixed, usually 64-bit or 128-bit, And the password length defined by the user
// You are not sure, so you usually need to change the password entered by the user and map it to a fixed-length key.
//, And then the algorithm uses this key for encryption. Therefore, the key used in the algorithm is generally different from the user's password.
Rc4_set_key (& Data (CTX)-> KS, evp_cipher_ctx_key_length (CTX ),
Key );
Return 1;
} // Encryption/Decryption processing function
// CTX: encryption/Decryption context; Out: output data; In: input data; INL: Input Data Length
Static int rc4_cipher (evp_cipher_ctx * CTX, unsigned char * Out,
Const unsigned char * In, unsigned int INL)
{
RC4 (& Data (CTX)-> KS, INL, in, out );
Return 1;
}
# Endif Add the encryption and decryption algorithm that defines the evp_cipher structure to the system algorithm linked list through the evp_add_cipher () function:
OpenSSL/EVP/c_alle.cvoid openssl_add_all_ciphers (void)
{
......
# Ifndef openssl_no_rc4
Evp_add_cipher (evp_rc4 ());
Evp_add_cipher (evp_rc4_40 ());
# Endif
...... In the future, the external function will call the RC4 algorithm, which is to find the evp_cipher structure pointer of RC4 and perform encryption and decryption after initialization. For example, the OpenSSL command: OpenSSL ENC-RC4-In aaa.txt-out AAA. the execution sequence of ENC is as follows: OpenSSL/apps/OpenSSL. cmain ()-> do_cmd ()-> main () (apps/ENC. c)-> evp_get_cipherbyname (), evp_bytestokey (), bio_set_cipher (), bio_set_cipher-> evp_cipherinit_ex-> CTX-> cipher-> init, the encryption algorithm is pushed to bio as a part of bio, in this way, the corresponding encryption and decryption algorithm is called through direct bio read/write operations. 3. block Encryption Algorithm definition macros have similar encryption and decryption functions for block encryption algorithms, such as AES, cast, and blowfish. OpenSSL also defines a series of macros to simplify the definition of the algorithm, for example, for the blowfish algorithm interface:/* OpenSSL/EVP/e_bf.c */# ifndef openssl_no_bf
# Include <stdio. h>
# Include "cryptlib. H"
# Include <OpenSSL/EVP. h>
# Include "evp_locl.h"
# Include <OpenSSL/objects. h>
# Include <OpenSSL/blowfish. h> static int bf_init_key (evp_cipher_ctx * CTX, const unsigned char * key,
Const unsigned char * iv, int ENC); typedef struct
{
Bf_key KS;
} Evp_bf_key; # define data (CTX) evp_c_data (evp_bf_key, CTX) // defines the macro of the Block Encryption Algorithm
Implement_block_cipher (Bf, KS, BF, evp_bf_key, nid_bf, 8, 16, 8, 64,
Evp_ciph_variable_length, bf_init_key, null,
Evp_cipher_set_asn0000iv, evp_cipher_get_asn0000iv, null) // explicitly, you only need to define an initialization key function.
Static int bf_init_key (evp_cipher_ctx * CTX, const unsigned char * key,
Const unsigned char * iv, int ENC)
{
Bf_set_key (& Data (CTX)-> KS, evp_cipher_ctx_key_length (CTX), key );
Return 1;
} # Endif in OpenSSL/EVP/evp_locl.h, this macro is defined as: # define implement_block_cipher (cname, ksched, cprefix, kstruct, NID ,\
Block_size, key_len, iv_len, cbits ,\
Flags, init_key ,\
Cleanup, set_asn1, get_asn1, CTRL )\
Block_cipher_all_funcs (cname, cprefix, cbits, kstruct, ksched )\
Block_cipher_defs (cname, kstruct, NID, block_size, key_len, iv_len ,\
Cbits, flags, init_key, cleanup, set_asn1 ,\
Get_asn1, CTRL) 1) macro block_cipher_all_funcs: # define block_cipher_all_funcs (cname, cprefix, cbits, kstruct, ksched )\
Block_cipher_func_cbc (cname, cprefix, kstruct, ksched )\
Block_cipher_func_cfb (cname, cprefix, cbits, kstruct, ksched )\
Block_cipher_func_ecb (cname, cprefix, kstruct, ksched )\
Block_cipher_func_ofb (cname, cprefix, cbits, kstruct, ksched) Where block_cipher_func_cbc is defined as: # define block_cipher_func_cbc )\
Static int cname # _ cbc_cipher (evp_cipher_ctx * CTX, unsigned char * Out, const unsigned char * In, unsigned int INL )\
{\
Cprefix # _ cbc_encrypt (In, out, (long) INL, & (kstruct *) CTX-> cipher_data)-> ksched, CTX-> IV, CTX-> encrypt );\
Return 1 ;\
} Note a # define technique: You can use # define to replace the variable or function name. When a parameter is hitting or ending, you can use it after or before the parameter ##; the parameter is in the middle, and the start and end of the parameter are all #; so for the blowfish definition, the macro above actually defines a function: static int bf_cbc_cipher (evp_cipher_ctx * CTX, unsigned char * Out, const unsigned char * In, unsigned int INL)
{
Bf_cbc_encrypt (In, out, (long) INL, & (kstruct *) CTX-> cipher_data)-> ksched, CTX-> IV, CTX-> encrypt );
Return 1;
} Other macro definitions are similar. BF encryption algorithms of different modes are defined, including CBC, CFB, ECB, and ofB. 2) macro block_cipher_defs is used to define the algorithm structure, defined as: # define block_cipher_defs (cname, kstruct ,\
NID, block_size, key_len, iv_len, cbits, flags ,\
Init_key, cleanup, set_asn1, get_asn1, CTRL )\
Block_cipher_def_cbc (cname, kstruct, NID, block_size, key_len, iv_len, flags ,\
Init_key, cleanup, set_asn1, get_asn1, CTRL )\
Block_cipher_def_cfb (cname, kstruct, NID, key_len, iv_len, cbits ,\
Flags, init_key, cleanup, set_asn1, get_asn1, CTRL )\
Block_cipher_def_ofb (cname, kstruct, NID, key_len, iv_len, cbits ,\
Flags, init_key, cleanup, set_asn1, get_asn1, CTRL )\
Block_cipher_def_ecb (cname, kstruct, NID, block_size, key_len, iv_len, flags ,\
Init_key, cleanup, set_asn1, get_asn1, CTRL) Where block_cipher_def_cbc is defined as: # define block_cipher_def_cbc (cname, kstruct, NID, block_size, key_len ,\
Iv_len, flags, init_key, cleanup, set_asn1 ,\
Get_asn1, CTRL )\
Block_cipher_def1 (cname, CBC, kstruct, NID, block_size, key_len ,\
Iv_len, flags, init_key, cleanup, set_asn1, get_asn1, CTRL) and block_cipher_def1 are defined as: # define struct (cname, nmode, mode, mode, kstruct, NID, block_size ,\
Key_len, iv_len, flags, init_key, cleanup ,\
Set_asn1, get_asn1, CTRL )\
Static const evp_cipher cname ##### mode = {\
NID ##### nmode, block_size, key_len, iv_len ,\
Flags | evp_ciph _ # mode ### _ mode ,\
Init_key ,\
Cname ##### mode ###_ cipher ,\
Cleanup ,\
Sizeof (kstruct ),\
Set_asn1, get_asn1 ,\
Ctrl ,\
Null \
};\
Const evp_cipher * EVP _ # cname ##### mode (void) {return & cname #### mode ;} therefore, after the macro block_cipher_def_cbc is expanded, it is the CBC algorithm structure definition of blowfish: static const evp_cipher bf_cbc = {
Nid_bf_cbc, 8, 16, 8,
Evp_ciph_variable_length | evp_ciph_cbc_mode,
Bf_init_key,
Bf_cbc_cipher,
Null,
Sizeof (evp_bf_key ),
Evp_cipher_set_asn1_iv, evp_cipher_get_asn1_iv,
Null,
Null
};
Const evp_cipher * evp_bf_cbc (void) {return & bf_cbc;} several other macro definitions are similar. The evp_cipher data structures of BF encryption algorithms in different modes are defined, including CBC, CFB, ECB, and ofB. 4. Conclusion OpenSSL adopts the unified evp_cipher algorithm structure, which encapsulates various symmetric encryption algorithms and achieves algorithm objectization. 5. The appendix CBC, CFB, ECB, and ofB is not a new encryption algorithm, but an application mode for the encryption algorithm. ECB: electronic code book, electronic cipher book mode, the most basic encryption mode, that is, encryption that is generally understood. The same plaintext will always be encrypted into the same ciphertext without an initial vector, it is vulnerable to password-based replay attacks and is rarely used in general. CBC: Cipher Block Chaining, a cryptographic group link. Before the plaintext is encrypted, it must undergo an exclusive or operation with the ciphertext before encryption. Therefore, you only need to select different initial vectors, the same ciphertext is encrypted to form different ciphertext, which is currently the most widely used mode. The ciphertext after CBC encryption is context-related, but the plaintext errors are not transmitted to subsequent groups. However, if one group is lost, all subsequent groups will be voided (synchronization errors ). CFB: Cipher Feedback, password feedback, similar to the self-synchronous sequence password. After grouping and encryption, the ciphertext and plain text are moved in an eight-bit group, or the output is returned to the shift register at the same time, the advantage is minimal. encryption and decryption can be performed in bytes or N-bit. CFB is also context-related. In CFB mode, an error in plaintext will affect the ciphertext (error spread ). OfB: Output Feedback, output feedback, run the group password as the synchronization sequence password, similar to CFB, but ofB uses the previous N-bit ciphertext output group feedback back to the shift register, ofB is not prone to errors.