SecuKit PQC

NIST 표준 기반 양자내성암호(PQC) 알고리즘

ML-KEM이란?

양자컴퓨터 환경에서도 안전하게 사용할 수 있도록 설계된 키 캡슐화 매커니즘입니다.
두 시스템이 같은 비밀값을 안전하게 만들고, 이 값을 이후 데이터 암호화에 활용합니다.

i 테스트 가이드

서버에서 키쌍을 생성한 뒤, 공개키로 캡슐화하고 개인키로 디캡슐화합니다.
캡슐화로 만든 공유 비밀값과 디캡슐화로 복원한 값이 일치하면 테스트 성공입니다.

  1. 1. 키 쌍 생성 — 서버에서 키쌍을 생성합니다.
  2. 2. 공유키 캡슐화 — 공개키로 캡슐화를 수행합니다.
  3. 3. 공유키 디캡슐화 — 개인키로 디캡슐화를 수행합니다.

ML-KEM 테스트

결과 로그 ML-KEM

        

CipherUtil

PQC(ML-KEM) 암복호 연산을 위한 CipherUtil 인스턴스를 생성하고 ML-KEM 키쌍을 생성합니다.

Request
CipherUtil Request
Name Type Description
algorithm String PQC 알고리즘명 (ML-KEM-512/768/1024)
Response
CipherUtil Response
Name Type Description
publicKey String 생성된 ML-KEM 공개키 (Base64)
Request

// ML-KEM 키쌍 생성 및 CipherUtil 인스턴스 생성
KeyPair keyPair = PQCKeyUtil.generatePQCKeyPair("ML-KEM-1024");
CipherUtil cipher = new CipherUtil("ML-KEM-1024");

result.put("algorithm", "ML-KEM-1024");
result.put("publicKey", Base64Util.encode(keyPair.getPublic().getEncoded()));
                        
Response

encryptMLKEM

수신자의 ML-KEM 공개키로 평문을 암호화합니다.

Request
encryptMLKEM Request
Name Type Description
publicKey PublicKey 수신자 ML-KEM 공개키
plaintext byte[] 암호화할 평문
Response
encryptMLKEM Response
Name Type Description
packet byte[] 암호 패킷 (Base64)
Request

KeyPair keyPair = PQCKeyUtil.generatePQCKeyPair("ML-KEM-1024");
CipherUtil cipher = new CipherUtil();

byte[] plaintext = "testDATA123!@#".getBytes();
byte[] packet = cipher.encryptMLKEM(keyPair.getPublic(), plaintext);
if (packet == null) {
    throw new Exception(cipher.getErrorMsg());
}
result.put("packet", Base64Util.encode(packet));
                        
Response

decryptMLKEM

수신자의 ML-KEM 개인키(PBES2 암호화본)로 암호 패킷을 복호화합니다.

Request
decryptMLKEM Request
Name Type Description
encryptedPrivateKey byte[] PBES2 암호화된 개인키
algorithm String ML-KEM 알고리즘명
password String 개인키 패스워드
packet byte[] 암호 패킷
Response
decryptMLKEM Response
Name Type Description
plaintext String 복호화된 평문
Request

KeyPair keyPair = PQCKeyUtil.generatePQCKeyPair("ML-KEM-1024");
byte[] encPriKey = KeyUtil.getPBES2EncryptedPrivateKey(keyPair.getPrivate(), "signgate1!");

CipherUtil cipher = new CipherUtil();
byte[] packet = cipher.encryptMLKEM(keyPair.getPublic(), "testDATA123!@#".getBytes());

byte[] decrypted = cipher.decryptMLKEM(encPriKey, "ML-KEM-1024", "signgate1!", packet);
if (decrypted == null) {
    throw new Exception(cipher.getErrorMsg());
}
result.put("plaintext", new String(decrypted));
                        
Response

wrapInit

수신자 공개키로 대칭키 래핑(wrap) 컨텍스트를 초기화합니다.

Request
wrapInit Request
Name Type Description
publicKey PublicKey 수신자 ML-KEM 공개키
Response
wrapInit Response
Name Type Description
wrapInit boolean 초기화 성공 여부
Request

KeyPair keyPair = PQCKeyUtil.generatePQCKeyPair("ML-KEM-1024");
CipherUtil cipher = new CipherUtil(keyPair.getPublic().getAlgorithm());

boolean init = cipher.wrapInit(keyPair.getPublic());
result.put("wrapInit", init);
                        
Response

wrapUpdate

대칭키(AES-256 + IV)를 ML-KEM 으로 래핑한 암호화 키를 생성합니다.

Request
wrapUpdate Request
Name Type Description
symmetricKey byte[] 래핑할 대칭키 (AES 32 + IV 16)
algorithm String 대칭키 알고리즘 ("AES")
Response
wrapUpdate Response
Name Type Description
wrappedKey byte[] 래핑된 암호화 키 (Base64)
Request

CipherUtil cipher = new CipherUtil(publicKey.getAlgorithm());
cipher.wrapInit(publicKey);

// AES-256 키(32) + IV(16) = 48 byte 대칭키
byte[] wrappedKey = cipher.wrapUpdate(symmetricKey, "AES");
cipher.wrapFinal();
result.put("wrappedKey", Base64Util.encode(wrappedKey));
                        
Response

wrapFinal

대칭키 래핑 연산을 종료하고 컨텍스트를 정리합니다.

Request
wrapFinal Request
Name Type Description
- - 입력 없음
Response
wrapFinal Response
Name Type Description
wrapFinal void 래핑 종료 결과
Request

cipher.wrapInit(publicKey);
byte[] wrappedKey = cipher.wrapUpdate(symmetricKey, "AES");
cipher.wrapFinal();   // 래핑 컨텍스트 정리
                        
Response

unwrapInit

수신자 개인키로 대칭키 언래핑(unwrap) 컨텍스트를 초기화합니다.

Request
unwrapInit Request
Name Type Description
privateKey PrivateKey 수신자 ML-KEM 개인키
Response
unwrapInit Response
Name Type Description
unwrapInit boolean 초기화 성공 여부
Request

KeyPair keyPair = PQCKeyUtil.generatePQCKeyPair("ML-KEM-1024");
CipherUtil cipher = new CipherUtil(keyPair.getPublic().getAlgorithm());

boolean init = cipher.unwrapInit(keyPair.getPrivate());
result.put("unwrapInit", init);
                        
Response

unwrapUpdate

랩핑된 암호화 키를 개인키로 복원하여 원본 대칭키를 추출합니다.

Request
unwrapUpdate Request
Name Type Description
wrappedKey byte[] 래핑된 암호화 키
algorithm String 대칭키 알고리즘 ("AES")
Response
unwrapUpdate Response
Name Type Description
unwrappedKey byte[] 복원된 대칭키 (Base64)
match boolean 원본 대칭키와 일치 여부
Request

CipherUtil dec = new CipherUtil(algorithm);
dec.unwrapInit(privateKey);

byte[] unwrappedKey = dec.unwrapUpdate(wrappedKey, "AES");
dec.unwrapFinal();
result.put("unwrappedKey", Base64Util.encode(unwrappedKey));
                        
Response

unwrapFinal

대칭키 언래핑을 종료하고, 복원한 대칭키로 AES 암복호 라운드트립을 검증합니다.

Request
unwrapFinal Request
Name Type Description
- - 입력 없음
Response
unwrapFinal Response
Name Type Description
aesRoundTrip String 복원 대칭키로 복호화한 평문
match boolean 원문 일치 여부
Request

dec.unwrapInit(privateKey);
byte[] unwrappedKey = dec.unwrapUpdate(wrappedKey, "AES");
dec.unwrapFinal();

// 복원한 대칭키(AES 256 + IV)로 평문 암복호 검증
byte[] aesKey = Arrays.copyOfRange(unwrappedKey, 0, 32);
byte[] iv     = Arrays.copyOfRange(unwrappedKey, 32, 48);

AESCipherUtil aes = new AESCipherUtil();
aes.decryptInit(aesKey, iv);
byte[] decrypted = aes.decryptUpdate(encrypted);
aes.decryptFinal();
result.put("aesRoundTrip", new String(decrypted));
                        
Response