ISMS AES-128 암호화키 관리
📝 ISMS 암호통제 지침
암호통제 지침 중 여러 조항이 있지만 개발과 관련있는 부분이다
아래 지침내용은 회사 내부 지침 일부 발췌
📝 암호화 기술 및 프로그램 선택기준
기밀성을 위한 암호 기술은 최소 128비트 이상의 키길이를 사용하는 암호화키를 사용하는 안정성이 입증된 대칭키 암호화 알고리즘을 이용한다
(암호화 대상 정보: 고유식별정보, 신용카드번호, 계좌번호, 바이오 정보 등)
보안강도 | 대칭키 암호 알고리즘 | 안정성 |
---|---|---|
80bit 미만 | DES | 권고하지 않음 |
80bit | 2TDEA | 권고하지 않음 |
112bit | 3TDEA | 권고하지 않음 |
128bit | SEED, HIGHT, ARIA-128, AES-128 | 권고 |
192bit | ARIA-192, AES-192 | 권고 |
256bit | ARIA-256, AES-256 | 권고 |
📝 암호화키 관리
- 암호화키가 외부 매체에 저장될 시에는 비인가자가 접근할 수 없는 안전한 매체에 저장되어야 한다
- 암호화키를 문서 형태로 보관시 암호화하여 보관한다
- 암호화키는 평문 파일로 또는 프로그램 소스에 삽입되어 운영시스템에 저장되어서는 안된다
- 운영시스템에는 암호화키가 삽입된 프로그램 소스는 삭제되어야 하며 로드모듈로만 저장해야 한다
- 서버에 저장되는 암호화키는 암호화되어 저장되어야 한다
📝 구현
Oracle DBMS_CRYPTO
앞서 포스팅 했던 대로 오라클 패키지 함수 내 암호화 키가 평문으로 함수 매개변수에 삽입되어 있어 수정해야 했다. 기존 암호화된 데이터가 AES128 방식으로 암호화 되어 있어 자바 소스에서도 AES128 암호화를 선택했다
✍ 설계
AS-IS:
1. 평문 암호키가 저장된 오라클 패키지 함수 호출
TO-BE:
1. 암호화키를 암/복호화 할 모듈 생성
2. 운영데이터 암/복호화 할 암호화키를 모듈로 암호화하여 txt 파일에 저장
3. txt파일 WAS 서버에 저장
4. WAS에서 AES128.jar 사용하여 txt파일의 암호키 복호화 후 오라클 패키지 함수 호출
✍ 모듈 소스
package com.erp.common;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AES128 {
//IV
private String ips;
//키 클래스
private Key keySpec;
//생성자
public AES128() {
//암호화키를 암/복호화하는 암호화키 16byte
String key = "test1234ttest1234";
try {
//암호화키 저장할 byte[] 변수
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
System.arraycopy(b, 0, keyBytes, 0, keyBytes.length);
//비밀키 클래스 선언
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
//운영중인 오라클 패키지 함수에서 IV를 사용하지 않기 때문에 null 16bytes
this.ips = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
//AES방식과 암호화 키 값을 Key 클래스에 저장
this.keySpec = keySpec;
} catch (Exception e) {
e.printStackTrace();
}
}
//생성자 오버로딩
public AES128(String key) {
try {
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
System.arraycopy(b, 0, keyBytes, 0, keyBytes.length);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
this.ips = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; //null 16bytes
this.keySpec = keySpec;
} catch (Exception e) {
e.printStackTrace();
}
}
//암호화
public String encrypt(String plainText) {
//암/복호화 암호 기능 제공 클래스 선언
Cipher cipher;
try {
//암호방식, 체인방식, 패딩방식 선언 및 인스턴스 득
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//인스턴스 얻은 후 암호화키와 IV로 암호 초기화
cipher.init(Cipher.ENCRYPT_MODE, keySpec
, new IvParameterSpec(ips.getBytes()) );
//암호화 실행1
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
//오라클 DBMS_CRYPTO 함수에서 HEX String을 반환하기 떄문에 byte[]->HEX 변환
String encryptStr = new String(byteArrayToHex(encrypted).toUpperCase());
//암호화된 문자열 반환
return encryptStr;
} catch (Exception e) {
return null;
}
}
//복호화
public String decrypt(String encryptStr) {
try {
//암호방식, 체인방식, 패딩방식 선언 및 인스턴스 득
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//인스턴스 얻은 후 암호화키와 IV로 암호 초기화
cipher.init(Cipher.DECRYPT_MODE, keySpec
, new IvParameterSpec(ips.getBytes("UTF-8")));
//HEX String->byte[] 로 변환
byte[] byteStr = hexToByteArray(encryptStr);
//복호화 실행
String decryptStr = new String(cipher.doFinal(byteStr), "UTF-8");
return decryptStr;
} catch (Exception e) {
return null;
}
}
//byte[]->hex String
private String byteArrayToHex(byte[] encrypted) {
if(encrypted == null || encrypted.length == 0){
return null;
}
StringBuffer sb = new StringBuffer();
for (byte b : encrypted) {
//앞 빈자리 0으로 채우는 16진수 (16진수 2자리가 1byte)
sb.append(String.format("%02x", b));
}
return sb.toString();
}
//hex String->byte[]
private byte[] hexToByteArray(String hex) {
if(hex == null || hex.length() == 0){
return null;
}
//16진수 2자리가 1byte
byte[] byteArray = new byte[hex.length() / 2 ];
for(int i = 0; i<byteArray.length; i++){
//2자리씩 16진수로 변환
byteArray[i] = (byte) Integer.parseInt(hex.substring(2*i, 2*i+2), 16);
}
return byteArray;
}
}
✍ 모듈 호출 소스
암호화키 복호화 후 저장
Util클래스에 static 함수로 구현
import java.io.File;
import java.util.Scanner;
public class Util{
public static String getEncKey(){
AES128 aes128 = new AES128();
String enc_key = null;
try {
//enc_key.txt 내용 :
//25570DDCCE2517C85728B94A051AF276A3D07E616EE120540EE4EFD7C88ED357
File f1 = new File("프로젝트 경로" + "/enc_key.txt");
Scanner sc = new Scanner(f1);
while (sc.hasNextLine()) {
String data = sc.nextLine();
enc_key = aes128.decrypt(data);
}
sc.close();
}
catch (Exception e) {
e.printStackTrace();
}
finally{
return enc_key;
}
}
}
서비스에서 DataMap paramData에 값 저장
//서비스 클래스 변수 선언
private String enc_key = Util.getEncKey();
//서비스 함수 내 쿼리실행 변수에 할당
public String getHpNo(DataMap paramData){
paramData.put("enc_key", enc_key);
}
쿼리 사용
SELECT CRYPTO.DECRYPT(HP_NO, ${enc_key}) FROM DUAL
📝 마치며
ISMS 인증을 앞두고 수정한 건이라 결함으로 판단될 경우 보완하여 수정 예정
Author And Source
이 문제에 관하여(ISMS AES-128 암호화키 관리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@conda/ISMSAES128저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)