2016년 1월 3일 일요일

RSA java 예제(2) - 3개 파트 분리 소스

앞에서 RSA 의 기본 개념을 살펴 봤습니다.
http://swlock.blogspot.kr/2014/11/rsa-java.html

하지만 대부분의 예제들이 암호화 하고 곧장 해제하는 등의 하나의 java 예제로 붙어있어서 무슨말인지 이해하기 어려울것 같아서 좀 더 쉽게 예제를 작성 하였습니다.

그림은 이전에 그린 그림과 같이 동일하나, 이번에 구현할 내용은 3개의 part로 나누어서 구현하였습니다.


1. 키생성 파트

이건 암호화나 복호화를 하는게 아니라 미리 개인키와 공개키를 보관하기 위해서 생성해 두는것입니다. 안드로이드 apk signing 시 keystore 파일을 만드는것처럼 개인키와 공개키를 미리 저장하는 개념으로 이해하면 됩니다.

2. 암호화 파트

공개키와 평문을 이용하여 암호화를 합니다.

3. 복호화 파트

전달된 암호문과 가지고 있는 개인키를 이용하여 복호화 합니다.



구현 코드

1. 키생성 파트



import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;

/*
Sample Result

pubKeyHex:30820122300d06092a864886f70d01010105000382010f003082010a02820101009852cfb349e4c63501ea5124b62bd96fac2e46a4cbc08745f8ef446e495433ecf55619fcff9e57f00a2ea19a6955598cfde5a9ebd0c04be9e4102c25dfa8e7538c1b7f4697ee8811fa15e76b60767d08e61d3dbf713f33c90fd0584e5b7808fcdfcce1b4fc8eec983dbdc9ee4a02b6564a8abdc1abddc0db7b320f697434ddbc5bc789636083c79e8f1a05c6c8d5c4c75a7fc2473de0ca84c41d8ed9416f5e8a8d87cab787950347b1392ecb87d7732b9f382308211f9a31f6b17611ab273e896e862b42aec7d1bea4a0b08a26d91244900aaeba172ed5dc48f985ad1a980148ce20b06d4f9fdcd2437a16ab6e93411aad1885bc3675fe563a654ee547e3433f0203010001
privKeyHex:308204bd020100300d06092a864886f70d0101010500048204a7308204a302010002820101009852cfb349e4c63501ea5124b62bd96fac2e46a4cbc08745f8ef446e495433ecf55619fcff9e57f00a2ea19a6955598cfde5a9ebd0c04be9e4102c25dfa8e7538c1b7f4697ee8811fa15e76b60767d08e61d3dbf713f33c90fd0584e5b7808fcdfcce1b4fc8eec983dbdc9ee4a02b6564a8abdc1abddc0db7b320f697434ddbc5bc789636083c79e8f1a05c6c8d5c4c75a7fc2473de0ca84c41d8ed9416f5e8a8d87cab787950347b1392ecb87d7732b9f382308211f9a31f6b17611ab273e896e862b42aec7d1bea4a0b08a26d91244900aaeba172ed5dc48f985ad1a980148ce20b06d4f9fdcd2437a16ab6e93411aad1885bc3675fe563a654ee547e3433f02030100010282010019070239631ac3b651ea3e0ada23ba462ef42b8748330a06e52feafe73edf1da2d35486fd9501b02c5a983c3eb2aaadc0f9b7c9fd25cc61c57ec905468bb47c6e26e622b272b7a0ffa173f3ed54aa2a0a3ae8a46ba44b82d80fbaa86b560b39958ec40e98bd5afea13baeb42cbc6464f4750247d7dcfa1b06e3d7b6ac83d27715a7987731f44c7d8109d6fa10425bc7a13347331a7d9f9629a4a2ff0ccb6270f8a8ae6a05ad92354c364e79837c0613c5375d476bc9291b24b1067439fbda1ba387589064cf1a0b050f1f8db7d5313bc6697c0e0736876847631ad7101263ae9a0f2f4738f297fcb55357c5d70518138c75e3be0ddd68cf6444b31c5cacf918102818100ca8a99d468aec849d1488fe032059d8ff1167c9278b3b8822bae8cb87191d3cfa4ae6e20493300bc7930e9dbb94197bee93f595cc32d9d037aebc868147a37cfcc788cf37d4187e3e040afd08f33a992ee73fa6162286ca5b6d1ad8a984554bc30f3491de3ee47e68eb2d08a1b09a99694bcd799df3af47285d4289fbd66ab8b02818100c08710bb50462ef44d793482d68eb63f06ed1d3d725b1154abe8de7db4b153d1b1d33f69f151b2550b4c18e15e2ac1419d936aa789d94e16989e10163668859665327b084cb9510922a80b0e45844a467f41520304b1bab05f6b1612f25d6b204d60a097fd1239835c8262f852cd4396264404e234706a9550defc067a620d9d0281804f7fefb98c0d6ed86aa94caff77274d21713787a159e9581a29bb4e880cb78943c53ab2e490d17f0e2b0ec5a2e712c9ae6fad29cb28fa8ddc0d5e3a7d6c1d23e6247bf2ba3b2a12034d9af28f1cc9976eed9df217261e3a3780afd4f354da160ece5d1814602357eadec4a26ab4e339ec36b0c457d75aa95792a3977d9e3fed902818100b2280a169b78e698515cb877de5d9f4d8176479985c9b9a6d5919ed94a2cd1b878ca57a30c9921e1ca9b77668d021965439097a04352600d4edaed5df0a915fd0ed600bdb469c410250ec5744665dd6990f67c12a8f462223599dd8a58d6937c07be43bd8184accddefc14e35f93ec57f43efb19eb969f3a5ee488e8e1b4fc8d02818010fff11dd0b121624e7b324001972652db00fe2d45fe98c80cac0e25e9e814b1c1f7373d939641a3a03529020c94e4e34471efaab5ccc23093f15d9c2202185a38af3df95e5adff66bcf29c22a1699ab46b00bc6b885f12e77a371a51e9a2228fac2369f52d5d2d27873e56e86a1f2dd0c5c5d67d9241592a876d06c78a13fcc

*/
public class RSAGenKey {
 /**
  * @param args
  * @throws NoSuchProviderException 
  * @throws NoSuchAlgorithmException 
  */
 public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException {
  SecureRandom random = new SecureRandom();
  //KeyPairGenerator generator = KeyPairGenerator.getInstance("DiffieHellman", "SunJCE"); Not an RSA key: DH
  //KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "SunRsaSign"); // OK
  KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "SunJSSE"); // OK
  
  generator.initialize(2048, random); // 여기에서는 2048 bit 키를 생성하였음
  KeyPair pair = generator.generateKeyPair();
  Key pubKey = pair.getPublic();  // Kb(pub) 공개키
  Key privKey = pair.getPrivate();// Kb(pri) 개인키

  System.out.println("pubKeyHex:"+byteArrayToHex(pubKey.getEncoded()));
  System.out.println("privKeyHex:"+byteArrayToHex(privKey.getEncoded()));
 }
 
 // hex string to byte[]
 public static byte[] hexToByteArray(String hex) {
     if (hex == null || hex.length() == 0) {
         return null;
     }
     byte[] ba = new byte[hex.length() / 2];
     for (int i = 0; i < ba.length; i++) {
         ba[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
     }
     return ba;
 }
  
 // byte[] to hex sting
 public static String byteArrayToHex(byte[] ba) {
     if (ba == null || ba.length == 0) {
         return null;
     }
     StringBuffer sb = new StringBuffer(ba.length * 2);
     String hexNumber;
     for (int x = 0; x < ba.length; x++) {
         hexNumber = "0" + Integer.toHexString(0xff & ba[x]);
  
         sb.append(hexNumber.substring(hexNumber.length() - 2));
     }
     return sb.toString();
 } 
}

설명:
hexToByteArray, byteArrayToHex라는 함수가 있는데 뒤쪽에도 공통적으로 나오는 함수입니다. 해당 함수는 byte[]의 값을 hex값으로 변환하여 출력을 용이 하게 하여 다른쪽으로 붙여넣어 전달하기 편하게 하기 위해서 사용되는 함수 입니다.
즉 " " 라는 문자열을 byteArrayToHex를 호출하면 "20" 이 되며 반대로 "20"을 hexToByteArray를 호출하면 " " 이 됩니다.

KeyPairGenerator.getInstance("RSA", "SunJSSE"); 함수의 인자는 두부분으로 구성되어있는데 Provider 관련 내용을 확인 하면 됩니다.
"SunJSSE"가 Provider로 RSA를 지원하는 Provider를 선택해서 기록하면 됩니다. Sun에서 지원하는 provider 종류는 아래 링크를 참고 하기 바랍니다.
provider 관련
https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html
코드 설명은 두개의 키를 만들어 화면에 출력하게 됩니다. random에 의해서 키는 실행될때마다 바뀝니다.

상단 주석 부분에 실행된 결과가 있습니다. 이것을 이용하여 다음 예제를 계속 하도록 하겠습니다.
다음은 공개키를 이용하여 암호화 하는 예제입니다.

2. 암호화 파트 소스



import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

//https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
//Cipher.getInstance 첫번째 인자 의미 
/*
Parameters:
transformation - the name of the transformation, e.g., DES/CBC/PKCS5Padding. See the Cipher section in the Java Cryptography Architecture Standard Algorithm Name Documentation for information about standard transformation names.
 Cipher Algorithm Names/Cipher Algorithm Modes/Cipher Algorithm Padding
 provider - the name of the provider.

provider 관련
https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html
*/

//https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Cipher
//http://stackoverflow.com/questions/7348224/generating-constant-rsa-keys-java

/*
Sample Result

pubKeyHex:30820122300d06092a864886f70d01010105000382010f003082010a02820101009852cfb349e4c63501ea5124b62bd96fac2e46a4cbc08745f8ef446e495433ecf55619fcff9e57f00a2ea19a6955598cfde5a9ebd0c04be9e4102c25dfa8e7538c1b7f4697ee8811fa15e76b60767d08e61d3dbf713f33c90fd0584e5b7808fcdfcce1b4fc8eec983dbdc9ee4a02b6564a8abdc1abddc0db7b320f697434ddbc5bc789636083c79e8f1a05c6c8d5c4c75a7fc2473de0ca84c41d8ed9416f5e8a8d87cab787950347b1392ecb87d7732b9f382308211f9a31f6b17611ab273e896e862b42aec7d1bea4a0b08a26d91244900aaeba172ed5dc48f985ad1a980148ce20b06d4f9fdcd2437a16ab6e93411aad1885bc3675fe563a654ee547e3433f0203010001
inputText:암호화된 문자열 abcdefg hijklmn
inputHex:(31):becfc8a3c8adb5c820b9aec0dabfad20616263646566672068696a6b6c6d6e
cipherHex:(256):74e199ec8b1d1845a7569622a43500598bab5b194b44915da91929aa2007564cbe8ac4e996ead6b3cdc337603c4a031e18471e35efd3d8e49590e3269ba2254c095bc6c0c38ca113b7760b7ea792f3fa1bb3b5560d918f81b48e189da29c369fffac7e7b4e722de70e87b719d827c380cbec1cd446c1f81084a7429f627443580943937f46af78d1e76b83fc26e2b1010a70cfcf396dfa76f0edfbee9c3515efcc1c803798411a54c83e35f60b1089626a4c6106a355b27e86d56d06447186b33b2884f8e73986cc5c44bf2a00ddab7c3fdb1138c3e86208ec7ed5210d18bd97bed15653f76ca7ddae2acf4d338cfd8bcd91fe18d94ca4fed5759dc7f1f0ec79
*/
public class RSAEncrypt {

 /**
  * @param args
  * @throws NoSuchPaddingException 
  * @throws NoSuchProviderException 
  * @throws NoSuchAlgorithmException 
  * @throws InvalidKeyException 
  * @throws BadPaddingException 
  * @throws IllegalBlockSizeException 
  */
 public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
  Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING", "SunJCE");
  String pubKeyStr = "30820122300d06092a864886f70d01010105000382010f003082010a02820101009852cfb349e4c63501ea5124b62bd96fac2e46a4cbc08745f8ef446e495433ecf55619fcff9e57f00a2ea19a6955598cfde5a9ebd0c04be9e4102c25dfa8e7538c1b7f4697ee8811fa15e76b60767d08e61d3dbf713f33c90fd0584e5b7808fcdfcce1b4fc8eec983dbdc9ee4a02b6564a8abdc1abddc0db7b320f697434ddbc5bc789636083c79e8f1a05c6c8d5c4c75a7fc2473de0ca84c41d8ed9416f5e8a8d87cab787950347b1392ecb87d7732b9f382308211f9a31f6b17611ab273e896e862b42aec7d1bea4a0b08a26d91244900aaeba172ed5dc48f985ad1a980148ce20b06d4f9fdcd2437a16ab6e93411aad1885bc3675fe563a654ee547e3433f0203010001";
  
  // Turn the encoded key into a real RSA public key.
  // Public keys are encoded in X.509.
  X509EncodedKeySpec ukeySpec = new X509EncodedKeySpec(hexToByteArray(pubKeyStr));
  KeyFactory ukeyFactory = KeyFactory.getInstance("RSA");
  PublicKey publicKey = null;
  try {
   publicKey = ukeyFactory.generatePublic(ukeySpec);
   System.out.println("pubKeyHex:"+byteArrayToHex(publicKey.getEncoded()));
  } catch (InvalidKeySpecException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  // 공개키를 전달하여 암호화
  byte[] input = "암호화된 문자열 abcdefg hijklmn".getBytes();
  cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  byte[] cipherText = cipher.doFinal(input);
  System.out.println("inputText:"+new String(input));
  System.out.println("inputHex:("+ input.length +"):"+byteArrayToHex(input));
  System.out.println("cipherHex:("+ cipherText.length +"):"+byteArrayToHex(cipherText));
 }
 
 // hex string to byte[]
 public static byte[] hexToByteArray(String hex) {
     if (hex == null || hex.length() == 0) {
         return null;
     }
     byte[] ba = new byte[hex.length() / 2];
     for (int i = 0; i < ba.length; i++) {
         ba[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
     }
     return ba;
 }
  
 // byte[] to hex sting
 public static String byteArrayToHex(byte[] ba) {
     if (ba == null || ba.length == 0) {
         return null;
     }
     StringBuffer sb = new StringBuffer(ba.length * 2);
     String hexNumber;
     for (int x = 0; x < ba.length; x++) {
         hexNumber = "0" + Integer.toHexString(0xff & ba[x]);
  
         sb.append(hexNumber.substring(hexNumber.length() - 2));
     }
     return sb.toString();
 } 
}

소스 설명
Cipher.getInstance("RSA/ECB/PKCS1PADDING", "SunJCE"); 이부분 아래 provider 부분을 보면 됩니다. 첫번째 인자는 transformation 으로서 Algorithm Names/Cipher Algorithm Modes/Cipher Algorithm Padding 를 선택하도록 합니다. provider 문서를 보면 제공하는 종류가 있습니다. https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html

그 다음은 X509EncodedKeySpec 관련 내용인데 public 키는 X509규격으로 인코딩 되어있습니다. 따라서 로딩할때 X509규격으로 로딩해줘야 합니다. hexToByteArray(pubKeyStr) 함수를 호출함으로서 공용키의 byte type으로 로딩되고 generatePublic 를 이용해서 PublicKey 에 공용키 값이 들어가게 됩니다.
input 은 암호화 하고자 하는 평문이고 byte[] cipherText = cipher.doFinal(input); 에 의해 cipherText가 암호화 된 문장입니다. cipherHex 는 Hex 포맷으로 화면에 나타내거나 다른쪽에서 읽어들이기 위해 변형된 문장입니다.




3. 복호화 파트 소스



import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/*
Sample Result

privKeyHex:308204bd020100300d06092a864886f70d0101010500048204a7308204a302010002820101009852cfb349e4c63501ea5124b62bd96fac2e46a4cbc08745f8ef446e495433ecf55619fcff9e57f00a2ea19a6955598cfde5a9ebd0c04be9e4102c25dfa8e7538c1b7f4697ee8811fa15e76b60767d08e61d3dbf713f33c90fd0584e5b7808fcdfcce1b4fc8eec983dbdc9ee4a02b6564a8abdc1abddc0db7b320f697434ddbc5bc789636083c79e8f1a05c6c8d5c4c75a7fc2473de0ca84c41d8ed9416f5e8a8d87cab787950347b1392ecb87d7732b9f382308211f9a31f6b17611ab273e896e862b42aec7d1bea4a0b08a26d91244900aaeba172ed5dc48f985ad1a980148ce20b06d4f9fdcd2437a16ab6e93411aad1885bc3675fe563a654ee547e3433f02030100010282010019070239631ac3b651ea3e0ada23ba462ef42b8748330a06e52feafe73edf1da2d35486fd9501b02c5a983c3eb2aaadc0f9b7c9fd25cc61c57ec905468bb47c6e26e622b272b7a0ffa173f3ed54aa2a0a3ae8a46ba44b82d80fbaa86b560b39958ec40e98bd5afea13baeb42cbc6464f4750247d7dcfa1b06e3d7b6ac83d27715a7987731f44c7d8109d6fa10425bc7a13347331a7d9f9629a4a2ff0ccb6270f8a8ae6a05ad92354c364e79837c0613c5375d476bc9291b24b1067439fbda1ba387589064cf1a0b050f1f8db7d5313bc6697c0e0736876847631ad7101263ae9a0f2f4738f297fcb55357c5d70518138c75e3be0ddd68cf6444b31c5cacf918102818100ca8a99d468aec849d1488fe032059d8ff1167c9278b3b8822bae8cb87191d3cfa4ae6e20493300bc7930e9dbb94197bee93f595cc32d9d037aebc868147a37cfcc788cf37d4187e3e040afd08f33a992ee73fa6162286ca5b6d1ad8a984554bc30f3491de3ee47e68eb2d08a1b09a99694bcd799df3af47285d4289fbd66ab8b02818100c08710bb50462ef44d793482d68eb63f06ed1d3d725b1154abe8de7db4b153d1b1d33f69f151b2550b4c18e15e2ac1419d936aa789d94e16989e10163668859665327b084cb9510922a80b0e45844a467f41520304b1bab05f6b1612f25d6b204d60a097fd1239835c8262f852cd4396264404e234706a9550defc067a620d9d0281804f7fefb98c0d6ed86aa94caff77274d21713787a159e9581a29bb4e880cb78943c53ab2e490d17f0e2b0ec5a2e712c9ae6fad29cb28fa8ddc0d5e3a7d6c1d23e6247bf2ba3b2a12034d9af28f1cc9976eed9df217261e3a3780afd4f354da160ece5d1814602357eadec4a26ab4e339ec36b0c457d75aa95792a3977d9e3fed902818100b2280a169b78e698515cb877de5d9f4d8176479985c9b9a6d5919ed94a2cd1b878ca57a30c9921e1ca9b77668d021965439097a04352600d4edaed5df0a915fd0ed600bdb469c410250ec5744665dd6990f67c12a8f462223599dd8a58d6937c07be43bd8184accddefc14e35f93ec57f43efb19eb969f3a5ee488e8e1b4fc8d02818010fff11dd0b121624e7b324001972652db00fe2d45fe98c80cac0e25e9e814b1c1f7373d939641a3a03529020c94e4e34471efaab5ccc23093f15d9c2202185a38af3df95e5adff66bcf29c22a1699ab46b00bc6b885f12e77a371a51e9a2228fac2369f52d5d2d27873e56e86a1f2dd0c5c5d67d9241592a876d06c78a13fcc
plainText:암호화된 문자열 abcdefg hijklmn
 */
public class RSADecrypt {

 /**
  * @param args
  * @throws BadPaddingException 
  * @throws IllegalBlockSizeException 
  * @throws NoSuchPaddingException 
  * @throws NoSuchProviderException 
  * @throws NoSuchAlgorithmException 
  * @throws InvalidKeyException 
  */
 public static void main(String[] args) throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException {
  String privKeyStr = "308204bd020100300d06092a864886f70d0101010500048204a7308204a302010002820101009852cfb349e4c63501ea5124b62bd96fac2e46a4cbc08745f8ef446e495433ecf55619fcff9e57f00a2ea19a6955598cfde5a9ebd0c04be9e4102c25dfa8e7538c1b7f4697ee8811fa15e76b60767d08e61d3dbf713f33c90fd0584e5b7808fcdfcce1b4fc8eec983dbdc9ee4a02b6564a8abdc1abddc0db7b320f697434ddbc5bc789636083c79e8f1a05c6c8d5c4c75a7fc2473de0ca84c41d8ed9416f5e8a8d87cab787950347b1392ecb87d7732b9f382308211f9a31f6b17611ab273e896e862b42aec7d1bea4a0b08a26d91244900aaeba172ed5dc48f985ad1a980148ce20b06d4f9fdcd2437a16ab6e93411aad1885bc3675fe563a654ee547e3433f02030100010282010019070239631ac3b651ea3e0ada23ba462ef42b8748330a06e52feafe73edf1da2d35486fd9501b02c5a983c3eb2aaadc0f9b7c9fd25cc61c57ec905468bb47c6e26e622b272b7a0ffa173f3ed54aa2a0a3ae8a46ba44b82d80fbaa86b560b39958ec40e98bd5afea13baeb42cbc6464f4750247d7dcfa1b06e3d7b6ac83d27715a7987731f44c7d8109d6fa10425bc7a13347331a7d9f9629a4a2ff0ccb6270f8a8ae6a05ad92354c364e79837c0613c5375d476bc9291b24b1067439fbda1ba387589064cf1a0b050f1f8db7d5313bc6697c0e0736876847631ad7101263ae9a0f2f4738f297fcb55357c5d70518138c75e3be0ddd68cf6444b31c5cacf918102818100ca8a99d468aec849d1488fe032059d8ff1167c9278b3b8822bae8cb87191d3cfa4ae6e20493300bc7930e9dbb94197bee93f595cc32d9d037aebc868147a37cfcc788cf37d4187e3e040afd08f33a992ee73fa6162286ca5b6d1ad8a984554bc30f3491de3ee47e68eb2d08a1b09a99694bcd799df3af47285d4289fbd66ab8b02818100c08710bb50462ef44d793482d68eb63f06ed1d3d725b1154abe8de7db4b153d1b1d33f69f151b2550b4c18e15e2ac1419d936aa789d94e16989e10163668859665327b084cb9510922a80b0e45844a467f41520304b1bab05f6b1612f25d6b204d60a097fd1239835c8262f852cd4396264404e234706a9550defc067a620d9d0281804f7fefb98c0d6ed86aa94caff77274d21713787a159e9581a29bb4e880cb78943c53ab2e490d17f0e2b0ec5a2e712c9ae6fad29cb28fa8ddc0d5e3a7d6c1d23e6247bf2ba3b2a12034d9af28f1cc9976eed9df217261e3a3780afd4f354da160ece5d1814602357eadec4a26ab4e339ec36b0c457d75aa95792a3977d9e3fed902818100b2280a169b78e698515cb877de5d9f4d8176479985c9b9a6d5919ed94a2cd1b878ca57a30c9921e1ca9b77668d021965439097a04352600d4edaed5df0a915fd0ed600bdb469c410250ec5744665dd6990f67c12a8f462223599dd8a58d6937c07be43bd8184accddefc14e35f93ec57f43efb19eb969f3a5ee488e8e1b4fc8d02818010fff11dd0b121624e7b324001972652db00fe2d45fe98c80cac0e25e9e814b1c1f7373d939641a3a03529020c94e4e34471efaab5ccc23093f15d9c2202185a38af3df95e5adff66bcf29c22a1699ab46b00bc6b885f12e77a371a51e9a2228fac2369f52d5d2d27873e56e86a1f2dd0c5c5d67d9241592a876d06c78a13fcc";
  String cipherText = "74e199ec8b1d1845a7569622a43500598bab5b194b44915da91929aa2007564cbe8ac4e996ead6b3cdc337603c4a031e18471e35efd3d8e49590e3269ba2254c095bc6c0c38ca113b7760b7ea792f3fa1bb3b5560d918f81b48e189da29c369fffac7e7b4e722de70e87b719d827c380cbec1cd446c1f81084a7429f627443580943937f46af78d1e76b83fc26e2b1010a70cfcf396dfa76f0edfbee9c3515efcc1c803798411a54c83e35f60b1089626a4c6106a355b27e86d56d06447186b33b2884f8e73986cc5c44bf2a00ddab7c3fdb1138c3e86208ec7ed5210d18bd97bed15653f76ca7ddae2acf4d338cfd8bcd91fe18d94ca4fed5759dc7f1f0ec79";
  Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING", "SunJCE");
  // Turn the encoded key into a real RSA private key.
  // Private keys are encoded in PKCS#8.
  PKCS8EncodedKeySpec rkeySpec = new PKCS8EncodedKeySpec(hexToByteArray(privKeyStr));
  KeyFactory rkeyFactory = KeyFactory.getInstance("RSA");
  PrivateKey privateKey = null;
  try {
   privateKey = rkeyFactory.generatePrivate(rkeySpec);
   System.out.println("privKeyHex:"+byteArrayToHex(privateKey.getEncoded()));
  } catch (InvalidKeySpecException e) {
   e.printStackTrace();
  }

  // 개인키를 가지고있는쪽에서 복호화
  cipher.init(Cipher.DECRYPT_MODE, privateKey);
  byte[] plainText = cipher.doFinal(hexToByteArray(cipherText));
  System.out.println("plainText:" + new String(plainText));
 }

 // hex string to byte[]
 public static byte[] hexToByteArray(String hex) {
     if (hex == null || hex.length() == 0) {
         return null;
     }
     byte[] ba = new byte[hex.length() / 2];
     for (int i = 0; i < ba.length; i++) {
         ba[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
     }
     return ba;
 }
  
 // byte[] to hex sting
 public static String byteArrayToHex(byte[] ba) {
     if (ba == null || ba.length == 0) {
         return null;
     }
     StringBuffer sb = new StringBuffer(ba.length * 2);
     String hexNumber;
     for (int x = 0; x < ba.length; x++) {
         hexNumber = "0" + Integer.toHexString(0xff & ba[x]);
  
         sb.append(hexNumber.substring(hexNumber.length() - 2));
     }
     return sb.toString();
 } 
}

소스 설명
privKeyStr , cipherText 에 각각 개인키, 암호화된 문장을 입력하여 byte타입으로 변경 후 복호화를 하게 되는데 개인키의 경우 PKCS#8 타입으로 인코딩 되어 있습니다. PKCS8EncodedKeySpec 클래스를 이용하여 로딩해줘야 합니다.
그리고 아래 함수들에 의해서 복호화가 이루어지게 되며 plainText에 처음 입력했던 문장이 나오게 됩니다.
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plainText = cipher.doFinal(hexToByteArray(cipherText));



여기까지 마치도록 하고 기회가 닿으면 안드로이드 단말의 apk signing에 대해서 알아보도록 하겠습니다.


댓글 없음:

댓글 쓰기