From 624e6095bebdc2139ada45037f7fd9d35abf5e64 Mon Sep 17 00:00:00 2001 From: "icksishu@gmail.com" Date: Wed, 24 Dec 2025 16:41:14 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=90=EC=9D=B4=EC=A0=84=ED=8A=B8=20ARIA=20?= =?UTF-8?q?=ED=82=A4=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20#4=20-=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/database/create-database.sql | 13 ++- .../front/src/views/CryptoKeyManageView.vue | 105 ++++++++++++++++-- .../app/agent/DfxAgentInfoController.java | 8 ++ .../app/agent/service/DfxCryptoKeyDto.java | 7 +- .../app/agent/service/DfxCryptoKeyMapper.java | 2 +- .../agent/service/DfxCryptoKeyService.java | 63 +++++++++-- .../resources/mapper/app/dfx-crypto-key.xml | 28 +++-- 7 files changed, 187 insertions(+), 39 deletions(-) diff --git a/src/database/create-database.sql b/src/database/create-database.sql index 5f3d934..fb2bba2 100644 --- a/src/database/create-database.sql +++ b/src/database/create-database.sql @@ -173,20 +173,21 @@ COMMENT ON COLUMN TB_DFX_AGENT_MESSAGE_HISTORY.PROCESS_ACK_TS IS '처리결과 CREATE TABLE TB_DFX_CRYPTO_KEY ( - KEY_VALUE VARCHAR(256) NOT NULL - , HASH_VALUE VARCHAR(256) NOT NULL + KEY_ID VARCHAR(256) NOT NULL + , KEY_TYPE_NAME VARCHAR(32) NOT NULL , ALGORITHM_NAME VARCHAR(64) NOT NULL - , MODE_NAME VARCHAR(64) NOT NULL , TARGET_AGENT_HOST_ID VARCHAR(256) , APPLY_TS TIMESTAMPTZ(3) , DATA_ENCRYPTION_YN VARCHAR(1) + , JSON_WEB_KEY TEXT + , CONSTRAINT PK_DFX_CRYPTO_KEY PRIMARY KEY (KEY_ID) ); COMMENT ON TABLE TB_DFX_CRYPTO_KEY IS '암호화키정보'; -COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.KEY_VALUE IS 'KEY VALUE'; -COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.HASH_VALUE IS 'HASH VALUE'; +COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.KEY_ID IS 'KEY ID'; +COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.KEY_TYPE_NAME IS '대칭키(oct), RSA공개/개인키(RSA), 타원곡선키(EC), Ed25519(OKP)'; COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.ALGORITHM_NAME IS '알고리즘'; -COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.MODE_NAME IS '모드'; COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.TARGET_AGENT_HOST_ID IS '적용 에이전트 ID'; COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.APPLY_TS IS '적용 시간'; COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.DATA_ENCRYPTION_YN IS '데이터 암호화 여부'; +COMMENT ON COLUMN TB_DFX_CRYPTO_KEY.JSON_WEB_KEY IS 'JWT 키 데이터'; diff --git a/src/main/front/src/views/CryptoKeyManageView.vue b/src/main/front/src/views/CryptoKeyManageView.vue index e1bec56..346d095 100644 --- a/src/main/front/src/views/CryptoKeyManageView.vue +++ b/src/main/front/src/views/CryptoKeyManageView.vue @@ -1,6 +1,7 @@ @@ -33,16 +73,15 @@ onMounted(async () => {
- +
- - + + - @@ -51,10 +90,9 @@ onMounted(async () => { - - + + - @@ -67,6 +105,53 @@ onMounted(async () => { + + + diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/DfxAgentInfoController.java b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/DfxAgentInfoController.java index 0fa4de0..7f47cd0 100644 --- a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/DfxAgentInfoController.java +++ b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/DfxAgentInfoController.java @@ -12,6 +12,8 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.util.List; import java.util.Map; @@ -92,4 +94,10 @@ public class DfxAgentInfoController { List dfxCryptoKeyDtoList = dfxCryptoKeyService.selectDfxCryptoKeyList(); return ResponseEntity.ok().body(dfxCryptoKeyDtoList); } + + @PostMapping("/app-api/agent/saveCryptoKeyDto") + public ResponseEntity saveCryptoKeyDto(@RequestBody DfxCryptoKeyDto dfxCryptoKeyDto) throws NoSuchAlgorithmException, NoSuchProviderException { + dfxCryptoKeyDto = dfxCryptoKeyService.saveDfxCryptoKey(dfxCryptoKeyDto); + return ResponseEntity.ok().body(dfxCryptoKeyDto); + } } diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyDto.java b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyDto.java index 7c89a42..0abf3fe 100644 --- a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyDto.java +++ b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyDto.java @@ -9,11 +9,12 @@ import lombok.*; @Builder @ToString public class DfxCryptoKeyDto { - private String keyValue; - private String hashValue; + private String keyword; + private String keyId; + private String keyTypeName; private String algorithmName; - private String modeName; private String targetAgentHostId; private long applyTs; private String dataEncryptionYn; + private String jsonWebKey; } diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyMapper.java b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyMapper.java index e317ffa..b995df7 100644 --- a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyMapper.java +++ b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyMapper.java @@ -9,7 +9,7 @@ import java.util.List; public interface DfxCryptoKeyMapper { List selectDfxCryptoKeyList(SearchParameterDto searchParameterDto); int selectDfxCryptoKeyListTotalCount(SearchParameterDto searchParameterDto); - DfxCryptoKeyDto selectDfxCryptoKeyByKeyValue(DfxCryptoKeyDto dfxCryptoKeyDto); + DfxCryptoKeyDto selectDfxCryptoKeyByKeyId(DfxCryptoKeyDto dfxCryptoKeyDto); void insertDfxCryptoKey(DfxCryptoKeyDto dfxCryptoKeyDto); int updateDfxCryptoKeyToApply(DfxCryptoKeyDto dfxCryptoKeyDto); } diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyService.java b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyService.java index 5082a00..093649d 100644 --- a/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyService.java +++ b/src/main/java/com/bsmlab/dfx/dfxconsole/app/agent/service/DfxCryptoKeyService.java @@ -14,12 +14,19 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.Security; +import java.util.Base64; import java.util.List; +import java.util.UUID; @Service @Slf4j @RequiredArgsConstructor public class DfxCryptoKeyService { + static { + if(Security.getProvider("BC") == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } private final DfxCryptoKeyMapper cryptoKeyMapper; public List selectDfxCryptoKeyList() { @@ -27,13 +34,55 @@ public class DfxCryptoKeyService { return dfxCryptoKeyDtoList; } - public DfxCryptoKeyDto generateNewKey() throws NoSuchAlgorithmException, NoSuchProviderException { - DfxCryptoKeyDto dfxCryptoKeyDto = DfxCryptoKeyDto.builder().build(); - Security.addProvider(new BouncyCastleProvider()); - KeyGenerator keyGenerator = KeyGenerator.getInstance("ARIA", "BC"); - keyGenerator.init(256, new SecureRandom()); - SecretKey key = keyGenerator.generateKey(); - + /** + * TB_DFX_CRYPTO_KEY 생성 또는 갱신한다. 생성을 위해서는 DfxCryptoKeyDto.keyId에 해당하는 정보가 없어야 하며 DfxCryptoKeyDto.keyword 값이 있어야 한다. + */ + public DfxCryptoKeyDto saveDfxCryptoKey(DfxCryptoKeyDto dfxCryptoKeyDto) throws NoSuchAlgorithmException, NoSuchProviderException { + DfxCryptoKeyDto existDfxCryptoKeyDto = cryptoKeyMapper.selectDfxCryptoKeyByKeyId(dfxCryptoKeyDto); + if(existDfxCryptoKeyDto == null) { + String keyId = this.generateKeyIdByKeyword(dfxCryptoKeyDto.getKeyword()); + dfxCryptoKeyDto.setKeyId(keyId); + String jsonWebKey = this.generateNewKey(keyId); + dfxCryptoKeyDto.setJsonWebKey(jsonWebKey); + cryptoKeyMapper.insertDfxCryptoKey(dfxCryptoKeyDto); + } + else { + cryptoKeyMapper.updateDfxCryptoKeyToApply(dfxCryptoKeyDto); + } return dfxCryptoKeyDto; } + + private String generateKeyIdByKeyword(String keyword) { + String keyId = keyword + "-" + UUID.randomUUID().toString(); + keyId = keyId.length() > 256 ? keyId.substring(0, 256) : keyId; + return keyId; + } + + /** + * 키 파일 형식: jwk 형식 - JSON Web Key (RFC7517) + * { + * "kid": "Key ID. 이 json object 에 대한 unique ID", + * "kty": "Key TYpe. oct(Octet sequence (대칭키). ARIA, AES, HMAC) ", + * "alg": "ALGorithm, DFX에서 지원하는 범위: ARIA-256-GCM", + * "k": "실제 키의 바이트(Base64 인코딩)" + * } + * @return jwk을 문자열로 변환한 값 + */ + private String generateNewKey(String keyId) { + byte[] key = new byte[32]; + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(key); // random key 생성 + String encodedKey = Base64.getEncoder().encodeToString(key); + String jwk = """ + { + "kid": "%s", + "kty": "oct", + "alg": "ARIA-256-GCM", + "k": "%s" + } + """.formatted(keyId, encodedKey); + return jwk; + } + + } diff --git a/src/main/resources/mapper/app/dfx-crypto-key.xml b/src/main/resources/mapper/app/dfx-crypto-key.xml index 9ccbb07..2d64ba7 100644 --- a/src/main/resources/mapper/app/dfx-crypto-key.xml +++ b/src/main/resources/mapper/app/dfx-crypto-key.xml @@ -4,14 +4,14 @@ -
선택KeyHashKey IDType AlgorithmMode Target agent Applied at Data encryption
{{ cryptoKeyDto.keyValue }}{{ cryptoKeyDto.hashValue }}{{ cryptoKeyDto.keyId }}{{ cryptoKeyDto.keyTypeName }} {{ cryptoKeyDto.algorithmName }}{{ cryptoKeyDto.modeName }} {{ cryptoKeyDto.targetAgentHostId }} {{ cryptoKeyDto.applyTs }} {{ cryptoKeyDto.dataEncryptionYn }}