From 19a5c6bb8313c9223b23914b89717e208f3a173f Mon Sep 17 00:00:00 2001 From: willjsw Date: Fri, 30 May 2025 16:21:17 +0900 Subject: [PATCH 1/8] =?UTF-8?q?KW-536/feat:=20did=20=EB=B0=9C=EA=B8=89=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++ did-agent | 1 + .../java/com/doubleo/didagent/agent/.gitkeep | 0 .../com/doubleo/didagent/controller/.gitkeep | 0 .../didagent/controller/DidController.java | 13 +++- .../dto/request/DidCreateRequest.java | 5 ++ .../dto/response/DidCreateResponse.java | 5 +- .../exception/errorcode/DIDErrorCode.java | 2 +- .../global/util/Ed25519KeyGenerator.java | 43 +++++++++++ .../didagent/global/util/KeyMaterial.java | 14 ++++ .../didagent/global/util/PeerDidUtil.java | 51 +++++++++++++ .../global/util/PeerDidValidator.java | 72 +++++++++++++++++++ .../doubleo/didagent/service/DidService.java | 34 +++++++++ 13 files changed, 240 insertions(+), 4 deletions(-) create mode 160000 did-agent delete mode 100644 src/main/java/com/doubleo/didagent/agent/.gitkeep delete mode 100644 src/main/java/com/doubleo/didagent/controller/.gitkeep create mode 100644 src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java create mode 100644 src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java create mode 100644 src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java create mode 100644 src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java create mode 100644 src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java create mode 100644 src/main/java/com/doubleo/didagent/service/DidService.java diff --git a/build.gradle b/build.gradle index d77c776..1fbae36 100644 --- a/build.gradle +++ b/build.gradle @@ -46,6 +46,10 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'io.micrometer:micrometer-core' implementation 'io.micrometer:micrometer-registry-prometheus' + //did + implementation 'org.bitcoinj:bitcoinj-core:0.15.10' + implementation 'org.json:json:20240303' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/did-agent b/did-agent new file mode 160000 index 0000000..8906266 --- /dev/null +++ b/did-agent @@ -0,0 +1 @@ +Subproject commit 8906266b20b0045cde2d8631ae01474370c66b04 diff --git a/src/main/java/com/doubleo/didagent/agent/.gitkeep b/src/main/java/com/doubleo/didagent/agent/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/didagent/controller/.gitkeep b/src/main/java/com/doubleo/didagent/controller/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/didagent/controller/DidController.java b/src/main/java/com/doubleo/didagent/controller/DidController.java index 73d2627..75d0164 100644 --- a/src/main/java/com/doubleo/didagent/controller/DidController.java +++ b/src/main/java/com/doubleo/didagent/controller/DidController.java @@ -1,16 +1,25 @@ package com.doubleo.didagent.controller; +import com.doubleo.didagent.dto.request.DidCreateRequest; import com.doubleo.didagent.dto.response.DidCreateResponse; +import com.doubleo.didagent.service.DidService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/dids") +@RequiredArgsConstructor public class DidController { + private final DidService didService; + @PostMapping - public DidCreateResponse didCreate() { - return new DidCreateResponse(); + public DidCreateResponse didCreate(@Valid @RequestBody DidCreateRequest request) + throws Exception { + return didService.createPeer2Did(request); } } diff --git a/src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java b/src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java new file mode 100644 index 0000000..65fce1b --- /dev/null +++ b/src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java @@ -0,0 +1,5 @@ +package com.doubleo.didagent.dto.request; + +import jakarta.validation.constraints.NotBlank; + +public record DidCreateRequest(@NotBlank String routingKey, @NotBlank String serviceEndpoint) {} diff --git a/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java b/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java index 9225cf5..83de6fe 100644 --- a/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java +++ b/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java @@ -1,3 +1,6 @@ package com.doubleo.didagent.dto.response; -public record DidCreateResponse() {} +import jakarta.validation.constraints.NotBlank; + +public record DidCreateResponse( + @NotBlank String peerDid2, @NotBlank String publicKey, @NotBlank String privateKey) {} diff --git a/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java b/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java index 9ffd69c..df4384e 100644 --- a/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java +++ b/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java @@ -7,7 +7,7 @@ @Getter @AllArgsConstructor public enum DIDErrorCode implements BaseErrorCode { - SAMPLE_ERROR(HttpStatus.NOT_FOUND, "DID Agent API Sample Error"), + MALFORMED_PEER_DID(HttpStatus.NOT_FOUND, "잘못된 형식의 DID 입니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java new file mode 100644 index 0000000..bf3103f --- /dev/null +++ b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java @@ -0,0 +1,43 @@ +package com.doubleo.didagent.global.util; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.interfaces.EdECPrivateKey; +import java.security.interfaces.EdECPublicKey; +import java.util.Arrays; +import org.bitcoinj.core.Base58; + +public class Ed25519KeyGenerator { + /** JDK 17 Ed25519 키쌍을 생성해 raw + Base58 형식으로 리턴 */ + public static KeyMaterial generate() throws Exception { + // 1. 표준 JDK로 키쌍 생성 + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519"); + KeyPair kp = kpg.generateKeyPair(); + + // 2. raw 32 byte 추출 + byte[] pubSpki = kp.getPublic().getEncoded(); // 44 bytes (12 byte header + 32 byte raw) + byte[] rawPub = Arrays.copyOfRange(pubSpki, pubSpki.length - 32, pubSpki.length); + + byte[] privPkcs8 = kp.getPrivate().getEncoded(); // 48 bytes (16 byte header + 32 byte raw) + byte[] rawPriv = Arrays.copyOfRange(privPkcs8, privPkcs8.length - 32, privPkcs8.length); + + // 3. multicodec(+multibase) 접두어 - 0xED01 (‘ed25519-pub’) + Base58btc(z…) + byte[] prefixed = new byte[rawPub.length + 2]; + prefixed[0] = (byte) 0xED; // multicodec 0xED 0x01 + prefixed[1] = 0x01; + System.arraycopy(rawPub, 0, prefixed, 2, rawPub.length); + + String publicKeyBase58 = "z" + Base58.encode(prefixed); // multibase ‘z’ + Base58 + String privateKeyBase58 = Base58.encode(rawPriv); // 비공개키는 접두어 없이 raw 만 + + return new KeyMaterial( + rawPub, + rawPriv, + publicKeyBase58, + privateKeyBase58, + (EdECPublicKey) kp.getPublic(), + (EdECPrivateKey) kp.getPrivate()); + } + + /** 결과 보관용 record (Java 16+ 기능) */ +} diff --git a/src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java b/src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java new file mode 100644 index 0000000..abdc939 --- /dev/null +++ b/src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java @@ -0,0 +1,14 @@ +package com.doubleo.didagent.global.util; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.security.interfaces.EdECPrivateKey; +import java.security.interfaces.EdECPublicKey; + +public record KeyMaterial( + @NotNull byte[] rawPub, + @NotNull byte[] rawPriv, + @NotBlank String pub58, + @NotBlank String priv58, + @NotNull EdECPublicKey jdkPub, + @NotNull EdECPrivateKey jdkPriv) {} diff --git a/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java b/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java new file mode 100644 index 0000000..5c30498 --- /dev/null +++ b/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java @@ -0,0 +1,51 @@ +package com.doubleo.didagent.global.util; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import org.json.JSONArray; +import org.json.JSONObject; + +public class PeerDidUtil { + + /** + * did:peer:2 DID를 생성합니다. + * + * @param publicKeyBase58 z6... 형식의 공개키 (인증 및 키교환 동일 사용) + * @param routingKey z6... 형식의 라우팅 키 (1개만 사용, 없으면 null 또는 빈 문자열) + * @param serviceEndpoint DIDComm 메시지를 받을 서비스 엔드포인트 + * @return did:peer:2 DID 문자열 + */ + public static String createPeerDid2( + String publicKeyBase58, String routingKey, String serviceEndpoint) { + // enc1: 인증용 키 + String enc1 = "V" + publicKeyBase58; + + // enc2: 키 교환용 키 (현재는 동일 키 사용) + String enc2 = "E" + publicKeyBase58; + + // enc3: 서비스 JSON → base64url 인코딩 + JSONObject service = new JSONObject(); + service.put("id", "#didcomm-0"); + service.put("type", "did-communication"); + service.put("priority", 0); + + JSONArray recipientKeys = new JSONArray().put("#key-1"); + service.put("recipientKeys", recipientKeys); + + if (routingKey != null && !routingKey.isBlank()) { + service.put("routingKeys", new JSONArray().put(routingKey)); + } + + service.put("serviceEndpoint", serviceEndpoint); + + String enc3 = + "S" + + Base64.getUrlEncoder() + .withoutPadding() + .encodeToString( + service.toString().getBytes(StandardCharsets.UTF_8)); + + // 최종 DID 조합 + return "did:peer:2." + enc1 + "." + enc2 + "." + enc3; + } +} diff --git a/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java b/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java new file mode 100644 index 0000000..489ea46 --- /dev/null +++ b/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java @@ -0,0 +1,72 @@ +package com.doubleo.didagent.global.util; + +import com.doubleo.didagent.global.exception.CommonException; +import com.doubleo.didagent.global.exception.errorcode.DIDErrorCode; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import lombok.extern.slf4j.Slf4j; +import org.bitcoinj.core.Base58; +import org.json.JSONObject; + +@Slf4j +public class PeerDidValidator { + + public static void isValidPeerDid2(String did) { + try { + if (!did.startsWith("did:peer:2.")) { + log.error("did:peer:2 형식이 아닙니다."); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + + String[] parts = did.substring("did:peer:2.".length()).split("\\."); + if (parts.length != 3) { + log.error("DID는 enc1, enc2, enc3 세 부분으로 구성되어야 합니다."); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + + // --- enc1 --- + String enc1 = parts[0]; + if (!enc1.startsWith("V") || !enc1.substring(1).startsWith("z")) { + log.error("enc1 (V 접두사)가 올바르지 않습니다."); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + Base58.decode(enc1.substring(2)); // 'Vz6...' + + // --- enc2 --- + String enc2 = parts[1]; + if (!enc2.startsWith("E") || !enc2.substring(1).startsWith("z")) { + log.error("enc2 (E 접두사)가 올바르지 않습니다."); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + Base58.decode(enc2.substring(2)); // 'Ez6...' + + // --- enc3 --- + String enc3 = parts[2]; + if (!enc3.startsWith("S")) { + log.error("enc3 (S 접두사)가 없습니다."); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + + String serviceBase64 = enc3.substring(1); + byte[] serviceBytes = Base64.getUrlDecoder().decode(serviceBase64); + String serviceJsonString = new String(serviceBytes, StandardCharsets.UTF_8); + JSONObject service = new JSONObject(serviceJsonString); + + if (!service.has("id") || !service.has("type") || !service.has("serviceEndpoint")) { + log.error("service JSON에 필수 필드가 없습니다."); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + + if (!service.has("recipientKeys")) { + log.error("recipientKeys가 없습니다."); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + + log.info("peer did check completed"); + + } catch (CommonException e) { + log.error("예외 발생: {}", e.getMessage()); + throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + } + } +} diff --git a/src/main/java/com/doubleo/didagent/service/DidService.java b/src/main/java/com/doubleo/didagent/service/DidService.java new file mode 100644 index 0000000..efa2897 --- /dev/null +++ b/src/main/java/com/doubleo/didagent/service/DidService.java @@ -0,0 +1,34 @@ +package com.doubleo.didagent.service; + +import com.doubleo.didagent.dto.request.DidCreateRequest; +import com.doubleo.didagent.dto.response.DidCreateResponse; +import com.doubleo.didagent.global.exception.CommonException; +import com.doubleo.didagent.global.util.Ed25519KeyGenerator; +import com.doubleo.didagent.global.util.KeyMaterial; +import com.doubleo.didagent.global.util.PeerDidUtil; +import com.doubleo.didagent.global.util.PeerDidValidator; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class DidService { + + public DidCreateResponse createPeer2Did(DidCreateRequest request) { + KeyMaterial key = getKeyMaterial(); + String peer2Did = + PeerDidUtil.createPeerDid2( + key.pub58(), request.routingKey(), request.serviceEndpoint()); + PeerDidValidator.isValidPeerDid2(peer2Did); + log.info("Created PeerDid2: {}", peer2Did); + return new DidCreateResponse(peer2Did, key.pub58(), key.priv58()); + } + + private KeyMaterial getKeyMaterial() throws CommonException { + try { + return Ed25519KeyGenerator.generate(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} From cdc65bed0351d7912f2959171b29a5b926881536 Mon Sep 17 00:00:00 2001 From: willjsw Date: Fri, 30 May 2025 16:23:59 +0900 Subject: [PATCH 2/8] =?UTF-8?q?KW-536/refactor:=20controller=20method=20?= =?UTF-8?q?=EC=88=98=EC=A0=95(peer2DidCreate)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/doubleo/didagent/controller/DidController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/doubleo/didagent/controller/DidController.java b/src/main/java/com/doubleo/didagent/controller/DidController.java index 75d0164..6d5c4ca 100644 --- a/src/main/java/com/doubleo/didagent/controller/DidController.java +++ b/src/main/java/com/doubleo/didagent/controller/DidController.java @@ -18,7 +18,7 @@ public class DidController { private final DidService didService; @PostMapping - public DidCreateResponse didCreate(@Valid @RequestBody DidCreateRequest request) + public DidCreateResponse peer2DidCreate(@Valid @RequestBody DidCreateRequest request) throws Exception { return didService.createPeer2Did(request); } From 36ef88596785e77bb3f3b36111a9ff06019fbd53 Mon Sep 17 00:00:00 2001 From: willjsw Date: Fri, 30 May 2025 16:26:24 +0900 Subject: [PATCH 3/8] =?UTF-8?q?KW-536/refactor:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/util/Ed25519KeyGenerator.java | 16 ++++++---------- .../didagent/global/util/PeerDidUtil.java | 13 +------------ .../didagent/global/util/PeerDidValidator.java | 5 +---- 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java index bf3103f..6f5b861 100644 --- a/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java +++ b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java @@ -10,25 +10,23 @@ public class Ed25519KeyGenerator { /** JDK 17 Ed25519 키쌍을 생성해 raw + Base58 형식으로 리턴 */ public static KeyMaterial generate() throws Exception { - // 1. 표준 JDK로 키쌍 생성 + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519"); KeyPair kp = kpg.generateKeyPair(); - // 2. raw 32 byte 추출 - byte[] pubSpki = kp.getPublic().getEncoded(); // 44 bytes (12 byte header + 32 byte raw) + byte[] pubSpki = kp.getPublic().getEncoded(); byte[] rawPub = Arrays.copyOfRange(pubSpki, pubSpki.length - 32, pubSpki.length); - byte[] privPkcs8 = kp.getPrivate().getEncoded(); // 48 bytes (16 byte header + 32 byte raw) + byte[] privPkcs8 = kp.getPrivate().getEncoded(); byte[] rawPriv = Arrays.copyOfRange(privPkcs8, privPkcs8.length - 32, privPkcs8.length); - // 3. multicodec(+multibase) 접두어 - 0xED01 (‘ed25519-pub’) + Base58btc(z…) byte[] prefixed = new byte[rawPub.length + 2]; - prefixed[0] = (byte) 0xED; // multicodec 0xED 0x01 + prefixed[0] = (byte) 0xED; prefixed[1] = 0x01; System.arraycopy(rawPub, 0, prefixed, 2, rawPub.length); - String publicKeyBase58 = "z" + Base58.encode(prefixed); // multibase ‘z’ + Base58 - String privateKeyBase58 = Base58.encode(rawPriv); // 비공개키는 접두어 없이 raw 만 + String publicKeyBase58 = "z" + Base58.encode(prefixed); + String privateKeyBase58 = Base58.encode(rawPriv); return new KeyMaterial( rawPub, @@ -38,6 +36,4 @@ public static KeyMaterial generate() throws Exception { (EdECPublicKey) kp.getPublic(), (EdECPrivateKey) kp.getPrivate()); } - - /** 결과 보관용 record (Java 16+ 기능) */ } diff --git a/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java b/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java index 5c30498..6ae72b9 100644 --- a/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java +++ b/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java @@ -7,23 +7,13 @@ public class PeerDidUtil { - /** - * did:peer:2 DID를 생성합니다. - * - * @param publicKeyBase58 z6... 형식의 공개키 (인증 및 키교환 동일 사용) - * @param routingKey z6... 형식의 라우팅 키 (1개만 사용, 없으면 null 또는 빈 문자열) - * @param serviceEndpoint DIDComm 메시지를 받을 서비스 엔드포인트 - * @return did:peer:2 DID 문자열 - */ public static String createPeerDid2( String publicKeyBase58, String routingKey, String serviceEndpoint) { - // enc1: 인증용 키 + String enc1 = "V" + publicKeyBase58; - // enc2: 키 교환용 키 (현재는 동일 키 사용) String enc2 = "E" + publicKeyBase58; - // enc3: 서비스 JSON → base64url 인코딩 JSONObject service = new JSONObject(); service.put("id", "#didcomm-0"); service.put("type", "did-communication"); @@ -45,7 +35,6 @@ public static String createPeerDid2( .encodeToString( service.toString().getBytes(StandardCharsets.UTF_8)); - // 최종 DID 조합 return "did:peer:2." + enc1 + "." + enc2 + "." + enc3; } } diff --git a/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java b/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java index 489ea46..9dc49f2 100644 --- a/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java +++ b/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java @@ -24,7 +24,6 @@ public static void isValidPeerDid2(String did) { throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); } - // --- enc1 --- String enc1 = parts[0]; if (!enc1.startsWith("V") || !enc1.substring(1).startsWith("z")) { log.error("enc1 (V 접두사)가 올바르지 않습니다."); @@ -32,7 +31,6 @@ public static void isValidPeerDid2(String did) { } Base58.decode(enc1.substring(2)); // 'Vz6...' - // --- enc2 --- String enc2 = parts[1]; if (!enc2.startsWith("E") || !enc2.substring(1).startsWith("z")) { log.error("enc2 (E 접두사)가 올바르지 않습니다."); @@ -40,7 +38,6 @@ public static void isValidPeerDid2(String did) { } Base58.decode(enc2.substring(2)); // 'Ez6...' - // --- enc3 --- String enc3 = parts[2]; if (!enc3.startsWith("S")) { log.error("enc3 (S 접두사)가 없습니다."); @@ -65,7 +62,7 @@ public static void isValidPeerDid2(String did) { log.info("peer did check completed"); } catch (CommonException e) { - log.error("예외 발생: {}", e.getMessage()); + log.error("exception: {}", e.getMessage()); throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); } } From e1b075b4514b3413ee4d79a1fe50bcd6380493b8 Mon Sep 17 00:00:00 2001 From: willjsw Date: Fri, 30 May 2025 17:19:22 +0900 Subject: [PATCH 4/8] =?UTF-8?q?KW-536/refactor:=20keypair=20=EC=BA=90?= =?UTF-8?q?=EC=B9=98=20=EC=98=A4=EB=A5=98=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?exception=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/doubleo/didagent/dto/request/.gitkeep | 0 .../exception/errorcode/DIDErrorCode.java | 5 +++-- .../global/util/Ed25519KeyGenerator.java | 2 +- .../didagent/global/util/PeerDidValidator.java | 18 +++++++++--------- .../doubleo/didagent/service/DidService.java | 3 ++- 5 files changed, 15 insertions(+), 13 deletions(-) delete mode 100644 src/main/java/com/doubleo/didagent/dto/request/.gitkeep diff --git a/src/main/java/com/doubleo/didagent/dto/request/.gitkeep b/src/main/java/com/doubleo/didagent/dto/request/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java b/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java index df4384e..7c3c156 100644 --- a/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java +++ b/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java @@ -6,8 +6,9 @@ @Getter @AllArgsConstructor -public enum DIDErrorCode implements BaseErrorCode { - MALFORMED_PEER_DID(HttpStatus.NOT_FOUND, "잘못된 형식의 DID 입니다."), +public enum DidErrorCode implements BaseErrorCode { + MALFORMED_PEER_DID(HttpStatus.BAD_REQUEST, "잘못된 형식의 DID 입니다."), + KEY_GENERATION_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "keypair 생성에 실패했습니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java index 6f5b861..5bb919b 100644 --- a/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java +++ b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java @@ -8,7 +8,7 @@ import org.bitcoinj.core.Base58; public class Ed25519KeyGenerator { - /** JDK 17 Ed25519 키쌍을 생성해 raw + Base58 형식으로 리턴 */ + public static KeyMaterial generate() throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519"); diff --git a/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java b/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java index 9dc49f2..c11ba54 100644 --- a/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java +++ b/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java @@ -1,7 +1,7 @@ package com.doubleo.didagent.global.util; import com.doubleo.didagent.global.exception.CommonException; -import com.doubleo.didagent.global.exception.errorcode.DIDErrorCode; +import com.doubleo.didagent.global.exception.errorcode.DidErrorCode; import java.nio.charset.StandardCharsets; import java.util.Base64; import lombok.extern.slf4j.Slf4j; @@ -15,33 +15,33 @@ public static void isValidPeerDid2(String did) { try { if (!did.startsWith("did:peer:2.")) { log.error("did:peer:2 형식이 아닙니다."); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } String[] parts = did.substring("did:peer:2.".length()).split("\\."); if (parts.length != 3) { log.error("DID는 enc1, enc2, enc3 세 부분으로 구성되어야 합니다."); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } String enc1 = parts[0]; if (!enc1.startsWith("V") || !enc1.substring(1).startsWith("z")) { log.error("enc1 (V 접두사)가 올바르지 않습니다."); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } Base58.decode(enc1.substring(2)); // 'Vz6...' String enc2 = parts[1]; if (!enc2.startsWith("E") || !enc2.substring(1).startsWith("z")) { log.error("enc2 (E 접두사)가 올바르지 않습니다."); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } Base58.decode(enc2.substring(2)); // 'Ez6...' String enc3 = parts[2]; if (!enc3.startsWith("S")) { log.error("enc3 (S 접두사)가 없습니다."); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } String serviceBase64 = enc3.substring(1); @@ -51,19 +51,19 @@ public static void isValidPeerDid2(String did) { if (!service.has("id") || !service.has("type") || !service.has("serviceEndpoint")) { log.error("service JSON에 필수 필드가 없습니다."); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } if (!service.has("recipientKeys")) { log.error("recipientKeys가 없습니다."); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } log.info("peer did check completed"); } catch (CommonException e) { log.error("exception: {}", e.getMessage()); - throw new CommonException(DIDErrorCode.MALFORMED_PEER_DID); + throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); } } } diff --git a/src/main/java/com/doubleo/didagent/service/DidService.java b/src/main/java/com/doubleo/didagent/service/DidService.java index efa2897..6fa9afd 100644 --- a/src/main/java/com/doubleo/didagent/service/DidService.java +++ b/src/main/java/com/doubleo/didagent/service/DidService.java @@ -3,6 +3,7 @@ import com.doubleo.didagent.dto.request.DidCreateRequest; import com.doubleo.didagent.dto.response.DidCreateResponse; import com.doubleo.didagent.global.exception.CommonException; +import com.doubleo.didagent.global.exception.errorcode.DidErrorCode; import com.doubleo.didagent.global.util.Ed25519KeyGenerator; import com.doubleo.didagent.global.util.KeyMaterial; import com.doubleo.didagent.global.util.PeerDidUtil; @@ -28,7 +29,7 @@ private KeyMaterial getKeyMaterial() throws CommonException { try { return Ed25519KeyGenerator.generate(); } catch (Exception e) { - throw new RuntimeException(e); + throw new CommonException(DidErrorCode.KEY_GENERATION_FAILED); } } } From 83e9cc5404218c437b1ec90789271be5dabe95c8 Mon Sep 17 00:00:00 2001 From: willjsw Date: Fri, 30 May 2025 17:25:57 +0900 Subject: [PATCH 5/8] =?UTF-8?q?KW-536/refactor:=20controller=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20x=20exception=20throws=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/doubleo/didagent/controller/DidController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/doubleo/didagent/controller/DidController.java b/src/main/java/com/doubleo/didagent/controller/DidController.java index 6d5c4ca..73384f5 100644 --- a/src/main/java/com/doubleo/didagent/controller/DidController.java +++ b/src/main/java/com/doubleo/didagent/controller/DidController.java @@ -18,8 +18,7 @@ public class DidController { private final DidService didService; @PostMapping - public DidCreateResponse peer2DidCreate(@Valid @RequestBody DidCreateRequest request) - throws Exception { + public DidCreateResponse peer2DidCreate(@Valid @RequestBody DidCreateRequest request) { return didService.createPeer2Did(request); } } From abd81ebb2271a9281e83252d7732bf56832942e4 Mon Sep 17 00:00:00 2001 From: willjsw Date: Fri, 30 May 2025 17:27:34 +0900 Subject: [PATCH 6/8] =?UTF-8?q?KW-536/refactor:=20test=20application=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doubleo/didagent/DidAgentApplicationTests.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/java/com/doubleo/didagent/DidAgentApplicationTests.java diff --git a/src/test/java/com/doubleo/didagent/DidAgentApplicationTests.java b/src/test/java/com/doubleo/didagent/DidAgentApplicationTests.java new file mode 100644 index 0000000..89ae8b0 --- /dev/null +++ b/src/test/java/com/doubleo/didagent/DidAgentApplicationTests.java @@ -0,0 +1,11 @@ +package com.doubleo.didagent; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class DidAgentApplicationTests { + + @Test + void contextLoads() {} +} From b34317ff5e6d3b9ede51de640c86da10442351bf Mon Sep 17 00:00:00 2001 From: willjsw Date: Wed, 4 Jun 2025 15:24:11 +0900 Subject: [PATCH 7/8] =?UTF-8?q?KW-536/refactor:=20sign=20key=20/agreement?= =?UTF-8?q?=20key=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20x255199=20=ED=82=A4?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doubleo/didagent/DidAgentApplication.java | 2 + .../doubleo/didagent/agent/AcapyAgent.java | 3 ++ .../dto/request/DidCreateRequest.java | 5 +- .../dto/response/DidCreateResponse.java | 6 ++- .../global/util/Ed25519KeyGenerator.java | 35 +++++++++++- .../didagent/global/util/KeyMaterial.java | 20 ++++--- .../didagent/global/util/PeerDidUtil.java | 54 ++++++++++++------- .../doubleo/didagent/service/DidService.java | 16 ++++-- src/main/resources/application.yml | 2 +- 9 files changed, 107 insertions(+), 36 deletions(-) create mode 100644 src/main/java/com/doubleo/didagent/agent/AcapyAgent.java diff --git a/src/main/java/com/doubleo/didagent/DidAgentApplication.java b/src/main/java/com/doubleo/didagent/DidAgentApplication.java index cec8ecb..3530511 100644 --- a/src/main/java/com/doubleo/didagent/DidAgentApplication.java +++ b/src/main/java/com/doubleo/didagent/DidAgentApplication.java @@ -1,5 +1,6 @@ package com.doubleo.didagent; +import java.security.Security; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -8,5 +9,6 @@ public class DidAgentApplication { public static void main(String[] args) { SpringApplication.run(DidAgentApplication.class, args); + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); } } diff --git a/src/main/java/com/doubleo/didagent/agent/AcapyAgent.java b/src/main/java/com/doubleo/didagent/agent/AcapyAgent.java new file mode 100644 index 0000000..01205a2 --- /dev/null +++ b/src/main/java/com/doubleo/didagent/agent/AcapyAgent.java @@ -0,0 +1,3 @@ +package com.doubleo.didagent.agent; + +public class AcapyAgent {} diff --git a/src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java b/src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java index 65fce1b..a947a8b 100644 --- a/src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java +++ b/src/main/java/com/doubleo/didagent/dto/request/DidCreateRequest.java @@ -1,5 +1,8 @@ package com.doubleo.didagent.dto.request; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.util.List; -public record DidCreateRequest(@NotBlank String routingKey, @NotBlank String serviceEndpoint) {} +public record DidCreateRequest( + @NotNull List routingKeys, @NotBlank String serviceEndpoint) {} diff --git a/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java b/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java index 83de6fe..1f9e80e 100644 --- a/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java +++ b/src/main/java/com/doubleo/didagent/dto/response/DidCreateResponse.java @@ -3,4 +3,8 @@ import jakarta.validation.constraints.NotBlank; public record DidCreateResponse( - @NotBlank String peerDid2, @NotBlank String publicKey, @NotBlank String privateKey) {} + @NotBlank String peerDid2, + @NotBlank String signingKeyMb58, + @NotBlank String signingPrivBase58, + @NotBlank String agreementKeyMb58, + @NotBlank String x25519PrivateMb58) {} diff --git a/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java index 5bb919b..31737e2 100644 --- a/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java +++ b/src/main/java/com/doubleo/didagent/global/util/Ed25519KeyGenerator.java @@ -6,6 +6,8 @@ import java.security.interfaces.EdECPublicKey; import java.util.Arrays; import org.bitcoinj.core.Base58; +import org.bouncycastle.jcajce.interfaces.XDHPrivateKey; +import org.bouncycastle.jcajce.interfaces.XDHPublicKey; public class Ed25519KeyGenerator { @@ -28,12 +30,43 @@ public static KeyMaterial generate() throws Exception { String publicKeyBase58 = "z" + Base58.encode(prefixed); String privateKeyBase58 = Base58.encode(rawPriv); + KeyPairGenerator xKpg = KeyPairGenerator.getInstance("X25519", "BC"); + KeyPair xKp = xKpg.generateKeyPair(); + + byte[] xPubSpki = xKp.getPublic().getEncoded(); + byte[] xRawPub = Arrays.copyOfRange(xPubSpki, xPubSpki.length - 32, xPubSpki.length); + + /* multicodec: 0xEC 0x01 = X25519 public key */ + byte[] xPrefixed = new byte[xRawPub.length + 2]; + xPrefixed[0] = (byte) 0xEC; + xPrefixed[1] = 0x01; + System.arraycopy(xRawPub, 0, xPrefixed, 2, xRawPub.length); + + String agreementKeyMb58 = "z" + Base58.encode(xPrefixed); + byte[] xPrivSpki = xKp.getPrivate().getEncoded(); + // PKCS#8 또는 SPKI 형식으로 인코딩된 값이 넘어오므로, 끝 32바이트가 실제 raw private + byte[] xRawPriv = Arrays.copyOfRange(xPrivSpki, xPrivSpki.length - 32, xPrivSpki.length); + + // multicodec 형식 붙이기 (0xEC 0x01 = X25519 private multicodec) + byte[] xPrivPrefixed = new byte[xRawPriv.length + 2]; + xPrivPrefixed[0] = (byte) 0xEC; + xPrivPrefixed[1] = 0x01; + System.arraycopy(xRawPriv, 0, xPrivPrefixed, 2, xRawPriv.length); + + // 최종적으로 multibase58 (z-prefixed) 문자열 + String x25519PrivateMb58 = "z" + Base58.encode(xPrivPrefixed); + + /* 반환 객체에 추가로 포함 */ return new KeyMaterial( rawPub, rawPriv, publicKeyBase58, privateKeyBase58, + agreementKeyMb58, // NEW: X25519 public multibase (EdECPublicKey) kp.getPublic(), - (EdECPrivateKey) kp.getPrivate()); + (EdECPrivateKey) kp.getPrivate(), + (XDHPublicKey) xKp.getPublic(), + (XDHPrivateKey) xKp.getPrivate(), + x25519PrivateMb58); } } diff --git a/src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java b/src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java index abdc939..6253541 100644 --- a/src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java +++ b/src/main/java/com/doubleo/didagent/global/util/KeyMaterial.java @@ -1,14 +1,18 @@ package com.doubleo.didagent.global.util; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import java.security.interfaces.EdECPrivateKey; import java.security.interfaces.EdECPublicKey; +import org.bouncycastle.jcajce.interfaces.XDHPrivateKey; +import org.bouncycastle.jcajce.interfaces.XDHPublicKey; public record KeyMaterial( - @NotNull byte[] rawPub, - @NotNull byte[] rawPriv, - @NotBlank String pub58, - @NotBlank String priv58, - @NotNull EdECPublicKey jdkPub, - @NotNull EdECPrivateKey jdkPriv) {} + byte[] rawEd25519Public, // 32-byte 원본 Ed25519 공개키 + byte[] rawEd25519Private, // 32-byte 원본 Ed25519 비밀키 + String signingKeyMb58, // 멀티코덱+멀티베이스(“z…”) Ed25519 공개키 + String signingPrivBase58, // Base58 인코딩된 Ed25519 비밀키(원본 32 바이트) + String agreementKeyMb58, // 멀티코덱+멀티베이스(“z…”) X25519 공개키 + EdECPublicKey signingPublic, // JCA Ed25519 PublicKey (서명용) + EdECPrivateKey signingPrivate, // JCA Ed25519 PrivateKey (서명용) + XDHPublicKey agreementPublic, // JCA X25519 PublicKey (암호화·키합의용) + XDHPrivateKey agreementPrivate, // JCA X25519 PrivateKey (암호화·키합의용) + String x25519PrivateMb58) {} diff --git a/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java b/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java index 6ae72b9..a8b32c4 100644 --- a/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java +++ b/src/main/java/com/doubleo/didagent/global/util/PeerDidUtil.java @@ -2,39 +2,53 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; +import java.util.List; +import org.bitcoinj.core.Base58; import org.json.JSONArray; import org.json.JSONObject; public class PeerDidUtil { public static String createPeerDid2( - String publicKeyBase58, String routingKey, String serviceEndpoint) { - - String enc1 = "V" + publicKeyBase58; - - String enc2 = "E" + publicKeyBase58; - - JSONObject service = new JSONObject(); - service.put("id", "#didcomm-0"); - service.put("type", "did-communication"); - service.put("priority", 0); - - JSONArray recipientKeys = new JSONArray().put("#key-1"); - service.put("recipientKeys", recipientKeys); - - if (routingKey != null && !routingKey.isBlank()) { - service.put("routingKeys", new JSONArray().put(routingKey)); + String signingKeyMb, // z6... (Ed25519) + String agreementKeyMb, // z6L... (X25519) + List routingKeys, + String serviceEndpoint) { + + String enc1 = "V" + signingKeyMb; // verification key + String enc2 = "E" + agreementKeyMb; // key-agreement key + List routingKeysDidUrl = PeerDidUtil.convertRoutingKeys(routingKeys); + JSONObject svc = new JSONObject(); + svc.put("id", "#didcomm-0"); + svc.put("t", "did-communication"); + svc.put("p", 0); + svc.put("recipientKeys", new JSONArray().put("#key-1")); + if (routingKeys != null && !routingKeys.isEmpty()) { + svc.put("r", new JSONArray(routingKeysDidUrl)); // routingKeys → r } - - service.put("serviceEndpoint", serviceEndpoint); + svc.put("s", serviceEndpoint); // serviceEndpoint → s String enc3 = "S" + Base64.getUrlEncoder() .withoutPadding() - .encodeToString( - service.toString().getBytes(StandardCharsets.UTF_8)); + .encodeToString(svc.toString().getBytes(StandardCharsets.UTF_8)); return "did:peer:2." + enc1 + "." + enc2 + "." + enc3; } + + private static String rawVerkeyToDidKey(String verkeyBase58) { + byte[] raw = Base58.decode(verkeyBase58); // 32-byte 공개키 + byte[] prefixed = new byte[raw.length + 2]; + prefixed[0] = (byte) 0xED; // multicodec: 0xED 0x01 = Ed25519 + prefixed[1] = 0x01; + System.arraycopy(raw, 0, prefixed, 2, raw.length); + + String multibase = "z" + Base58.encode(prefixed); + return "did:key:" + multibase + "#" + multibase; + } + + private static List convertRoutingKeys(List rawKeys) { + return rawKeys.stream().map(PeerDidUtil::rawVerkeyToDidKey).toList(); + } } diff --git a/src/main/java/com/doubleo/didagent/service/DidService.java b/src/main/java/com/doubleo/didagent/service/DidService.java index 6fa9afd..3caa676 100644 --- a/src/main/java/com/doubleo/didagent/service/DidService.java +++ b/src/main/java/com/doubleo/didagent/service/DidService.java @@ -7,7 +7,6 @@ import com.doubleo.didagent.global.util.Ed25519KeyGenerator; import com.doubleo.didagent.global.util.KeyMaterial; import com.doubleo.didagent.global.util.PeerDidUtil; -import com.doubleo.didagent.global.util.PeerDidValidator; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -19,14 +18,23 @@ public DidCreateResponse createPeer2Did(DidCreateRequest request) { KeyMaterial key = getKeyMaterial(); String peer2Did = PeerDidUtil.createPeerDid2( - key.pub58(), request.routingKey(), request.serviceEndpoint()); - PeerDidValidator.isValidPeerDid2(peer2Did); + key.signingKeyMb58(), // Ed25519 서명 키 (V) + key.agreementKeyMb58(), // X25519 암호화 키 (E) + request.routingKeys(), + request.serviceEndpoint()); log.info("Created PeerDid2: {}", peer2Did); - return new DidCreateResponse(peer2Did, key.pub58(), key.priv58()); + System.out.println(peer2Did); + return new DidCreateResponse( + peer2Did, + key.signingKeyMb58(), + key.signingPrivBase58(), + key.agreementKeyMb58(), + key.x25519PrivateMb58()); } private KeyMaterial getKeyMaterial() throws CommonException { try { + System.out.println(Ed25519KeyGenerator.generate()); return Ed25519KeyGenerator.generate(); } catch (Exception e) { throw new CommonException(DidErrorCode.KEY_GENERATION_FAILED); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bd4a304..62328f4 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,6 @@ spring: application: - name: did-service + name: did-agent server: port: 8080 management: From 1fd883dad78ed3364897f74a4709e6023bb184ec Mon Sep 17 00:00:00 2001 From: willjsw Date: Wed, 4 Jun 2025 15:30:12 +0900 Subject: [PATCH 8/8] =?UTF-8?q?KW-536/refactor:=20=EB=AF=B8=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20validatior=20=EC=82=AD=EC=A0=9C,=20DidErrorCode=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{DIDErrorCode.java => DidErrorCode.java} | 0 .../global/util/PeerDidValidator.java | 69 ------------------- .../doubleo/didagent/service/DidService.java | 1 - 3 files changed, 70 deletions(-) rename src/main/java/com/doubleo/didagent/global/exception/errorcode/{DIDErrorCode.java => DidErrorCode.java} (100%) delete mode 100644 src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java diff --git a/src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java b/src/main/java/com/doubleo/didagent/global/exception/errorcode/DidErrorCode.java similarity index 100% rename from src/main/java/com/doubleo/didagent/global/exception/errorcode/DIDErrorCode.java rename to src/main/java/com/doubleo/didagent/global/exception/errorcode/DidErrorCode.java diff --git a/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java b/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java deleted file mode 100644 index c11ba54..0000000 --- a/src/main/java/com/doubleo/didagent/global/util/PeerDidValidator.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.doubleo.didagent.global.util; - -import com.doubleo.didagent.global.exception.CommonException; -import com.doubleo.didagent.global.exception.errorcode.DidErrorCode; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.Base58; -import org.json.JSONObject; - -@Slf4j -public class PeerDidValidator { - - public static void isValidPeerDid2(String did) { - try { - if (!did.startsWith("did:peer:2.")) { - log.error("did:peer:2 형식이 아닙니다."); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - - String[] parts = did.substring("did:peer:2.".length()).split("\\."); - if (parts.length != 3) { - log.error("DID는 enc1, enc2, enc3 세 부분으로 구성되어야 합니다."); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - - String enc1 = parts[0]; - if (!enc1.startsWith("V") || !enc1.substring(1).startsWith("z")) { - log.error("enc1 (V 접두사)가 올바르지 않습니다."); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - Base58.decode(enc1.substring(2)); // 'Vz6...' - - String enc2 = parts[1]; - if (!enc2.startsWith("E") || !enc2.substring(1).startsWith("z")) { - log.error("enc2 (E 접두사)가 올바르지 않습니다."); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - Base58.decode(enc2.substring(2)); // 'Ez6...' - - String enc3 = parts[2]; - if (!enc3.startsWith("S")) { - log.error("enc3 (S 접두사)가 없습니다."); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - - String serviceBase64 = enc3.substring(1); - byte[] serviceBytes = Base64.getUrlDecoder().decode(serviceBase64); - String serviceJsonString = new String(serviceBytes, StandardCharsets.UTF_8); - JSONObject service = new JSONObject(serviceJsonString); - - if (!service.has("id") || !service.has("type") || !service.has("serviceEndpoint")) { - log.error("service JSON에 필수 필드가 없습니다."); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - - if (!service.has("recipientKeys")) { - log.error("recipientKeys가 없습니다."); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - - log.info("peer did check completed"); - - } catch (CommonException e) { - log.error("exception: {}", e.getMessage()); - throw new CommonException(DidErrorCode.MALFORMED_PEER_DID); - } - } -} diff --git a/src/main/java/com/doubleo/didagent/service/DidService.java b/src/main/java/com/doubleo/didagent/service/DidService.java index 3caa676..9f462e5 100644 --- a/src/main/java/com/doubleo/didagent/service/DidService.java +++ b/src/main/java/com/doubleo/didagent/service/DidService.java @@ -23,7 +23,6 @@ public DidCreateResponse createPeer2Did(DidCreateRequest request) { request.routingKeys(), request.serviceEndpoint()); log.info("Created PeerDid2: {}", peer2Did); - System.out.println(peer2Did); return new DidCreateResponse( peer2Did, key.signingKeyMb58(),