nRF52

nRF52840 AES-128, AES-256의 동작 원리와 모드(ECB, CBC, CTR 등)

임베디드 친구 2025. 2. 20. 15:42
728x90
반응형

AES-128, AES-256의 동작 원리와 모드(ECB, CBC, CTR 등)

1. AES 개요

AES(Advanced Encryption Standard)는 대칭 키 블록 암호화 알고리즘으로, 데이터 보안과 무결성을 보장하기 위해 널리 사용됩니다. 2001년 미국 국립 표준 기술 연구소(NIST)가 Rijndael 알고리즘을 표준으로 채택하면서 AES는 공식 암호화 표준으로 자리 잡았습니다.

AES는 128비트 블록 크기를 기반으로 하며, 키 길이에 따라 AES-128, AES-192, AES-256으로 구분됩니다. 일반적으로 AES-128과 AES-256이 가장 널리 사용됩니다. 이 중 AES-256은 더 긴 키 길이로 인해 보안성이 뛰어나지만, 처리 성능은 다소 낮아질 수 있습니다.


2. AES-128과 AES-256의 차이

구분 AES-128 AES-256
키 길이 128비트 (16바이트) 256비트 (32바이트)
라운드 수 10 라운드 14 라운드
보안 수준 높은 수준 매우 높은 수준
성능 상대적으로 빠름 상대적으로 느림
  • AES-128: 16바이트 키를 사용하며, 10번의 라운드를 통해 데이터를 암호화합니다. 속도가 빠르고, 보안성도 충분히 우수합니다.
  • AES-256: 32바이트 키를 사용하고 14번의 라운드를 수행합니다. 더 강력한 보안을 제공하지만, 성능 저하가 발생할 수 있습니다.

3. AES의 운영 모드

AES는 다양한 운영 모드를 통해 데이터를 암호화하는 방식이 결정됩니다. 다음은 대표적인 운영 모드입니다.

3.1 ECB (Electronic Codebook) 모드

ECB 모드는 블록별로 독립적으로 암호화를 수행하는 방식입니다. 같은 평문 블록은 같은 암호문 블록으로 변환됩니다.

특징:

  • 구현이 간단하고 빠름
  • 동일한 입력 데이터는 동일한 출력 값을 생성
  • 패턴이 반복되는 데이터를 암호화하면 보안성이 약해짐

단점:
이미지와 같은 패턴이 있는 데이터에서는 암호화 후에도 원본의 패턴이 유지되는 문제가 있습니다.

3.2 CBC (Cipher Block Chaining) 모드

CBC 모드는 각 블록을 암호화할 때 이전 블록의 암호문과 XOR 연산을 수행하는 방식입니다. 첫 블록에는 초기화 벡터(IV)가 사용됩니다.

특징:

  • 동일한 데이터라도 서로 다른 IV를 사용하면 다른 결과가 생성
  • 보안성이 ECB보다 뛰어남

단점:

  • 병렬 처리가 불가능하여 속도가 느릴 수 있음
  • IV가 노출되면 보안성이 약해질 수 있음

3.3 CTR (Counter) 모드

CTR 모드는 블록 번호와 nonce(일회성 숫자)를 조합해 카운터 값을 생성하고, 이를 암호화하여 키 스트림을 만든 후 평문과 XOR 연산을 수행합니다.

특징:

  • 병렬 처리 가능
  • IV와 카운터가 같으면 동일한 키 스트림이 생성됨

단점:

  • 카운터와 nonce가 고유하지 않으면 보안성이 약해짐

4. nRF52 SDK를 활용한 AES 데이터 암호화 및 복호화

nRF52840과 같은 nRF52 시리즈는 AES 암호화 기능을 하드웨어 가속기로 제공하여 성능을 향상시킵니다. 다음은 AES-128 CBC 모드를 활용한 데이터 암호화 및 복호화 예제입니다.

4.1 환경 설정

먼저 nRF52 SDK와 SoftDevice를 설치하고 개발 환경을 설정합니다. SDK의 nrf_crypto 라이브러리를 이용하면 AES 기능을 쉽게 사용할 수 있습니다.

4.2 AES-128 CBC 암호화 예제 코드

#include "nrf_crypto.h"
#include "nrf_log.h"

#define AES_KEY_SIZE 16
#define AES_BLOCK_SIZE 16

static uint8_t aes_key[AES_KEY_SIZE] = {
    0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
    0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81
};

static uint8_t iv[AES_BLOCK_SIZE] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};

static uint8_t plain_text[] = "Hello, nRF52840 AES!";
static uint8_t encrypted_text[AES_BLOCK_SIZE];
static uint8_t decrypted_text[AES_BLOCK_SIZE];

void aes_encrypt(void)
{
    nrf_crypto_aes_context_t aes_context;
    ret_code_t ret;

    // AES CBC 모드 초기화
    ret = nrf_crypto_aes_init(&aes_context, &g_nrf_crypto_aes_cbc_128_info, NRF_CRYPTO_ENCRYPT);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES init failed: %d", ret);
        return;
    }

    // 암호화 수행
    ret = nrf_crypto_aes_crypt(&aes_context, aes_key, iv, plain_text, sizeof(plain_text), encrypted_text);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES encryption failed: %d", ret);
        return;
    }

    NRF_LOG_INFO("Encrypted data: ");
    for (int i = 0; i < sizeof(encrypted_text); i++) {
        NRF_LOG_INFO("%02x ", encrypted_text[i]);
    }

    nrf_crypto_aes_uninit(&aes_context);
}

void aes_decrypt(void)
{
    nrf_crypto_aes_context_t aes_context;
    ret_code_t ret;

    // AES CBC 모드 초기화
    ret = nrf_crypto_aes_init(&aes_context, &g_nrf_crypto_aes_cbc_128_info, NRF_CRYPTO_DECRYPT);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES init failed: %d", ret);
        return;
    }

    // 복호화 수행
    ret = nrf_crypto_aes_crypt(&aes_context, aes_key, iv, encrypted_text, sizeof(encrypted_text), decrypted_text);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES decryption failed: %d", ret);
        return;
    }

    NRF_LOG_INFO("Decrypted data: %s", decrypted_text);
    nrf_crypto_aes_uninit(&aes_context);
}

int main(void)
{
    NRF_LOG_INIT(NULL);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("AES Example Start\n");

    aes_encrypt();
    aes_decrypt();

    while (true)
    {
        NRF_LOG_FLUSH();
    }
}

4.3 AES-256 CBC 암호화 예제 코드

#include "nrf_crypto.h"
#include "nrf_log.h"

#define AES_256_KEY_SIZE 32
#define AES_BLOCK_SIZE 16

static uint8_t aes256_key[AES_256_KEY_SIZE] = {
    0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
    0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
    0x24, 0x45, 0xa2, 0x31, 0x0b, 0x6e, 0xa7, 0x94,
    0x75, 0x16, 0x2e, 0x88, 0x3f, 0xd7, 0x2d, 0x6a
};

static uint8_t iv[AES_BLOCK_SIZE] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};

static uint8_t plain_text[] = "Hello, nRF52840 AES-256!";
static uint8_t encrypted_text[AES_BLOCK_SIZE];
static uint8_t decrypted_text[AES_BLOCK_SIZE];

void aes256_encrypt(void)
{
    nrf_crypto_aes_context_t aes_context;
    ret_code_t ret;

    ret = nrf_crypto_aes_init(&aes_context, &g_nrf_crypto_aes_cbc_256_info, NRF_CRYPTO_ENCRYPT);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES-256 init failed: %d", ret);
        return;
    }

    ret = nrf_crypto_aes_crypt(&aes_context, aes256_key, iv, plain_text, sizeof(plain_text), encrypted_text);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES-256 encryption failed: %d", ret);
        return;
    }

    NRF_LOG_INFO("AES-256 Encrypted data:");
    for (int i = 0; i < sizeof(encrypted_text); i++) {
        NRF_LOG_INFO("%02x ", encrypted_text[i]);
    }

    nrf_crypto_aes_uninit(&aes_context);
}

void aes256_decrypt(void)
{
    nrf_crypto_aes_context_t aes_context;
    ret_code_t ret;

    ret = nrf_crypto_aes_init(&aes_context, &g_nrf_crypto_aes_cbc_256_info, NRF_CRYPTO_DECRYPT);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES-256 init failed: %d", ret);
        return;
    }

    ret = nrf_crypto_aes_crypt(&aes_context, aes256_key, iv, encrypted_text, sizeof(encrypted_text), decrypted_text);
    if (ret != NRF_SUCCESS) {
        NRF_LOG_ERROR("AES-256 decryption failed: %d", ret);
        return;
    }

    NRF_LOG_INFO("AES-256 Decrypted data: %s", decrypted_text);
    nrf_crypto_aes_uninit(&aes_context);
}

int main(void)
{
    NRF_LOG_INIT(NULL);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("AES-256 Example Start\n");

    aes256_encrypt();
    aes256_decrypt();

    while (true)
    {
        NRF_LOG_FLUSH();
    }
}

5. 결론

AES는 데이터 보안에 필수적인 알고리즘으로, nRF52 시리즈의 하드웨어 가속 기능을 이용하면 성능 저하 없이 안전한 통신과 데이터를 보호할 수 있습니다.

운영 모드 선택 시 보안과 성능의 균형을 고려해야 하며, CBC와 CTR 모드는 실제 환경에서 많이 사용됩니다. nRF52 SDK의 nrf_crypto API를 이용하면 이러한 AES 암호화를 쉽게 구현할 수 있습니다.

반응형