결제 관련 외부 API를 연동할 때, 해당 암호화 방식을 사용해야 하는 경우가 있습니다.
파이썬 코드를 제공하는 곳을 아직 찾지 못해 PHP 코드를 참고하여 구현했습니다.
# pip install cryptography
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
import base64
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()에 있다.
- PHP 해당 함수를 파이썬으로 나타내보면, 아래와 같다.
# 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)
- 위 함수를 파이썬에서는 구현하지 않아도 된다.
'Python tips' 카테고리의 다른 글
임시 비밀번호, 랜덤 문자열 generator (0) | 2024.05.08 |
---|---|
@property와 __call__ 비교 (0) | 2024.05.08 |
map(), filter(), pipe()를 활용하여 데이터 다루기 (0) | 2024.04.08 |
Pydantic을 활용한 JSON, dict 다루기 (0) | 2024.04.01 |
python-dotenv, pydantic_settings를 통한 환경 변수 관리 (0) | 2024.03.28 |