CryptoJS를 이용한 AES256 암호화 / 복호화

자바스크립트에서 CryptoJS 라이브러리를 사용하여 AES256 방식으로 데이터를 암호화하기 위한 함수는 다음과 같습니다.

encodeByAES56(key, data){
    const cipher = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(""),
        padding: CryptoJS.pad.Pkcs7,
        mode: CryptoJS.mode.CBC
    });

    return cipher.toString();
}

위의 함수를 사용하는 예는 다음과 같구요.

const k = "key";
const rk = k.padEnd(32, " "); // AES256은 key 길이가 32자여야 함
const b = "암호화는 보안을 위해 매우 중요합니다.";
const eb = this.encodeByAES56(rk, b);

console.log(eb);

출력 결과는 다음과 같습니다.

mXK9nlcT70QdTjKgzxAD99zS4UYah0OZI8GFT8Pg+Vu3GFmF/HPmlV0PA/sUy7rr4+2Sh319ZEIz2TlyiPWcvw==

암호화된 위의 문자열을 복호화하는 함수는 다음과 같습니다.

decodeByAES256(key, data){
    const cipher = CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(""),
        padding: CryptoJS.pad.Pkcs7,
        mode: CryptoJS.mode.CBC
    });

    return cipher.toString(CryptoJS.enc.Utf8);
};

위의 함수를 사용하는 예는 다음과 같구요.

const k = "key"; // 암호화에서 사용한 값과 동일하게 해야함
const rk = k.padEnd(32, " "); // AES256은 key 길이가 32자여야 함
const eb = "mXK9nlcT70QdTjKgzxAD99zS4UYah0OZI8GFT8Pg+Vu3GFmF/HPmlV0PA/sUy7rr4+2Sh319ZEIz2TlyiPWcvw==";
const b = this.decodeByAES56(rk, eb);

console.log(b);

실행 결과는 다음과 같습니다.

암호화는 보안을 위해 매우 중요합니다.

Javascript의 디스트럭처링(Destructuring)

자바스크립트의 디스트럭처링은 객체와 배열에 적용이 가능한데요. 디스트럭처링은 객체와 배열을 구성하는 개별 요소를 독립적인 상수나 변수에 저장하는 방법입니다.

먼저 객체에 대한 디스트럭처링 예제는 다음과 같습니다.

const Dip2K = {
    name: "김형준",
    company: {
        name: "GEOSERVICE",
        contacts: {
            address: "에이펙센터 208",
            telephone: "02-525-0421"
        }
    }
}

const { name } = Dip2K
console.log(name) // 김형준

const { address, telephone } = Dip2K.company.contacts
console.log(address, telephone) // 에이펙센터 208 02-525-0421

const { name: companyName} = Dip2K.company
console.log(companyName) // GEOSERVICE

const { alias = "닌자" } = Dip2K.company
console.log(alias) // 닌자

다음은 배열에 대한 디스트럭처링 예제입니다.

const Dip2K = [ "김형준", "지오서비스", "hjkim@geoservice.co.kr" ]

const [name, company, email] = Dip2K
//console.log(name, company, email) // 김형준 지오서비스 hjkim@geoservice.co.kr

const [name2, company2 ] = Dip2K
//console.log(name2, company2) // 김형준 지오서비스

const [name3, ...others] = Dip2K 
console.log(name3, others) // 김형준 (2) ['지오서비스', 'hjkim@geoservice.co.kr']

Javascript, Object 이 놈을 알아야 그 놈을 잡는다.

Javascipt에서 Object는 모든 객체의 슈퍼 타입(최상위 타입)입니다. Object를 더 많이 알수록 이 놈을 통해 파생된 그 놈들을 더 잘.. 알 수 있습니다. 이 글은 Object의 내용중 유용한 정적 매서드 몇가지를 살펴봅니다.

먼저 객체의 키(key)만을 배열로 가져오는 keys입니다.

const obj = {
    "key0": "value0",
    "key1": "value1",
    "key2": "value2"
}

const keys = Object.keys(obj)
console.log(keys) // ["key0", "key1", "key2"]

다음은 값(Value)만을 배열로 가져오는 values입니다.

const obj = {
    "key0": "value0",
    "key1": "value1",
    "key2": "value2"
}

const values = Object.values(obj)
console.log(values) // ["value0", "value1", "value2"]

그럼 키와 값 모두를 배열로 가져오기 위해서는? 바로 entries 정적 매서드를 사용하면 됩니다.

const obj = {
    "key0": "value0",
    "key1": "value1",
    "key2": "value2"
}

const entries = Object.entries(obj)
console.log(entries)
/*
[
    ["key0", "value0"],
    ["key1", "value1"],
    ["key2", "value2"]
]
*/

이제 반대로 위의 entries 정적 매서드로 가져온 결과를 통해 다시 원래의 객체를 만들고자 한다면? 바로 fromEntries 정적 매서드를 사용하면 됩니다.

const arr = [
    ["K1", "V1"], 
    ["K2", "V2"]
];

const obj = Object.fromEntries(arr);
console.log(obj); // {K1: "V1", K2: "V2"}

다음 예제는 지금까지와는 다른 흐름인데요. 객체를 복사하기 위한 Javascript 적인 방법은 여러가지가 있는데요. 그 중 Object의 assign 정적 매서드를 사용하는 방법이있습니다.

const a = {}
b = Object.assign(a, obj)
console.log(b, a === b, a === obj) 
// {key0: "value0", key1: "value1", key2: "value2"} true false

fetch API를 이용한 REST API 호출

2개 REST API를 순차적으로 호출하는 코드는 아래와 같습니다.

const url1 = "http://localhost:8080/Xr?qryHub|0004259886";
const url2 = "http://localhost:8080/Xr?qryHub|0002097186";

fetch(url1).then(response => {
    return response.json();
}).then(json => {
    console.log("First", json);
    return fetch(url2);
}).then(response => {
    return response.json();
}).then(json => {
    console.log("Second", json);
}).catch(function (error) {
    console.warn(error);
});

url1에 대한 REST API의 호출이 성공하면 url2에 대한 REST API가 호출됩니다. 이 두 개의 REST API가 문제가 없다면 결과가 호출된 순서대로 아래처럼 콘솔에 표시됩니다.

위의 코드를 보면 2개의 REST API는 그 결과에 종속적이지 않으므로 순차적으로 호출하지 않고 동시에 호출하는 것이 효율적입니다. 아래의 코드는 이 2개의 REST API를 동시에 호출하여 2개의 결과를 취합해 출력하는 코드입니다.

const url1 = "http://localhost:8080/Xr?qryHub|0004259886";
const url2 = "http://localhost:8080/Xr?qryHub|0002097186";

Promise.all([fetch(url1), fetch(url2)]).then(responses => {
    return Promise.all(responses.map(response => {
        return response.json();
    }));
}).then(json => {
    console.log(json);
}).catch(error => {
    console.log(error);
});

결과는 다음과 같습니다.

지금까지 살펴보면 REST API는 GET 방식인데요. POST 방식을 fetch API로 호출하는 코드의 예는 다음과 같습니다.

const url = "http://localhost:8080/Xr?sql|postgis|1";
fetch(url, {
    method: "POST",
    //headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
    body: `
        SELECT 0 as project_id, zone_id, hub_id
        FROM zone_hub_map
        WHERE zone_id
        IN (
            SELECT zone_id FROM project_zone_map WHERE project_id = 0
        );
    `
}).then(response => {
    return response.text();
}).then(text => {
    console.log(text);
});

결과는 다음과 같습니다.