[개발] 암복호화 aes-128-ecb / java, nodejs
개발하다보면 이게 개발 언어가 다른 경우가 있음.
특히 암복호화 같은게 이기종에서 자주 씀. 그래서 기록용으로 남겨 봄.
( nodejs 의 결과와 java 의 결과가 동일 해야 됨 )
누군가에게 도움이 되길 ...
NODEJS
////////////////////////////////
//
// info
//
// 빠른 테스트를 위한 nodejs 용 api 호출 및 암복호화 처리 샘플
//
////////////////////////////////
//
// require
//
require('dotenv').config; // npm i dotenv - optional / .env 설정 정보 로딩용
const crypto = require('crypto'); // default - 암복호화 처리
const dateformat = require('dateformat'); // npm i dateformat - date 유틸
////////////////////////////////
//
// const
//
const API_SECRET_KEY = process.env.API_SECRET_KEY || '012345678901234567890123456789ab';
const CRYPTO_CONFIG = {
ALGORITHM : 'aes-128-ecb',
IV : '',
HEX : 'hex',
UTF_8 : 'utf-8',
};
////////////////////////////////
//
// private function
//
/**
* 로그를 기록한다
* @param {...any} args 파라미터
* @since 2021.02.24
*/
const _log = (...args) => {
let df = dateformat(new Date(), `yy-mm-dd HH:MM:ss`);
console.log(`[${df}] `, ...args);
}
////////////////////////////////
//
// public function
//
/**
* 암호화를 수행한다
* @param {String} plainText 평문
* @param {String} key 암복호화 키
* @since 2021.02.24
*/
function aes_encrypt(plainText, key = API_SECRET_KEY){
let hexKey = Buffer.from(key, CRYPTO_CONFIG.HEX);
let cipher = crypto.createCipheriv(CRYPTO_CONFIG.ALGORITHM, hexKey, CRYPTO_CONFIG.IV);
let encrypted = cipher.update(plainText,CRYPTO_CONFIG.UTF_8,CRYPTO_CONFIG.HEX);
encrypted += cipher.final(CRYPTO_CONFIG.HEX);
return encrypted;
}
/**
* 복호화를 수행한다
* @param {String} encText 암호화 된 HEX 문자열
* @param {String} key 암복호화 키
* @since 2021.02.24
*/
function aes_decrypt(encText, key = API_SECRET_KEY){
let hexKey = Buffer.from(key, CRYPTO_CONFIG.HEX);
let cipher = crypto.createDecipheriv(CRYPTO_CONFIG.ALGORITHM, hexKey, CRYPTO_CONFIG.IV);
let decrypted = cipher.update(encText,CRYPTO_CONFIG.HEX, CRYPTO_CONFIG.UTF_8);
decrypted += cipher.final(CRYPTO_CONFIG.UTF_8);
return decrypted;
}
////////////////////////////////
//
// entry point
//
/**
* 진입점
* @since 2021.02.24
*/
async function init(){
// ----- 1. 암복호화 테스트 ------
_log('1. 암복호화 테스트');
let plain_text = "가나다";
_log('plain_text', plain_text);
let encrypt_text = aes_encrypt(plain_text);
_log('encrypt_text', encrypt_text);
let decrypt_text = aes_decrypt('c898d3081b18a58c0f6bbbab927591275c30a9532ea96b925c85133aceedec4c');
_log('decrypt_text', decrypt_text);
}
init();
JAVA
package sample;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/**
* AES 암복호화 유틸리티
* @author wonsama
* @see https://boneman.tistory.com/entry/ByteUtiljava
*/
public class AESCrypto {
private String cipherKey;
/**
* 생성자
* @param cipherKey 암/복호화 키
* @since 2021.02.24
*/
public AESCrypto(String cipherKey){
this.cipherKey = cipherKey;
}
/**
* 모드에 따른 암복호화 처리기
* @param mode Cipher.ENCRYPT_MODE / Cipher.DECRYPT_MODE
* @return Cipher
* @throws Exception - NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException
* @since 2021.02.24
*/
private Cipher getCipher(int mode) throws Exception{
Key key = new SecretKeySpec(toBytes(cipherKey, 16), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(mode, key);
return cipher;
}
/**
* AES(aes-128-ecb)암호화
* @param src 평문
* @return 암호화 된 HEX문자열
* @throws Exception
* @since 2021.02.24
*/
public String encrypt(String src) throws Exception {
Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
byte[] plain = src.getBytes();
byte[] encrypt = cipher.doFinal(plain);
return toHexString(encrypt);
}
/**
* AES(aes-128-ecb)복호화
* @param hex 암호화 된 HEX문자열
* @return 복호화 된 평문
* @throws Exception
* @since 2021.02.24
*/
public String decrypt(String hex) throws Exception {
Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
byte[] encrypt = toBytesFromHexString(hex);
byte[] decrypt = cipher.doFinal(encrypt);
return new String(decrypt);
}
/**
* 8, 10, 16진수 문자열을 바이트 배열로 변환한다.
* 8, 10진수인 경우는 문자열의 3자리가, 16진수인 경우는 2자리가, 하나의 byte로 바뀐다.
* @param digits 문자열
* @param radix 진수 (8,10,16만 가능)
* @return byte[]
* @throws Exception - NumberFormatException, IllegalArgumentException
*/
private byte[] toBytes(String digits, int radix) throws Exception {
if (digits == null) {
return null;
}
if (radix != 16 && radix != 10 && radix != 8) {
throw new IllegalArgumentException("For input radix: \"" + radix+ "\"");
}
int divLen = (radix == 16) ? 2 : 3;
int length = digits.length();
if (length % divLen == 1) {
throw new IllegalArgumentException("For input string: \"" + digits+ "\"");
}
length = length / divLen;
byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
int index = i * divLen;
bytes[i] = (byte) (Short.parseShort(digits.substring(index, index + divLen), radix));
}
return bytes;
}
/**
* 입력받은 HEX 문자열을 byte[] 로 변환
* @param digits 입력 문자열
* @return byte[]
* @throws Exception - IllegalArgumentException, NumberFormatException
*/
private byte[] toBytesFromHexString(String digits) throws Exception {
if (digits == null) {
return null;
}
int length = digits.length();
if (length % 2 == 1) {
throw new IllegalArgumentException("For input string: \"" + digits + "\"");
}
length = length / 2;
byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
int index = i * 2;
bytes[i] = (byte) (Short.parseShort(digits.substring(index, index + 2), 16));
}
return bytes;
}
/**
* unsigned byte(바이트) 배열을 16진수 문자열로 바꾼다.
* @param bytes 배열
* @return 16진수 문자열
*/
private String toHexString(byte[] bytes) {
if (bytes == null) {
return null;
}
StringBuffer result = new StringBuffer();
for (byte b : bytes) {
result.append(Integer.toString((b & 0xF0) >> 4, 16));
result.append(Integer.toString(b & 0x0F, 16));
}
return result.toString();
}
}
Java for test
package sample;
public class Main {
public static void main(String[] args) {
try {
new Main();
} catch (Exception e) {
e.printStackTrace();
}
}
Main() throws Exception{
AESCrypto aes = new AESCrypto("012345678901234567890123456789ab");
String plainText = "가나다";
String encText = "e49bd4ca6f6717a22edcbb353c9a57da";
String decText = "";
// 평문
System.out.println(String.format("plain : %s", plainText));
// 암호화
encText = aes.encrypt(plainText);
System.out.println(String.format("encrypt : %s", encText));
// 복호화
decText = aes.decrypt(encText);
System.out.println(String.format("descypt : %s", decText));
}
}
@wonsama transfered 4 KRWP to @krwp.burn. voting percent : 9.56%, voting power : 89.47%, steem power : 1715320.55, STU KRW : 1200.
@wonsama staking status : 822.929 KRWP
@wonsama limit for KRWP voting service : 2.468 KRWP (rate : 0.003)
What you sent : 4 KRWP
Refund balance : 1.532 KRWP [51484800 - bb94aa8347f599c771138a8382bbbdbbc3b2ae8b]