Symmetric cryptography (ciphers)

Updated: April 19, 2023

The qcrypto library API includes cryptographic cipher functions.

See the library reference for detailed information on the following functions:

Advanced Encryption Standard (AES)

Some of the AES cipher algorithms the library supports have particular features and restrictions and should be used in specific ways.

CTR mode

The counter is 128 bits long, which is the size of the initialization vector (IV). It is up to the client code to make sure that the IV never repeats itself for the same key.

XTS mode

  • Unit size — The unit size represents the disk unit size that is encrypted or decrypted as a whole. It must be a multiple of the block size (16 bytes) and the number of blocks in a data unit size must be in the range 1 through 220-1 blocks.
  • Encryption and decryption — Encryption and decryption must be done as a single operation. Unlike other modes, XTS mode does not support partial operations. In addition, the buffer input size must be a multiple of the block size (16 bytes).

GCM mode

CCM mode

Because CCM mode does not support incremental updates, the caller must complete encrypting the plaintext or decrypting the ciphertext in one call.

Block cipher mode of operation

All qcrypto library cipher algorithms working in a block cipher mode of operation (for example, AES CBC (Cipher Block Chaining)) require that the total input size be a multiple of the cipher block size.

  • When padding is QCRYPTO_CIPHER_PADDING_NONE in qcrypto_cipher_args_t, the caller is responsible for providing an input total size that is a multiple of the cipher block size.
  • If you specify a valid padding mode other than QCRYPTO_CIPHER_PADDING_NONE, when you call qcrypto_cipher_final(), the data is either automatically padded (encryption) or unpadded (decryption). If there is a padding violation on decryption, an error is returned to the caller. The caller needs to provide a buffer large enough to receive the remaining encrypted or decrypted data.
For cipher algorithms that don't use a block cipher mode of operation, configuring any value other than QCRYPTO_CIPHER_PADDING_NONE returns an error to the caller.

Cipher examples

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <qcrypto/qcrypto.h>
#include <qcrypto/qcrypto_error.h>
#include <qcrypto/qcrypto_keys.h>
#include <private/qcrypto/qcrypto_internal.h>

int main(void)
{
    int ret;
    int enc_result = 1;
    int dec_result = 1;
    qcrypto_ctx_t *qctx = NULL;
    qcrypto_ctx_t *qkeyctx = NULL;
    qcrypto_key_t *qkey = NULL;

    const char key_hex[] = "000102030405060708090a0b0c0d0e0f";
    const size_t keysize = (sizeof(key_hex)-1)/2;
    uint8_t key_bin[keysize];

    const char ptext_hex[] = "00112233445566778899aabbccddeeff";
    const size_t psize = (sizeof(ptext_hex)-1)/2;
    uint8_t ptext_bin[psize];
    uint8_t ptext_cmp[psize];
    uint8_t *ptext_ptr = ptext_cmp;
    size_t psize_cmp = 0;

    const char ctext_hex[] = "69c4e0d86a7b0430d8cdb78070b4c55a";
    const size_t csize = (sizeof(ctext_hex)-1)/2;
    uint8_t ctext_bin[csize];
    uint8_t ctext_cmp[csize];
    uint8_t *ctext_ptr = ctext_cmp;
    size_t csize_cmp = 0;

    /* Initialize the Qcrypto Library */
    ret = qcrypto_init(QCRYPTO_INIT_LAZY, NULL);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcryto_init() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Request symmetric keygen */
    ret = qcrypto_keygen_request("symmetric", NULL, 0, &qkeyctx);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_keygen_request() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Initialize cipher arguments */
    qcrypto_cipher_args_t cargs = {
        .action = QCRYPTO_CIPHER_ENCRYPT,
        .iv = NULL,
        .ivsize = 0,
    };

    /* Request aes-128-ecb */
    ret = qcrypto_cipher_request("aes-128-ecb", NULL, 0, &qctx);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_cipher_request() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert key */
    ret = qcrypto_hex2bin(key_bin, key_hex, keysize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_hex2bin() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert ptext */
    ret = qcrypto_hex2bin(ptext_bin, ptext_hex, psize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_hex2bin() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert ctext */
    ret = qcrypto_hex2bin(ctext_bin, ctext_hex, csize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_hex2bin() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Load key */
    ret = qcrypto_key_from_mem(qkeyctx, &qkey, key_bin, keysize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_key_from_mem() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Initialize cipher encryption */
    ret = qcrypto_cipher_init(qctx, qkey, &cargs);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_cipher_init() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Cipher encryption */
    ret = qcrypto_cipher_encrypt(qctx, ptext_bin, psize, ctext_ptr, &csize_cmp);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_cipher_encrypt() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Finalize cipher encryption */
    ret = qcrypto_cipher_final(qctx, ctext_ptr, &csize_cmp);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_cipher_final() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Compare the encryption results */
    enc_result = memcmp(ctext_bin, ctext_cmp, csize);
    if (enc_result == 0) {
         printf("Computed encryption matches with expected encryption\n");
    } else {
         fprintf(stderr, "Computed encryption failed to match with expected encryption\n");
         goto done;
    }

    /* Switch to decryption mode */
    cargs.action = QCRYPTO_CIPHER_DECRYPT;

    /* Initialize cipher encryption */
    ret = qcrypto_cipher_init(qctx, qkey, &cargs);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_cipher_init() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Cipher decryption */
    ret = qcrypto_cipher_decrypt(qctx, ctext_bin, csize, ptext_ptr, &psize_cmp);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_cipher_decrypt() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Finalize cipher decryption */
    ret = qcrypto_cipher_final(qctx, ptext_ptr, &psize_cmp);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_cipher_final() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    dec_result = memcmp(ptext_bin, ptext_cmp, psize);
    if (dec_result == 0) {
         printf("Computed decryption matches with expected decryption\n");
    } else {
         fprintf(stderr, "Computed decryption failed to match with expected decryption\n");
         goto done;
    }
    goto done;

done:
    /* Release all context handles */
    qcrypto_release_ctx(qctx);
    qcrypto_release_ctx(qkeyctx);

    /* Release the key handle */
    qcrypto_release_key(qkey);

    /* Uninitialize the Qcrypto Library */
    qcrypto_uninit();

    return ret;
}

#if defined(__QNXNTO__) && defined(__USESRCVERSION)
#include <sys/srcversion.h>
__SRCVERSION("$URL$ $Rev$")
#endif