- damo-manager Gradle 프로젝트 초기 구성
- scpdb 부재 시 fake 모드 자동 fallback - ScpEncB64/DecB64/HashB64 래핑 + 유틸 보존 - RealBridge 격리로 NoClassDefFoundError 방지 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
package com.eactive.apim.custom.djb.damomanager;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 운영(penta scpdb 라이브러리 존재) / 로컬(scpdb 부재) 양쪽에서 동작하는 단일 클래스.
|
||||
*
|
||||
* 클래스패스에 {@code com.penta.scpdb.ScpDbAgent} 가 존재하면 실 호출, 아니면 fake 모드로 자동 fallback.
|
||||
* fake 모드 진입 시 클래스 로딩 시점에 System.err 로 강한 경고 배너 출력.
|
||||
*
|
||||
* fake 모드 동작:
|
||||
* - encrypt(s) : Base64.encode(s.getBytes(EUC-KR)) -- 암호화 없음
|
||||
* - decrypt(s) : new String(Base64.decode(s), EUC-KR)
|
||||
* - hash(t, s) : SHA-256(71) / SHA-512(73) JRE MessageDigest -> Base64
|
||||
*/
|
||||
public class DamoManager {
|
||||
|
||||
public static final int SHA256 = 71;
|
||||
public static final int SHA512 = 73;
|
||||
|
||||
private static final String INI_FILE = "/prod/damo/ba_scp/scpdb_agent.ini";
|
||||
private static final String KEY = "KEY1";
|
||||
private static final String CHARSET = "EUC-KR";
|
||||
|
||||
private static final int SCP_OK = 0;
|
||||
private static final int SCP_FAIL = -1;
|
||||
|
||||
private static final boolean REAL_MODE;
|
||||
|
||||
static {
|
||||
boolean real;
|
||||
try {
|
||||
Class.forName("com.penta.scpdb.ScpDbAgent", false,
|
||||
DamoManager.class.getClassLoader());
|
||||
real = true;
|
||||
} catch (Throwable t) {
|
||||
real = false;
|
||||
printFakeBanner();
|
||||
}
|
||||
REAL_MODE = real;
|
||||
}
|
||||
|
||||
private static void printFakeBanner() {
|
||||
String line = "============================================================";
|
||||
System.err.println();
|
||||
System.err.println(line);
|
||||
System.err.println(" *** DAMO-MANAGER FAKE MODE ***");
|
||||
System.err.println(" com.penta.scpdb.ScpDbAgent NOT FOUND on classpath.");
|
||||
System.err.println(" Fallback:");
|
||||
System.err.println(" encrypt/decrypt -> Base64 (NO ENCRYPTION)");
|
||||
System.err.println(" hash -> JRE MessageDigest (SHA-256 / SHA-512)");
|
||||
System.err.println(" *** DO NOT use this build for production! ***");
|
||||
System.err.println(line);
|
||||
System.err.println();
|
||||
System.err.flush();
|
||||
}
|
||||
|
||||
private final String szRevision = "20160503";
|
||||
private int nReturn;
|
||||
private final RealBridge bridge;
|
||||
|
||||
public DamoManager() {
|
||||
if (REAL_MODE) {
|
||||
this.bridge = new RealBridge();
|
||||
int rc = this.bridge.init();
|
||||
if (rc == 0 || rc == 118) {
|
||||
this.nReturn = SCP_OK;
|
||||
} else {
|
||||
this.nReturn = rc;
|
||||
}
|
||||
} else {
|
||||
this.bridge = null;
|
||||
this.nReturn = SCP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
public String getRevision() {
|
||||
return this.szRevision;
|
||||
}
|
||||
|
||||
public int getReturnCode() {
|
||||
return this.nReturn;
|
||||
}
|
||||
|
||||
public boolean isFakeMode() {
|
||||
return !REAL_MODE;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// 운영: ScpEncB64 / ScpDecB64 / ScpHashB64 래핑
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 평문 문자열을 ScpEncB64 로 암호화하여 Base64 cipher text 반환.
|
||||
* fake 모드: 단순 Base64 인코딩.
|
||||
*/
|
||||
public String encrypt(String plain) {
|
||||
if (plain == null) {
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
if (REAL_MODE) {
|
||||
try {
|
||||
String out = this.bridge.encB64(plain);
|
||||
this.nReturn = SCP_OK;
|
||||
return out;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.nReturn = SCP_OK;
|
||||
return Base64.getEncoder().encodeToString(plain.getBytes(CHARSET));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
this.nReturn = SCP_FAIL;
|
||||
return Base64.getEncoder().encodeToString(plain.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 cipher text 를 ScpDecB64 로 복호화하여 평문 반환.
|
||||
* fake 모드: 단순 Base64 디코딩.
|
||||
*/
|
||||
public String decrypt(String base64Cipher) {
|
||||
if (base64Cipher == null) {
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
if (REAL_MODE) {
|
||||
try {
|
||||
String out = this.bridge.decB64(base64Cipher);
|
||||
this.nReturn = SCP_OK;
|
||||
return out;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
try {
|
||||
byte[] decoded = Base64.getDecoder().decode(base64Cipher);
|
||||
this.nReturn = SCP_OK;
|
||||
try {
|
||||
return new String(decoded, CHARSET);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return new String(decoded);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 단방향 해시. type 71 = SHA-256, 73 = SHA-512. 결과는 Base64 문자열.
|
||||
* fake 모드: JRE MessageDigest 사용 (실제 SHA-256/512 결과를 Base64 로 반환).
|
||||
*/
|
||||
public String hash(int type, String src) {
|
||||
if (src == null) {
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
if (REAL_MODE) {
|
||||
try {
|
||||
String out = this.bridge.hashB64(type, src);
|
||||
this.nReturn = SCP_OK;
|
||||
return out;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
String algo;
|
||||
if (type == SHA256) {
|
||||
algo = "SHA-256";
|
||||
} else if (type == SHA512) {
|
||||
algo = "SHA-512";
|
||||
} else {
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance(algo);
|
||||
byte[] bytes;
|
||||
try {
|
||||
bytes = md.digest(src.getBytes(CHARSET));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
bytes = md.digest(src.getBytes());
|
||||
}
|
||||
this.nReturn = SCP_OK;
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
this.nReturn = SCP_FAIL;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Utility (원본 DamoManager 에서 그대로 보존)
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
public String Base64Encode(byte[] var1) {
|
||||
char[] var2 = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
|
||||
StringBuilder var3 = new StringBuilder();
|
||||
int var4 = 0;
|
||||
|
||||
for (int var5 = 0; var5 < var1.length; var5 += 3) {
|
||||
int var6 = (var1[var5] & 255) << 16 & 16777215;
|
||||
if (var5 + 1 < var1.length) {
|
||||
var6 |= (var1[var5 + 1] & 255) << 8;
|
||||
} else {
|
||||
++var4;
|
||||
}
|
||||
|
||||
if (var5 + 2 < var1.length) {
|
||||
var6 |= var1[var5 + 2] & 255;
|
||||
} else {
|
||||
++var4;
|
||||
}
|
||||
|
||||
for (int var7 = 0; var7 < 4 - var4; ++var7) {
|
||||
int var8 = (var6 & 16515072) >> 18;
|
||||
var3.append(var2[var8]);
|
||||
var6 <<= 6;
|
||||
}
|
||||
}
|
||||
|
||||
for (int var9 = 0; var9 < var4; ++var9) {
|
||||
var3.append("=");
|
||||
}
|
||||
|
||||
return var3.toString();
|
||||
}
|
||||
|
||||
public byte[] Base64Decode(String var1) {
|
||||
int[] var2 = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||
byte[] var3 = var1.getBytes();
|
||||
ByteArrayOutputStream var4 = new ByteArrayOutputStream();
|
||||
int var5 = 0;
|
||||
|
||||
while (var5 < var3.length) {
|
||||
int var6 = 0;
|
||||
if (var2[var3[var5]] != -1) {
|
||||
var6 = (var2[var3[var5]] & 255) << 18;
|
||||
int var7 = 0;
|
||||
if (var5 + 1 < var3.length && var2[var3[var5 + 1]] != -1) {
|
||||
var6 |= (var2[var3[var5 + 1]] & 255) << 12;
|
||||
++var7;
|
||||
}
|
||||
|
||||
if (var5 + 2 < var3.length && var2[var3[var5 + 2]] != -1) {
|
||||
var6 |= (var2[var3[var5 + 2]] & 255) << 6;
|
||||
++var7;
|
||||
}
|
||||
|
||||
if (var5 + 3 < var3.length && var2[var3[var5 + 3]] != -1) {
|
||||
var6 |= var2[var3[var5 + 3]] & 255;
|
||||
++var7;
|
||||
}
|
||||
|
||||
while (var7 > 0) {
|
||||
int var8 = (var6 & 16711680) >> 16;
|
||||
var4.write((char) var8);
|
||||
var6 <<= 8;
|
||||
--var7;
|
||||
}
|
||||
|
||||
var5 += 4;
|
||||
} else {
|
||||
++var5;
|
||||
}
|
||||
}
|
||||
|
||||
return var4.toByteArray();
|
||||
}
|
||||
|
||||
public String byteToHex(byte[] var1) {
|
||||
String var2 = "";
|
||||
String var3 = "";
|
||||
|
||||
for (int var4 = 0; var4 < var1.length; ++var4) {
|
||||
var3 = Integer.toHexString(var1[var4]);
|
||||
if (var3.length() >= 2) {
|
||||
var3 = var3.substring(var3.length() - 2);
|
||||
} else {
|
||||
for (int var5 = 0; var5 < 2 - var3.length(); ++var5) {
|
||||
var3 = "0" + var3;
|
||||
}
|
||||
}
|
||||
|
||||
var2 = var2 + " " + var3;
|
||||
}
|
||||
|
||||
return var2.toUpperCase();
|
||||
}
|
||||
|
||||
public String byteArrayToHex(byte[] var1) {
|
||||
StringBuilder var2 = new StringBuilder();
|
||||
|
||||
for (byte var6 : var1) {
|
||||
var2.append(String.format("%02x ", var6 & 255));
|
||||
}
|
||||
|
||||
return var2.toString();
|
||||
}
|
||||
|
||||
public boolean checkHangul(char var1) {
|
||||
return var1 >= '가' && var1 <= '힣';
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// 운영 ScpDbAgent 호출 격리. REAL_MODE == true 일 때만 인스턴스화되어
|
||||
// ScpDbAgent 심볼이 JVM 에 resolve 된다. fake 모드에서는 이 클래스 자체가
|
||||
// 로딩되지 않으므로 NoClassDefFoundError 가 발생하지 않는다.
|
||||
// -----------------------------------------------------------------
|
||||
private static final class RealBridge {
|
||||
private final com.penta.scpdb.ScpDbAgent agt = new com.penta.scpdb.ScpDbAgent();
|
||||
|
||||
int init() {
|
||||
return agt.AgentInit(INI_FILE);
|
||||
}
|
||||
|
||||
String encB64(String src) {
|
||||
return agt.ScpEncB64(INI_FILE, KEY, src, CHARSET);
|
||||
}
|
||||
|
||||
String decB64(String src) {
|
||||
return agt.ScpDecB64(INI_FILE, KEY, src, CHARSET);
|
||||
}
|
||||
|
||||
String hashB64(int type, String src) {
|
||||
return agt.ScpHashB64(type, src, CHARSET);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Smoke test 용 main. 운영 코드에서는 호출되지 않음.
|
||||
// -----------------------------------------------------------------
|
||||
public static void main(String[] args) {
|
||||
DamoManager m = new DamoManager();
|
||||
System.out.println("revision = " + m.getRevision());
|
||||
System.out.println("fakeMode = " + m.isFakeMode());
|
||||
|
||||
String plain = "hello, 다모";
|
||||
String enc = m.encrypt(plain);
|
||||
String dec = m.decrypt(enc);
|
||||
System.out.println("encrypt = " + enc);
|
||||
System.out.println("decrypt = " + dec);
|
||||
System.out.println("roundtrip = " + plain.equals(dec));
|
||||
|
||||
String h256 = m.hash(SHA256, plain);
|
||||
String h512 = m.hash(SHA512, plain);
|
||||
System.out.println("sha256 b64 = " + h256 + " (len=" + h256.length() + ")");
|
||||
System.out.println("sha512 b64 = " + h512 + " (len=" + h512.length() + ")");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user