From ad5a5cbcfcd96426db8ab597413cf3199335a6a2 Mon Sep 17 00:00:00 2001 From: jaewohong Date: Tue, 25 Nov 2025 16:19:31 +0900 Subject: [PATCH] =?UTF-8?q?ECDHESA256=20=EC=95=94=ED=98=B8=ED=99=94=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 --- .../exchange/crypto/ECDHESA256Cipher.java | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/main/java/com/kjbank/encrypt/exchange/crypto/ECDHESA256Cipher.java 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..a382e17 --- /dev/null +++ b/src/main/java/com/kjbank/encrypt/exchange/crypto/ECDHESA256Cipher.java @@ -0,0 +1,112 @@ +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.interfaces.ECPublicKey; +import java.security.KeyStore; +import java.security.PrivateKey; + +public class ECDHESA256Cipher { + + private ECKey myECKey; + private ECKey receiverPublicJWK; + + // 생성자: 수신자 키 쌍을 준비 + public ECDHESA256Cipher() throws Exception { + this.myECKey = new ECKeyGenerator(Curve.P_256) + .keyUse(KeyUse.ENCRYPTION) + .keyID("receiver-key") + .generate(); + + this.receiverPublicJWK = myECKey.toPublicJWK(); + } + + + //생성자: 내 키쌍 로드용 생성자 (복호화할 때 필요) + public ECDHESA256Cipher(String myKeystorePath, String storePass, String keyAlias, String keyPass) throws Exception { + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(new FileInputStream(myKeystorePath), storePass.toCharArray()); + + PrivateKey myPrivateKey = (PrivateKey) ks.getKey(keyAlias, keyPass.toCharArray()); + X509Certificate myCert = (X509Certificate) ks.getCertificate(keyAlias); + ECPublicKey myPublicKey = (ECPublicKey) myCert.getPublicKey(); + + this.myECKey = new ECKey.Builder(Curve.P_256, myPublicKey) + .privateKey(myPrivateKey) + .keyUse(KeyUse.ENCRYPTION) + //.keyID("my-key") + .keyID(myCert.getSerialNumber().toString()) // 인증서 시리얼번호를 keyID로 사용 + .build(); + } + + // 생성자: 상대방 인증서에서 공개키 로드 + public ECDHESA256Cipher(String certPath) throws Exception { + // 1. 인증서 로드 + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + try (FileInputStream fis = new FileInputStream(certPath)) { + X509Certificate cert = (X509Certificate) cf.generateCertificate(fis); + + // 2. 공개키 추출 + ECPublicKey publicKey = (ECPublicKey) cert.getPublicKey(); + + // 3. Nimbus ECKey로 변환 + this.receiverPublicJWK = new ECKey.Builder(Curve.P_256, publicKey) + .keyUse(KeyUse.ENCRYPTION) + //.keyID("receiver-key") + .keyID(cert.getSerialNumber().toString()) // 인증서 시리얼번호를 keyID로 사용 + .build(); + } + } + + // 암호화 메서드 + public String encrypt(String jsonPayload) throws Exception { + if (receiverPublicJWK == null) { + throw new IllegalStateException("상대방 공개키가 초기화되지 않았습니다."); + } + + JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES_A256KW, EncryptionMethod.A256GCM) + .contentType("application/json") + .keyID(receiverPublicJWK.getKeyID()) + .build(); + + JWEObject jweObject = new JWEObject(header, new Payload(jsonPayload)); + + JWEEncrypter encrypter = new ECDHEncrypter(receiverPublicJWK); + jweObject.encrypt(encrypter); + + return jweObject.serialize(); + } + + // 복호화 메서드(상대방이 나한테 보낸것) + public String decrypt(String jweString) throws Exception { + if (myECKey == null) { + throw new IllegalStateException("내 개인키가 초기화되지 않았습니다."); + } + JWEObject decryptedJWE = JWEObject.parse(jweString); + JWEDecrypter decrypter = new ECDHDecrypter(myECKey); + decryptedJWE.decrypt(decrypter); + + 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(); + } +}