결제 API 연동 개발을 할 때, AES/CBC/PKCS5Padding 암호화를 사용합니다.
PHP 코드를 참고하여 파이썬으로 이용 가능한 코드를 구현했습니다.
# pip install cryptography
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
class SEEDCBC:
def __init__(self, iv, key):
self.iv = bytes(iv, 'utf-8')
self.key = base64.b64decode(key.encode('utf-8'))
self.cipher = Cipher(algorithms.SEED(self.key), modes.CBC(self.iv), backend=default_backend())
pass
def pad(self, s: str):
BLOCK_SIZE = 16
return s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
def encrypt(self, plain_text):
encryptor = self.cipher.encryptor()
padded = self.pad(plain_text) # Ensure plaintext is padded to 16 bytes (block size)
result = encryptor.update(padded.encode()) + encryptor.finalize()
return base64.b64encode(result).decode()
def decrypt(self, b64_text):
decryptor = self.cipher.decryptor()
unpad = padding.PKCS7(128).unpadder()
plain_text = base64.b64decode(b64_text.encode('utf-8'))
enc = decryptor.update(plain_text) + decryptor.finalize()
result = unpad.update(enc) + unpad.finalize()
return result.decode()
s = SEEDCBC(iv='16자리 문자열', key='해당 암호화로 encrypt된 문자열')
enc = s.encrypt('안녕하세요')
result = s.decrypt(enc) # 안녕하세요
참고한 php 코드
// 문자열 Base64 복호화 후 16진수 byte 변환
function getBytesBase64($base64String) {
$decodedData = base64_decode($base64String);
$byteArray = [];
for ($i = 0; $i < strlen($decodedData); $i++) {
$byteArray[] = ord($decodedData[$i]);
if ($byteArray[$i] > 127) {
$byteArray[$i] -= 256;
}
}
return $byteArray;
}
// 문자열 16진수 byte 변환
function getBytes($str) {
$byteArray = unpack('C*', $str);
$byteValues = [];
foreach ($byteArray as $byte) {
$byteValues[] = $byte;
}
return $byteValues;
}
// SEED/CBC/PKCS5Padding 암호화
function encrypt($bszIV, $bszUser_key, $str) {
$planBytes = $this->getBytes($str);
$keyBytes = $this->getBytesBase64($bszUser_key);
$IVBytes = $this->getBytes($bszIV);
$message_offset = 0;
$message_length = count($planBytes);
$bszChiperText = KISA_SEED_CBC::SEED_CBC_Encrypt($keyBytes, $IVBytes, $planBytes, $message_offset, $message_length);
$string = '';
foreach ($bszChiperText as $byte) {
$string .= chr($byte);
}
$base64EncodedString = base64_encode($string);
return $base64EncodedString;
}
// SEED/CBC/PKCS5Padding 복호화
function decrypt($bszIV, $bszUser_key, $str) {
$planBytes = $this->getBytesBase64($str);
$keyBytes = $this->getBytesBase64($bszUser_key);
$IVBytes = $this->getBytes($bszIV);
$message_offset = 0;
$message_length = count($planBytes);
$bszPlainText = null;
$bszPlainText = KISA_SEED_CBC::SEED_CBC_Decrypt($keyBytes, $IVBytes, $planBytes, $message_offset, $message_length);
return implode(array_map('chr', $bszPlainText));
}
- getBytesBase64(), getBytes() 에서의 차이점
# 파이썬으로 나타낸 해당 함수 # getBytesBase64() for i in base64.b64decode(b64_text.encode('utf-8')): print(i) # ord가 128부터는 ’\x80’인데 여기서는 -256을 한다. # getBytes() for i in bytes(bytes_text, 'utf-8'): print(i) - 파이썬에서는 해당 함수를 따로 구현하지 않아도 된다.
'파이썬' 카테고리의 다른 글
| 파이썬 임시 이미지 파일 처리 (0) | 2024.11.10 |
|---|---|
| AES256 파이썬 구현 (MODE_EAX, MODE_CBC) (0) | 2024.10.23 |
| FastAPI Request에서 form-data, query string 읽기 (0) | 2024.10.10 |
| FastAPI 이미지 파일을 포함한 form-data 예제 (0) | 2024.10.10 |
| 파이썬 requests SSLError 발생 (운영 환경) (0) | 2024.10.10 |