공개키 암호화 기법 - 타원곡선 암호(楕圓曲線暗號, Elliptic curve cryptography)의 주요 특징과 예시
타원곡선 암호(楕圓曲線暗號, 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;
}