본문 바로가기
일하딩/Web

[AES] Java encrypt -> javascript decrypt

by 별난형 2019. 10. 29.

[AES] Java 암호화 -> javascript 복호화

 

javascript -> Java 는 정보가 많이 있었지만

 

Java -> javascript 는 찾기가 힘들었다. (이렇게는 잘 안하니.....)

 

또는 찾은 소스들 중에서는 key 값 외에 iv, salt 등의 추가적인 값들을 필요로 하였다.

 

그래서 생각해낸 방법은

 

Java 에서 암호화한 로직을 그대로 javascript에서 역으로 푸는 것!

 

우선, 

 

---------- Java 암/복호화 하는 부분 ----------

 

public Key generateKey(String key) throws Exception {
	Key keySpec;

	byte[] keyBytes = new byte[16];
	byte[] b = key.getBytes("UTF-8");

	int len = b.length;
	if (len > keyBytes.length) {
		len = keyBytes.length;
	}

	System.arraycopy(b, 0, keyBytes, 0, len);
	keySpec = new SecretKeySpec(keyBytes, "AES");

	return keySpec;
}

 

위에 method 는 키값을 사용하여 암호화키를 만드는 부분. AES128, 196, 256 이 있는데

 

내가 찾은 걸로는 key 값의 길이에 따라 나뉘는 것 같다.

 

new byte[16] -> 배열의 길이를 16으로 만드는 것은 AES128 로 하겠다는 의미!

public String encryptText(String text, String key) {
	String encrypted = "";
	try {
		SecretKeySpec ks = (SecretKeySpec) this.generateKey(key);
		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, ks);
		byte[] encryptedBytes = cipher.doFinal(text.getBytes());
		String base64 = Base64.encode(encryptedBytes);
		encrypted = new String(base64);
	} catch (Exception e) {
//		throw new IKEP4ApplicationException("", e);
	}

	return encrypted;
}

 

이 method 가 암호화 키값을 사용하여 평문을 암호화 하는 부분.

 

내가 참여하고있는 프로젝트는 AES 방식에 ECB 모드, PKCS5Padding 으로 암호화를 한다.

 

public String decAES(String enStr, String key) throws Exception {
	SecretKeySpec ks = (SecretKeySpec) this.generateKey(key);

	Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
	c.init(Cipher.DECRYPT_MODE, ks);
	    
	byte[] byteStr = Base64.decode(enStr.getBytes("UTF-8"));
	String decStr = new String(c.doFinal(byteStr), "UTF-8");

	return decStr;
}

 

이 부분은 복호화를 하는 부분.

 

암호화 부분을 역순으로 진행한다.

 

-----------------------------------------------------------------------------------------------

 

그리고 이제 이 복호화 부분의 로직을 javascript 에서 구현할 생각인데....

 

쉽지가 않다......역시 난 개발자가 아닌 코더...복붙만 잘하는 코더....

 

뭐 애시당초 client side 인 javascript 에서 복호화를 하는게 좀 말이 안되는 거 같긴 하지만....

 

지금 환경은 javascript 에서 복호화를 해야만한다. 고로 한다.

 

우선,

 

---------- javascript 암/복호화 하는 부분 ----------

 

javascript 에서 암/복호화를 하기 위해 

 

내가 사용한 javascript Library 는 CryptoJS

 

https://cryptojs.gitbook.io/docs/

 

CryptoJS

Original documentation: https://code.google.com/archive/p/crypto-js/

cryptojs.gitbook.io

여기에서 사용법을 익히고 라이브러리를 다운 받을 수 있다.

 

기본적인 사용법.

 

var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");

암호화 하는 방법은 아주 간단!

 

var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");

console.log(decrypted.toString(CryptoJS.enc.Utf8));

복호화 하는 방법도 아주 간단!

 

여기까지가 CryptoJS 를 사용한 javascript 암/복호화의 기본 사용법이다.

 

--------------------------------------------------------------------------------------------

 

그럼 이제 Java 의 복호화를 javascript 로 구현해보자는 생각으로 달려듬.

 

Java 와 javascript(CryptoJS) 확인해야할 사항들.

 

1. 암호화 방식

   Java : AES128/ECB/PKCS5Padding

   javascript : AES256/CBC/PKCS7Padding

 

2. 문자, key 사용 방식

   Java : getBytet() 를 사용하여 처리

   javascript : 문자 그대로 처리

 

3. 문자열 처리 방식

   UTF-8, EUC-KR, ISO... 등 암호화할 때와 동일한 문자열로 복호화를 해야 제대로 나온다.

   예로 한글을 EUC-KR 로 복호화 하면 2바이트 기준, UTF-8 로 복호화 하면 3바이트 기준이다.

   하지만 우리는 UTF-8로 암복호화 하니 상관이 없스

 

--------------------------------------------------------------------------------------------

 

이제 해결해보기

 

1. 암호화 방식

 

CryptoJS 라이브러리는 기본 AES256/CBC/PKCS7 인데

 

복호화를 위해 Java에서 설정한 것과 동일하게 맞춰줘야한다.

 

AES256은 키값의 길이. 고로 이건 키의 길이를 맞춰주면 해결!

 

CBC 는 ECB 로 바꿔줘야하니깐 mode_ecb.js 를 사용 후.

var decrypt = CryptoJS.AES.decrypt(encrypted, key, {
	mode: CryptoJS.mode.ECB,
	padding: CryptoJS.pad.Pkcs7
});
console.log(decrypt.toString(CryptoJS.enc.Utf8));

위에서 처럼 mode 에 ECB 를 지정 해주면 해결!

 

PKCS7 은 PKCS5 의 상위 버전이라 PKCS5도 지원 한다. 위에서 선언해주긴 했지만 default 라 신경 안써도 됨.

 

혹시나 해서 이대로 복호화를 했는데 역시나 아무런 값이 안나옴.

 

2. 값 사용 방식

 

for 문을 사용하여 값들의 byte 를 다 받아와서 처리하였음.

 

역시 안나옴.

 

무엇이 문제일까......

 

Java 의 암/복호화 하는 부분을 보면 Base64 로 encode/decode 하는 부분이 있네?!

 

복호화할 값에 Base64 로 decode 를 한 다음 적용.

 

안나옴........젠장 젠장....역시 난 코더인가.....단순 따라하기만 가능한가.....

 

테스트 방법

  key

Base64

encode

O O
O X
X O
X X
  key

Base64

parsing

O O
O X
X O
X X
  key

byte

처리

O O
O X
X O
X X

이거 외에도 Base64 후 byte 로 처리도 해보고 다 했지만 안됨.

 

2일 고생하고

 

3일째 되는날 문득 

 

검색을 하다

 

https://coderanch.com/t/637480/engineering/Java-encryption-javascript-decryption

 

Java encryption -> javascript decryption (Security forum at Coderanch)

 

coderanch.com

여기에서 생각지 못한 부분을 발견함.

 

암호화된 텍스트는 그대로 사용하고 key 값을 Base64 로 인코딩 한 다음 그걸

 

CryptoJS 를 사용하여 다시 Base64 paring 을 한 후에 적용.

 

풀린다.

 

와.........Base64 한걸로 적용해보기는 했지만 한번더 parsing 을 해야하다니....

 

이렇게 풀리다니 내가 소스를 끝까지 다 안까본 잘못도 있지만....

 

역시 난 코더 ^^ ㅎㅎ 그냥 궁금증이 많은 코더로 남아야겠숴..

 

아래는 복호화 방법.

var base64 = btoa(key);
var decrypt = CryptoJS.AES.decrypt(encrypted, CryptoJS.enc.Base64.parse(base64)), {
	mode: CryptoJS.mode.ECB,
	padding: CryptoJS.pad.Pkcs7
});

후우 해결이 되었다....이렇게 하루하루 근근히 살아간다.....

댓글