bundle 병합 문제 수정

This commit is contained in:
Rinjae
2025-10-01 13:46:18 +09:00
parent e1aa97ac24
commit 4c427cf7c6
5 changed files with 0 additions and 388 deletions
-2
View File
@@ -1,2 +0,0 @@
SafeDBSDK_v4.0.19.jar 파일은 빌드결과에 포함되지 않고 compileOnly 로만 사용
실제 라이브러리는 WAS classpath 로 지정
Binary file not shown.
@@ -1,94 +0,0 @@
package com.eactive.ext.kjb.safedb;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
/**
* SafeDBFaker provides a fake encryption method for testing purposes when the real SafeDB library is not available.
*/
@Slf4j
public abstract class SafeDBFaker {
private static final String AES_256_KEY = "1234567890123456" + "1234567890123456";
private static final byte[] IV = "1234567890123456".getBytes();
public byte[] encrypt(String userId, String table, String column, byte[] data) {
if (SafeDBColumns.PSWD.isEqualsIgnoreCase(column)) {
// SHA256 + Base64 인코딩된 가짜 비밀번호 반환
return sha256(data);
} else {
// AES256 암호화된 가짜 데이터 반환
return aes256Encrypt(data);
}
}
public byte[] decrypt(String userId, String table, String column, byte[] data) {
if (SafeDBColumns.PSWD.isEqualsIgnoreCase(column)) {
// 비밀번호는 복호화하지 않음
throw new UnsupportedOperationException("Password decryption is not supported.");
} else {
// AES256 복호화된 가짜 데이터 반환
return aes256Decrypt(data);
}
}
private byte[] sha256(byte[] data) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
return digest.digest(data);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Error generating SHA-256 hash", e);
}
}
private String sha256Base64(String data) {
return Base64.getEncoder().encodeToString(this.sha256(data.getBytes()));
}
// AES256 암호화
private byte[] aes256Encrypt(byte[] data) {
try {
Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new javax.crypto.spec.SecretKeySpec(AES_256_KEY.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(IV));
return cipher.doFinal(data);
} catch (Exception e) {
throw new RuntimeException("Error during AES encryption", e);
}
}
private String getAes256KeyString(String data) {
return Base64.getEncoder().encodeToString(this.aes256Encrypt(data.getBytes()));
}
private byte[] aes256Decrypt(byte[] encryptedData) {
try {
Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new javax.crypto.spec.SecretKeySpec(AES_256_KEY.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(IV));
log.debug("encryptedData : {}", Arrays.toString(encryptedData));
log.debug("encryptedData toString() : {}", new String(encryptedData));
return cipher.doFinal(encryptedData);
} catch (Exception e) {
throw new RuntimeException("Error during AES decryption", e);
}
}
public String encryptString(String userId, String table, String column, String data) {
// return new String(this.encrypt(safedb, s, notRnno, data.getBytes()));
return Base64Utils.encodeToString(this.encrypt(userId, table, column, data.getBytes()));
}
protected String decryptString(String userId, String table, String column, String data) {
return new String(this.decrypt(userId, table, column, Base64Utils.decodeFromString(data)));
}
}
@@ -1,142 +0,0 @@
package com.eactive.ext.kjb.safedb;
import com.initech.safedb.SimpleSafeDB;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.repository.init.ResourceReader;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
@Slf4j
public class SafeDBWrapper extends SafeDBBroker {
private static SafeDBWrapper instance;
private SimpleSafeDB safedb;
@Getter
private boolean isRealSafeDB = false;
public static SafeDBWrapper getInstance() {
if ( instance == null ) {
synchronized ( SafeDBWrapper.class ) {
if ( instance == null ) {
instance = new SafeDBWrapper();
}
}
}
return instance;
}
public static boolean isBase64(String str) {
if (str == null || str.isEmpty()) {
return false;
}
String base64Pattern = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$";
return str.matches(base64Pattern);
}
private SafeDBWrapper() throws SafeDBWrapperException {
synchronized ( SafeDBWrapper.class ) {
// "com.initech.safedb.SimpleSafeDB" 클래스 존재 여부 확인
try {
Class.forName("com.initech.safedb.SimpleSafeDB");
try (InputStream is = ResourceReader.class.getClassLoader().getResourceAsStream("SafeDBMap_config.xml")) {
if (is == null) {
isRealSafeDB = false;
return;
} else {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
br.lines().forEach(log::debug);
}
}
}
this.safedb = SimpleSafeDB.getInstance();
if (safedb.login()) {
log.debug("[SafeDBWrapper] isLoginCheck : {}", safedb.getSafeDBConfigMgr().isLoginCheck());
} else {
log.warn("[SafeDBWrapper] isLoginCheck : {}", safedb.getSafeDBConfigMgr().isLoginCheck());
}
isRealSafeDB = true; // 클래스가 존재하면 true로 설정
} catch (Exception e) {
isRealSafeDB = false; // 클래스가 존재하지 않으면 false로 설정
log.info("SafeDB 클래스 로딩 실패 - 로컬 환경이거나 설정 오류 / Fake 모드로 동작함", e);
}
if (isRealSafeDB) {
try {
super.initialize();
} catch (Exception e) {
throw new SafeDBWrapperException("[SafeDBWrapper] Initialization error: " + e.getMessage(), e);
}
}
}
}
@Override
public byte[] encrypt(String userId, String table, String column, byte[] data) throws SafeDBWrapperSdkException {
if (isRealSafeDB) {
try {
log.debug("[SafeDBWrapper] real / userId : {}, table : {}, column : {}, data : {}", userId, table, column, data);
return safedb.encrypt(userId, table, column, data);
} catch (Exception e) {
throw new SafeDBWrapperSdkException("[SafeDBWrapper] Encrypt error: " + e.getMessage(), e);
}
} else {
return super.encrypt(userId, table, column, data);
}
}
@Override
public String encryptString(String userId, String tables, String column, String data) {
if (isRealSafeDB) {
try {
return this.safedb.encryptString(userId, tables, column, data);
} catch (Exception e) {
throw new SafeDBWrapperSdkException("[SafeDBWrapper] Encrypt error: " + e.getMessage(), e);
}
} else {
return super.encryptString(userId, tables, column, data);
}
}
public String encryptNotRnnoString(String data) throws SafeDBWrapperSdkException {
return this.encryptString("SAFEDB", "SAFEDB.POLICY", "NOT_RNNO", data);
}
@Override
public byte[] decrypt(String userId, String table, String column, byte[] data) throws SafeDBWrapperSdkException {
if (isRealSafeDB) {
try {
return safedb.decrypt(userId, table, column, data);
} catch (Exception e) {
throw new SafeDBWrapperException("[SafeDBWrapper] Decrypt error: " + e.getMessage(), e);
}
} else {
return super.decrypt(userId, table, column, data);
}
}
public String decryptString(String userId, String table, String column, String data) throws SafeDBWrapperSdkException {
if (isRealSafeDB) {
try {
return safedb.decryptString(userId, table, column, data);
} catch (Exception e) {
throw new SafeDBWrapperException("[SafeDBWrapper] Decrypt error: " + e.getMessage(), e);
}
} else {
return super.decryptString(userId, table, column, data);
}
}
public String decryptNotRnno(String data) throws SafeDBWrapperSdkException {
return this.decryptString("SAFEDB", "SAFEDB.POLICY", "NOT_RNNO", data);
}
}
@@ -1,150 +0,0 @@
package com.eactive.ext.kjb.safedb.test;
import com.eactive.ext.kjb.safedb.SafeDBWrapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@Slf4j
public class SafeDbWrapperTest {
@Test
public void fakeSafeDBTest() {
log.info("FakeSafeDBWrapper Length Validation Start");
if ("true".equalsIgnoreCase(System.getenv("safedb"))) {
log.info("실제 Safedb 테스트를 위해 테스트 종료 처리");
assertTrue("true".equalsIgnoreCase(System.getenv("safedb")));
return;
}
SafeDBWrapper wrapper;
try {
wrapper = SafeDBWrapper.getInstance();
} catch (Exception e) {
// classloader 에러인지 initialization 에러인지 구분
if (e.getMessage().contains("Classloader error")) {
throw new RuntimeException("SafeDBWrapper classloader error: " + e.getMessage(), e);
} else {
// initialization 에러(로컬에서는 동작하지 않는다 = 정상 처리)
log.info("SafeDBWrapper initialization error (expected in local environment): " + e.getMessage());
return;
}
}
if (wrapper.isRealSafeDB()) {
log.info("This test is for FakeSafeDBWrapper only. Skipping test.");
return;
}
for (int len = 1; len <= 255; len++) {
String originalData = repeat("A", len); // JDK8 호환 반복 문자열
try {
log.debug("OriginalData: {}", originalData);
// 암호화 (Base64 인코딩 결과 가정)
String encryptedData = wrapper.encryptNotRnnoString(originalData);
log.debug("Encrypted Data: {}", encryptedData);
// 예상 암호문 길이 계산
int expectedLen = getExpectedCipherLength(len, true);
// 복호화
String decryptedData = wrapper.decryptNotRnno(encryptedData);
log.debug("Decrypted Data: {}", decryptedData);
assertEquals(originalData, decryptedData, "Decrypted data does not match original at plain length=" + len);
// 로그 출력
log.info(String.format("Plain=%3d, Encrypted=%3d, Expected=%3d %s",
len, encryptedData.length(), expectedLen,
(encryptedData.length() == expectedLen ? "" : "")));
// 검증
// "Length mismatch at plain length="
assertEquals(len, expectedLen, encryptedData.length());
// 암복호화 로그 출력
log.info(String.format("Original: %s", originalData) +
String.format("\nEncrypted: %s", encryptedData) +
String.format("\nDecrypted: %s", decryptedData) + "\n");
} catch (Exception e) {
throw new RuntimeException("Error at plain length=" + len, e);
}
}
}
@SuppressWarnings("CallToPrintStackTrace")
@Test
public void safeDBTest() {
// safedb 프러퍼티가 활성화 일때만 동작
if (!"true".equalsIgnoreCase(System.getProperty("safedb"))) {
log.info("gradle : -Psafedb 일때만 동작 - {}", System.getProperty("safedb"));
return;
}
SafeDBWrapper wrapper;
try {
wrapper = SafeDBWrapper.getInstance();
} catch (Exception e) {
log.error("SafeDBWrapper 활성화 실패");
fail();
return;
}
if (!wrapper.isRealSafeDB()) {
log.error("실제 Safedb 로 동작하지 않음");
fail();
return;
}
String value = "한글암호화테스트";
log.info("Original : {}", value);
try {
String encryptValue = wrapper.encryptNotRnnoString(value);
log.info("Encrypted : {}", encryptValue);
String decryptedValue = wrapper.decryptNotRnno(encryptValue);
log.info("Decrypted : {}", decryptedValue);
assertEquals(value, decryptedValue);
} catch (Exception e) {
e.printStackTrace();
fail();
return;
}
assertTrue(true);
}
/**
* 암호문 예상 길이 계산 (AES/SEED/ARIA CBC 기준, PKCS5Padding)
*/
@SuppressWarnings("SameParameterValue")
private int getExpectedCipherLength(int plainLength, boolean base64Encoding) {
int blockSize = 16;
int paddedLength = ((plainLength / blockSize) + 1) * blockSize;
if (base64Encoding) {
return (int) (Math.ceil(paddedLength / 3.0) * 4);
} else {
return paddedLength;
}
}
/** JDK8에서 문자열 반복 (String.repeat 대체) */
@SuppressWarnings("SameParameterValue")
private String repeat(String s, int count) {
StringBuilder sb = new StringBuilder(s.length() * count);
for (int i = 0; i < count; i++) {
sb.append(s);
}
return sb.toString();
}
}