/* This program is released under the Common Public License V1.0
*
* You should have received a copy of Common Public License V1.0 along with
* with this program.
*
* Copyright IBM Corp. 2017
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ica_api.h>
/* The name of the file to calculate the SHAKE-128 hash from */
#define FILE_NAME "example_shake_128.c"
/* Size of the chunks in which the file is read.
* Must be a multiple of 168 bytes (the SHAKE-128 block size).
*/
#define CHUNK_SIZE 168
/* An arbitrary output_length in case the user did not specify a value via args */
#define SAMPLE_SHAKE_OUTPUT_LENGTH 123
/* Prints hex values to standard out. */
static void dump_data(unsigned char *data, unsigned long length);
/* Prints a description of the return value to standard out. */
static int handle_ica_error(int rc);
int main(int argc, char **argv)
{
int rc=0;
unsigned int output_length = SAMPLE_SHAKE_OUTPUT_LENGTH;
/* Try to read the user specified output length. If none given, use our
* sample value.
*/
if (argc > 1 && argv[1] != NULL)
output_length = atoi(argv[1]);
/* This is the buffer where the SHAKE-128 hash is generated into.
* The SHAKE algorithm can create output of any length greater or equal
* to 8 bytes. Let's use an output length of 256 bytes for this example.
*/
unsigned char* shake_result_p;
/* The file will be read in several chunks into this buffer.
* The chunks will be the input to the ica_shake_128 function which
* we call for each chunk.
*/
unsigned char shake_input[CHUNK_SIZE];
/* This is the SHAKE-128 context. It stores intermediate values
* needed when chaining multiple chunks (as we do).
*/
shake_128_context_t context;
/* Open the file in binary mode and read its content in chunks */
FILE *f;
f = fopen(FILE_NAME, "r");
if (f == NULL)
return handle_ica_error(errno);
/* Allocate a buffer for the output value */
shake_result_p = malloc(output_length);
if (shake_result_p == NULL) {
printf("Cannot malloc %d bytes for output value. \n", output_length);
return EINVAL;
}
/* Perform the shake-128 operation ... */
int len;
unsigned long total_size = 0;
memset((char*)&context, 0, sizeof(context));
while (!feof(f)) {
/* read a chunk of data */
len = fread(shake_input, 1, CHUNK_SIZE, f);
if (total_size == 0) {
/* this is the first chunk */
rc = ica_shake_128(SHA_MSG_PART_FIRST, len, shake_input,
&context, shake_result_p, output_length);
} else if (!feof(f)) {
/* add this chunk to the hash */
rc = ica_shake_128(SHA_MSG_PART_MIDDLE, len, shake_input,
&context, shake_result_p, output_length);
} else {
/* this is the last chunk */
rc = ica_shake_128(SHA_MSG_PART_FINAL, len, shake_input,
&context, shake_result_p, output_length);
}
total_size += len;
if (rc)
break;
}
/* close the file */
fclose(f);
/* Error handling (if necessary). */
if (rc)
return handle_ica_error(rc);
/* Dump the generated hash to standard output, just for
* a visual control.
*/
printf("SHAKE-128 hash with %d bytes of file '%s' (%lu bytes):\n", output_length,
FILE_NAME, total_size);
dump_data(shake_result_p, output_length);
}
static void dump_data(unsigned char *data, unsigned long length)
{
unsigned char *ptr;
int i;
for (ptr = data, i = 1; ptr < (data + length); ptr++, i++) {
printf("0x%02x ", *ptr);
if ((i % 16) == 0)
printf("\n");
}
if (i % 16)
printf("\n");
}
static int handle_ica_error(int rc)
{
switch (rc) {
case 0:
printf("OK\n");
break;
case EINVAL:
printf("Incorrect parameter.\n");
break;
case EPERM:
printf("Operation not permitted by Hardware (CPACF).\n");
break;
case EIO:
printf("I/O error.\n");
break;
default:
printf("unknown error.\n");
}
return rc;
}