ChaCha20

Encrypt

To test a function that encrypts with ChaCha20 only, its name must conform to the following convention:

CC_ChaCha20_encrypt

Its signature must be:

int CC_ChaCha20_encrypt(
uint8_t *ciphertext,
const uint8_t *plaintext,
size_t text_size,
const uint8_t key[32],
const uint8_t *nonce,
size_t nonce_size,
uint32_t init_counter,
)
Parameters:
  • ciphertext[Out] An allocated buffer to return the resulting ciphertext.

  • plaintext[In] The plaintext to encrypt.

  • text_size[In] The size of the plaintext and ciphertext buffers.

  • key[In] The 32-byte key to use.

  • nonce[In] The nonce.

  • nonce_size[In] The size of the nonce in bytes.

  • init_counter[In] An absolute position within the keystream in bytes to seek before encrypting.

Returns:

A status value.

Return values:
  • 1 – OK.

  • 0 – Failed to encrypt.

Example

#include <openssl/err.h>
#include <openssl/evp.h>

// TODO: We use EVP_chacha20_poly1305() for both, as the test vector for
// ChaCha20 has counter=1 and it seems that there is no way to set it in EVP.
// This works with the current test vector, but will break with other values of
// counter.

int CC_ChaCha20_encrypt(uint8_t *ciphertext, const uint8_t *plaintext,
                        size_t text_size, const uint8_t key[32],
                        const uint8_t *nonce, size_t nonce_size,
                        uint32_t init_counter) {
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  int len = 0;

  if (!ctx)
    goto error;
  if (1 != EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce))
    goto error;
  if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, text_size))
    goto error;
  if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
    goto error;

  EVP_CIPHER_CTX_free(ctx);
  return 1;

error:
  ERR_print_errors_fp(stderr);
  EVP_CIPHER_CTX_free(ctx);
  return 0;
}

Compile with:

gcc -fPIC -shared -o chacha20_openssl_encrypt.so chacha20_openssl_encrypt.c -lssl -lcrypto

Then test with:

crypto-condor-cli test harness chacha20_openssl_encrypt.so

Decrypt

To test a function that decrypts with ChaCha20 only, its name must conform to the following convention:

CC_ChaCha20_decrypt

Its signature must be:

void CC_ChaCha20_decrypt(
uint8_t *plaintext,
const uint8_t *ciphertext,
size_t text_size,
const uint8_t key[32],
const uint8_t *nonce,
size_t nonce_size,
uint64_t init_counter,
)
Parameters:
  • plaintext[out] an allocated buffer to return the resulting plaintext.

  • ciphertext[in] the ciphertext to decrypt.

  • text_size[in] the size of the plaintext and ciphertext buffers.

  • key[In] The 32-byte key to use.

  • nonce[In] The nonce.

  • nonce_size[In] The size of the nonce in bytes.

  • init_counter[In] An absolute position within the keystream in bytes to seek before encrypting.

Returns:

A status value.

Return values:
  • 1 – OK.

  • 0 – Failed to decrypt.

Example

#include <openssl/err.h>
#include <openssl/evp.h>

// TODO: We use EVP_chacha20_poly1305() for both, as the test vector for
// ChaCha20 has counter=1 and it seems that there is no way to set it in EVP.
// This works with the current test vector, but will break with other values of
// counter.


int CC_ChaCha20_decrypt(uint8_t *plaintext, const uint8_t *ciphertext,
                        size_t text_size, const uint8_t key[32],
                        const uint8_t *nonce, size_t nonce_size,
                        uint64_t init_counter) {
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  int len = 0;

  if (!ctx)
    goto error;

  if (1 != EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce))
    goto error;
  if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, text_size))
    goto error;
  if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
    goto error;

  EVP_CIPHER_CTX_free(ctx);
  return 1;

error:
  ERR_print_errors_fp(stderr);
  EVP_CIPHER_CTX_free(ctx);
  return 0;
}

Compile with:

gcc -fPIC -shared -o chacha20_openssl_decrypt.so chacha20_openssl_decrypt.c -lssl -lcrypto

Then test with:

crypto-condor-cli test harness chacha20_openssl_decrypt.so

Encrypt with Poly1305

To test a function that encrypts with ChaCha20-Poly1305, its name must conform to the following convention:

CC_ChaCha20_encrypt_poly

Its signature must be:

int CC_ChaCha20_encrypt_poly(
uint8_t *ciphertext,
uint8_t mac[16],
const uint8_t *plaintext,
size_t text_size,
const uint8_t key[32],
const uint8_t *nonce,
size_t nonce_size,
const uint8_t *aad,
size_t aad_size,
)
Parameters:
  • ciphertext[Out] An allocated buffer to return the resulting ciphertext.

  • mac[Out] buffer to store the resulting 16-byte MAC tag.

  • plaintext[In] The plaintext to encrypt.

  • text_size[In] The size of the plaintext and ciphertext buffers.

  • key[In] The 32-byte key to use.

  • nonce[In] The nonce.

  • nonce_size[In] The size of the nonce in bytes.

  • aad[In] The optional associated data. NULL if not used.

  • aad_size[In] The size of the associated data in bytes. 0 if not used.

Returns:

A status value.

Return values:
  • 1 – OK.

  • 0 – Failed to encrypt.

Example

#include <openssl/err.h>
#include <openssl/evp.h>

int CC_ChaCha20_encrypt_poly(uint8_t *ciphertext, uint8_t mac[16],
                             const uint8_t *plaintext, size_t text_size,
                             const uint8_t key[32], const uint8_t *nonce,
                             size_t nonce_size, const uint8_t *aad,
                             size_t aad_size) {
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  int len = 0;

  // Adhere to the RFC 7539 version with 12-byte nonces.
  if (nonce_size != 12)
    goto error;

  if (!ctx)
    goto error;

  if (1 != EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce))
    goto error;

  if (aad_size > 0) {
    if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_size))
      goto error;
  }

  if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, text_size))
    goto error;

  if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
    goto error;

  if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac))
    goto error;

  EVP_CIPHER_CTX_free(ctx);
  return 1;

error:
  ERR_print_errors_fp(stderr);
  EVP_CIPHER_CTX_free(ctx);
  return 0;
}

Compile with:

gcc -fPIC -shared -o chacha20_poly1305_openssl_encrypt.so chacha20_poly1305_openssl_encrypt.c -lssl -lcrypto

Then test with:

crypto-condor-cli test harness chacha20_poly1305_openssl_encrypt.so

Decrypt with Poly1305

To test a function that decrypts with ChaCha20-Poly1305, its name must conform to the following convention:

CC_ChaCha20_poly1305_decrypt

Its signature must be:

int CC_ChaCha20_decrypt_poly(
uint8_t *plaintext,
const uint8_t *ciphertext,
size_t text_size,
const uint8_t key[32],
const uint8_t mac[16],
const uint8_t *nonce,
size_t nonce_size,
const uint8_t *aad,
size_t aad_size,
)
Parameters:
  • plaintext[out] an allocated buffer to return the resulting plaintext.

  • ciphertext[in] the ciphertext to decrypt.

  • text_size[in] the size of the plaintext and ciphertext buffers.

  • key[In] The 32-byte symmetric key.

  • mac[In] The 16-byte MAC tag to verify.

  • nonce[In] The nonce.

  • nonce_size[In] The size of the nonce in bytes.

  • aad[In] The optional associated data. NULL if not used.

  • aad_size[In] The size of the associated data. 0 if not used.

Returns:

A status value.

Return values:
  • 1 – OK.

  • 0 – The MAC verification failed.

  • -1 – Failed to decrypt.

Example

#include <openssl/err.h>
#include <openssl/evp.h>

int CC_ChaCha20_decrypt_poly(uint8_t *plaintext, const uint8_t *ciphertext,
                             size_t text_size, const uint8_t key[32],
                             const uint8_t mac[16], const uint8_t *nonce,
                             size_t nonce_size, const uint8_t *aad,
                             size_t aad_size) {
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  int len = 0, ret = 0;

  // Adhere to the RFC 7539 version with 12-byte nonces.
  if (nonce_size != 12)
    goto error;

  if (!ctx)
    goto error;

  if (1 != EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce))
    goto error;

  if (aad_size > 0) {
    if (1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_size))
      goto error;
  }

  if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, text_size))
    goto error;

  if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (void *)mac))
    goto error;

  ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
  EVP_CIPHER_CTX_free(ctx);
  return ret;

error:
  ERR_print_errors_fp(stderr);
  EVP_CIPHER_CTX_free(ctx);
  return -1;
}

Compile with:

gcc -fPIC -shared -o chacha20_poly1305_openssl_decrypt.so chacha20_poly1305_openssl_decrypt.c -lssl -lcrypto

Then test with:

crypto-condor-cli test harness chacha20_poly1305_openssl_decrypt.so