implementation "com.nimbusds:nimbus-jose-jwt:9.37.3"
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;

import java.nio.charset.StandardCharsets;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

public class RSAUtil {
    
    // RSA 키 생성 (개인키, 공개키)
    public static RSAKey generateRSAKey(String keyId) throws JOSEException {
        return new RSAKeyGenerator(2048).keyID(keyId).generate();
    }

    // 공개키로 암호화
    public static String encrypt(String message, RSAPublicKey publicKey) throws JOSEException {
        JWEObject encryptObject = new JWEObject(
                new JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM),
                new Payload(message.getBytes(StandardCharsets.UTF_8))
        );
        encryptObject.encrypt(new RSAEncrypter(publicKey));
        return encryptObject.serialize();
    }

    // 개인키로 서명
    public static String sign(String payload, RSAPrivateKey privateKey) throws JOSEException {
        JWSObject signObject = new JWSObject(
                new JWSHeader(JWSAlgorithm.RS256),
                new Payload(payload)
        );
        signObject.sign(new RSASSASigner(privateKey));
        return signObject.serialize();
    }

    // 공개키로 서명검증
    public static String verifySignature(String signedToken, RSAPublicKey publicKey) throws Exception {
        JWSObject signObject = JWSObject.parse(signedToken);
        if (signObject.verify(new RSASSAVerifier(publicKey))) {
            return signObject.getPayload().toString();
        }else{
            throw new RuntimeException("공개키 서명 검증 실패");
        } 
    }

    // 개인키로 복호화
    public static String decrypt(String encryptedToken, RSAPrivateKey privateKey) throws Exception {
        JWEObject encryptObject = JWEObject.parse(encryptedToken);
        encryptObject.decrypt(new RSADecrypter(privateKey));
        return encryptObject.getPayload().toString();
    }

}

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.RSAKey;

public class RSADemo {

    public static void main(String[] args) throws Exception {
        String msg = "나는 오늘 백운포에 송원 왕갈비를 먹으러 간다 비밀이다!!";

        // 0. A(송신자), B(수신자) RSA 키 생성
        RSAKey aKey = RSAUtil.generateRSAKey("A");
        RSAKey bKey = RSAUtil.generateRSAKey("B");
        RSAKey cKey = RSAUtil.generateRSAKey("C");

        // ===== 송신 과정 =====
        // 1. 수신자(B)의 공개키로 암호화
        String encrypted = RSAUtil.encrypt(msg, bKey.toRSAPublicKey());
        System.out.println("1. 암호화: " + encrypted.substring(0, 50) + "...");

        // 2. 송신자(A)의 개인키로 서명
        String signed = RSAUtil.sign(encrypted, aKey.toRSAPrivateKey());
        System.out.println("2. 서명: " + signed.substring(0, 50) + "...");

        System.out.println();

        // ===== 수신 과정 =====
        // 3. 송신자(A)의 공개키로 서명 검증
        String verify = RSAUtil.verifySignature(signed, aKey.toRSAPublicKey());
        System.out.println("3. 서명 검증: " + verify);

        // 4. 수신자(B)의 개인키로 복호화
        String decrypted = RSAUtil.decrypt(verify, bKey.toRSAPrivateKey());
        System.out.println("4. 복호화: " + decrypted);

    }
}