
window.crypto API를 이용한 AES256 암호화 및 복호화
Java Script안녕하세요 Lovefield입니다.
웹 개발을 하다보면, 민감한 사용자 정보를 안전하게 전송해야 하는 경우가 생깁니다. 중요한 데이터를 서버로 전송해야 할때, 이러한 정보가 중간에 탈취되거나 변조되지 않도록 암호화 하는 과정이 필요합니다. 이번 글에서는 TypeScript 환경에서 웹 표준 암호화 API인 'window.crypto'를 이용하여 AES256 알고리즘으로 데이터를 암호화하고 복호화 하는 방법에 대해서 알아봅니다.
AES256 암호화 알고리즘이란?
AES(Advanced Encryption Standard)는 현재 가장 널리 사용되는 대칭키 암호화 알고리즘 중 하나입니다. '대칭키'라는 의미는 암호화와 복호화에 동일한 키를 사용한다는 것을 뜻합니다. AES는 다양한 키 길이를 지원하며, 그중 AES256은 256비트의 키를 사용하여 매우 강력한 보안 수준을 제공합니다. 이는 현대의 컴퓨팅 능력으로도 해독하는 데 막대한 시간과 노력이 필요하기 때문에 안전한 암호화 방식으로 널리 인정받고 있습니다. window.crypto API 란?
window.crypto API 란?
window.crypto는 웹 브라우저에서 제공하는 암호화 관련 기능을 사용할 수 있도록 하는 JavaScript API입니다. 이 API는 난수 생성, 암호화, 복호화, 디지털 서명 등 다양한 암호화 관련 작업을 안전하게 수행할 수 있도록 설계되었습니다. 특히, crypto.subtle 인터페이스는 암호화, 복호화와 같은 저수준 암호화 작업을 위한 메서드를 제공하며, AES와 같은 다양한 암호화 알고리즘을 지원합니다.
암호화 함수
TypeScript
async function encodeAESValue(value:string) : string {
if(window.crypto !== undefined){
const key: string = ""; // 32byte 의 고정 키
const iv: string = ""; // 16byte 의 고정 iv
const keyData = new TextEncoder().encode(key);
const ivData = new TextEncoder().encode(iv);
const importKey = await crypto.subtle.importKey("raw", keyData, { name: "AES-CBC" }, false, ["encrypt"]);
const textData = new TextEncoder().encode(value);
const encrypted = await crypto.subtle.encrypt({ name: "AES-CBC", iv: ivData }, importKey, textData);
return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}else{
throw new Error(“Not Supported”);
}
}
설명
- if(window.crypto !== undefined) : crypto API를 지원하는지 확인합니다.
- new TextEncoder() : key와 iv를 각각 Uint8Array 형태로 인코딩합니다.
- await crypto.subtle.importKey : 암호화에 사용할 키를 가져옵니다.
- raw : 키 형식을 지정합니다.
- keyData : 앞서 인코딩한 키 데이터입니다.
- name: “AES-CBC” : 사용할 암호화 알고리즘과 모드를 지정합니다. 여기서는 CBC(Chipher Block Chaining) 모드를 사용했습니다.
- false : 키 추출 가능 여부를 설정합니다.
- [“encrypt”] : 키의 사용 목적을 지정합니다. 여기서는 암호화에만 사용하도록 설정했습니다. - new TextEncoder().encode(value) : 암호화 할 문자열 값을 Uint8Array 형태로 인코딩합니다.
- await crypto.subtle.encrypt : 실제로 암호화를 수행합니다.
- { name: "AES-CBC", iv: ivData } : 사용할 암호화 알고리즘과 iv를 지정합니다.
- importKey : 앞서 가져온 키입니다.
- textData : 인코딩된 암호화 문자열 값입니다. - btoa(String.fromCharCode(...new Uint8Array(encrypted))) : 암호화된 ArrayBuffer 데이터를 Base64 문자열로 인코딩하여 반환합니다.
복호화 함수
TypeScript
async function decodeAESValue(value:string) : string {
if(window.crypto !== undefined){
const key: string = ""; // 32byte 의 고정 키
const iv: string = ""; // 16byte 의 고정 iv
const keyData = new TextEncoder().encode(key);
const ivData = new TextEncoder().encode(iv);
const importKey = await crypto.subtle.importKey("raw", keyData, { name: "AES-CBC" }, false, ["decrypt"]);
const textData = base64ToUint8Array(value);
const encrypted = await crypto.subtle.decrypt({ name: "AES-CBC", iv: ivData }, importKey, textData);
const decryptedBytes = new Uint8Array(decrypted);
return new TextDecoder().decode(decryptedBytes);
}else{
throw new Error(“Not Supported”);
}
}
설명
- if(window.crypto !== undefined) : crypto API 지원 여부를 확인합니다.
- new TextEncoder().encode(key), new TextEncoder().encode(iv) : 암호화에 사용된 키와 초기화 벡터(IV)를 Uint8Array 형태로 변환합니다.
- crypto.subtle.importKey("raw", keyData, { name: "AES-CBC" }, false, ["decrypt"]) : 복호화 전용 키를 가져옵니다.
- base64ToUint8Array(value) : 암호화된 Base64 문자열을 Uint8Array로 변환합니다.
- crypto.subtle.decrypt({ name: "AES-CBC", iv: ivData }, importKey, textData) : 암호화된 데이터를 복호화합니다.
- new TextDecoder().decode(decryptedBytes) : 복호화된 바이너리 데이터를 다시 문자열로 변환하여 원본 데이터를 복원합니다.
Base64 문자열을 Uint8Array로 변환하는 함수
복호화 과정에서는 암호화된 Base64 문자열을 다시 바이너리 데이터로 변환하는 과정이 필요합니다. 이를 위해 다음과 같은 헬퍼 함수를 추가로 구현할 수 있습니다.
TypeScript
function base64ToUint8Array(base64: string): Uint8Array {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i += 1) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
이번 글에서는 TypeScript 환경에서 웹 표준 API인 window.crypto와 crypto.subtle 인터페이스를 이용하여 AES256 알고리즘을 사용한 데이터 암호화 및 복호화 방법에 대해 알아봤습니다.
이 방식을 활용하면 민감한 사용자 데이터를 안전하게 서버로 전송할 수 있으며, 특히 로그인, 결제, 개인정보 입력 등 보안이 필수적인 기능 구현 시 매우 유용합니다. 또한 브라우저에 기본적으로 내장된 API를 사용하기 때문에 별도의 라이브러리 없이도 간단하고 효율적으로 암호화를 적용할 수 있다는 장점이 있습니다.
다만, 실제 서비스에서는 고정된 키와 IV를 사용하는 것은 보안상 위험할 수 있습니다. 보다 안전한 암호화 통신을 위해서는 키를 동적으로 생성하고, 주기적으로 변경하며, 안전한 채널을 통해 키를 관리하는 방법을 병행하는 것이 필요합니다.
암호화는 데이터 보안의 기본이자 필수 요소입니다. 보다 안전한 웹 서비스를 만들기 위해 이번 내용을 다양한 프로젝트에 적용해보시길 바랍니다.