Tech-Trends

공개키 암호화 기법 - 타원곡선 암호(楕圓曲線暗號, Elliptic curve cryptography)의 주요 특징과 예시

IT오이시이 2024. 2. 17. 00:07
728x90

 

타원곡선 암호(楕圓曲線暗號, Elliptic curve cryptography)는 타원곡선 이론에 기반한 공개 키 암호 방식의 주요 특징과 예시에 대해 아래에 설명하겠습니다:

전통적인 대칭 및 비대칭 암호화 방법과는 다르게 타원 곡선을 사용하여 데이터를 안전하게 전송하고 보호하는 기법으로기본적으로 타원형 암호화는 타원 곡선 위의 점들 간의 연산을 기반으로 합니다. 이 연산을 통해 암호화 키의 생성, 서명, 키 교환 등이 이루어 집니다. 타원 곡선의 수학적 특성은 기존의 암호화 기법보다 효과적으로 안전한 키 길이를 제공할수 있어  주로 작은 키 사이즈로도 강력한 보안을 제공할 수있어서  리소스가 제한된 환경에서 중요합니다.. 

 




1. 타원곡선 암호 특징:



(1) 수학적 안전성: 타원 곡선 암호화는 타원 곡선 이론의 수학적인 특성을 기반으로 하므로 기존의 RSA와 같은 알고리즘에 비해 더 적은 비트 수로 안전한 수준의 보안을 제공할 수 있습니다.

(2) 효율성: 타원 곡선 암호화는 비교적 짧은 키 길이로 강력한 보안을 제공하기 때문에 작은 데이터 패킷에서도 빠르고 효율적으로 동작합니다. 이는 특히 리소스 제한된 환경에서 중요합니다.

(3) 저전력 장치 및 모바일 보안: 작은 키 사이즈와 빠른 암호화/복호화 속도로 인해 타원 곡선 암호화는 모바일 기기 및 저전력 장치에서의 보안 향상에 적합합니다.

(4) TLS 및 보안 프로토콜: 타원 곡선 암호화는 Transport Layer Security(TLS)와 같은 보안 프로토콜에서도 적극적으로 사용되어 네트워크 통신의 보안을 강화합니다.

(5) 키 교환 기능: 타원형 암호화는 Diffie-Hellman 키 교환과 같은 프로토콜에서 사용될 수 있어 안전한 통신을 위한 키 교환 기능을 제공합니다.
  (주로 두 통신 당사자 간에 안전한 키를 교환하는 데 사용되며, 특히 디지털 서명 및 대칭 키 암호화에서 키 교환을 위한 보안 메커니즘으로 활용됩니다.)

(6) 다양한 응용 분야: 타원형 암호화는 블록체인 기술, 디지털 서명, 키 교환 등 다양한 보안 응용 분야에서 활용되고 있습니다.
   . 블록체인과 암호화폐 분야 일부 블록체인 플랫폼에서는 타원 곡선 암호화를 사용하여 디지털 서명 및 트랜잭션 보안을 제공합니다.

 


2. ECDH(Elliptic Curve Diffie-Hellman)의 특징:

 

(1) 공개키 기반:

ECDH는 공개키 기반의 암호화 기술로, 각 사용자는 공개키와 개인키를 생성합니다. 공개키는 다른 사용자와 공유되고, 개인키는 비밀로 유지됩니다.

(2) 타원 곡선 활용:

ECDH에서는 타원 곡선 알고리즘을 사용하여 키 교환을 수행합니다. 타원 곡선 알고리즘은 기존의 유명한 키 교환 알고리즘들에 비해 더 적은 비트 수로 강력한 보안을 제공합니다.

(3) Perfect Forward Secrecy (PFS):

ECDH는 Perfect Forward Secrecy를 제공합니다. 이는 한 번의 키 교환 후에도 이전 세션의 키가 유출되어도 현재 및 미래 세션은 안전하다는 것을 의미합니다.

(4) 단순하고 효율적:

ECDH는 구현이 간단하면서도 효율적인 키 교환 메커니즘을 제공합니다. 작은 키 크기로도 강력한 보안을 제공하므로 자원 효율성이 뛰어납니다.

 


3.  Elliptic Curve Diffie-Hellman (ECDH) 키 교환 예시:

 

다음은 Python에서 Elliptic Curve Diffie-Hellman (ECDH) 키 교환 방식으로 안전한 통신을 위한 키 교환을 제공하는 데 사용간단한 예시  코드입니다.  ( pip install cryptography 명령을 사용하여 cryptography 라이브러리를 설치하여 실행합니다.)

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization

# Alice의 키 생성
alice_private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
alice_public_key = alice_private_key.public_key()

# Bob의 키 생성
bob_private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
bob_public_key = bob_private_key.public_key()

# Alice이 Bob의 공개 키로 비밀 공유 키 계산
shared_key_alice = alice_private_key.exchange(ec.ECDH(), bob_public_key)

# Bob이 Alice의 공개 키로 비밀 공유 키 계산
shared_key_bob = bob_private_key.exchange(ec.ECDH(), alice_public_key)

# 비밀 공유 키 출력
print("Shared Key Alice:", shared_key_alice.hex())
print("Shared Key Bob:", shared_key_bob.hex())

 

* ec.SECP256R1() 은 SECP256R1 타원 곡선을 나타냅니다. SECP256R1은 NIST에서 정의한 타원 곡선 중 하나로, ECDSA (Elliptic Curve Digital Signature Algorithm) 및 ECDH (Elliptic Curve Diffie-Hellman)와 같은 알고리즘에서 사용됩니다. SECP256R1은 256 비트의 보안 수준을 제공합니다.

 

4. ECDH (Elliptic Curve Diffie-Hellman)를 사용하여 전문을 전송하고 복호화하는 예시 코드

 

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

def generate_key_pair():
    # 개인 키와 공개 키 생성
    private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
    public_key = private_key.public_key()

    # 공개 키를 바이트로 변환하여 반환
    serialized_public_key = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )
    
    return private_key, serialized_public_key

def derive_shared_key(my_private_key, peer_public_key):
    # 상대방의 공개 키를 로드
    loaded_peer_public_key = serialization.load_pem_public_key(peer_public_key, default_backend())

    # ECDH로 공유 키 생성
    shared_key = my_private_key.exchange(ec.ECDH(), loaded_peer_public_key)

    # HKDF를 사용하여 공유 키 확장
    derived_key = HKDF(
        algorithm=hashes.SHA256(),
        length=32,
        salt=None,
        info=b'ecdh_key_derivation',
        backend=default_backend()
    ).derive(shared_key)

    return derived_key

def encrypt_message(message, key):
    # AES-GCM 암호화
    cipher = Cipher(algorithms.AES(key), modes.GCM())
    encryptor = cipher.encryptor()
    ciphertext = encryptor.update(message) + encryptor.finalize()
    tag = encryptor.tag

    return ciphertext, tag

def decrypt_message(ciphertext, tag, key):
    # AES-GCM 복호화
    cipher = Cipher(algorithms.AES(key), modes.GCM(tag))
    decryptor = cipher.decryptor()
    plaintext = decryptor.update(ciphertext) + decryptor.finalize()

    return plaintext

# Alice와 Bob의 키 생성
alice_private_key, alice_public_key = generate_key_pair()
bob_private_key, bob_public_key = generate_key_pair()

# Alice과 Bob이 서로의 공개 키를 교환
alice_shared_key = derive_shared_key(alice_private_key, bob_public_key)
bob_shared_key = derive_shared_key(bob_private_key, alice_public_key)

# 공유된 키를 사용하여 전문 암호화
message_to_send = b"안녕, Bob! 이 메시지는 Alice에서 전송되었습니다."
ciphertext, tag = encrypt_message(message_to_send, alice_shared_key)

# Bob이 공유된 키를 사용하여 전문 복호화
received_message = decrypt_message(ciphertext, tag, bob_shared_key)

# 결과 출력
print("Original Message:", message_to_send.decode('utf-8'))
print("Decrypted Message by Bob:", received_message.decode('utf-8'))

 


4.2 C언어로 작성한 ECDH를 사용하여 메시지를 전송하고 복호화하는  코드

-  OpenSSL 라이브러리를 사용하여 C 언어로 작성된 ECDH를 이용한 메시지 전송 및 복호화 예

#include <stdio.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

void handleErrors()
{
    fprintf(stderr, "오류가 발생했습니다.\n");
    exit(EXIT_FAILURE);
}

EC_KEY *generate_key_pair()
{
    EC_KEY *key_pair = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
    if (!key_pair)
        handleErrors();

    if (EC_KEY_generate_key(key_pair) != 1)
        handleErrors();

    return key_pair;
}

unsigned char *derive_shared_key(const EC_KEY *my_private_key, const EC_KEY *peer_public_key)
{
    int shared_key_size = EC_GROUP_get_degree(EC_KEY_get0_group(my_private_key)) / 8;
    unsigned char *shared_key = malloc(shared_key_size);
    if (!shared_key)
        handleErrors();

    if (ECDH_compute_key(shared_key, shared_key_size, EC_KEY_get0_public_key(peer_public_key), my_private_key, NULL) == -1)
        handleErrors();

    return shared_key;
}

void encrypt_message(const unsigned char *message, size_t message_len, const unsigned char *key, unsigned char **ciphertext, unsigned char *tag)
{
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if (!ctx)
        handleErrors();

    if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, NULL) != 1)
        handleErrors();

    *ciphertext = malloc(message_len);
    if (!*ciphertext)
        handleErrors();

    if (EVP_EncryptUpdate(ctx, *ciphertext, NULL, message, message_len) != 1)
        handleErrors();

    if (EVP_EncryptFinal_ex(ctx, *ciphertext + message_len, NULL) != 1)
        handleErrors();

    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1)
        handleErrors();

    EVP_CIPHER_CTX_free(ctx);
}

void decrypt_message(const unsigned char *ciphertext, size_t ciphertext_len, const unsigned char *tag, const unsigned char *key, unsigned char **plaintext)
{
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if (!ctx)
        handleErrors();

    if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, NULL) != 1)
        handleErrors();

    *plaintext = malloc(ciphertext_len);
    if (!*plaintext)
        handleErrors();

    if (EVP_DecryptUpdate(ctx, *plaintext, NULL, ciphertext, ciphertext_len) != 1)
        handleErrors();

    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (void *)tag) != 1)
        handleErrors();

    if (EVP_DecryptFinal_ex(ctx, *plaintext + ciphertext_len, NULL) != 1)
        handleErrors();

    EVP_CIPHER_CTX_free(ctx);
}

int main()
{
    // Alice와 Bob의 키 생성
    EC_KEY *alice_private_key = generate_key_pair();
    EC_KEY *bob_private_key = generate_key_pair();

    // Alice과 Bob이 서로의 공개 키를 교환
    const EC_POINT *alice_public_key = EC_KEY_get0_public_key(alice_private_key);
    const EC_POINT *bob_public_key = EC_KEY_get0_public_key(bob_private_key);

    // Alice과 Bob이 서로의 공유된 키를 계산
    unsigned char *alice_shared_key = derive_shared_key(alice_private_key, bob_public_key);
    unsigned char *bob_shared_key = derive_shared_key(bob_private_key, alice_public_key);

    // 공유된 키를 사용하여 전문 암호화
    const unsigned char *message_to_send = (const unsigned char *)"안녕, Bob! 이 메시지는 Alice에서 전송되었습니다.";
    unsigned char *ciphertext;
    unsigned char tag[16];

    encrypt_message(message_to_send, strlen((const char *)message_to_send), alice_shared_key, &ciphertext, tag);

    // Bob이 공유된 키를 사용하여 전문 복호화
    unsigned char *received_message;
    decrypt_message(ciphertext, strlen((const char *)ciphertext), tag, bob_shared_key, &received_message);

    // 결과 출력
    printf("Original Message: %s\n", message_to_send);
    printf("Decrypted Message by Bob: %s\n", received_message);

    // 메모리 해제
    EC_KEY_free(alice_private_key);
    EC_KEY_free(bob_private_key);
    free(alice_shared_key);
    free(bob_shared_key);
    free(ciphertext);
    free(received_message);

    return 0;
}
728x90
반응형