Before doing anything with libfko, you need to create a context. A context is created for one of two reasons. One is for the purpose of building a new fko SPA message from scratch (typically to be packaged and sent to an fwknop server somewhere). The other would be a context for taking an existing SPA message for decoding, parsing, and data extraction.
For building a new fko SPA message, you will use the fko_new
function:
The function
fko_new
sets up and initializes a newfko_ctx_t
object, pre-populates default values and returns a handle for it in ctx. The function returns the error codeFKO_SUCCESS
if the context was successfully created. Otherwise an another error code will be returned (see Error Handling for details on the various error codes and their meanings).
fko_ctx_t ctx; int rc; rc = fko_new(&ctx); if(rc != FKO_SUCCESS) { fprintf(stderr, "Error %i from fko_new: %s\n", rc, fko_errstr(rc)); exit(1); }
For a context that will be used for receiving and parsing an existing
SPA message, you will use the fko_new_with_data
function:
The function
fko_new_with_data
sets up and initializes a newfko_ctx_t
context, but instead of initializing default values, it stores the encrypted message data and makes it ready for parsing. This can be done in one of two ways. One is to passNULL
for the third argument. The context will be created and the data will be stored, but no decryption or decoding takes place. In this case, you will need to callfko_decrypt_spa_data
at a later time. The other way to do it is to supply the key value (decryption passphrase) and assocated length. In this case, the context is created, the SPA data is decrypted, decoded, parsed, and stored in the context ready for retrieval. If an HMAC is also desired or required, then the hmac_key and associated length can be passed in. This will cause libfko to authenticate the SPA data before decryption is attempted, and this is strongly recommended to do.The
fko_new_with_data
function returns the error codeFKO_SUCCESS
if the context was successfully created. If any of the intermediate steps in parsing the data, validating the SPA message digest, or any other internal action fails, then the appropriate error code is returned.
The most common (simple) case...
fko_ctx_t ctx; char *spa_data; char *key; int key_len; char *hmac_key; int hmac_key_len; int hmac_type = FKO_HMAC_SHA256; int enc_mode = FKO_ENC_MODE_CBC; int rc; /* Assume we called code that retrieves the data and key */ rc = fko_new_with_data(&ctx, spa_data, key, key_len, \\ enc_mode, hmac_key, hmac_key_len, hmac_type); if(rc != FKO_SUCCESS) { fprintf(stderr, "Error %i from fko_new_with_data: %s\n", rc, fkoerrstr(rc)); exit(1); }
Or, perhaps you need to defer decryption and parsing to a later point in the program. We could use fko_new_with_data(), passing NULL for the decryption key and HMAC keys, or we could use fko_new() to create an empty context, then use fko_set_spa_data() to add the encypted data (see comments in the code samples).
fko_ctx_t ctx; char *spa_data; char *key; int rc; /* Assume we called code that retrieves the data and key */ rc = fko_new_with_data(&ctx, spa_data, NULL, 0, FKO_ENC_MODE_CBC, NULL, 0, FKO_HMAC_SHA256); if(rc != FKO_SUCCESS) { fprintf(stderr, "Error from fko_new_with_data: %s\n", fko_errstr(rc)); exit(1); } /* We could also just create and empty context and add the * encrypted data as follows: * * rc = fko_new(&ctx); * ... check rc ... * rc = fko_set_spa_data(ctx, spa_data); * ... */ /* Assume we called other code and functions... */ /* Verify HMAC */ rc = fko_verify_hmac(ctx, hmac_key, hmac_key_len); if(rc != FKO_SUCCESS) { fprintf(stderr, "Error from fko_verify_hmac: %s\n", fko_errstr(rc)); exit(1); } /* Decrypt and decode... */ rc = fko_decrypt_spa_data(ctx, key, key_len); if(rc != FKO_SUCCESS) { fprintf(stderr, "Error from fko_decrypt_spa_data: %s\n", fko_errstr(rc)); exit(1); }