본문 바로가기

Java

공인인증서 개인키에서 신원확인 값 추출하기

반응형

앞장의 "공인인증서 개인키를 PrivateKey 로 추출하기"를 통해서 암호화 되어 있는 개인키 정보를 복호화해서 PrivateKey 객체로 변환하는 방법을 알아보았다.

이번에는 복호화된 개인키 정보에서 신원확인 값 추출하기를 알아보자.

복호화된 개인키 정보의 구조를 먼저 알아보기 위해서 검색한 결과 아래의 링크를 통해서 어떤 구조인지 알 수 있었다.

공인인증서내 신원확인 기술규격 v1.10 (https://www.rootca.or.kr/kcac/down/TechSpec/1.5-Subscriber%20Identification%20Based%20on%20Virtual%20ID.pdf)

문서의 정보 중 encryptedData는 앞장의 개인키를 얻기 위한 소스의 내용 중 decryptedKey 에 해당한다고 보면 되겠다.

그렇다면 decryptedKey에는 순차적으로 version, privateKeyAlgorithm, privateKey, attributes 순으로 데이터가 저장이 되어 있을 것 같다.

역시나 ASN.1 형태로 이 내용을 확인한 결과 ASN1Integer, DLSequence, DEROctetString, DLTaggedObject 형태로 변환이 가능하였다.

문서 내용으로 보면 맨 마지막의 DLTaggedObject에 우리가 원하는 신원확인 값이 있을 것으로 생각이 된다.

DLTaggedObject를 다시 풀어보면 ASN1ObjectIdentifier과 DERBitString으로 되어 있었다.

ASN1ObjectIdentifier을 보니 1.2.410.200004.10.1.1.3 이란 값이 있었고 검색 결과 신원확인 값(Random number)에 대한 내용이 맞았다.

http://oid-info.com/get/1.2.410.200004.10.1.1.3

그렇다면 DERBitString의 내용을 Base64 인코딩하여 문자열로 얻어 국세청으로 전송할 randomEnc 항목에 넣게 되면 된다.

이 내용을 코드로 변경하면 다음과 같다.

/**
 * 복호화된 개인키 byte[]로 신원확인용 RValue를 Base64 인코딩해서 반환.
 * @param keyDER
 * @param passwd
 * @return
 */
public static String getRValue(byte[] keyDER, String passwd) {
    
    if (null == keyDER) {
        return null;
    }
    
    if (null == passwd || "".equals(passwd)) {
        return null;
    }
    
    try {
        byte[] decryptedKey = getDecryptedKey(keyDER, passwd);
        
        try (ByteArrayInputStream bIn2 = new ByteArrayInputStream(decryptedKey);
                ASN1InputStream aIn2 = new ASN1InputStream(bIn2);) {
            
            ASN1Object asn1Object = aIn2.readObject();
            DLSequence seq = (DLSequence)asn1Object.toASN1Object();

            int i = 0;
            while (i < seq.size()) {
                
                if(seq.getObjectAt(i) instanceof DLTaggedObject) {
                    DLTaggedObject dlTaggedObject = (DLTaggedObject)seq.getObjectAt(i);
                    
                    if (dlTaggedObject.getTagNo() == 0) {
                        DLSequence seq2 = (DLSequence)dlTaggedObject.getObject();
                        
                        int j = 0;
                        while (j < seq2.size()) {
                            
                            if(seq2.getObjectAt(j) instanceof ASN1ObjectIdentifier) {
                                ASN1ObjectIdentifier idRandomNumOID = (ASN1ObjectIdentifier)seq2.getObjectAt(j);
                                
                                if ("1.2.410.200004.10.1.1.3".equals(idRandomNumOID.toString())) {
                                    DLSet dlSet = (DLSet) seq2.getObjectAt(j + 1);
                                    
                                    DERBitString DERBitString = (DERBitString)dlSet.getObjectAt(0);
                                    
                                    return new String(Base64.encode(DERBitString.getOctets()));
                                }
                                
                            }
                            
                            j++;
                        }
                        
                    }
                    
                }
                
                i++;
        }
            
        }
    } catch (Exception e) {
        logger.error("getRValue 오류", e);
    }
    return null;
}

getDecryptedKey 메소드는 앞장의 코드를 리팩토링하여 개인키를 복호화여 byte[]로 얻는 것과 PrivateKey 객체로 변환하는 것을 분리하기 위해 만든 메소드이다.

그래야 복호화된 개인키 정보를 통해서 중복되는 코드 없이 필요에 따라 PrivateKey 객체를 얻거나 신원확인 값을 얻을 수 있기 때문이다.

반응형