오늘은 어디로 갈까...

PKCS #8 개인 키 정보 구문 표준에 관한 단상 본문

낙서

PKCS #8 개인 키 정보 구문 표준에 관한 단상

剛宇 2009. 12. 29. 18:00

1. 잡설
 서버와 클라이언트간의 데이터를 암호화하기 위해서 RSA와 AES를 사용하기도 했다. 문제는 클라어언트의 JAVA가 나이가 연로(年老)하셔서 RSAPrivateKey를 지원안하는줄 알고 한번 구현해보고자 하는 그릇된 욕망으로 인해 삽질을 시작하게되었다. 1.3에서는 있는거 같은데, STB(셋탑)의 JAVA께서는 지원을 하시는지 확실히는 몰겄다. 언제나 느끼는 것이지만, 만들기 전에 찾아보는 현명한 습관을 하루 빨리 체득해야하는데 말이다.. --; 단지 지적 욕구를 충족하고자 하시는분만 이 글을 읽으시고, 절대로 현실세계에서는 사용하지 말기 바란다.

2. RSA용 키 생성
 일단 RSA에 사용하기 위한 키를 생성해보자.

package kr.kangwoo.moon.sample;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import kr.kangwoo.util.ByteUtils;

public class KeyGen {

	public static void main(String[] args) throws Exception {
		
		// 1. 키 생성 완료
		KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
//		gen.initialize(1024); // 1024 bits
		KeyPair keyPair = gen.generateKeyPair();
		
		PublicKey pubKey = keyPair.getPublic();
		PrivateKey priKey = keyPair.getPrivate();
		
		byte[] pubBytes = pubKey.getEncoded();
		byte[] priBytes = priKey.getEncoded();
		
		// 2. 키 불러오기
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		
		PKCS8EncodedKeySpec priSpec = new PKCS8EncodedKeySpec(priBytes);
		PrivateKey privateKey = keyFactory.generatePrivate(priSpec);

		System.out.println(priKey);
		System.out.println(privateKey);
		System.out.println(priKey.equals(privateKey));
		
		X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubBytes);
		PublicKey publicKey = keyFactory.generatePublic(pubSpec);
		
		System.out.println(pubKey);
		System.out.println(publicKey);
		System.out.println(pubKey.equals(publicKey));
		
		
		System.out.println("개인키입니다.");
		System.out.println(ByteUtils.toHexString(privateKey.getEncoded()));
	}
}

  실행결과
Sun RSA private CRT key, 1024 bits
  modulus:          98235479183090963770432427642200442983675739444442006745888910614495825811982664163947878578914073870500014846784140598420160562292254019341975013655587919214510314839243283904038428619767073656329177318864029779895278607160852761668068560384471619957237410923582565792151121560119515816871893117811308979089
  public exponent:  65537
  private exponent: 95424982464164318408735053611818737525775743847171323579913328769092776032507444130876449121730133676301508234676167032006717758161793725366568706522148356314255952502618174670664289187298920132480956331892827405186415397044362320128949328957015105859759408000615566939338475899541162627898412351669762844673
  prime p:          12008250515849944108488102843499187655464462509731422296877150117470960033720378393817005998217639840722804588451011564705219732141220363017738196616705489
  prime q:          8180665372814122660173069738611390116430652686953417350545079644723331346304424811054335466600885913977520264222372188538563562437033369510447765531902401
  prime exponent p: 6589265682759291545683341539251381455754962857240359013081100333010218116982044460357464786424504691274753171641596012785588476849147301445655141778384161
  prime exponent q: 3658125630036325719502448719955832564080087700747010831668738332060697749893914483616252730277638015091096767677813133913837126520586842957004168892044673
  crt coefficient:  2931067481768796750197829654251952834275144311709208657122584273794219248528207319954346442077549609036355755736257063586611921256982012960072866836025831
Sun RSA private CRT key, 1024 bits
  modulus:          98235479183090963770432427642200442983675739444442006745888910614495825811982664163947878578914073870500014846784140598420160562292254019341975013655587919214510314839243283904038428619767073656329177318864029779895278607160852761668068560384471619957237410923582565792151121560119515816871893117811308979089
  public exponent:  65537
  private exponent: 95424982464164318408735053611818737525775743847171323579913328769092776032507444130876449121730133676301508234676167032006717758161793725366568706522148356314255952502618174670664289187298920132480956331892827405186415397044362320128949328957015105859759408000615566939338475899541162627898412351669762844673
  prime p:          12008250515849944108488102843499187655464462509731422296877150117470960033720378393817005998217639840722804588451011564705219732141220363017738196616705489
  prime q:          8180665372814122660173069738611390116430652686953417350545079644723331346304424811054335466600885913977520264222372188538563562437033369510447765531902401
  prime exponent p: 6589265682759291545683341539251381455754962857240359013081100333010218116982044460357464786424504691274753171641596012785588476849147301445655141778384161
  prime exponent q: 3658125630036325719502448719955832564080087700747010831668738332060697749893914483616252730277638015091096767677813133913837126520586842957004168892044673
  crt coefficient:  2931067481768796750197829654251952834275144311709208657122584273794219248528207319954346442077549609036355755736257063586611921256982012960072866836025831
true
Sun RSA public key, 1024 bits
  modulus: 98235479183090963770432427642200442983675739444442006745888910614495825811982664163947878578914073870500014846784140598420160562292254019341975013655587919214510314839243283904038428619767073656329177318864029779895278607160852761668068560384471619957237410923582565792151121560119515816871893117811308979089
  public exponent: 65537
Sun RSA public key, 1024 bits
  modulus: 98235479183090963770432427642200442983675739444442006745888910614495825811982664163947878578914073870500014846784140598420160562292254019341975013655587919214510314839243283904038428619767073656329177318864029779895278607160852761668068560384471619957237410923582565792151121560119515816871893117811308979089
  public exponent: 65537
true
개인키입니다.
30820276020100300d06092a864886f70d0101010500048202603082025c020100028181008be457e074b6b858eab9c2ac7be531eb30b8b61c936ad65943a4d01e777c1459f1184861e633878be716fb31cc8b28ff7c6cdf174eb8b60ff82add86c172aafec5b9b41f1f1ecd6f0a77f07a83e7075458995ba8460a5029320e2affb075df035f6aa399b73520c4b2443d5cbf123a3a1d97ffe44781baadd4d03acfbbe1639102030100010281810087e3c271692eed98823afc9e6ca3d17ff38e1a695bd25671d3c1cfe128944178b538af675a250830a0c4b43245cd907fcdb03c6df9ac783ebf0574b7a846e94ea8f40eaf4b2d590fb288058e386e04eb98707e13a1949b3a55aacd983c7a0714f67407997dc43770da7cf22ee1cdc74a48dcfe66087116370ac7505d0768e801024100e5471b19ae5d167ef5e1d6acef66dd84f4fc64609f4204ef2c35a645eeabaca54c9f56a8e84c268807a55f25a76fcec45f98a2f67528619fb399894d359775d10241009c3242680aafe43a9459a7388fa66a7b2fde15725bc0d1b37a07e43ffc5058d4a53e5d3039c7969c4cc1f672a7aa1a9de1ad44b57f3180b85c5d5747abafc1c102407dcfa8e54cb2b3f773013c05a550b2d9947d32af7a7485b4a073c80bb3cdec6cc040e712c47594e72c1ae8bd06c5e996044703956df07cb15fa22e9f797ae521024045d88bad6ea9fccadd2fc2011eeb71ce28378d2b982fff15dcc9ce9d763c8f9c77500de7d4ce9560cb4a28e458694e81af3b05f08b321db7534642134088d581024037f6c268f9747a8c7b409db9f5e8988b8be091fd264a0164871118031e5cf579d38c701930fc9e5958af188274143126347277b815d7d91ea4fce1c9c4b091e7
 소스의 1번을 통해 생성한 키를 파일로 저장해서 재 사용할 예정이다. 문제는 바이트배열로 저장한 데이터를 다시 키로 만드는 방법인데, 소스의 2번을 이용하면 아주 손쉽게 사용할 수 있다. 그러나~~ 무덤파길 좋아하는 본인은 이 PKCS8EncodedKeySpec 를 직접 구현해보기로 했다.


3. PKCS #8이란?
 PKCS#8 : Private­Key Information Syntax Standard PKCS#8은 비밀키 정보를 위한 구문을 정의한다.
 비밀키 정보는 어떤 공개키 알고리즘에 대한 비밀키와 그것에 대한 속성들로 구성된다. 또한, 본 표준은 암호화된 비밀키에 대한 구문 설명도 포함한다. (출처:모름 --;)
 고 한다... 즉 비밀키를 저정하는 구문이라고 하는데, 이놈의 속살을 볼려면... 당연히 RFC를 뒤져주자.
 RFC5208(http://www.ietf.org/rfc/rfc5208.txt)에 가면 상세한 설명이 나오는거 같다. 2페이지쯤 보면,
5.  Private-Key Information Syntax

   This section gives the syntax for private-key information.

   Private-key information shall have ASN.1 type PrivateKeyInfo:

      PrivateKeyInfo ::= SEQUENCE {
        version                   Version,
        privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
        privateKey                PrivateKey,
        attributes           [0]  IMPLICIT Attributes OPTIONAL }

      Version ::= INTEGER

      PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier

      PrivateKey ::= OCTET STRING

      Attributes ::= SET OF Attribute

   The fields of type PrivateKeyInfo have the following meanings:

      version is the syntax version number, for compatibility with
      future revisions of this document.  It shall be 0 for this version
      of the document.

      privateKeyAlgorithm identifies the private-key algorithm.  One
      example of a private-key algorithm is PKCS #1's rsaEncryption
      [PKCS#1].

      privateKey is an octet string whose contents are the value of the
      private key.  The interpretation of the contents is defined in the
      registration of the private-key algorithm.  For an RSA private
      key, for example, the contents are a BER encoding of a value of
      type RSAPrivateKey.

      attributes is a set of attributes.  These are the extended
      information that is encrypted along with the private-key
      information.
이렇게 친절하게 설명을 해주신다. 까막눈이라서 정확한 뜻은 모르겠지만, 개인키정보는는 버전과, 개인키알고리즘, 개인키, 기타등등으로 이루어진다고 한다.
      PrivateKeyInfo ::= SEQUENCE {
        version                   Version,
        privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
        privateKey                PrivateKey,
        attributes           [0]  IMPLICIT Attributes OPTIONAL }

      Version ::= INTEGER

      PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier

      PrivateKey ::= OCTET STRING

      Attributes ::= SET OF Attribute
저 놈이 ASN.1(Abstract Syntax Notation One)이라는 것인데, 복잡한 데이터 구조를 내부 구현에 독립적으로 추상화하여 표현하기 위한 표준 구문법이라고 한다. 저 구문법에 따로 표현된 타입에 할당된 값을 부호화하여 방법을 제공하는게 BER(Basic Encoding Rules)라고 하고, DER(Distinguished Encoding Rules)은 유일한 Octet 문자열로 부호화하는 BER의 부분집이라고 하는데, 뭔소리인지... 본인도 잘 모르겠다. Octect은 8비트의 집합으로 흔히 알고 있는 바이트와 비슷하다고 보면 된다.(8비는 1바이트라고 알고 있지만, 컴에 따라 달라질수도 있단다. 그래서 저런 용어를 사용한다고 한다.)
 그럼 저 추상화 같은 놈을 어떻게 하면 실체화시킬수 있는것일까? 조금전 설명한 BER을 이용하면 된다. 간단히 설명하면 BER format은 타입(Type)과 값의 길이(Length), 값(Value)으로 이루어진 TLV로 만들어진다. 타입은 octect으로 구성되어 있는데 8,7 비트는 class를, 6비트는 primitive/construected, 5-1비티는 숫자를 나타난다. 자세한 설명은 위키(http://en.wikipedia.org/wiki/Basic_Encoding_Rules)와 http://www.vijaymukhi.com/vmis/ber.htm를 참조하기 바란다.

 자, 저 글들을 바탕으로 한 번 구현해보자.
 테스트용 데이터는 조금전 생성한 "30820276020100300d06092a864886f70d0101010500048202603082025c020100028181008be457e074b6b858eab9c2ac7be531eb30b8b61c936ad65943a4d01e777c1459f1184861e633878be716fb31cc8b28ff7c6cdf174eb8b60ff82add86c172aafec5b9b41f1f1ecd6f0a77f07a83e7075458995ba8460a5029320e2affb075df035f6aa399b73520c4b2443d5cbf123a3a1d97ffe44781baadd4d03acfbbe1639102030100010281810087e3c271692eed98823afc9e6ca3d17ff38e1a695bd25671d3c1cfe128944178b538af675a250830a0c4b43245cd907fcdb03c6df9ac783ebf0574b7a846e94ea8f40eaf4b2d590fb288058e386e04eb98707e13a1949b3a55aacd983c7a0714f67407997dc43770da7cf22ee1cdc74a48dcfe66087116370ac7505d0768e801024100e5471b19ae5d167ef5e1d6acef66dd84f4fc64609f4204ef2c35a645eeabaca54c9f56a8e84c268807a55f25a76fcec45f98a2f67528619fb399894d359775d10241009c3242680aafe43a9459a7388fa66a7b2fde15725bc0d1b37a07e43ffc5058d4a53e5d3039c7969c4cc1f672a7aa1a9de1ad44b57f3180b85c5d5747abafc1c102407dcfa8e54cb2b3f773013c05a550b2d9947d32af7a7485b4a073c80bb3cdec6cc040e712c47594e72c1ae8bd06c5e996044703956df07cb15fa22e9f797ae521024045d88bad6ea9fccadd2fc2011eeb71ce28378d2b982fff15dcc9ce9d763c8f9c77500de7d4ce9560cb4a28e458694e81af3b05f08b321db7534642134088d581024037f6c268f9747a8c7b409db9f5e8988b8be091fd264a0164871118031e5cf579d38c701930fc9e5958af188274143126347277b815d7d91ea4fce1c9c4b091e7"을 사용하겠다.
 1바이트씩 읽어보겠다.
 처음 0x30은 2진수 00110000 로서 Type을 나타낸다. Class가 00이므로 Universal을 나타내고, P/C가 1이니 constructed, 숫자가 10000 즉 16을 나타내므로 SEQUENCE가 된다.
 두번째 0x82는 길이를 나타낸다. 만약 길이가 1바이트만으로 표현된다면 255자 이상의 데이터는 나타낼 수가 없을것이다. 그래서 길이 데이터의 8번째 비트가 1을 나타내면 7-1비트는 길이의 길이를 나타내게 된다. 즉 7-1비티의 값이 2이면, 다음 바이트부터 2바이트가 길이 값으로 쓰인다는것이다. 0x82abcd이면 0x82는 길이의 길이값이 2바이트고, 길이는 0xabcd (43981)이 된다는 것이다. 여기서는 0x820276이므로, 630의 값을 나타낸다.
 다섯번째 0x02부터 630개의 바이트들은 데이터로 사용된다. 이로서 SEQUENCE 구문이 끝났다.
 다시 데이터의 0x02부터 분석해보면, ASN.1에 나타난데로 INTEGER라 것을 알수 있고, 값을 0이다. 이런식으로 계속 분석해보면 아래와 같은 값들을 얻을 수 있다. (OID 계산하는방법은 생략하겠다.)
package kr.kangwoo.moon.sample;

import java.io.IOException;
import java.math.BigInteger;

import kr.kangwoo.bada.server.KeyGen;
import kr.kangwoo.util.ByteUtils;

public class PKCS8EncodedKeySpec {
	
    public static final int BOOLEAN             = 0x01;
    public static final int INTEGER             = 0x02;
    public static final int BIT_STRING          = 0x03;
    public static final int OCTET_STRING        = 0x04;
    public static final int NULL                = 0x05;
    public static final int OBJECT_IDENTIFIER   = 0x06;
    public static final int EXTERNAL            = 0x08;
    public static final int ENUMERATED          = 0x0a;
    public static final int SEQUENCE            = 0x10;
    public static final int SEQUENCE_OF         = 0x10; // for completeness
    public static final int SET                 = 0x11;
    public static final int SET_OF              = 0x11; // for completeness
    
    public static final int CONSTRUCTED         = 0x20;
    public static final int APPLICATION         = 0x40;
    public static final int TAGGED              = 0x80;
    
	private byte[] bytes;
	private int index = 0;
	
	public PKCS8EncodedKeySpec(byte[] bytes) {
		this.bytes = bytes;
	}
	
	public void readObject() throws IOException {
		while (index < bytes.length) {
			byte type = read();
			int length = readLength();

			if (length >= 0) {
				if (type == 0 || length == 0) {
					return;
				}
				byte[] value = new byte[length];
				readFully(value);
				
				if (type == (CONSTRUCTED | SEQUENCE)) {
					System.out.println("SEQUENCE Length=" + length);

					PKCS8EncodedKeySpec k = new PKCS8EncodedKeySpec(value);
					k.readObject();
				} else if (type == INTEGER) {
					System.out.println("INTEGER " + new BigInteger(value));
				} else if (type == OCTET_STRING) {
					System.out.println("OCTET_STRING " + ByteUtils.toHexString(value));
				} else if (type == NULL) {
					System.out.println("NULL ");
				} else if (type == OBJECT_IDENTIFIER) {
					System.out.println("OBJECT_IDENTIFIER " + getObjectIdentifier(value));
				}
			} else {
				// 뭘 처리 할까요?
			}
		}

	}
	
	public byte read() {
//		System.out.println("[" + bytes.length + "-" + index + "] " + ByteUtils.toHexString(bytes[index]) + " " + ByteUtils.toBinaryString(bytes[index]));
		return bytes[index++];
	}
	
	public void readFully(byte[] bytes) {
		for (int i = 0; i < bytes.length; i++) {
			bytes[i] = read();
		}
	}
	
	private int readLength() throws IOException {
		int length = read() & 0xff;
		if (length < 0) {
			
		}
		
		if (length == 0x80) {
			return -1;
		}
		
		if (length > 127) {
			int size = length & 0x7f;
			if (size > 4) {
				throw new IOException("DER length more than 4 bytes");
			}
			
			length = 0;
			for (int i = 0; i < size; i++) {
				int next = read() & 0xff;

				if (next < 0) {
					throw new IOException("EOF found reading length");
				}

				length = (length << 8) + next;
			}
            
			if (length < 0) {
				throw new IOException("corrupted stream - negative length found");
			}
		}
		return length;
	}
	
	public String getObjectIdentifier(byte[] bytes) {
		StringBuffer objId = new StringBuffer();
		long value = 0;
		BigInteger bigValue = null;
		boolean first = true;

		for (int i = 0; i != bytes.length; i++) {
			int b = bytes[i] & 0xff;

			if (value < 0x80000000000000L) {
				value = value * 128 + (b & 0x7f);
				if ((b & 0x80) == 0) { // end of number reached
					if (first) {
						switch ((int) value / 40) {
						case 0:
							objId.append('0');
							break;
						case 1:
							objId.append('1');
							value -= 40;
							break;
						default:
							objId.append('2');
							value -= 80;
						}
						first = false;
					}

					objId.append('.');
					objId.append(value);
					value = 0;
				}
			} else {
				if (bigValue == null) {
					bigValue = BigInteger.valueOf(value);
				}
				bigValue = bigValue.shiftLeft(7);
				bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
				if ((b & 0x80) == 0) {
					objId.append('.');
					objId.append(bigValue);
					bigValue = null;
					value = 0;
				}
			}
		}

		return objId.toString();
	}

	public static void main(String[] args) throws Exception {
//		Sun RSA private CRT key, 1024 bits
//		  modulus:          98235479183090963770432427642200442983675739444442006745888910614495825811982664163947878578914073870500014846784140598420160562292254019341975013655587919214510314839243283904038428619767073656329177318864029779895278607160852761668068560384471619957237410923582565792151121560119515816871893117811308979089
//		  public exponent:  65537
//		  private exponent: 95424982464164318408735053611818737525775743847171323579913328769092776032507444130876449121730133676301508234676167032006717758161793725366568706522148356314255952502618174670664289187298920132480956331892827405186415397044362320128949328957015105859759408000615566939338475899541162627898412351669762844673
//		  prime p:          12008250515849944108488102843499187655464462509731422296877150117470960033720378393817005998217639840722804588451011564705219732141220363017738196616705489
//		  prime q:          8180665372814122660173069738611390116430652686953417350545079644723331346304424811054335466600885913977520264222372188538563562437033369510447765531902401
//		  prime exponent p: 6589265682759291545683341539251381455754962857240359013081100333010218116982044460357464786424504691274753171641596012785588476849147301445655141778384161
//		  prime exponent q: 3658125630036325719502448719955832564080087700747010831668738332060697749893914483616252730277638015091096767677813133913837126520586842957004168892044673
//		  crt coefficient:  2931067481768796750197829654251952834275144311709208657122584273794219248528207319954346442077549609036355755736257063586611921256982012960072866836025831
		
		String digits = "30820276020100300d06092a864886f70d0101010500048202603082025c020100028181008be457e074b6b858eab9c2ac7be531eb30b8b61c936ad65943a4d01e777c1459f1184861e633878be716fb31cc8b28ff7c6cdf174eb8b60ff82add86c172aafec5b9b41f1f1ecd6f0a77f07a83e7075458995ba8460a5029320e2affb075df035f6aa399b73520c4b2443d5cbf123a3a1d97ffe44781baadd4d03acfbbe1639102030100010281810087e3c271692eed98823afc9e6ca3d17ff38e1a695bd25671d3c1cfe128944178b538af675a250830a0c4b43245cd907fcdb03c6df9ac783ebf0574b7a846e94ea8f40eaf4b2d590fb288058e386e04eb98707e13a1949b3a55aacd983c7a0714f67407997dc43770da7cf22ee1cdc74a48dcfe66087116370ac7505d0768e801024100e5471b19ae5d167ef5e1d6acef66dd84f4fc64609f4204ef2c35a645eeabaca54c9f56a8e84c268807a55f25a76fcec45f98a2f67528619fb399894d359775d10241009c3242680aafe43a9459a7388fa66a7b2fde15725bc0d1b37a07e43ffc5058d4a53e5d3039c7969c4cc1f672a7aa1a9de1ad44b57f3180b85c5d5747abafc1c102407dcfa8e54cb2b3f773013c05a550b2d9947d32af7a7485b4a073c80bb3cdec6cc040e712c47594e72c1ae8bd06c5e996044703956df07cb15fa22e9f797ae521024045d88bad6ea9fccadd2fc2011eeb71ce28378d2b982fff15dcc9ce9d763c8f9c77500de7d4ce9560cb4a28e458694e81af3b05f08b321db7534642134088d581024037f6c268f9747a8c7b409db9f5e8988b8be091fd264a0164871118031e5cf579d38c701930fc9e5958af188274143126347277b815d7d91ea4fce1c9c4b091e7";
		byte[] bytes = ByteUtils.toBytesFromHexString(digits);
		
		PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
		spec.readObject();
	}
}

실행결과
SEQUENCE Length=630
INTEGER 0
SEQUENCE Length=13
OBJECT_IDENTIFIER 1.2.840.113549.1.1.1
OCTET_STRING 3082025c020100028181008be457e074b6b858eab9c2ac7be531eb30b8b61c936ad65943a4d01e777c1459f1184861e633878be716fb31cc8b28ff7c6cdf174eb8b60ff82add86c172aafec5b9b41f1f1ecd6f0a77f07a83e7075458995ba8460a5029320e2affb075df035f6aa399b73520c4b2443d5cbf123a3a1d97ffe44781baadd4d03acfbbe1639102030100010281810087e3c271692eed98823afc9e6ca3d17ff38e1a695bd25671d3c1cfe128944178b538af675a250830a0c4b43245cd907fcdb03c6df9ac783ebf0574b7a846e94ea8f40eaf4b2d590fb288058e386e04eb98707e13a1949b3a55aacd983c7a0714f67407997dc43770da7cf22ee1cdc74a48dcfe66087116370ac7505d0768e801024100e5471b19ae5d167ef5e1d6acef66dd84f4fc64609f4204ef2c35a645eeabaca54c9f56a8e84c268807a55f25a76fcec45f98a2f67528619fb399894d359775d10241009c3242680aafe43a9459a7388fa66a7b2fde15725bc0d1b37a07e43ffc5058d4a53e5d3039c7969c4cc1f672a7aa1a9de1ad44b57f3180b85c5d5747abafc1c102407dcfa8e54cb2b3f773013c05a550b2d9947d32af7a7485b4a073c80bb3cdec6cc040e712c47594e72c1ae8bd06c5e996044703956df07cb15fa22e9f797ae521024045d88bad6ea9fccadd2fc2011eeb71ce28378d2b982fff15dcc9ce9d763c8f9c77500de7d4ce9560cb4a28e458694e81af3b05f08b321db7534642134088d581024037f6c268f9747a8c7b409db9f5e8988b8be091fd264a0164871118031e5cf579d38c701930fc9e5958af188274143126347277b815d7d91ea4fce1c9c4b091e7


단지 흐름만 느끼기 위해서 꼭 필요한 부분만 구현하였다. 실행해보면, 버젼이 0이고, OID가 "1.2.840.113549.1.1.1"이고, 개인키가 "3082025c020100028181008be457e074b6b858eab9c2ac7be531eb30b8b61c936ad65943a4d01e777c1459f1184861e633878be716fb31cc8b28ff7c6cdf174eb8b60ff82add86c172aafec5b9b41f1f1ecd6f0a77f07a83e7075458995ba8460a5029320e2affb075df035f6aa399b73520c4b2443d5cbf123a3a1d97ffe44781baadd4d03acfbbe1639102030100010281810087e3c271692eed98823afc9e6ca3d17ff38e1a695bd25671d3c1cfe128944178b538af675a250830a0c4b43245cd907fcdb03c6df9ac783ebf0574b7a846e94ea8f40eaf4b2d590fb288058e386e04eb98707e13a1949b3a55aacd983c7a0714f67407997dc43770da7cf22ee1cdc74a48dcfe66087116370ac7505d0768e801024100e5471b19ae5d167ef5e1d6acef66dd84f4fc64609f4204ef2c35a645eeabaca54c9f56a8e84c268807a55f25a76fcec45f98a2f67528619fb399894d359775d10241009c3242680aafe43a9459a7388fa66a7b2fde15725bc0d1b37a07e43ffc5058d4a53e5d3039c7969c4cc1f672a7aa1a9de1ad44b57f3180b85c5d5747abafc1c102407dcfa8e54cb2b3f773013c05a550b2d9947d32af7a7485b4a073c80bb3cdec6cc040e712c47594e72c1ae8bd06c5e996044703956df07cb15fa22e9f797ae521024045d88bad6ea9fccadd2fc2011eeb71ce28378d2b982fff15dcc9ce9d763c8f9c77500de7d4ce9560cb4a28e458694e81af3b05f08b321db7534642134088d581024037f6c268f9747a8c7b409db9f5e8988b8be091fd264a0164871118031e5cf579d38c701930fc9e5958af188274143126347277b815d7d91ea4fce1c9c4b091e7"라는 것을 알 수 있다.
 http://www.oid-info.com/를 통해 해당 OID를 조회해보자.

 너무 당연한 결과이지만 RSA (PKCS #1 v1.5) key transport algorithm라는 것을 친절히 알려준다.
 그럼 PKCS #1을 연구해보자. RFC2313(http://www.ietf.org/rfc/rfc2313.txt)을 보면 된다. 현재 우리가 필요한 부분은 개인키 부분이니, 6페이지로 넘어가자. RSAPrivateKey를 정의한곳이 보인다. INTEGER로 도배가 되어있다. 귀찮은 관계로 조금전 만들 소스를 재활용해서 돌려보자.
		String keyDigits = "3082025c020100028181008be457e074b6b858eab9c2ac7be531eb30b8b61c936ad65943a4d01e777c1459f1184861e633878be716fb31cc8b28ff7c6cdf174eb8b60ff82add86c172aafec5b9b41f1f1ecd6f0a77f07a83e7075458995ba8460a5029320e2affb075df035f6aa399b73520c4b2443d5cbf123a3a1d97ffe44781baadd4d03acfbbe1639102030100010281810087e3c271692eed98823afc9e6ca3d17ff38e1a695bd25671d3c1cfe128944178b538af675a250830a0c4b43245cd907fcdb03c6df9ac783ebf0574b7a846e94ea8f40eaf4b2d590fb288058e386e04eb98707e13a1949b3a55aacd983c7a0714f67407997dc43770da7cf22ee1cdc74a48dcfe66087116370ac7505d0768e801024100e5471b19ae5d167ef5e1d6acef66dd84f4fc64609f4204ef2c35a645eeabaca54c9f56a8e84c268807a55f25a76fcec45f98a2f67528619fb399894d359775d10241009c3242680aafe43a9459a7388fa66a7b2fde15725bc0d1b37a07e43ffc5058d4a53e5d3039c7969c4cc1f672a7aa1a9de1ad44b57f3180b85c5d5747abafc1c102407dcfa8e54cb2b3f773013c05a550b2d9947d32af7a7485b4a073c80bb3cdec6cc040e712c47594e72c1ae8bd06c5e996044703956df07cb15fa22e9f797ae521024045d88bad6ea9fccadd2fc2011eeb71ce28378d2b982fff15dcc9ce9d763c8f9c77500de7d4ce9560cb4a28e458694e81af3b05f08b321db7534642134088d581024037f6c268f9747a8c7b409db9f5e8988b8be091fd264a0164871118031e5cf579d38c701930fc9e5958af188274143126347277b815d7d91ea4fce1c9c4b091e7";
		byte[] keyBytes = ByteUtils.toBytesFromHexString(keyDigits);
		
		PKCS8EncodedKeySpec x = new PKCS8EncodedKeySpec(keyBytes);
		x.readObject();

실행결과
SEQUENCE Length=604
INTEGER 0
INTEGER 98235479183090963770432427642200442983675739444442006745888910614495825811982664163947878578914073870500014846784140598420160562292254019341975013655587919214510314839243283904038428619767073656329177318864029779895278607160852761668068560384471619957237410923582565792151121560119515816871893117811308979089
INTEGER 65537
INTEGER 95424982464164318408735053611818737525775743847171323579913328769092776032507444130876449121730133676301508234676167032006717758161793725366568706522148356314255952502618174670664289187298920132480956331892827405186415397044362320128949328957015105859759408000615566939338475899541162627898412351669762844673
INTEGER 12008250515849944108488102843499187655464462509731422296877150117470960033720378393817005998217639840722804588451011564705219732141220363017738196616705489
INTEGER 8180665372814122660173069738611390116430652686953417350545079644723331346304424811054335466600885913977520264222372188538563562437033369510447765531902401
INTEGER 6589265682759291545683341539251381455754962857240359013081100333010218116982044460357464786424504691274753171641596012785588476849147301445655141778384161
INTEGER 3658125630036325719502448719955832564080087700747010831668738332060697749893914483616252730277638015091096767677813133913837126520586842957004168892044673
INTEGER 2931067481768796750197829654251952834275144311709208657122584273794219248528207319954346442077549609036355755736257063586611921256982012960072866836025831


오예~ 값들을 비교해보면 처음 만든 값과 일치하는것을 알 수 있을것이다.~~~ 삽질하느로 수고하셨다. 편히 쉬시길...