How to Integrate a Symmetric Cipher
This page serves to provide a guideline on how to integrate a symmetric block cipher into OpenSSL 1.1.1. This integration procedure will cover all aspects of integration for both libcrypto and libssl. ARIA will be used as the example cipher throughout. ARIA is a basic C implementation without the extra complexity of assembly optimization and lacking support for some of the more complex chaining modes.
Create the Cipher
All cryptographic functions are stored within the crypto/ directory and this is where ARIA's cipher will be implemented. To begin, create the directory.
mkdir crypto/aria
Now that the directory is created, the creation of the cipher can begin by opening:
vi crypto/aria/aria.c
You need to define two functions to do the lowest level encryption and decryption, although for ARIA they are both the same and only the first was actually defined:
void ARIA_encrypt(const unsigned char *in, unsigned char *out, const ARIA_KEY *key) void ARIA_decrypt(const unsigned char *in, unsigned char *out, const ARIA_KEY *key)
Secondly, in the case of ARIA, you must also provide functions to set the encryption and decryption keys:
int ARIA_set_encrypt_key(const unsigned char *userKey, const int bits, ARIA_KEY *key) int ARIA_set_decrypt_key(const unsigned char *userKey, const int bits, ARIA_KEY *key)
To prototype these functions you may create an aria_locl.h within crypto/aria/, however, the current preferred method is to prototype these functions in crypto/include/internal/aria.h. The prototyped functions contained within crypto/include/internal/aria.h can then be included by:
#include "internal/aria.h"
The last step in ARIA's low level implementation is to create a build.info file. This tells the Configure file in the root directory of OpenSSL on how to compile the files in ARIA's directory and configure the OpenSSL's library Makefile. The following is a simple example:
LIBS=../../libcrypto SOURCE[../../libcrypto]=\ aria.c
In short, this tells Configure that the code contained within aria.c, relies on code contained within the rest of the libcrypto library and include ARIA in libcrypto. For further guidance on creating more complex build.info files please view the README file contained within the Configurations directory or view other cipher's implementations. For assembly optimized versions, there is a lot more involved and is beyond the scope of this guide. This impacts not only the cryptographic implementation but also the EVP layer.
Changes to the Configuration
At this point the low level interface for ARIA has been implemented but we still need to modify the config and Configure files. This is necessary to have Configure recognize the build.info file previously created and the ability to detect an enable-aria flag.
Changes to config
The config file requires the ability to detect an enable-aria flag which is done by adding aria to the argument of a for loop:
for i in aes aria bf camellia cast des dh dsa ec hmac idea md2 md5 mdc2 rc2 rc4 rc5 ripemd rsa seed sha do if [ ! -d $THERE/crypto/$i ] then options="$options no-$i" fi done
Changes to Configure
The following will include ARIA when Configure searches for a build.info file.
$config{sdirs} = [ "objects", "md2", "md4", "md5", "sha", "mdc2", "hmac", "ripemd", "whrlpool", "poly1305", "blake2", "siphash", "des", "aes", "rc2", "rc4", "rc5", "idea", "aria", "bf", "cast", "camellia", "seed", "chacha", "modes", "bn", "ec", "rsa", "dsa", "dh", "dso", "engine", "buffer", "bio", "stack", "lhash", "rand", "err", "evp", "asn1", "pem", "x509", "x509v3", "conf", "txt_db", "pkcs7", "pkcs12", "comp", "ocsp", "ui", "cms", "ts", "srp", "cmac", "ct", "async", "kdf" ];
The following steps are optional if you would like to have the cipher be disabled, should someone compiling choose to do so. Start by including ARIA to the disables table.
my @disablables = ( "afalgeng", "aria", "asan", "asm", "async",
Then, have ARIA disabled by default:
our %disabled = ( # "what" => "comment" "aria" => "default", "asan" => "default", "crypto-mdebug" => "default",
EVP Interface Integration
In short, the EVP provides a programmer with a high level interface to easily interact with low level OpenSSL cryptographic functions. A crypto/evp/e_aria.c file must be created to branch the gap between the high level EVP and the newly created ARIA cipher. At the bare minimum the file will include:
- Key struct
- EVP_CIPHER struct
- Naming the EVP_CIPHER
- Key Initialization Function
- Cipher Initialization Function
Key Structure
The structure of the key is up to the developer implementing the cipher.
/* ARIA subkey Structure */ typedef struct { ARIA_KEY ks; } EVP_ARIA_KEY;
This is a very simple example but this structure will include all necessary key material for both the encrypt and decrypt functions. It is also possible to include a function pointer in this struct to control whether the key is being used for encryption or decryption. This will be further explained below.
EVP_CIPHER struct
The following is the definition of an EVP_CIPHER struct found in crypto/crypto/include/internal/evp_int.h:
struct evp_cipher_st { int nid; int block_size; /* Default value for variable length ciphers */ int key_len; int iv_len; /* Various flags */ unsigned long flags; /* init key */ int (*init) (EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc); /* encrypt/decrypt data */ int (*do_cipher) (EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl); /* cleanup ctx */ int (*cleanup) (EVP_CIPHER_CTX *); /* how big ctx->cipher_data needs to be */ int ctx_size; /* Populate a ASN1_TYPE with parameters */ int (*set_asn1_parameters) (EVP_CIPHER_CTX *, ASN1_TYPE *); /* Get parameters from a ASN1_TYPE */ int (*get_asn1_parameters) (EVP_CIPHER_CTX *, ASN1_TYPE *); /* Miscellaneous operations */ int (*ctrl) (EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Application data */ void *app_data; } /* EVP_CIPHER */ ;
The ARIA EVP_CIPHER struct uses C preprocessor techniques to dynamically create the EVP_CIPHER struct and is outside the scope of this guide. Instead, the RC4 EVP_CIPHER struct is much easier to follow and mimic.
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, NULL };
Notice the function pointers rc4_init_key and rc4_cipher as these are the functions to create the key and run the cipher respectively.
Naming the EVP_CIPHER
Again, since ARIA uses C preprocessor techniques to dynamically create the names of each of the modes of operation, we will take a look at RC4's implmentation as it is very easy to understand.
const EVP_CIPHER *EVP_rc4(void) { return (&r4_cipher); }
Notice the name in this example is EVP_rc4() and r4_cipher is the name of the cipher initialization function.
Key Initialization Function
The following initializes the key for ARIA depending on the mode the user requests through the EVP interface.
static int aria_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) { int ret; int mode = EVP_CIPHER_CTX_mode(ctx); if (mode==EVP_CIPH_CFB_MODE||mode==EVP_CIPH_OFB_MODE||enc) ret = ARIA_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, EVP_CIPHER_CTX_get_cipher_data(ctx)); else ret = ARIA_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, EVP_CIPHER_CTX_get_cipher_data(ctx)); if(ret < 0) { EVPerr(EVP_F_ARIA_INIT_KEY,EVP_R_ARIA_KEY_SETUP_FAILED); return 0; } return 1; }
An alternative approach is to use the enc parameter to determine whether the key is being used for encryption or decryption. The value of 1 for enc is encryption and 0 for decryption.
Cipher Initialization Function
Once the key has been created, the EVP will then call the cipher initialization function assigned in the EVP_CIPHER struct. This function will pass the parameters to the low level implementation of ARIA.
static void aria_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t len, const ARIA_KEY *key, unsigned char *ivec, const int enc) { if (enc) CRYPTO_cbc128_encrypt(in, out, len, key, ivec, (block128_f) aria_encrypt); else CRYPTO_cbc128_decrypt(in, out, len, key, ivec, (block128_f) aria_encrypt); }
Another approach is to assign a function pointer in the creation of the key as to whether an encrypt or decrypt routine is about to happen using the enc parameter.
/* EVP_CIPHER struct */ typedef struct { MYKEY k; union { void (*cipher) (MYKEY *k, size_t len, const unsigned char *in, unsigned char *out); } stream; } EVP_MYCIPHER_KEY;
/* Key Initialization Function */ static int mycipher_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) { enc ? mycipher_enc_set_key(&data(ctx)->k) : mycipher_dec_set_key(&data(ctx)->k); data(ctx)->stream.cipher = enc ? encrypt_mycipher : decrypt_mycipher; return 1; }
/* Cipher Initialization Function */ static int mycipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl) { (*data(ctx)->stream.cipher) (&data(ctx)->k, inl, in, out); return 1; }
Once completed, add e_aria.c into crypto/evp's build.info file.
LIBS=../../libcrypto SOURCE[../../libcrypto]=\ encode.c digest.c evp_enc.c evp_key.c evp_cnf.c \ e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c\ e_rc4.c e_aes.c names.c e_seed.c e_aria.c \
Now that e_aria.c has been built, we have to register it with the EVP subsystem. Modify crypto/evp/c_allc.c to register ARIA.
#ifndef OPENSSL_NO_ARIA EVP_add_cipher(EVP_aria_128_ecb()); EVP_add_cipher(EVP_aria_128_cbc()); EVP_add_cipher(EVP_aria_128_cfb()); EVP_add_cipher(EVP_aria_128_cfb1()); EVP_add_cipher(EVP_aria_128_cfb8()); EVP_add_cipher(EVP_aria_128_ofb()); EVP_add_cipher_alias(SN_aria_128_cbc, "ARIA128"); EVP_add_cipher_alias(SN_aria_128_cbc, "aria128"); EVP_add_cipher(EVP_aria_192_ecb()); EVP_add_cipher(EVP_aria_192_cbc()); EVP_add_cipher(EVP_aria_192_cfb()); EVP_add_cipher(EVP_aria_192_cfb1()); EVP_add_cipher(EVP_aria_192_cfb8()); EVP_add_cipher(EVP_aria_192_ofb()); EVP_add_cipher_alias(SN_aria_192_cbc, EVP_add_cipher_alias(SN_aria_192_cbc, EVP_add_cipher(EVP_aria_256_ecb()); EVP_add_cipher(EVP_aria_256_cbc()); EVP_add_cipher(EVP_aria_256_cfb()); EVP_add_cipher(EVP_aria_256_cfb1()); EVP_add_cipher(EVP_aria_256_cfb8()); EVP_add_cipher(EVP_aria_256_ofb()); EVP_add_cipher_alias(SN_aria_256_cbc, EVP_add_cipher_alias(SN_aria_256_cbc, #endif
This adds all of the cipher chaining modes that were provided by the e_aria.c files except for CTR mode. It also includes some aliases for the CBC modes. ARIA also has some optional but recommended custom error messages. These are added to the crypto/evp/evp_err.c file:
static ERR_STRING_DATA EVP_str_functs[] = { ... {ERR_FUNC(EVP_F_ARIA_INIT_KEY), "aria_init_key"},
and
static ERR_STRING_DATA EVP_str_reasons[] = { ... {ERR_REASON(EVP_R_ARIA_KEY_SETUP_FAILED), "aria key setup failed"},
Crypto Objects
Crypto object IDs are used to map a name to a given ARIA cipher mode. To add object Ids for the ARIA suite, the crypto/objects/objects.txt file must be modified:
!Alias aria 1 2 410 200046 1 1 aria 1 : ARIA-128-ECB : aria-128-ecb aria 2 : ARIA-128-CBC : aria-128-cbc !Cname aria-128-cfb128 aria 3 : ARIA-128-CFB : aria-128-cfb !Cname aria-128-ofb128 aria 4 : ARIA-128-OFB : aria-128-ofb aria 5 : ARIA-128-CTR : aria-128-ctr aria 6 : ARIA-192-ECB : aria-192-ecb aria 7 : ARIA-192-CBC : aria-192-cbc !Cname aria-192-cfb128 aria 8 : ARIA-192-CFB : aria-192-cfb !Cname aria-192-ofb128 aria 9 : ARIA-192-OFB : aria-192-ofb aria 10 : ARIA-192-CTR : aria-192-ctr aria 11 : ARIA-256-ECB : aria-256-ecb aria 12 : ARIA-256-CBC : aria-256-cbc !Cname aria-256-cfb128 aria 13 : ARIA-256-CFB : aria-256-cfb !Cname aria-256-ofb128 aria 14 : ARIA-256-OFB : aria-256-ofb aria 15 : ARIA-256-CTR : aria-256-ctr # There are no OIDs for these ARIA modes... : ARIA-128-CFB1 : aria-128-cfb1 : ARIA-192-CFB1 : aria-192-cfb1 : ARIA-256-CFB1 : aria-256-cfb1 : ARIA-128-CFB8 : aria-128-cfb8 : ARIA-192-CFB8 : aria-192-cfb8 : ARIA-256-CFB8 : aria-256-cfb8
For more elaborate documentation inserting entries into crypto/objects/objects.txt, view the README file under crypto/objects/. Note that you must also run make update to automatically generate crypto/objects/obj_dat.h and crypto/objects/obj_mac.num.
Update Headers
evp.h
To begin, the include/openssl/evp.h header requires three changes. Firstly, ARIA's modes must be added:
# ifndef OPENSSL_NO_ARIA const EVP_CIPHER *EVP_aria_128_ecb(void); const EVP_CIPHER *EVP_aria_128_cbc(void); const EVP_CIPHER *EVP_aria_128_cfb1(void); const EVP_CIPHER *EVP_aria_128_cfb8(void); const EVP_CIPHER *EVP_aria_128_cfb128(void); # define EVP_aria_128_cfb EVP_aria_128_cfb128 const EVP_CIPHER *EVP_aria_128_ofb(void); ... const EVP_CIPHER *EVP_aria_256_ofb(void); # endif
This is the name of the EVP_CIPHER created in e_aria.c. Secondly, we must add in the optional but recommended failure and reason codes:
# define EVP_F_ARIA_INIT_KEY 168
and
# define EVP_R_ARIA_KEY_SETUP_FAILED 163
ssl.h
/include/openssl/ssl.h needs the string names to be later used in the ARIA cipher suites.
# define SSL_TXT_ARIA128 "ARIA128" # define SSL_TXT_ARIA256 "ARIA256" # define SSL_TXT_ARIA "ARIA"
tls1.h
/include/openssl/tls1.h is where ARIA's cipher suite signatures will be defined. These come directly from RFC6209:
/* ARIA based ciphersuites from RFC6209 */ # define TLS1_CK_RSA_WITH_ARIA_128_CBC_SHA256 0x0300C03C # define TLS1_CK_RSA_WITH_ARIA_256_CBC_SHA384 0x0300C03D ... # define TLS1_CK_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 0x0300C071
It is important to note that this is where the key exchange, authentication, and MAC algorithms can be chosen by name and later implemented in s3_lib.c. Once the signatures are defined, the text representations need to be defined:
/* ARIA based ciphersuites from RFC6209 */ # define TLS1_TXT_RSA_WITH_ARIA_128_CBC_SHA256 "ARIA128-CBC-SHA256" # define TLS1_TXT_RSA_WITH_ARIA_256_CBC_SHA384 "ARIA256-CBC-SHA384" ... # define TLS1_TXT_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 "ECDHE-PSK-ARIA256-CBC-SHA384"
TLS
tls1.h
/include/openssl/tls1.h is where ARIA's cipher suite signatures will be defined. These come directly from RFC6209:
/* ARIA based ciphersuites from RFC6209 */ # define TLS1_CK_RSA_WITH_ARIA_128_CBC_SHA256 0x0300C03C # define TLS1_CK_RSA_WITH_ARIA_256_CBC_SHA384 0x0300C03D ... # define TLS1_CK_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 0x0300C071
It is important to note that this is where the key exchange, authentication, and MAC algorithms can be chosen by name and later implemented in s3_lib.c. Once the signatures are defined, the text representations need to be defined:
/* ARIA based ciphersuites from RFC6209 */ # define TLS1_TXT_RSA_WITH_ARIA_128_CBC_SHA256 "ARIA128-CBC-SHA256" # define TLS1_TXT_RSA_WITH_ARIA_256_CBC_SHA384 "ARIA256-CBC-SHA384" ... # define TLS1_TXT_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 "ECDHE-PSK-ARIA256-CBC-SHA384"
ssl.h
/include/openssl/ssl.h needs the string names to be later used in the ARIA cipher suites.
# define SSL_TXT_ARIA128 "ARIA128" # define SSL_TXT_ARIA256 "ARIA256" # define SSL_TXT_ARIA "ARIA"
s3_lib.c
To use ARIA with TLS, it is necessary to define the suite combinations that are legal as per the various standards. These are defined in the ssl/s3_lib.c file. In all cases the security level is considered high, the suite is not a default, and is supported only in TLS 1.2.
#ifndef OPENSSL_NO_ARIA { 1, TLS1_TXT_RSA_WITH_ARIA_128_CBC_SHA256, TLS1_CK_RSA_WITH_ARIA_128_CBC_SHA256, SSL_kRSA, SSL_aRSA, SSL_ARIA128, SSL_SHA256, TLS1_2_VERSION, TLS1_2_VERSION, DTLS1_2_VERSION, DTLS1_2_VERSION, SSL_NOT_DEFAULT | SSL_HIGH, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128, }, { 1, TLS1_TXT_RSA_WITH_ARIA_256_CBC_SHA384, TLS1_CK_RSA_WITH_ARIA_256_CBC_SHA384, SSL_kRSA, SSL_aRSA, SSL_ARIA256, SSL_SHA384, TLS1_2_VERSION, TLS1_2_VERSION, DTLS1_2_VERSION, DTLS1_2_VERSION, SSL_NOT_DEFAULT | SSL_HIGH, SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, 256, 256, }, ... { 1, TLS1_TXT_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, TLS1_CK_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, SSL_kECDHEPSK, SSL_aPSK, SSL_ARIA256, SSL_SHA384, TLS1_2_VERSION, TLS1_2_VERSION, DTLS1_2_VERSION, DTLS1_2_VERSION, SSL_NOT_DEFAULT | SSL_HIGH, SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, 256, 256, }, # endif /* OPENSSL_NO_EC */ # endif /* OPENSSL_NO_PSK */ #endif /* OPENSSL_NO_ARIA */
It is critical to note that if the cipher suite implementation uses eliptical curve (EC) for instance, that the cipher suite implementation is inside the OPENSSL_NO_EC preprocessor directives.
ssl_ciph.c
The ssl/ssl_ciph.c file needs indices for the ARIA ciphers available from TLS. In the initial table of #defines:
#define SSL_ENC_ARIA128_IDX 20 #define SSL_ENC_ARIA256_IDX 21 #define SSL_ENC_NUM_IDX 22
Later in the ssl_cipher_table_cipher table of NIDs for each cipher:
{SSL_ARIA128, NID_aria_128_cbc}, /* SSL_ENC_ARIA128_IDX 20 */ {SSL_ARIA256, NID_aria_256_cbc} /* SSL_ENC_ARIA256_IDX 21 */
This maps libssl's request of ARIA to ARIA's respective NID value which will later be looked up to dive into ARIA's implementation within libcrypto. This can be seen as bridging the gap between libssl and libcrypto. To continue, alias's must be created for the cipher suite:
{0, SSL_TXT_ARIA128, 0, 0, 0, SSL_ARIA128, 0, 0, 0, 0, 0, 0}, {0, SSL_TXT_ARIA256, 0, 0, 0, SSL_ARIA256, 0, 0, 0, 0, 0, 0}, {0, SSL_TXT_ARIA, 0, 0, 0, SSL_ARIA128 | SSL_ARIA256, 0, 0, 0, 0, 0, 0},
Lastly, add ARIA's description into the switch statement within the SSL_CIPHER_description function:
case SSL_ARIA128: enc = "ARIA(128)"; break; case SSL_ARIA256: enc = "ARIA(256)"; break;
ssl/ssl_init.c
The ssl/ssl_init.c function needs to conditionally register the ARIA ciphers and can be inserted along with the other ciphers:
#ifndef OPENSSL_NO_ARIA EVP_add_cipher(EVP_aria_128_cbc()); EVP_add_cipher(EVP_aria_256_cbc()); #endif #ifndef OPENSSL_NO_DES EVP_add_cipher(EVP_des_cbc()); EVP_add_cipher(EVP_des_ede3_cbc()); #endif
ssl/ssl_locl.h
This file contains the bits for SSL_ARIA as well as the group definition:
# define SSL_ARIA128 0x00100000L # define SSL_ARIA256 0x00200000L # define SSL_ARIA (SSL_ARIA128|SSL_ARIA256)
ssl/t1_trce.c
Finally, the ssl/t1_trce.c file contains a table of the protocol numbers and text descriptions for all legal TLS protocols. If your cipher suites are not already present in this file, they should be added to it. This step proved unnecessary for ARIA because the required definitions were already present.
Unit Testing
OpenSSL has a built in test suite that can be leveraged for ARIA. The test/evptests.txt unit test vectors for ARIA need to be added:
# ARIA test vectors from RFC5794 Cipher = ARIA-128-ECB Key = 000102030405060708090a0b0c0d0e0f Operation = ENCRYPT Plaintext = 00112233445566778899aabbccddeeff Ciphertext = d718fbd6ab644c739da95f3be6451778 Cipher = ARIA-128-ECB Key = 000102030405060708090a0b0c0d0e0f Operation = DECRYPT Plaintext = 00112233445566778899aabbccddeeff Ciphertext = d718fbd6ab644c739da95f3be6451778 Cipher = ARIA-192-ECB Key = 000102030405060708090a0b0c0d0e0f1011121314151617 Operation = ENCRYPT Plaintext = 00112233445566778899aabbccddeeff Ciphertext = 26449c1805dbe7aa25a468ce263a9e79 Cipher = ARIA-192-ECB Key = 000102030405060708090a0b0c0d0e0f1011121314151617 Operation = DECRYPT Plaintext = 00112233445566778899aabbccddeeff Ciphertext = 26449c1805dbe7aa25a468ce263a9e79 Cipher = ARIA-256-ECB Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f Operation = ENCRYPT Plaintext = 00112233445566778899aabbccddeeff Ciphertext = f92bd7c79fb72e2f2b8f80c1972d24fc Cipher = ARIA-256-ECB Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f Operation = DECRYPT Plaintext = 00112233445566778899aabbccddeeff Ciphertext = f92bd7c79fb72e2f2b8f80c1972d24fc
These values are pulled from ARIA'a RFC and others can be added if desired. Once the integration is complete with the remaining steps below, the test suite can be ran with make test.
Utilities
In util/mkdir.pl ARIA must be added to the list of known_algorithms and the include path to the ARIA header file added (unless no_aria) is defined:
$crypto.=" include/openssl/aria.h" ; # unless $no_aria;
Applications
The apps/openssl.c needs to be able to print that it does not support ARIA via the list_disabled function:
#ifdef OPENSSL_NO_ARIA BIO_puts(bio_out, "ARIA\n"); #endif
The apps/progs.h needs the available cipher definitions included in the functions array:
#ifndef OPENSSL_NO_ARIA { FT_cipher, "aria-128-cbc", enc_main, enc_options }, #endif #ifndef OPENSSL_NO_ARIA { FT_cipher, "aria-128-ecb", enc_main, enc_options }, #endif #ifndef OPENSSL_NO_ARIA { FT_cipher, "aria-192-cbc", enc_main, enc_options }, #endif #ifndef OPENSSL_NO_ARIA { FT_cipher, "aria-192-ecb", enc_main, enc_options }, #endif #ifndef OPENSSL_NO_ARIA { FT_cipher, "aria-256-cbc", enc_main, enc_options }, #endif #ifndef OPENSSL_NO_ARIA { FT_cipher, "aria-256-ecb", enc_main, enc_options }, #endif
The apps/progs.pl program needs to know about the ARIA cipher:
"aria-128-cbc", "aria-128-ecb", "aria-192-cbc", "aria-192-ecb", "aria-256-cbc", "aria-256-ecb",
Speed Test
It is possible to natively integrate ARIA into OpenSSL's built in speed test, however, once a cipher is integrated into the EVP the speed test can access the cipher using the -evp flag. For completeness sake, the following steps are necessary to manually integrated ARIA into OpenSSL's speedtest.
First the ARIA header file needs to be conditionally included:
#ifndef OPENSSL_NO_ARIA # include <openssl/aria.h> #endif
The number of algorithms increased:
#define ALGOR_NUM 33
The algorithms themselves defined in the names array:
"aria-128 cbc", "aria-192 cbc", "aria-256 cbc"
The speed_options indicies defined:
#define D_CBC_128_ARIA 30 #define D_CBC_192_ARIA 31 #define D_CBC_256_ARIA 32
The doit_choices text mapping defined:
#ifndef OPENSSL_NO_ARIA {"aria-128-cbc", D_CBC_128_ARIA}, {"aria-192-cbc", D_CBC_192_ARIA}, {"aria-256-cbc", D_CBC_256_ARIA}, #endif
The initialisation key vectors defined:
#ifndef OPENSSL_NO_ARIA static const unsigned char akey24[24] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34 }; static const unsigned char akey32[32] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56 }; ARIA_KEY aria_ks1, aria_ks2, aria_ks3; #endif
The command line processing adjusted:
# ifndef OPENSSL_NO_ARIA if (strcmp(*argv, "aria") == 0) { doit[D_CBC_128_ARIA] = doit[D_CBC_192_ARIA] = doit[D_CBC_256_ARIA] = 1; continue; } # endif
Keys are set:
# ifndef OPENSSL_NO_ARIA ARIA_set_encrypt_key(key16, 128, &aria_ks1); ARIA_set_encrypt_key(akey24, 192, &aria_ks2); ARIA_set_encrypt_key(akey32, 256, &aria_ks3); # endif
Counts initialized:
c[D_CBC_128_ARIA][0] = count; c[D_CBC_192_ARIA][0] = count; c[D_CBC_256_ARIA][0] = count;
and adjusted:
c[D_CBC_128_ARIA][i] = c[D_CBC_128_ARIA][i - 1] * l0 / l1; c[D_CBC_192_ARIA][i] = c[D_CBC_192_ARIA][i - 1] * l0 / l1; c[D_CBC_256_ARIA][i] = c[D_CBC_256_ARIA][i - 1] * l0 / l1;
Finally, the actual speed testing code:
#ifndef OPENSSL_NO_ARIA if (doit[D_CBC_128_ARIA]) { if (async_jobs > 0) { BIO_printf(bio_err, "Async mode is not supported with %s\n", names[D_CBC_128_ARIA]); doit[D_CBC_128_ARIA] = 0; } for (testnum = 0; testnum < SIZE_NUM&&async_init == 0; testnum++) { print_message(names[D_CBC_128_ARIA], c[D_CBC_128_ARIA][testnum], lengths[testnum]); Time_F(START); for (count = 0, run = 1; COND(c[D_CBC_128_ARIA][testnum]); count++) ARIA_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, (size_t)lengths[testnum], &aria_ks1, iv, ARIA_ENCRYPT); d = Time_F(STOP); print_result(D_CBC_128_ARIA, testnum, count, d); } } if (doit[D_CBC_192_ARIA]) { if (async_jobs > 0) { BIO_printf(bio_err, "Async mode is not supported with %s\n", names[D_CBC_192_ARIA]); doit[D_CBC_192_ARIA] = 0; } for (testnum = 0; testnum < SIZE_NUM&&async_init == 0; testnum++) { print_message(names[D_CBC_192_ARIA], c[D_CBC_192_ARIA][testnum], lengths[testnum]); if (async_jobs > 0) { BIO_printf(bio_err, "Async mode is not supported, exiting..."); exit(1); } Time_F(START); for (count = 0, run = 1; COND(c[D_CBC_192_ARIA][testnum]); count++) ARIA_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, (size_t)lengths[testnum], &aria_ks2, iv, ARIA_ENCRYPT); d = Time_F(STOP); print_result(D_CBC_192_ARIA, testnum, count, d); } } if (doit[D_CBC_256_ARIA]) { if (async_jobs > 0) { BIO_printf(bio_err, "Async mode is not supported with %s\n", names[D_CBC_256_ARIA]); doit[D_CBC_256_ARIA] = 0; } for (testnum = 0; testnum < SIZE_NUM&&async_init == 0; testnum++) { print_message(names[D_CBC_256_ARIA], c[D_CBC_256_ARIA][testnum], lengths[testnum]); Time_F(START); for (count = 0, run = 1; COND(c[D_CBC_256_ARIA][testnum]); count++) ARIA_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, (size_t)lengths[testnum], &aria_ks3, iv, ARIA_ENCRYPT); d = Time_F(STOP); print_result(D_CBC_256_ARIA, testnum, count, d); } } #endif
Manual Pages
OpenSSL has the strong philosophy of containing documentation and manual pages for all code. The relevant manual pages require updating because they will gain automatic support for ARIA. Many of these pages require the same automatic change. These are doc/man1/dsa.pod, doc/man1/gendsa.pod, doc/man1/genrsa.pod and doc/man1/rsa.pod. The new command line options need to be added to the documentation:
[B<-aria128>] [B<-aria192>] [B<-aria256>]
and updating the brief description line:
=item B<-aes128|-aes192|-aes256|-aria128|-aria192|-aria256|-camellia128|- camellia192|-camellia256|-des|-des3|-idea>
The doc/man1/pkcs12.pod requires that the new ciphers are added to the command line options:
[B<-des | -des3 | -idea | -aes128 | -aes192 | -aes256 | -aria128 | -aria192 | -aria256 | -camellia128 | -camellia192 | -camellia256 | -nodes>]
and a description is added in the body of the text:
=item B<-aria128>, B<-aria192>, B<-aria256> use ARIA to encrypt private keys before outputting.
The doc/man1/ciphers.pod file requires a section describing the new cipher:
=item B<ARIA128>, B<ARIA256>, B<ARIA> cipher suites using 128 bit ARIA, 256 bit ARIA or either 128 or 256 bit ARIA.
And an update to the cipher suites that are supported:
=head2 ARIA cipher suites from RFC6209, extending TLS v1.2 TLS_RSA_WITH_ARIA_128_CBC_SHA256 ARIA128-CBC-SHA256 TLS_RSA_WITH_ARIA_256_CBC_SHA384 ARIA256-CBC-SHA384 TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 DHE-DSS-ARIA128-CBC-SHA256 TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 DHE-DSS-ARIA256-CBC-SHA384 TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 DHE-RSA-ARIA128-CBC-SHA256 TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 DHE-RSA-ARIA256-CBC-SHA384 TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 DH-anon-ARIA128-CBC-SHA256 TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 DH-anon-ARIA256-CBC-SHA384 TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 ECDHE-ECDSA-ARIA128-CBC-SHA256 TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 ECDHE-ECDSA-ARIA256-CBC-SHA384 TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 ECDHE-RSA-ARIA128-CBC-SHA256 TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 ECDHE-RSA-ARIA256-CBC-SHA384
Building
There are a number of commands to build and test everything. Note the enable-aria to include it in the building of OpenSSL:
./config enable-aria && make && make update && make test && LD_LIBRARY_PATH=. apps/openssl speed aria
Also try a build with aria disabled:
./config no-aria && make && make test &&
Both sequences should work and the tests should all pass.