>

libsecurity

#Overview

For Project 2, we’re using OpenSSL 3’s libcrypto for cryptographic primitives. However, directly interfacing with libcrypto may prove to be quite challenging for a lot of students. As such, we’re providing our own libsecurity that has more course-grained cryptographic primitives that are specific to Project 2.

(If you attended week 7’s discussion, you’ve already used some of these functions.)

#Global Variables

#EVP_PKEY* ec_peer_public_key

This variable is populated after a valid call to load_peer_public_key. Use this as the authority for verify if you’d like to check if some data was signed with the peer’s (the other client or server) private key.

#EVP_PKEY* ec_ca_public_key

This variable is populated after a valid call to load_ca_public_key. Use this as the authority for verify if you’d like to check if some data was signed with the certificate authority’s private key.

#uint8_t* certificate and size_t cert_size

This variable is populated after a valid call to load_certificate. This certificate is already encoded as TLV 0xA0 (see the Project 2 spec for more info).
cert_size is the corresponding total length of the certificate.

#uint8_t* public_key and size_t pub_key_size

This variable is populated after a valid call to derive_public_key. This public key is encoded as ASN.1 DER; you do not need to know the specifics about this encoding. This is the format that we use to send public keys over the wire.
pub_key_size is the corresponding total length of the public_key.

#load_private_key

void load_private_key(const char* filename);

From a file on the local file system, load in a private key.

#Parameters

#get_private_key

EVP_PKEY* get_private_key();

Retrieve the current private key to potentially restore it later (using set_private_key).

#Returns

A pointer to the current state of the private key.

#set_private_key

void set_private_key(EVP_PKEY* key);

Set the private key to some previously known private key state (retrieved using get_private_key).

#Parameters

#load_peer_public_key

void load_peer_public_key(const uint8_t* peer_key, size_t size);

Take some public key sent over the wire and load it as the peer’s public key (in ec_peer_public_key).

#Parameters

#load_ca_public_key

void load_ca_public_key(const char* filename);

From a file on the local file system, load in the CA’s public key.

#Parameters

#load_certificate

void load_certificate(const char* filename);

From a file on the local file system, load in your certificate that has been signed by the CA into the certificate global variable.

#Parameters

#generate_private_key

void generate_private_key();

Randomly generate a private key (can be retrieved using get_private_key). Make sure to call this (or load_private_key/set_private_key) before any operations that require a private key (such as derive_public_key, derive_secret, derive_keys, sign, encrypt_data, decrypt_cipher, and hmac).

#derive_public_key

void derive_public_key();

From the loaded private key, generate the public key in ASN.1 format and place it in the public_key global variable.

#derive_secret

void derive_secret();

After loading the peer public key with load_peer_public_key and generating a private key, you may derive the shared (EC) Diffie-Hellman secret by calling this function.

#derive_keys

void derive_keys(const uint8_t* salt, size_t size);

Using HKDF, derive two keys: 1) info ENC for symmetric encryption, and 2) info MAC for message authentication. Both keys need a salt.

#Parameters

#sign

size_t sign(uint8_t* signature, const uint8_t* data, size_t size);

Generate a signature over the given data using the private key.

#Parameters

#Returns

The resulting size of the signature stored in the signature buffer.

#verify

int verify(const uint8_t* signature, size_t sig_size, const uint8_t* data, size_t size, EVP_PKEY* authority);

Verify if a given signature has indeed been signed by some authority over some data.

#Parameters

#Returns

1 if verification is successful, 0 if the signature is invalid, and any other value if there was some error in processing the parameters.

#generate_nonce

void generate_nonce(uint8_t* buf, size_t size);

Write random bytes to a buffer up to a given size.

#Parameters

#encrypt_data

size_t encrypt_data(uint8_t* iv, uint8_t* cipher, const uint8_t* data, size_t size);

After deriving the ENC key, this function can take some data and output the corresponding ciphertext + IV (AES-256-CBC).

#Parameters

#Returns

The size of the ciphertext. Please note that the ciphertext can be up to 16 bytes longer than the plaintext.

#decrypt_cipher

size_t decrypt_cipher(uint8_t* data, const uint8_t* cipher, size_t size, const uint8_t* iv);

After deriving the ENC key, this function can take some ciphertext and IV and output the corresponding plaintext.

#Parameters

#Returns

The size of the plaintext.

#hmac

void hmac(uint8_t* digest, const uint8_t* data, size_t size);

Calculates HMAC digest over some given data using the derived MAC key.

#Parameters