Blog | G5 Cyber Security

BLE Security: ChaCha20-Poly1305 Encryption

TL;DR

This guide shows you how to add strong encryption (ChaCha20-Poly1305) to your Bluetooth Low Energy (BLE) application. This protects the data sent between devices, making it much harder for anyone to eavesdrop.

Prerequisites

1. Choose Your Library

Implementing ChaCha20-Poly1305 from scratch is complex and error-prone. Use a well-tested library instead.

This guide assumes you’ll use mbed TLS as an example.

2. Include the Library and Header Files

Add the necessary header files to your project. The exact method depends on your build system.

#include "mbedtls/crypto.h"
#include "mbedtls/aes.h"
#include "mbedtls/chacha20.h"
#include "mbedtls/md.h"

3. Generate a Key

You need a secret key to encrypt and decrypt data. This should be generated randomly and securely stored on both devices.

unsigned char key[32];
mbedtls_random_bytes(key, sizeof(key));

4. Implement Encryption

This is where you use the ChaCha20-Poly1305 algorithm to encrypt your data.

#include 

void encrypt_data(unsigned char *plaintext, size_t plaintext_len,
unsigned char *key, unsigned char *nonce,
unsigned char *ciphertext) {
  mbedtls_chacha20_context ctx;
  mbedtls_md_context md_ctx;
  const mbedtls_cipher_info_t *cipher_info = &mbedtls_cipher_info_chacha20;

  mbedtls_chacha20_init(&ctx);
  mbedtls_md_init(&md_ctx);

  mbedtls_chacha20_setkey(&ctx, key, 32); // Key length is 32 bytes for ChaCha20

  mbedtls_chacha20_crypt(&ctx, plaintext, plaintext_len, nonce, ciphertext);

  // Poly1305 MAC calculation (simplified example - check mbed TLS documentation)
  unsigned char mac[16];
  mbedtls_md_init(&md_ctx);
  mbedtls_md_setup(&md_ctx, mbedtls_md_poly1305, 0); // Poly1305 MAC algorithm
  mbedtls_md_update(&md_ctx, ciphertext, plaintext_len);
  mbedtls_md_finish(&md_ctx, mac);

  // Append the MAC to the ciphertext (important for authentication)
  memcpy(ciphertext + plaintext_len, mac, 16);

  mbedtls_chacha20_free(&ctx);
  mbedtls_md_free(&md_ctx);
}

5. Implement Decryption

The decryption process is the reverse of encryption.

void decrypt_data(unsigned char *ciphertext, size_t ciphertext_len,
unsigned char *key, unsigned char *nonce) {
  mbedtls_chacha20_context ctx;
  mbedtls_md_context md_ctx;
  const mbedtls_cipher_info_t *cipher_info = &mbedtls_cipher_info_chacha20;

  mbedtls_chacha20_init(&ctx);
  mbedtls_md_init(&md_ctx);

  mbedtls_chacha20_setkey(&ctx, key, 32); // Key length is 32 bytes for ChaCha20

  // Verify MAC before decrypting (simplified example)
  unsigned char mac[16];
  memcpy(mac, ciphertext + ciphertext_len - 16, 16);

  mbedtls_md_init(&md_ctx);
  mbedtls_md_setup(&md_ctx, mbedtls_md_poly1305, 0); // Poly1305 MAC algorithm
  mbedtls_md_update(&md_ctx, ciphertext, ciphertext_len - 16);
  unsigned char calculated_mac[16];
  mbedtls_md_finish(&md_ctx, calculated_mac);

  if (memcmp(mac, calculated_mac, 16) != 0) {
    // MAC verification failed - reject the ciphertext!
    return;
  }

  mbedtls_chacha20_crypt(&ctx, ciphertext, ciphertext_len - 16, nonce, ciphertext);

  mbedtls_chacha20_free(&ctx);
  mbedtls_md_free(&md_ctx);
}

6. Secure Key Exchange

Getting the key onto both devices securely is critical! Do *not* hardcode keys.

7. Testing

Thoroughly test your implementation.

Exit mobile version