How to Integrate a Symmetric Cipher

From OpenSSLWiki
Jump to: navigation, search

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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.

Error/Reason Codes[edit]

Error codes are handled dynamically in OpenSSL by using make update. make update will, in part, call make errors which will later execute util/mkerr.pl recursively on crypto/*.c, crypto/*/*.c, ssl/*.c, and apps/*.c. This script will scan for error and function codes and automatically add them as error/reason codes in the library. Essentially, it will look for strings that "look like" function or reason codes: basically anything consisting of all upper case and numerics which has _F_ or _R_ in it and which has the name of an error library at the start. For example, EVP_F_ARIA_INIT_KEY and EVP_R_ARIA_KEY_SETUP_FAILED. For more detailed documentation please view crypto/err/README and util/mkerr.pl.

Crypto Objects[edit]

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[edit]

evp.h[edit]

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

Utilities[edit]

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;


TLS[edit]

At this point the cipher has now been implemented into the OpenSSL library and the following TLS section is optional. This section is only necessary if the cipher must be implemented as a TLS ciphersuite.

tls1.h[edit]

/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[edit]

/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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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.

Applications[edit]

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[edit]

Just as it was explained in the TLS section, the speed test integration is optional and only needs to be implemented if desired. That being said, 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[edit]

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[edit]

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.