'Key'에 해당되는 글 3건

  1. 2015.11.05 전자서명
  2. 2015.11.05 RSA 암호화
  3. 2015.11.05 Session key

전자서명

UP! 2015. 11. 5. 11:00

전자서명

 

     내용

가)    개인 키와 함께 생성된 메시지 다이제스트

나)    서명

 

다)    서명 검증

 

 

     목적

가)    무결성

     데이터에 대해서 바뀌지 않았다는 것을 증명

     데이터와 메시지 다이제스트 두 개를 다 바꿀 수 있음

     다이제스트를 개인키로 서명하면 이것은 불가능해 짐

나)    인증

     개인 키의 소유자만이 데이터에 서명할 수 있음

     키가 안전하다면 사용자가 실제로 서명했다는 것을 확신할 수 있음

 

     활용

가)    계약서에 서명

     1999 7월부터 전자서명법이 발효됨

     기존의 일반 종이문서에 사용되는 인감이나 서명과 같은 법적 효력을 갖게 됨

나)    이메일 서명

     S/MIME PGP를 사용해서 개인 키로 이메일을 서명할 수 있음

다)    타임서버 생성

     타임 스탬프는 데이터에 시간과 함께 서명해서 어떤 특정 시간에 정보가 존재했는지를 증명

라)    서버 승인

     요청에 서명을 하면 사용자가 서버가 특정한 개인 키를 가졌는지 확인 가능

 

     RSA vs. DSA

가)    RSA

     서명을 검증하는데 빠름

 

나)    DSA(Digital Signature Algorithm)

     RSA에서 서명하는 것과 비슷하지만 암호화 기능은 없음

     서명을 만드는데 빠름

 

     자바의 전자 서명

가)    java.security.Signature

     getInstance() : 알고리즘 이름을 인자로 해서 객체의 인스턴스 획득

     initSign() : 개인 키를 인자로 서명

     initVerify() : 공개 키를 인자로 검증

     update() : 데이터를 전달하여 서명/검증을 수행

     sign() : 전자서명을 반환

     verify() : 전자서명의 유효성을 반환

 

     간단한 전자서명 예제

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.Signature;

import java.security.SignatureException;

 

import com.Ostermiller.util.Base64;

 

public class SignatureExample {

 

       public static void main(String[] args) throws Exception{

             //RSA 생성

             System.out.println("RSA 생성...");

             KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");

             kpg.initialize(1024);

             KeyPair keyPair = kpg.genKeyPair();

             System.out.println("RSA 생성 완료");

            

             // 서명할 데이터

             byte[] data = "i love you.".getBytes("UTF-8");

            

             // 서명을 위해 Signatrue 객체 생성 개인 키로 초기화

             Signature sig = Signature.getInstance("MD5WithRSA");

             sig.initSign(keyPair.getPrivate());

             sig.update(data);

             // 실제 서명

             byte[] signaturedBytes = sig.sign();

             System.out.println("전자서명된 데이타 : " + Base64.encode(signaturedBytes));

            

             // 전자서명 검증

             sig.initVerify(keyPair.getPublic());

             sig.update(data);

             boolean verified = false;

             try {

                    verified = sig.verify(signaturedBytes);

             } catch (SignatureException e) {

                    verified = false;

                    System.out.println("전자서명 형식에 문제가 발생하였습니다.");

                    e.printStackTrace();

             }

            

             if(verified)

                    System.out.println("전자서명 검증 성공");

             else

                    System.out.println("전자서명 검증 실패");

 

       }

 

}

 

     전자 서명의 한계

가)    검증을 위해서 공개 키가 필요

나)    공개 키의 소유자를 확신하기가 힘듬

다)    전자 인증서로 문제 해결

 

Posted by 으랏차
,

RSA 암호화

카테고리 없음 2015. 11. 5. 10:57

RSA 파일 암호화

 

     RSA 키 쌍 생성

 

     공개 키로 파일을 암호화

가)    RSA 키의 인코딩

     X.509를 사용하여 인코딩 사용(공개 키와 인증서를 전달할 때 사용하는 공개 형식)

     개인 키는 PKCS#8로 인코딩

     공개/개인 키든 getEncoded()를 호출하면 자동으로 인코딩 됨

나)    RSA 키의 디코딩

     인코딩된 키의 스펙 객체를 생성

     KeyFactory를 사용하여 적절한 키 타입의 인스턴스를 활성화

     공개 키 디코딩

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);

PublicKey publicKey = keyFactory.generatePublic(keySpec);

 

     개인 키의 디코딩

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);

PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

 

다)    암호화된 파일 형식

     포맷

키의 길이

암호화된 키

초기화백터(16바이트)

암호문서

 

라)    예제

private static void createKey(String password) throws Exception {

             // RSA 생성

             KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

             keyPairGenerator.initialize(1024);

             KeyPair keyPair = keyPairGenerator.genKeyPair();

            

             //공개키를 파일에 쓴다.

             byte[] publicKeyBytes = keyPair.getPublic().getEncoded();

             FileOutputStream fos = new FileOutputStream("c:\\publicKey");

             fos.write(publicKeyBytes);

             fos.close();

            

             // 개인 키를 암호화한 후에 파일에 쓴다.

             byte[] privateKeyBytes = passwordEncrypt(password.toCharArray(), keyPair.getPrivate().getEncoded());

             fos = new FileOutputStream("c:\\privateKey");

             fos.write(publicKeyBytes);

             fos.close();

       }

      

       private static byte[] passwordEncrypt(char[] password, byte[] plaintext) throws Exception {

             // salt 생성

             byte[] salt = new byte[9];

             Random random = new Random();

             random.nextBytes(salt);

            

             // PBE 키와 사이퍼 생성

             PBEKeySpec keySpec = new PBEKeySpec(password);

             SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwofish-CBC");

             SecretKey key = keyFactory.generateSecret(keySpec);

             PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);

            

             Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC");

             cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

            

             byte[] cipherText = cipher.doFinal(plaintext);

            

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

             baos.write(salt);

             baos.write(cipherText);

            

            

             return baos.toByteArray();

       }

      

       private static void encrypt(String fileInput) throws Exception {

             String publicKeyFileName = "c:\\publicKey";

             // 공개 키가 저장된 파일로부터 keyByte 바이트 배열을 생성한다.

             FileInputStream fis = new FileInputStream(publicKeyFileName);

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

            

             int theByte = 0;

             while((theByte = fis.read()) != -1)

                    baos.writeTo(baos);

             fis.close();

            

             byte[] keyBytes = baos.toByteArray();

             baos.close();

            

             // 인코딩된 키를 RSA 공개 키의 인스턴스로 바꾼다.

             X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

             KeyFactory keyFactory = KeyFactory.getInstance("RSA");

             PublicKey publicKey = keyFactory.generatePublic(keySpec);

            

             String fileOutput = fileInput + ENCRYPTED_FILENAME_SUFFIX;

             DataOutputStream output = new DataOutputStream(new FileOutputStream(fileOutput));

            

             // RSA 공개 키를 이용하여 세션 키를 암호화할 사이퍼를 생성한다.

             Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

             rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);

            

             // 세션 생성

             KeyGenerator rijndaelKeyGenerator = KeyGenerator.getInstance("Rijndael");

             rijndaelKeyGenerator.init(256);

             Key rijndaelKey = rijndaelKeyGenerator.generateKey();

            

             // RSA 사이퍼를 이용하여 세션 키를 암호화 하고 파일에 저장한다.

             // 키의 길이, 인코딩된 세션 형식이다.

             byte[] encodedKeyBytes = rsaCipher.doFinal(rijndaelKey.getEncoded());

             output.writeInt(encodedKeyBytes.length);

             output.write(encodedKeyBytes);

            

             // 초기화 벡터

             SecureRandom random = new SecureRandom();

             byte[] iv = new byte[16];

             random.nextBytes(iv);

            

             //IV 파일에 쓴다

             output.write(iv);

            

             //IV 생성한 세션 키를 이용하여 파일의 내용을 암호화한다.

             IvParameterSpec spec = new IvParameterSpec(iv);

             Cipher symmetricCipher = Cipher.getInstance("Rijndael/CBC/PKCS5Padding");

             symmetricCipher.init(Cipher.ENCRYPT_MODE, rijndaelKey, spec);

             CipherOutputStream cos = new CipherOutputStream(output, symmetricCipher);

            

             FileInputStream input = new FileInputStream(fileInput);

             theByte = 0;

             while((theByte = input.read()) != -1)

                    cos.write(theByte);

            

             input.close();

             cos.close();

             return;

       }

 

     개인 키로 복호화

가)    예제

private static byte[] passwordDecrypt(char[] password, byte[] ciphertext) throws Exception {

             // salt 읽는다. 개인키는 8byte salt 사용했다.

             byte[] salt = new byte[8];

             ByteArrayInputStream bais = new ByteArrayInputStream(ciphertext);

             bais.read(salt, 0 ,8);

            

             byte[] remainingCiphertext = new byte[ciphertext.length-8];

             bais.read(remainingCiphertext, 0, ciphertext.length-8);

            

             //PBE 사이퍼를 생성하여 세션 키를 복원한다.

             PBEKeySpec keySpec = new PBEKeySpec(password);

             SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwofish-CBC");

             SecretKey key = keyFactory.generateSecret(keySpec);

             PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);

             Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC");

            

             // 복호화

             cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

             return cipher.doFinal(remainingCiphertext);

       }

      

       private static void decrypt(String password, String fileInput) throws Exception {

             String privateKeyFilename = "c:\\privateKey";

             // 파일로부터 개인 키를 읽어들인다.

             FileInputStream fis = new FileInputStream(privateKeyFilename);

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

            

             int theByte = 0;

             while((theByte = fis.read()) != -1)

                    baos.write(theByte);

             fis.close();

             byte[] keyByte = baos.toByteArray();

             baos.close();

            

              // 암호화된 개인 바이트를 복원한다.

             keyByte = passwordDecrypt(password.toCharArray(), keyByte);

            

             // RSA 개인 키를 복원한다.

             PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyByte);

             KeyFactory keyFactory = KeyFactory.getInstance("RSA");

             PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

            

             // 개인 키를 이용하여 사이퍼를 생성하고 세션 키를 복호화한다

             Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

             DataInputStream dis = new DataInputStream(new FileInputStream(fileInput));

             byte[] encryptedKeyBytes = new byte[dis.readInt()];

             dis.readFully(encryptedKeyBytes);

            

             rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);

             byte[] rijndaelKeyByte = rsaCipher.doFinal(encryptedKeyBytes);

            

             SecretKey rijndaelKey = new SecretKeySpec(rijndaelKeyByte, "Rijndael");

            

             byte[] iv = new byte[16];

             dis.readFully(iv);

             IvParameterSpec spec = new IvParameterSpec(iv);

            

             Cipher cipher = Cipher.getInstance("Rijndael/CBC/PKCS5padding");

             cipher.init(Cipher.DECRYPT_MODE, rijndaelKey, spec);

             CipherInputStream cis = new CipherInputStream(dis, cipher);

            

             FileOutputStream fos = new FileOutputStream(fileInput + DECRYPTED_FILENAME_SUFFIX);

            

             theByte = 0;

             while((theByte = cis.read()) != -1)

                    fos.write(theByte);

            

             cis.close();

             fos.close();

            

             return;     

       }

 

나)    복호화 과정

 

     세션 키 암호화를 사용해야 하는 이유

가)    해킹에 대비해, 개인 키를 저장할 때 암호화할 필요가 있다.

나)    세션 키를 사용하면 속도가 훨씬 빨라진다.

다)    RSA는 특정 메시지에 대해서 매우 취약하다.

 

Posted by 으랏차
,

Session key

UP!/Crypto 2015. 11. 5. 10:56

세션 키 암호화

 

     개념

가)    비대칭 암호화는 대칭 암호화보다 1000배 느림

나)    메시지는 대칭 키로 암호화하고 이 대칭 키가 수신자의 공개키로 암호화됨

다)    암호화된 공개 키는 메시지에 덧붙여서 수신자에게 전달됨

 

 

     예제

 

 import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class SimpleRSAExample {
 public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
  String plainText = "iloveyou";
  // 대칭 키 생성
  KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
  keyGenerator.init(128);
  Key blowfishKey = keyGenerator.generateKey();
  
  Cipher blowfishCipher = Cipher.getInstance("Blowfish/ECB/PKCS5padding");
  blowfishCipher.init(Cipher.ENCRYPT_MODE, blowfishKey);
  
  byte[] ciphertext = blowfishCipher.doFinal(plainText.getBytes());
  
  System.out.println("암호화된 문서 : " + ciphertext);
  
  // RSA 키 쌍 생성
  KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
  keyPairGenerator.initialize(1024);
  KeyPair keyPair = keyPairGenerator.genKeyPair();
  
  Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  rsaCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
  
  //대칭 키의 바이트 획득
  byte[] blowfishKeyBytes = blowfishKey.getEncoded();
  
  // 대칭 키 바이트를 RSA 개인키로 암호화
  byte[] cipherKeyBytes = rsaCipher.doFinal(blowfishKeyBytes);
  
  // 수신측에서 동작한다고 가정
  // 암호화된 문서와 암호화된 대칭키가 전달된다고 가정
  // 수신자의 공개키로 키 복호화
  rsaCipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
  byte[] decryptedKeyBytes = rsaCipher.doFinal(cipherKeyBytes);
  SecretKey newBlowfishKey = new SecretKeySpec(decryptedKeyBytes, "Blowfish");
  
  // 복호화된 대칭키로 전달된 암호문 복호화
  blowfishCipher.init(Cipher.DECRYPT_MODE, newBlowfishKey);
  byte[] decryptedText = blowfishCipher.doFinal(ciphertext);
  
  System.out.println("복호화된 문서 : " + new String(decryptedText));
 }

}

 

'UP! > Crypto' 카테고리의 다른 글

MAC  (0) 2015.11.05
MessageDigest  (0) 2015.11.05
대칭키 암호화  (0) 2015.11.05
패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
Posted by 으랏차
,