2016년 12월 19일 월요일

AES 암복호화 보완, (AES/CBC/PKCS5Padding 방식으로)

특정 DB컬럼의 값을 암호화하여 저장하라는 회사의 아키텍쳐 요건을 만족시키기 위해서 AES로 암호화하여 사용하고 있었다. 그런데 기존 방식이 AES/ECB/PKCS5Padding를 사용하고 있었는데 ECB가 문제가 되서 AES/CBC/PKCS5Padding로 변경하는 작업을 진행했다.
 

1.
암호화로 사용할 키는 KeyGeneratorSecureRandom으로 생성한다.

```
KeyGenerator generator = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
generator.init(128, random);
Key secureKey = generator.generateKey();

System.out.println(Base64.encodeBase64String(secureKey.getEncoded()));
```

2.
같은 문자열도 암호화할때마다 다른 문자열을 만들어내기 위해서 IV값을 랜덤하게 만들어준다.

```
/**
* 랜덤하게 IV 생성
*
* 같은 평문도 암호화할 때마다 암호문을 다르게 만들어 낸다.
* @return 랜덤하게 생성된 IvParameterSpec
*/
private static IvParameterSpec getRandomIvParameterSpec() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
```

3.
IV값과 암호키로 암호화한 값을 합쳐야 하는데 java byte concat으로 검색해보니 무려 자바 System 클래스에 배열복사가 있었다!

```
// IV + 암호문으로 출력할 Byte를 붙인다.
byte[] ivcipherByte = new byte[16 + cipherByte.length];
System.arraycopy(iv.getIV(), 0, ivcipherByte, 0, 16);
System.arraycopy(cipherByte, 0, ivcipherByte, 16, cipherByte.length);
```

4.
다시 복호화할때는 입력된 byte를 IV와 암호값으로 다시 나눈다.

```
// 입력된 Byte를 IV + 암호문으로 나눈다.
byte[] originalIvByte = Arrays.copyOfRange(cipherByte, 0, 16);
byte[] originalCipherByte = Arrays.copyOfRange(cipherByte, 16, cipherByte.length);
```

5.
이렇게 만든 encrypt와 decrypt를 IN/OUT을 모두 String으로 만들어서 쓰기 좋게

```
/**
* 암호화하고, Base64로 인코딩
* @param plainText - 평문
* @return 암호문
*/
public static String encryptAndEncoding(String plainText) {
// 암호화하고 나서, 다시 문자열로 만들기위해 Base64 인코딩
return Base64.encodeBase64String(encrypt(plainText));
}

/**
* Base64로 디코딩하고, 복호화
* @param cipherText - 암호문
* @return 평문
*/
public static String decodeAndDecrypt(String cipherText) {
// 다시 Byte로 만들기위해 Base64 디코딩하고 복호화
return decrypt(Base64.decodeBase64(cipherText));
}
```


댓글 없음:

댓글 쓰기