diff --git a/build.gradle b/build.gradle index 5173c19..77012b9 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,14 @@ def hibernateVersion = "5.6.15.Final" def nexusUrl = "https://nexus.eactive.synology.me:8090" def generatedJavaDir = "$buildDir/generated/java" +// FOR LOCAL +repositories { + maven { + url "${nexusUrl}/repository/maven-public/" + allowInsecureProtocol = true + } +} +// java { toolchain { languageVersion = JavaLanguageVersion.of(8) @@ -65,6 +73,8 @@ dependencies { api "org.springframework:spring-context-support:${springVersion}" api 'jakarta.interceptor:jakarta.interceptor-api:2.1.0' + + implementation 'com.nimbusds:nimbus-jose-jwt:9.24.3' //jwhong compileOnly group: 'com.ibm.db2', name: 'jcc', version: '11.5.7.0' diff --git a/src/main/java/com/eactive/eai/common/context/ElinkTransactionContext.java b/src/main/java/com/eactive/eai/common/context/ElinkTransactionContext.java new file mode 100644 index 0000000..e16884e --- /dev/null +++ b/src/main/java/com/eactive/eai/common/context/ElinkTransactionContext.java @@ -0,0 +1,119 @@ +package com.eactive.eai.common.context; + +import java.util.HashMap; +import java.util.Map; + +/** + * 트랜잭션 범위 컨텍스트 관리 + * - ThreadLocal 기반으로 현재 스레드의 트랜잭션 컨텍스트 관리 + * - Lazy initialization: 최초 put 시 자동 생성 + * - 비동기 전달: getAll()로 복사본 획득, restore()로 복원 + * + *
+ * [동기 거래]
+ * ApiAdapterController → ... → JEP 함수에서 set/get → ... → finally { clear() }
+ *
+ * [비동기 거래]
+ * 송신측: FlowRouter → eaiMessage.setTransactionContextTransfer(getAll()) → JMS Queue
+ * 수신측: Consumer → ElinkESBProcessProxy → restore(transfer) → JEP 함수 → clear()
+ * 
+ */ +public class ElinkTransactionContext { + + private static final ThreadLocal> THREAD_LOCAL = new ThreadLocal<>(); + + // Context Map Keys + private static final String KEY_SEED_SALT = "SEED_SALT"; + private static final String KEY_ENCRYPTION_KEY = "ENCRYPTION_KEY"; + private static final String SEED_KEY = "SEED_KEY"; + public static final String REQUEST_BIZ_DATA = "REQUEST_BIZ_DATA"; + + // ==================== 컨텍스트 관리 ==================== + + /** + * 컨텍스트 정리 (필수) + * - 동기: ApiAdapterController finally 블록에서 호출 + * - 비동기: ElinkESBProcessProxy finally 블록에서 호출 + */ + public static void clear() { + THREAD_LOCAL.remove(); + } + + /** + * 비동기 전달용 컨텍스트 복사본 반환 + * - FlowRouter에서 JMS 송신 전 호출 + * - 컨텍스트가 없으면 null 반환 + */ + public static Map getAll() { + Map ctx = THREAD_LOCAL.get(); + return ctx != null ? new HashMap<>(ctx) : null; + } + + /** + * 비동기 수신 시 컨텍스트 복원 + * - ElinkESBProcessProxy에서 비동기 거래 처리 시작 시 호출 + */ + public static void restore(Map transferContext) { + if (transferContext != null && !transferContext.isEmpty()) { + THREAD_LOCAL.set(new HashMap<>(transferContext)); + } + } + + // ==================== 내부 헬퍼 ==================== + + private static Map getOrCreate() { + Map ctx = THREAD_LOCAL.get(); + if (ctx == null) { + ctx = new HashMap<>(); + THREAD_LOCAL.set(ctx); + } + return ctx; + } + + private static void put(String key, Object value) { + if (value != null) { + getOrCreate().put(key, value); + } + } + + private static String get(String key) { + Map ctx = THREAD_LOCAL.get(); + return ctx != null ? (String) ctx.get(key) : null; + } + + // ==================== 명시적 변수 접근자 ==================== + + public static void setSeedSalt(String seedSalt) { + put(KEY_SEED_SALT, seedSalt); + } + + public static String getSeedSalt() { + return get(KEY_SEED_SALT); + } + + public static void setEncryptionKey(String encryptionKey) { + put(KEY_ENCRYPTION_KEY, encryptionKey); + } + + public static String getEncryptionKey() { + return get(KEY_ENCRYPTION_KEY); + } + + // ==================== 실 사용 변수 접근자 ==================== + + public static void setSeedKey(String encryptionKey) { + put(SEED_KEY, encryptionKey); + } + + public static String getSeedKey() { + return get(SEED_KEY); + } + + public static void setRequestBizData(String bizData) { + put(REQUEST_BIZ_DATA, bizData); + } + + public static String getRequestBizData() { + return get(REQUEST_BIZ_DATA); + } +} diff --git a/src/main/java/com/eactive/eai/common/monitor/MonitorVO.java b/src/main/java/com/eactive/eai/common/monitor/MonitorVO.java index e8daeba..5c830c8 100644 --- a/src/main/java/com/eactive/eai/common/monitor/MonitorVO.java +++ b/src/main/java/com/eactive/eai/common/monitor/MonitorVO.java @@ -370,8 +370,8 @@ public class MonitorVO implements Serializable //if (logger.isError()) logger.error("MonitorVO["+this.eaiServiceCode+"] "+svcOgNo+" - "+logSequence+" ["+iErrorCode+"] : "+msgRcvTm+" / "+(msgPssTm-msgRcvTm)+" msec",e); //throw new Exception("RECEAICMT101"); // String msg = ErrorCodeHandler.getMessage("RECEAICMT101", new String[]{this.eaiServiceCode, svcOgNo, String.valueOf(logSequence), String.valueOf(iErrorCode), String.valueOf(msgRcvTm), String.valueOf(msgPssTm-msgRcvTm)}); - if (logger.isError()) { - logger.error(ExceptionUtil.make(e, "RECEAICMT101"), e); + if (logger.isInfo()) { + logger.info(ExceptionUtil.make(e, "RECEAICMT101"), e); } } } @@ -1014,7 +1014,11 @@ public class MonitorVO implements Serializable **/ synchronized private void countM02(String logSeq, long msgPssTm, long msgRcvTm, int iErrorCode){ if(iErrorCode == 0){ - long psstmp = Long.parseLong((this.pssCnt.get(logSeq).toString())); + Object o = this.pssCnt.get(logSeq); + long psstmp = 0; + if( o != null ) { + psstmp = Long.parseLong((this.pssCnt.get(logSeq).toString())); + } long psstmpIn = Long.parseLong((this.pssCntInPeriod.get(logSeq).toString())); psstmp++; psstmpIn++; diff --git a/src/main/java/com/eactive/eai/common/seed/Seed.java b/src/main/java/com/eactive/eai/common/seed/Seed.java index 9d2a578..fe88f1a 100644 --- a/src/main/java/com/eactive/eai/common/seed/Seed.java +++ b/src/main/java/com/eactive/eai/common/seed/Seed.java @@ -10,7 +10,7 @@ public class Seed { public static void main(String[] args) throws Exception { - System.out.println( Seed.decrypt("47T1fWZ+PqF2pqseL++jLg==")); + // System.out.println( Seed.decrypt("47T1fWZ+PqF2pqseL++jLg==")); // //// String planText = "AIORTA00051001001R0000AIORULE01 0000001 0821400646003112000000004721212121061705G30011 0000000000006520507000000000000000000000000010200 1000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000001400000091 90 92 Q 21000000000000000000000004000000000000005000000000000000000000000000004000000000000000000100000000004000000646000000000000000FR00200000000400000000330906REJECT G301 00652 31742FILTER F200 0102721 R001 0000 0000 0000 0000 0000 30840MAIN G300 0061707 06 P3501 P4401 P4601 N4501 P3402 P4201 00000235143TEMP 31955TEMP 00000000231758TEMP 30623TEMP 00004830906BASE00 G301_BASE00 N 000000000000000000000025230906L11210000 G301_L11210000_37 N 000000000000000000000003730906L9Z000007 G301_L9Z000007_42 N 000000000000000000000004230906L9Z000210 G301_L9Z000210_47 N 000000000000000000000004730906CF0342210 G301_CF0342210_26 N 000000000000000000000002630906CF1200610 G301_CF1200610_00 N 000000000000000000000000030906L21210100 G301_L21210100_57 N 000000000000000000000005730906LA0600104 G301_LA0600104_55 N 000000000000000000000005530906LC0000008 G301_LC0000008_00 N 000000000000000000000000030906PE0000026 G301_PE0000026_90 N 000000000000000000000009030906NPF003_D G301_NPF003_D_46 S92 0004631742CD002 CD002_A 0000 N 000000000000000000000000031742FR002 FR002_A 0000 N 000000000000000000000000031742FR003 FR003_A 0000 N 000000000000000000000000031742FR004 FR004_A 0000 N 000000000000000000000000031742FR005 FR005_A 0000 N 000000000000000000000000031742FR006 FR006_A 0000 N 000000000000000000000000031742FR007 FR007_A 0000 N 000000000000000000000000031742IA004 IA004_R R001 N 000000000000000000000102731742LD002 LD002_A 0000 N 000000000000000000000000031742D10210000 D10210000_A 0000 N 000000000000000000000000031742D10210600 D10210600_A 0000 N 000000000000000000000000031742D20210000 D20210000_A 0000 N 000000000000000000000000031742D30210000 D30210000_A 0000 N 000000000000000000000000031742P27000100 P27000100_A 0000 N 000000000000000000000000031742XZ021 XZ021_A 0000 N 000000000000000000000000031742B12000200 B12000200_A 0000 N 000000000000000000000000031742B22000200 B22000200_A 0000 N 000000000000000000000000031742LE0021201 LE0021201_A 0000 N 000000000000000000000000031742L21201300 L21201300_A 0000 N 000000000000000000000000031742NLD010 NLD010_A 0000 N 000000000000000000000000031742G20220L00 G20220L00_A 0000 N 000000000000000000000000030840BASE00 G300_BASE00 N 000000000000000000000026130840NPF003 G300_NPF003_00 S91 0000030840NPF004 G300_NPF004_00 N 000000000000000000000000030840P13000500 G300_P13000500_32 N 000000000000000000000003230840PH0000043 G300_PH0000043_53 P4601 N 000000000000000000000005330840LC0027001 G300_LC0027001_23 P2401 N 000000000000000000000002330840NCBTM206A G300_NCBTM206A_47 P4401 N 000000000000000000000004730840L9Z000006 G300_L9Z000006_29 P3402 N 000000000000000000000002930840L11210000 G300_L11210000_30 N 000000000000000000000003030840U5Z000015 G300_U5Z000015_10 N 000000000000000000000001030840CF1200610 G300_CF1200610_00 N4501 N 000000000000000000000000030840C1Z200031 G300_C1Z200031_77 P3501 N 000000000000000000000007730840CF0642229 G300_CF0642229_09 N 000000000000000000000000930840L21210100 G300_L21210100_46 P4201 N 000000000000000000000004630840LC0000008 G300_LC0000008_00 N 000000000000000000000000030840KCBC14063 G300_KCBC14063_00 N 0000000000000000000000000";//2Byte이상의 문자 취 // String planText = "";//2Byte이상의 문자 취 diff --git a/src/main/java/com/eactive/eai/common/server/EAIServerManager.java b/src/main/java/com/eactive/eai/common/server/EAIServerManager.java index 477be4a..0b144d3 100644 --- a/src/main/java/com/eactive/eai/common/server/EAIServerManager.java +++ b/src/main/java/com/eactive/eai/common/server/EAIServerManager.java @@ -369,9 +369,9 @@ public class EAIServerManager implements Lifecycle { } } public static void main(String[] args) throws Exception{ - System.out.println(substrRule("card-internal-runtime-568fd58554-b2cnk","[5,2],[5,2],[-2]",0)); - System.out.println(substrRule("card-internal-runtime-568fd58554-b2cnk","[5,2],[5,2],[-2]",1)); - System.out.println(substrRule("card-internal-runtime-568fd58554-b2cnk","[0,2],[0,2],[-2]",2)); + // System.out.println(substrRule("card-internal-runtime-568fd58554-b2cnk","[5,2],[5,2],[-2]",0)); + // System.out.println(substrRule("card-internal-runtime-568fd58554-b2cnk","[5,2],[5,2],[-2]",1)); + // System.out.println(substrRule("card-internal-runtime-568fd58554-b2cnk","[0,2],[0,2],[-2]",2)); } } diff --git a/src/main/java/com/eactive/eai/common/server/EAIServerVO.java b/src/main/java/com/eactive/eai/common/server/EAIServerVO.java index 6f18c02..9f86f75 100644 --- a/src/main/java/com/eactive/eai/common/server/EAIServerVO.java +++ b/src/main/java/com/eactive/eai/common/server/EAIServerVO.java @@ -23,8 +23,8 @@ public class EAIServerVO implements Serializable { * 리모트 호출 url ==> rmi://{ip}:{rmi RegistryPort}/xxxxx * 사이트마다 다를수 있음. */ - //private int plusRmiPort = 1; - private int plusRmiPort = 11; //jwhong for weblogic + private int plusRmiPort = 1; + //private int plusRmiPort = 11; //jwhong for weblogic /** * sessionManager에서 쓰기위해 diff --git a/src/main/java/com/eactive/eai/common/util/LogKeys.java b/src/main/java/com/eactive/eai/common/util/LogKeys.java index ba6ee90..ecff4ee 100644 --- a/src/main/java/com/eactive/eai/common/util/LogKeys.java +++ b/src/main/java/com/eactive/eai/common/util/LogKeys.java @@ -47,6 +47,7 @@ public interface LogKeys public static final String DATE_PATTERN ="date.pattern"; public static final String APPEND ="append"; public static final String MAX_BACKUP_INDEX ="max.backup.index"; + public static final String MAX_FILE_SIZE ="max.file.size"; public static final String ENCODING ="encoding"; public static final String COMPRESS_EXT ="compress.ext"; diff --git a/src/main/java/com/eactive/eai/common/util/Logger.java b/src/main/java/com/eactive/eai/common/util/Logger.java index c967420..89f5396 100644 --- a/src/main/java/com/eactive/eai/common/util/Logger.java +++ b/src/main/java/com/eactive/eai/common/util/Logger.java @@ -27,8 +27,9 @@ import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.Context; import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.rolling.RollingFileAppender; -import ch.qos.logback.core.rolling.TimeBasedRollingPolicy; +import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy; import ch.qos.logback.core.sift.AppenderFactory; +import ch.qos.logback.core.util.FileSize; import co.elastic.logging.logback.EcsEncoder; /** @@ -846,9 +847,16 @@ public class Logger implements LogKeys { rollingFileAppender.setName("FILE-" + discriminatingValue); rollingFileAppender.setFile(appenderLogDirectory + localServer + File.separator + appenderLogDirectorySub + File.separator + discriminatingValue + ".log"); - TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy<>(); + String sMaxFileSize = pmanager.getProperty(APPENDER_SIFT, MAX_FILE_SIZE, "500MB"); + + SizeAndTimeBasedRollingPolicy rollingPolicy = new SizeAndTimeBasedRollingPolicy<>(); rollingPolicy.setContext(context); - rollingPolicy.setFileNamePattern(appenderLogDirectory + localServer + File.separator + appenderLogDirectorySub + File.separator + discriminatingValue + datePattern + ".log"); + rollingPolicy.setFileNamePattern(appenderLogDirectory + localServer + File.separator + appenderLogDirectorySub + File.separator + discriminatingValue + datePattern + ".%i.log"); + if (StringUtils.isNotBlank(sMaxFileSize)) { + rollingPolicy.setMaxFileSize(FileSize.valueOf(sMaxFileSize)); + } else { + rollingPolicy.setMaxFileSize(FileSize.valueOf("500MB")); + } rollingPolicy.setParent(rollingFileAppender); rollingPolicy.setMaxHistory(maxBackupIndex); rollingPolicy.start(); @@ -1044,17 +1052,25 @@ public class Logger implements LogKeys { appender = new RollingFileAppender(); String localServer = EAIServerManager.getInstance().getLocalServerName(); - TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy(); + String sMaxFileSize = pmanager.getProperty(appenderName, MAX_FILE_SIZE, "500MB"); + + SizeAndTimeBasedRollingPolicy rollingPolicy = new SizeAndTimeBasedRollingPolicy(); if (StringUtils.isNotBlank(compressExt)){ if (compressExt.startsWith(".")) { compressExt = compressExt.substring(1); + } - rollingPolicy.setFileNamePattern( logDirectory + localServer + File.separator + logFile + datePattern + "." + compressExt); + rollingPolicy.setFileNamePattern( logDirectory + localServer + File.separator + logFile + datePattern + ".%i." + compressExt); }else{ - rollingPolicy.setFileNamePattern( logDirectory + localServer + File.separator + logFile + datePattern); + rollingPolicy.setFileNamePattern( logDirectory + localServer + File.separator + logFile + datePattern + ".%i."); } rollingPolicy.setContext( (LoggerContext) LoggerFactory.getILoggerFactory() ); rollingPolicy.setParent(appender); + if (StringUtils.isNotBlank(sMaxFileSize)) { + rollingPolicy.setMaxFileSize(FileSize.valueOf(sMaxFileSize)); + } else { + rollingPolicy.setMaxFileSize(FileSize.valueOf("500MB")); // 기본값 + } rollingPolicy.setMaxHistory(maxBackupIndex); rollingPolicy.start(); diff --git a/src/main/java/com/eactive/eai/common/util/StringUtil.java b/src/main/java/com/eactive/eai/common/util/StringUtil.java index 04d3718..3a856af 100644 --- a/src/main/java/com/eactive/eai/common/util/StringUtil.java +++ b/src/main/java/com/eactive/eai/common/util/StringUtil.java @@ -644,26 +644,26 @@ public final class StringUtil { boolean isDBUtf8 = true; String[] chunks = null; - System.out.println("\n test string:" + test); - System.out.println("utf-8 length = " + getBytesLength(test, true)); - System.out.println("ms949 length = " + getBytesLength(test, false)); - System.out.println("\n"); + // System.out.println("\n test string:" + test); + // System.out.println("utf-8 length = " + getBytesLength(test, true)); + // System.out.println("ms949 length = " + getBytesLength(test, false)); + // System.out.println("\n"); for(int len=6; len<9; len++) { - System.out.println(String.format(">> chunk length=%d, isDBUtf8=%b",len, isDBUtf8)); + // System.out.println(String.format(">> chunk length=%d, isDBUtf8=%b",len, isDBUtf8)); chunks = chunkStringArray(test,len,isDBUtf8); - System.out.println("chunk = "+ chunkString(test,len,isDBUtf8)); - System.out.println("chunks[0] = "+ chunks[0]); - System.out.println("chunks[1] = "+ chunks[1]); + // System.out.println("chunk = "+ chunkString(test,len,isDBUtf8)); + // System.out.println("chunks[0] = "+ chunks[0]); + // System.out.println("chunks[1] = "+ chunks[1]); } - System.out.println("\n"); + // System.out.println("\n"); isDBUtf8 = false; for(int len=6; len<9; len++) { - System.out.println(String.format(">> chunk length=%d, isDBUtf8=%b",len, isDBUtf8)); + // System.out.println(String.format(">> chunk length=%d, isDBUtf8=%b",len, isDBUtf8)); chunks = chunkStringArray(test,len,isDBUtf8); - System.out.println("chunk = "+ chunkString(test,len,isDBUtf8)); - System.out.println("chunks[0] = "+ chunks[0]); - System.out.println("chunks[1] = "+ chunks[1]); + // System.out.println("chunk = "+ chunkString(test,len,isDBUtf8)); + // System.out.println("chunks[0] = "+ chunks[0]); + // System.out.println("chunks[1] = "+ chunks[1]); } } } \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/util/TypeConversion.java b/src/main/java/com/eactive/eai/common/util/TypeConversion.java index cb75489..ddf7f66 100644 --- a/src/main/java/com/eactive/eai/common/util/TypeConversion.java +++ b/src/main/java/com/eactive/eai/common/util/TypeConversion.java @@ -229,27 +229,27 @@ public class TypeConversion short sInit = 730; byte[] bytes = TypeConversion.short2byte(sInit); short sLL = TypeConversion.parseShort(bytes,0); - System.out.println("-----Message Old LL : " + sLL); - System.out.println("-----Message bytes toString : " + bytes); + // System.out.println("-----Message Old LL : " + sLL); + // System.out.println("-----Message bytes toString : " + bytes); short sNewLL = 152; bytes = TypeConversion.replaceShort(bytes, 0, sNewLL); sNewLL = TypeConversion.parseShort(bytes,0); - System.out.println("-----Message New LL : " + sNewLL); - System.out.println("-----Message bytes toString : " + bytes); + // System.out.println("-----Message New LL : " + sNewLL); + // System.out.println("-----Message bytes toString : " + bytes); String strMsg = "DA F23456789012345678901234567890123456 "; short minusOne = -1; byte[] bytesMsg = strMsg.getBytes(); bytesMsg = TypeConversion.replaceShort(bytesMsg, 47, minusOne); - System.out.println("-----minusOne : [" + new String(bytesMsg)+"]"); + // System.out.println("-----minusOne : [" + new String(bytesMsg)+"]"); short rtnMinusOne = TypeConversion.parseShort(bytesMsg, 47); - System.out.println("-----minusOne : [" + rtnMinusOne+"]"); + // System.out.println("-----minusOne : [" + rtnMinusOne+"]"); bytesMsg = TypeConversion.replaceShort(bytesMsg, 0, sNewLL); - System.out.println("-----minusOne : [" + new String(bytesMsg)+"]"); + // System.out.println("-----minusOne : [" + new String(bytesMsg)+"]"); } diff --git a/src/main/java/com/eactive/eai/common/util/UUIDGenerator.java b/src/main/java/com/eactive/eai/common/util/UUIDGenerator.java index 1b553aa..192148c 100644 --- a/src/main/java/com/eactive/eai/common/util/UUIDGenerator.java +++ b/src/main/java/com/eactive/eai/common/util/UUIDGenerator.java @@ -129,8 +129,8 @@ public final class UUIDGenerator { // System.out.println(getGUID("user000001")); // System.out.println(new Integer("01")); seq = 99999999; - System.out.println(getGUID("MCI")); - System.out.println(getGUID("MCI")); + // System.out.println(getGUID("MCI")); + // System.out.println(getGUID("MCI")); long start = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { char[] seq = String.valueOf(i).toCharArray(); @@ -139,14 +139,14 @@ public final class UUIDGenerator { System.arraycopy(seq, 0, formatSeq, destPos, seq.length); } long end = System.currentTimeMillis() - start; - System.out.println("c1 time-" + end); + // System.out.println("c1 time-" + end); start = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { String formatSeq = StringUtils.leftPad(String.valueOf(i), 10, '0'); } end = System.currentTimeMillis() - start; - System.out.println("c2 time-" + end); + // System.out.println("c2 time-" + end); // System.out.println(formatSeq); } diff --git a/src/main/java/com/ext/eai/common/stdmessage/STDMessageKeys.java b/src/main/java/com/ext/eai/common/stdmessage/STDMessageKeys.java index 00ba711..f4755c9 100644 --- a/src/main/java/com/ext/eai/common/stdmessage/STDMessageKeys.java +++ b/src/main/java/com/ext/eai/common/stdmessage/STDMessageKeys.java @@ -49,8 +49,9 @@ public interface STDMessageKeys { public static final String OUTPUT_TYPE_ERR = "02"; //응답결과구분코드 - public static final String RESPONSE_TYPE_CODE_N = "0";//정상(normal) - public static final String RESPONSE_TYPE_CODE_E = "1";//오류(error) + public static final String RESPONSE_TYPE_CODE_N = "NR";//정상(normal) + public static final String RESPONSE_TYPE_CODE_E = "ER";//오류(error) + public static final String RESPONSE_TYPE_CODE_C = "1";//대상시스템연결오류(connect fail) public static final String RESPONSE_TYPE_CODE_T = "1";//타임아웃(timeout) public static final String RESPONSE_TYPE_CODE_F = "1";//시스템오류(fatal) @@ -68,6 +69,9 @@ public interface STDMessageKeys { public static final String PUSH_DVSN_CD_R = "R";// 청단위 public static final String PUSH_DVSN_CD_B = "B";// 국단위 public static final String PUSH_DVSN_CD_A = "A";// 전체 - - + + public static final String SYS_OPRT_ENV_DVCD_ONLINE = "O"; //운영 + public static final String SYS_OPRT_ENV_DVCD_TESTSTAGE = "S"; //검증 + public static final String SYS_OPRT_ENV_DVCD_DEV = "D"; //테스트 + public static final String SYS_OPRT_ENV_DVCD_DR = "R"; //DR } diff --git a/src/main/java/com/kjbank/encrypt/exchange/crypto/AESCipher.java b/src/main/java/com/kjbank/encrypt/exchange/crypto/AESCipher.java index 7241637..4306508 100644 --- a/src/main/java/com/kjbank/encrypt/exchange/crypto/AESCipher.java +++ b/src/main/java/com/kjbank/encrypt/exchange/crypto/AESCipher.java @@ -110,7 +110,7 @@ public class AESCipher } catch (Exception e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } return resultData; diff --git a/src/main/java/com/kjbank/encrypt/exchange/crypto/ECDHESA256Cipher.java b/src/main/java/com/kjbank/encrypt/exchange/crypto/ECDHESA256Cipher.java new file mode 100644 index 0000000..2c99d15 --- /dev/null +++ b/src/main/java/com/kjbank/encrypt/exchange/crypto/ECDHESA256Cipher.java @@ -0,0 +1,223 @@ +package com.kjbank.encrypt.exchange.crypto; + +import com.nimbusds.jose.*; +import com.nimbusds.jose.crypto.*; +import com.nimbusds.jose.jwk.*; +import com.nimbusds.jose.jwk.gen.*; +import java.io.FileInputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.cert.Certificate; +import java.security.interfaces.ECPublicKey; +import java.security.KeyStore; +import java.security.PrivateKey; + +//공개키 관련 (RSA) +import java.security.interfaces.RSAPublicKey; +import java.security.PublicKey; + +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.KeyUse; + +import java.io.FileNotFoundException; +import java.security.cert.CertificateException; +import java.io.IOException; +import java.util.Collection; +import java.security.Security; +//import org.bouncycastle.jce.provider.BouncyCastleProvider; + +public class ECDHESA256Cipher { + + private ECKey myECKey; + private ECKey receiverPublicJWK; + private RSAKey receiverPublicRSAKey; + private PublicKey pubKey; + private JWEObject jweObject; + + // 생성자: 수신자 키 쌍을 준비 + public ECDHESA256Cipher() throws Exception { + this.myECKey = new ECKeyGenerator(Curve.P_256) + .keyUse(KeyUse.ENCRYPTION) + .keyID("receiver-key") + .generate(); + + this.receiverPublicJWK = myECKey.toPublicJWK(); + } + + + //생성자: 내 키쌍 로드용 생성자 (복호화할 때 필요) + // 생성자: 키스토어에서 RSA 개인키/인증서 로드 (복호화용) + public ECDHESA256Cipher(String keystorePath, String storePass, String keyAlias, String keyPass) throws Exception { + KeyStore ks = KeyStore.getInstance("PKCS12"); + try (FileInputStream fis = new FileInputStream(keystorePath)) { + ks.load(fis, storePass.toCharArray()); + + PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, keyPass.toCharArray()); + X509Certificate cert = (X509Certificate) ks.getCertificate(keyAlias); + + if (privateKey == null || cert == null) { + throw new IllegalStateException("키스토어에서 개인키 또는 인증서를 로드하지 못했습니다."); + } + + this.pubKey = cert.getPublicKey(); + // System.out.println(pubKey.getAlgorithm()); // "RSA" 또는 "EC" + + if ("RSA".equals(pubKey.getAlgorithm())) { + RSAPublicKey rsaPub = (RSAPublicKey) cert.getPublicKey(); + this.receiverPublicRSAKey = new RSAKey.Builder(rsaPub) + .privateKey(privateKey) // ★ 개인키 포함 + .keyUse(KeyUse.ENCRYPTION) + .keyID(cert.getSerialNumber().toString()) + .build(); + } else if ("EC".equals(pubKey.getAlgorithm())) { + ECPublicKey ecPub = (ECPublicKey) cert.getPublicKey(); + // EC 복호화를 위해서는 EC 개인키도 필요합니다. + this.myECKey = new ECKey.Builder(Curve.P_256, ecPub) + .privateKey(privateKey) + .keyUse(KeyUse.ENCRYPTION) + .keyID(cert.getSerialNumber().toString()) + .build(); + } else { + throw new IllegalStateException("지원하지 않는 공개키 알고리즘: " + pubKey.getAlgorithm()); + } + } + } + + + // 생성자: 상대방 인증서에서 공개키 로드 + public ECDHESA256Cipher(String certPath) throws Exception { + //0. 개인키 새성 + //String certPath = "C:/imsi/mytestcert/signCert.der"; + String priPath = "C:/imsi/mytestcert/signPri.key"; + char[] password = "aaa1001".toCharArray(); + //Security.addProvider(new BouncyCastleProvider()); // bouncycastle 관련 일단 comment + PrivateKey myPrivateKey1 = NPKILoader.loadPrivateKey(priPath, password, pubKey.getAlgorithm()); + + // 1. 인증서 로드 + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + try (FileInputStream fis = new FileInputStream(certPath)) { + X509Certificate cert = null; + //인증서 묶음인 경우(PKCS#7 경우) + Collection certs = cf.generateCertificates(fis); + for (Certificate c : certs) { + if (c instanceof X509Certificate) { + cert = (X509Certificate) c; + // System.out.println("Subject: " + cert.getSubjectDN()); + } + } + + if (cert == null) { + throw new IllegalStateException("인증서를 찾을 수 없습니다."); + } + + // 공개키 저장 및 알고리즘 확인 + this.pubKey = cert.getPublicKey(); + // System.out.println(pubKey.getAlgorithm()); // "RSA" 또는 "EC" + + KeyStore ks = KeyStore.getInstance("PKCS12"); + + if ("RSA".equals(pubKey.getAlgorithm())) { + //PrivateKey myPrivateKey = (PrivateKey) ks.getKey(keyAlias, keyPass.toCharArray()); + //PrivateKey myPrivateKey = (PrivateKey) ks.getKey("mykey", "key1234".toCharArray()); + PrivateKey myPrivateKey = NPKILoader.loadPrivateKey(priPath, password, pubKey.getAlgorithm()); + // System.out.println("PrivateKey Alg: " + myPrivateKey.getAlgorithm()); + + RSAPublicKey publicKey = (RSAPublicKey) cert.getPublicKey(); + this.receiverPublicRSAKey = new RSAKey.Builder(publicKey) + .privateKey(myPrivateKey) //개인키 포함 + .keyUse(KeyUse.ENCRYPTION) + .keyID(cert.getSerialNumber().toString()) + .build(); + } else if ("EC".equals(pubKey.getAlgorithm())) { + ECPublicKey ecPub = (ECPublicKey) cert.getPublicKey(); + this.receiverPublicJWK = new ECKey.Builder(Curve.P_256, ecPub) + .keyUse(KeyUse.ENCRYPTION) + .keyID(cert.getSerialNumber().toString()) + .build(); + } else { + throw new IllegalStateException("지원하지 않는 공개키 알고리즘: " + pubKey.getAlgorithm()); + } + + } catch (FileNotFoundException e) { + System.err.println("인증서 파일을 찾을 수 없습니다: " + e.getMessage()); + } catch (CertificateException e) { + System.err.println("인증서 파싱 오류: " + e.getMessage()); + } catch (IOException e) { + System.err.println("파일 읽기 오류: " + e.getMessage()); + } catch (ClassCastException e) { + System.err.println("X509Certificate 형변환 오류: " + e.getMessage()); + } + } + + // 암호화 메서드 + public String encrypt(String jsonPayload) throws Exception { + if (receiverPublicJWK == null && receiverPublicRSAKey == null ) { + throw new IllegalStateException("상대방 공개키가 초기화되지 않았습니다."); + } + + if (receiverPublicJWK != null && KeyType.EC.equals(receiverPublicJWK.getKeyType())) { + JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES_A256KW, EncryptionMethod.A256GCM) + .contentType("application/json") + .keyID(receiverPublicJWK.getKeyID()) + .build(); + + this.jweObject = new JWEObject(header, new Payload(jsonPayload)); + + JWEEncrypter encrypter = new ECDHEncrypter(receiverPublicJWK); + jweObject.encrypt(encrypter); + + } else if (receiverPublicRSAKey != null && "RSA".equals(receiverPublicRSAKey.getKeyType().getValue())) { + JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM) + .contentType("application/json") + .keyID(receiverPublicRSAKey.getKeyID()) + .build(); + + this.jweObject = new JWEObject(header, new Payload(jsonPayload)); + + JWEEncrypter encrypter = new RSAEncrypter(receiverPublicRSAKey); + jweObject.encrypt(encrypter); + } + return jweObject.serialize(); + + } + + // 복호화 메서드(상대방이 나한테 보낸것) + public String decrypt(String jweString) throws Exception { + if (myECKey == null && receiverPublicRSAKey == null) { + throw new IllegalStateException("내 개인키 또는 RSA 키가 초기화되지 않았습니다."); + } + + JWEObject decryptedJWE = JWEObject.parse(jweString); + + if (myECKey != null) { + // EC 키로 복호화 + JWEDecrypter decrypter = new ECDHDecrypter(myECKey); + decryptedJWE.decrypt(decrypter); + + } else if (receiverPublicRSAKey != null && receiverPublicRSAKey.isPrivate()) { + // RSA 키로 복호화 + JWEDecrypter decrypter = new RSADecrypter(receiverPublicRSAKey.toPrivateKey()); + decryptedJWE.decrypt(decrypter); + } else { + throw new IllegalStateException("복호화에 필요한 키가 준비되지 않았습니다. (EC 개인키 또는 RSA 개인키)"); + } + + return decryptedJWE.getPayload().toString(); + } + + // 상대방 공개키를 외부에 제공할 수 있도록 getter + public ECKey getReceiverPublicJWK() { + if (receiverPublicJWK == null) { + throw new IllegalStateException("상대방 공개키가 초기화되지 않았습니다."); + } + return receiverPublicJWK; + } + + // 내 공개키를 상대방에게 제공할 수 있도록 getter + public ECKey getMyPublicJWK() { + if (myECKey == null) { + throw new IllegalStateException("내 키쌍이 초기화되지 않았습니다."); + } + return myECKey.toPublicJWK(); + } +} diff --git a/src/main/java/com/kjbank/encrypt/exchange/crypto/NPKILoader.java b/src/main/java/com/kjbank/encrypt/exchange/crypto/NPKILoader.java new file mode 100644 index 0000000..aa84d9e --- /dev/null +++ b/src/main/java/com/kjbank/encrypt/exchange/crypto/NPKILoader.java @@ -0,0 +1,60 @@ +package com.kjbank.encrypt.exchange.crypto; + +import java.io.FileInputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.*; +import java.security.cert.*; +import java.security.spec.PKCS8EncodedKeySpec; +import javax.crypto.*; +import javax.crypto.spec.PBEKeySpec; + +public class NPKILoader { + + // 1) Provider 등록 (예: KISA SEED JCE, KSign 등) + static { + // 예시: Security.addProvider(new com.kisa.seed.KISASeedJCE()); + // 또는 Security.addProvider(new com.ksign.security.provider.KsignProvider()); + // 실제 사용하는 라이브러리 명으로 교체 + } + + public static X509Certificate loadCert(String certDerPath) throws Exception { + try (FileInputStream fis = new FileInputStream(certDerPath)) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (X509Certificate) cf.generateCertificate(fis); + } + } + + public static PrivateKey loadPrivateKey(String priDerPath, char[] password, String keyAlg) throws Exception { + // 암호화된 PKCS#8 (DER) 읽기 + byte[] enc = Files.readAllBytes(Paths.get(priDerPath)); + EncryptedPrivateKeyInfo encInfo = new EncryptedPrivateKeyInfo(enc); + + // 알고리즘 확인 (OID → 알고리즘 이름 매핑 필요) + String algName = encInfo.getAlgName(); // 일부 Provider는 빈 문자열을 반환할 수 있음 + AlgorithmParameters params = encInfo.getAlgParameters(); + + // 국내 OID 매핑: 1.2.410.200004.1.15 → PBEWithSHA1AndSEED (Provider에 따라 이름 다를 수 있음) + if (algName == null || algName.isEmpty()) { + String oid = encInfo.getAlgParameters().getAlgorithm(); // 일부 Provider는 여기서도 OID를 줍니다 + // 필요 시 강제 설정 + algName = "PBEWithSHA1AndSEED"; // 사용 중인 Provider 문서의 이름으로 맞추세요 + } + + // PBE 키 생성 + SecretKeyFactory skf = SecretKeyFactory.getInstance(algName); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password); + SecretKey pbeKey = skf.generateSecret(pbeKeySpec); + + // 복호화 + Cipher cipher = Cipher.getInstance(algName); + cipher.init(Cipher.DECRYPT_MODE, pbeKey, params); + byte[] pkcs8 = cipher.doFinal(encInfo.getEncryptedData()); + + // PKCS#8 → PrivateKey + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8); + KeyFactory kf = KeyFactory.getInstance(keyAlg); // "RSA" 또는 "EC" + return kf.generatePrivate(keySpec); + } +} + diff --git a/src/main/java/com/kjbank/encrypt/exchange/crypto/RSAOAEP256Cipher.java b/src/main/java/com/kjbank/encrypt/exchange/crypto/RSAOAEP256Cipher.java new file mode 100644 index 0000000..10d1790 --- /dev/null +++ b/src/main/java/com/kjbank/encrypt/exchange/crypto/RSAOAEP256Cipher.java @@ -0,0 +1,54 @@ +package com.kjbank.encrypt.exchange.crypto; + +import com.nimbusds.jose.*; +import com.nimbusds.jose.crypto.*; +import com.nimbusds.jose.util.StandardCharset; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import com.nimbusds.jose.crypto.RSAEncrypter; +import java.security.interfaces.RSAPublicKey; + +public class RSAOAEP256Cipher { + + // 암호화: 상대방 공개 인증서(RSA)로 암호화 + public static String encrypt(byte[] plaintext, X509Certificate recipientCert, String kidOptional) throws Exception { + // 인증서에서 RSA 공개키 추출 + if (!"RSA".equalsIgnoreCase(recipientCert.getPublicKey().getAlgorithm())) { + throw new IllegalArgumentException("Recipient certificate public key is not RSA"); + } + RSAPublicKey recipientPublicKey = (RSAPublicKey) recipientCert.getPublicKey(); + + JWEHeader header = new JWEHeader.Builder( + JWEAlgorithm.RSA_OAEP_256, + EncryptionMethod.A256GCM + ) + .contentType("application/octet-stream") + .keyID(kidOptional) + .build(); + + JWEObject jweObject = new JWEObject(header, new Payload(plaintext)); + JWEEncrypter encrypter = new RSAEncrypter(recipientPublicKey); + jweObject.encrypt(encrypter); + + return jweObject.serialize(); + } + + // 복호화: 내 RSA 개인키로 복호화 + public static byte[] decrypt(String jweCompact, PrivateKey myPrivateKey) throws Exception { + JWEObject jweObject = JWEObject.parse(jweCompact); + JWEDecrypter decrypter = new RSADecrypter(myPrivateKey); + jweObject.decrypt(decrypter); + return jweObject.getPayload().toBytes(); + } + + // 편의 함수 + public static String encryptText(String text, X509Certificate cert, String kidOptional) throws Exception { + return encrypt(text.getBytes(StandardCharset.UTF_8), cert, kidOptional); + } + + public static String decryptToText(String jweCompact, PrivateKey myPrivateKey) throws Exception { + return new String(decrypt(jweCompact, myPrivateKey), StandardCharset.UTF_8); + } +} \ No newline at end of file