libec manual

Channels

Libec uses channels to implement secure communication between two entities. Data is encrypted and protected with a MAC.

API

ec_channel_clean()

`void ec_channel_clean(ec_channel_t *ch);

Clean a previously used channel for reuse or free. Unlocks locked memory and zeros entire structure. Should be run once a channel is no longer required, before disposing of the channel.

#include <ec.h>
...
ec_channel_clean(ch);
...

ec_channel_init()

ec_err_t ec_channel_init(ec_channel_t *ch, ec_cert_t *c, ec_ctx_t *ctx, unsigned char *dh);

Initialise a channel and generate a signed Diffie-Hellman packet to pass to the remote endpoint. Returns zero on success, a nonzero error code otherwise. Once the channel is no longer required, it should be scrubbed using ec_channel_clean().

ctx should point to a context where the remote certificate can be found, and will be used for validation purposes - if trust chain checks are performed, then those certificates will also need to be available.

c is the certificate used as the local endpoint. This certificate does not need to be available in ctx.

Data to be passed to the remote endpoint (the negotiation packet) will be stored in dh, which should be a buffer of at least EC_CHANNEL_DH_BYTES bytes. The contents of this buffer should be provided to ec_channel_start() on the remote end.

#include <ec.h>
...
ec_channel_t *ch;
unsigned char dh[EC_CHANNEL_DH_BYTES];
if(ec_channel_init(ch, c, ctx, dh) != 0) {
    //init failed
}
...

ec_channel_start()

ec_err_t ec_channel_start(ec_channel_t *ch, unsigned char *dh, int checks);

Finish Diffie-Hellman negotiation and finalise channel setup. Returns zero on success, a nonzero error code otherwise.

dh should contain the negotiation packet generated by ec_channel_init() on the remote end.

checks is a bitfield determining which checks should be run on the remote certificate. All checks must pass for channel setup to complete successfully. EC_CHECK_CERT and EC_CHECK_SIGN will always be tested, whether or not they are set.

#include <ec.h>
...
if(ec_channel_start(ch, dh, EC_CHECK_ALL) != 0) {
    //negotiation failed
}
...

ec_channel_encrypt()

ec_err_t ec_channel_encrypt(ec_channel_t *ch, unsigned char *buf, size_t len,
unsigned char *mac, uint64_t *ctr);

Encrypt a buffer, for later decryption by the other end of a channel. Returns zero on success, a nonzero error code otherwise.

A MAC (EC_CHANNEL_MAC_BYTES bytes) for the message will be stored in *mac, and the message sequence number will be stored in *ctr if ctr is not NULL.

#include <ec.h>
...
unsigned char mac[EC_CHANNEL_MAC_BYTES];
uint64_t ctr;
if(ec_channel_encrypt(ch, buf, buf_length, mac, &ctr) != 0) {
    //encryption failed
}
...

ec_channel_decrypt()

ec_err_t ec_channel_decrypt(ec_channel_t *ch, unsigned char *buf, size_t len,
unsigned char *mac, uint64_t ctr);

Decrypt a buffer previously encrypted by the other end of the channel. Returns zero on success, a nonzero error code otherwise.

mac should be the MAC generated by the other end of the channel using ec_channel_encrypt().

If messages are not decrypted in linear order, then ctr should be set to the sequence number of the message being decrypted. Otherwise, this can be left at zero, and it will be set automatically.

#include <ec.h>
...
if(ec_cert_decrypt(ch, buf, buf_length, mac, 0) != 0) {
    //decryption failed
}
...

ec_channel_remote()

ec_cert_t *ec_channel_remote(ec_channel_t *ch);

Get the certificate for the remote channel endpoint. Returns NULL on failure.

#include <ec.h>
...
ec_cert_t *c = ec_channel_remote(ch);
if(c == NULL) {
    //unable to get remote certificate
}
...