CK_RV aes_cbc_multipart_sample()

in src/encrypt/aes_cbc.c [39:193]


CK_RV aes_cbc_multipart_sample(CK_SESSION_HANDLE session) {
    CK_RV rv;
    CK_BYTE_PTR decrypted_ciphertext = NULL;

    // Generate a 256 bit AES key.
    CK_OBJECT_HANDLE aes_key;
    rv = generate_aes_key(session, 32, &aes_key);
    if (CKR_OK != rv) {
        printf("AES key generation failed: %lu\n", rv);
        return rv;
    }


    // Prepare the mechanism 
    // The IV is hardcoded to all 0x01 bytes for this example.
    CK_BYTE iv[16] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
                      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
    CK_MECHANISM mech = {CKM_AES_CBC_PAD, iv, 16};

    //**********************************************************************************************
    // Encrypt
    //**********************************************************************************************    

    rv = funcs->C_EncryptInit(session, &mech, aes_key);
    if (CKR_OK != rv) {
        printf("Encryption Init failed: %lu\n", rv);
        return rv;
    }

    // We will stream several chunks of non block aligned random data to encrypt
    size_t max_chunks = 4;
    size_t chunk_idx = 0;

    // The encrypted chunks will be stored in the ciphertext buffer
    CK_BYTE_PTR ciphertext = NULL;
    CK_ULONG ciphertext_size = 0;
    CK_ULONG encrypted_chunk_size = 0;

    // We store the randomly generated plaintext as well, for visual comparison
    // 512 will hold enough for this sample.
    CK_BYTE plaintext[512] = { };
    CK_ULONG plaintext_size = CHUNK_SIZE * max_chunks;

    while(chunk_idx < max_chunks) {
        CK_BYTE chunk[CHUNK_SIZE] = { };
        get_random_data(chunk, CHUNK_SIZE);
        memcpy(&plaintext[chunk_idx * CHUNK_SIZE], chunk, CHUNK_SIZE);
        chunk_idx += 1;

        // Determine how much memory will be required to hold this chunk of ciphertext.
        rv = funcs->C_EncryptUpdate(session, chunk, CHUNK_SIZE, NULL, &encrypted_chunk_size);
        if (CKR_OK != rv) {
            printf("Encryption failed: %lu\n", rv);
            goto done;
        }

        // Increase the ciphertext buffer to hold the new chunk.
        CK_BYTE_PTR new_ciphertext = realloc(ciphertext, ciphertext_size + encrypted_chunk_size);
        if (NULL == new_ciphertext) {
            printf("Could not allocate memory for ciphertext\n");
            goto done;
        }
        ciphertext = new_ciphertext;

        // Encrypt the data.
        rv = funcs->C_EncryptUpdate(session, chunk, CHUNK_SIZE, &ciphertext[ciphertext_size], &encrypted_chunk_size);
        if (CKR_OK != rv) {
            printf("Encryption failed: %lu\n", rv);
            goto done;
        }

        ciphertext_size += encrypted_chunk_size;
    }

    // Calculate the size needed for the final buffer. This could include a block of padding.
    rv = funcs->C_EncryptFinal(session, NULL, &encrypted_chunk_size);
    if (CKR_OK != rv) {
        printf("Encryption failed: %lu\n", rv);
        goto done;
    }

    CK_BYTE_PTR new_ciphertext = realloc(ciphertext, ciphertext_size + encrypted_chunk_size);
    if (NULL == new_ciphertext) {
        printf("Could not allocate memory for ciphertext\n");
        goto done;
    }
    ciphertext = new_ciphertext;

    // Finalize the encryption, including any final padding
    rv = funcs->C_EncryptFinal(session, &ciphertext[ciphertext_size], &encrypted_chunk_size);
    if (CKR_OK != rv) {
        printf("Encryption failed: %lu\n", rv);
        goto done;
    }

    ciphertext_size += encrypted_chunk_size;

    printf("Plaintext: ");
    print_bytes_as_hex(plaintext, plaintext_size);
    printf("Plaintext length: %lu\n", plaintext_size);

    // Print just the ciphertext in hex format
    printf("Ciphertext: ");
    print_bytes_as_hex(ciphertext, ciphertext_size);
    printf("Ciphertext length: %lu\n", ciphertext_size);

    //**********************************************************************************************
    // Decrypt
    //**********************************************************************************************    

    rv = funcs->C_DecryptInit(session, &mech, aes_key);
    if (CKR_OK != rv) {
        printf("Decryption Init failed: %lu\n", rv);
        goto done;
    }

    // Determine how much memory is required to hold the decrypted text.
    CK_ULONG decrypted_ciphertext_length = 0;
    rv = funcs->C_Decrypt(session, ciphertext, ciphertext_size, NULL, &decrypted_ciphertext_length);
    if (CKR_OK != rv) {
        printf("Decryption failed: %lu\n", rv);
        goto done;
    }

    // Allocate memory for the decrypted ciphertext.
    printf("Allocating %lu for decryption\n", decrypted_ciphertext_length);
    decrypted_ciphertext = malloc(decrypted_ciphertext_length + 1); //We want to null terminate the raw chars later
    if (NULL == decrypted_ciphertext) {
        rv = 1;
        printf("Could not allocate memory for decrypted ciphertext\n");
        goto done;
    }

    // Decrypt the ciphertext.
    rv = funcs->C_Decrypt(session, ciphertext, ciphertext_size, decrypted_ciphertext, &decrypted_ciphertext_length);
    if (CKR_OK != rv) {
        printf("Decryption failed: %lu\n", rv);
        goto done;
    }
    decrypted_ciphertext[decrypted_ciphertext_length] = 0; // Turn the chars into a C-String via null termination

    printf("Decrypted ciphertext: ");
    print_bytes_as_hex(decrypted_ciphertext, decrypted_ciphertext_length);
    printf("Decrypted ciphertext length: %lu\n", decrypted_ciphertext_length);

done:
    if (NULL != decrypted_ciphertext) {
        free(decrypted_ciphertext);
    }

    if (NULL != ciphertext) {
        free(ciphertext);
    }
    return rv;
}