지난 주 작업 중 클라이언트로부터 HTTP Request로 RSA Public Key를 받아서
보안 토큰을 암호화한 후 Response에 실어서 보내는 작업이 있었다.
클라이언트는 Crypto++이라는 C++ 라이브러리를 사용하고 있었다.

이 작업을 위해 RSA 2.0과 PyCrypto를 먼저 사용해 보았으나
Crypto++과 결과물이 맞지 않았다. 
같은 RSA 알고리즘을 사용했다면 기대대로 동작을 해야할텐데
이상하다고 생각했으나 일단 작업은 진행을 해야하니까...
(혹시, 필자가 삽질해서 안된거라면 성공 경험이 있으신 분은 커멘트 부탁드립니다.) 
M2Crypto에서 Crypto++에서 생성한 키들을 이용한 암복호화를 검증하여
옳바르게 작업하는 것을 확인 후 사용하였다.

아래 코드는 해당 작업을 위하여
python 콘솔에서 검증 작업한 코드르 정리/재구성 한 것이다.
사용된 패키지 및 함수에 대해서는 레퍼런스 문서를 찾아보길 바란다.

아래 코드에서 pub_key_hex, priv_key_hex는 DER 포맷의 RSA 키 쌍 이다.
HTTP로 전달하기 위해서는 문자열을 사용해야만 했으며,
Base64 인코딩 시 종종 개행문자가 들어가기도 하는데 이 경우 문제의 소지가 있어
16진수 문자열로 변환하여 전달했다.
PEM 형식은 Base64를 쓸 뿐만 아니라 Crypto++에서 직접 지원하지 않기 때문에
DER 포맷을 사용하였다.
(아이러니 하게도 M2Crypto는 PEM 포맷만 직접 지원한다.)

아래 코드는 16진수 문자열로 된 DER 포맷을 PEM 포맷으로 전환하여
키 객체를 만든 후 값을 처리한다.


import base64

import binascii

from M2Crypto import BIO, RSA

plain_text = '12345' 


TEMPLATE = """-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----"""

raw = binascii.a2b_hex(pub_key_hex)

data = TEMPLATE % base64.encodestring(raw).rstrip()

bio = BIO.MemoryBuffer(data)

pub_key = RSA.load_pub_key_bio(bio)

enc = pub_key.public_encrypt(plain_text, RSA.pkcs1_oaep_padding)

enc_text = binascii.b2a_hex(enc_text)


TEMPLATE = """-----BEGIN RSA PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----"""

raw = binascii.b2a_hex(priv_key_hex)

data = TEMPLATE % base64.encodestring(raw).rstrip()

priv_key = RSA.load_key_string(data)
enc = binascii.a2b_hex(
enc_text)

plain_text = priv_key.private_decrypt(enc, M2Crypto.RSA.pkcs1_oaep_padding)

 
|

ghilbut's Blog is powered by Daum & tistory