'분류 전체보기'에 해당되는 글 304건

  1. 2015.11.05 전자서명
  2. 2015.11.05 MAC
  3. 2015.11.05 MessageDigest
  4. 2015.11.05 RSA 암호화
  5. 2015.11.05 Session key
  6. 2015.11.05 대칭키 암호화
  7. 2015.11.05 패스워드 기반 암호화
  8. 2015.11.05 JCA, JCE
  9. 2015.11.05 인증, 전자서명
  10. 2015.11.05 대칭 비대칭 암호화

전자서명

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 으랏차
,

MAC

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

메시지 인증 코드(MAC)

 

     내용

가)    키가 있는 메시지 다이제스트

나)    안전하지 않은 네트워크를 통해 수신된 데이터를 인증할 때

다)    수신자와 송신자가 비밀 키를 교환하여 이 키를 이용하여 검증

라)    SSL에 많이 사용됨

마)    비밀 키를 공유해야 하는 것이 문제

바)    수신측에서 데이터 검증

사)    HMAC(Hashed Message Authentication Code)라 불리는 암호화 해쉬 함수에 기반

아)    Sun JCE에서 제공하는 HMAC 함수

     HmacMD5

     HmacSHA1

 

     사용방법

가)    javax.crypto.Mac

     Cipher MessageDigest가 합쳐진 것

 

나)    예제

import java.security.SecureRandom;

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

import com.Ostermiller.util.Base64;

 

public class MACExample {

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

             SecureRandom random = new SecureRandom();

             byte[] keyBytes = new byte[20];

             random.nextBytes(keyBytes);

             SecretKeySpec key = new SecretKeySpec(keyBytes, "HMACSHA1");

             System.out.println("Key: " + Base64.encode(key.getEncoded()));

             //Mac 인스턴스를 획득하고 초기화한다.

             Mac mac = Mac.getInstance("HmacSHA1");

             mac.init(key);

             mac.update("I LOVE YOU!".getBytes("UTF8"));

             byte[] result = mac.doFinal();

            

             System.out.println("MAC: " + Base64.encode(result));

       }

}

 

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

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

MessageDigest

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

자세한 내용을 알고 싶은 분은 다음의 블로그를 참조하세요

http://blog.naver.com/dury00?Redirect=Log&logNo=130044978311

 

     내용

가)    일종의 데이터 지문

나)    데이터가 바뀌지 않았다는 것을 증명

다)    데이터의 길이에 상관없이 보통 16 또는 20byte

라)    FTP파일 검증에 많이 사용

마)    해쉬를 이용

바)    한 방향 변환이고 역으로는 불가능

 

     자바에서의 메시지 다이제스트 사용

가)    java.security.MessageDigest

     getInstance()로 인자 생성

     MD5, SHA-1이 주로 사용됨

 

나)    update()

     데이터를 해쉬 함

 

다)    digest()

     바이트 배열로 해쉬를 반환

     적은 데이터일 경우 digest에 직접 입력 가능

 

라)    파일의 메시지 다이제스트 계산

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.io.IOException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

 

import com.Ostermiller.util.Base64;

 

public class DigestFile {

 

       public static void main(String[] args) throws NoSuchAlgorithmException, IOException {

             MessageDigest md = MessageDigest.getInstance("MD5");

             BufferedInputStream in = new BufferedInputStream(new FileInputStream("c:\\test.txt"));

            

             int theByte = 0;

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

                    md.update((byte)theByte);

            

             in.close();

             byte[] theDigest = md.digest();

            

             System.out.println(Base64.encode(theDigest));

 

       }

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 마)    실행결과

     test.txt 파일에는 ‘this is a test file’이 들어 있음 : [B@1a758

     ‘this is a test file.’로 수정한 결과 : [B@1b67f74

 

바)    스트림에서의 메시지 다이제스트

     DigestInputStream & DigestOutputStream

MessageDigest messageDigest = MessageDigest.getInstance(“MD5”);

DigestOutputStream output = new

DigestOutputStream(existingOutputStream, messageDigest);

 

     출력에 쓰는 모든 바이트가 자동으로 메시지 다이제스트를 계산할 때 사용됨

     예제

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.security.DigestInputStream;

import java.security.MessageDigest;

 

import com.Ostermiller.util.Base64;

 

public class DigestStreamExample {

 

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

             MessageDigest md = MessageDigest.getInstance("MD5");

             BufferedInputStream in = new BufferedInputStream(new FileInputStream("c:\\test.txt"));

            

             //DigestInputStream 생성한다.

             DigestInputStream digestIn = new DigestInputStream(in, md);

             // 모든 데이터를 읽어들인다.

             while(digestIn.read() != -1);

             byte[] theDigest = md.digest();

            

             System.out.println(Base64.encode(theDigest));

       }

}

 

 

     패스워드 인증

가)    의미

     패스워드를 해쉬하여 저장할 경우 복호화는 불가능하지만 모든 가능한 패스워드를 해쉬한 다음 비교해서 추즉하는게 가능함

     이런 공격을 막기 위해 salt와 패스워드를 같이 저장해야 함

     서버가 실제 패스워드를 알 필요 없이 사용자가 정한 패스워드를 검증하는게 목적

 

 

나)    패스워드 저장

     랜덤 salt 생성하여 패스워드 앞에 붙임

     이것을 해쉬함

     패스워드 입력될 때마다 비교를 위해 salt와 해쉬 결과를 붙여서 저장

 

 

다)    패스워드 인증

     저장된 패스워드의 salt와 사용자가 입력한 패스워드를 합친다.

     salt와 패스워드를 해쉬한다.

     결과 해쉬값을 파일에 저장된 것을 비교한다. 같다면 패스워드가 같은 것이다.

 

라)    예제

import java.io.ByteArrayOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.security.MessageDigest;

import java.security.SecureRandom;

import java.util.Arrays;

 

public class Passwordauthenticator {

 

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

             createPassword("iloveyou");

             authenticatePassword("iloveyou");

 

       }

      

       private static void createPassword(String password) throws Exception {

             // salt 생성

             SecureRandom random = new SecureRandom();

             byte[] salt = new byte[12];

             random.nextBytes(salt);

            

             // salt 패스워드를 붙여서 해쉬한다.

             MessageDigest md = MessageDigest.getInstance("MD5");

             md.update(salt);

             md.update(password.getBytes("UTF-8"));

             byte[] digest = md.digest();

            

             // salt 해쉬 결과를 파일에 저장한다.

             FileOutputStream fos = new FileOutputStream("c:\\password.txt");

             fos.write(salt);

             fos.write(digest);

             fos.close();

       }

      

       private static void authenticatePassword(String password) throws Exception {

             // 파일을 읽어들인다.

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

             FileInputStream fis = new FileInputStream("c:\\password.txt");

             int theByte = 0;

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

                    baos.write(theByte);

             fis.close();

             byte[] hashedPasswordWithSalt = baos.toByteArray();

             baos.reset();

            

             //salt 얻는다.

             byte[] salt = new byte[12];

             System.arraycopy(hashedPasswordWithSalt, 0, salt, 0, 12);

            

             // salt 입력한 패스워드를 붙여서 해쉬한다.

             MessageDigest md = MessageDigest.getInstance("MD5");

             md.update(salt);

             md.update(password.getBytes("UTF-8"));

              byte[] digest = md.digest();

            

             // 파일에 있는 내용과 비교한다.

             byte[] digestInFile = new byte[hashedPasswordWithSalt.length-12];

             System.arraycopy(hashedPasswordWithSalt, 12, digestInFile, 0, hashedPasswordWithSalt.length-12);

            

             if(Arrays.equals(digest, digestInFile))

                    System.out.println("Password matches.");

             else

                    System.out.println("Password does not matches.");

       }

}

 

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

MAC  (0) 2015.11.05
Session key  (0) 2015.11.05
대칭키 암호화  (0) 2015.11.05
패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
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 으랏차
,

대칭키 암호화

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

     키의 저장

파일 시스템 안에 키를 저장할 경우 이에 대한 보안이 필요

가)    키 래핑(Wrapping)과 언래핑(Unwrapping)

     wrap() 함수 : Cipher 클래스에 있는 함수로 키를 매개변수로 받아서 암호화된 키의 바이트 배열을 반환

cipher.init(Cipher.WRAP_MODE, passwordKey, paramSpec);

byte[] encryptedKeyBytes = cipher.wrap(secretKey);

 

     unwrap() : 암호화된 키의 바이트 배열을 Key로 반환

cipher.init(Cipher.UNWRAP_MODE, passwordKey, paramSpec);

Key key = cipher.unwrap(encryptedKeyBytes, “Blowfish”, Cipher.SECRET_KEY);

 

나)    래핑을 하지 않는 키 암호화

     wrap() unwrap()이 없다면 Key.getEncoded(), SecretKeySpec을 이용해 암호화

     java.security.Key : 암호화된 키의 바이트 배열을 반환

byte[] keyBytes = myKey.getBytes();

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

byte[] encryptedKeyBytes = cipher.doFinal(keyBytes);

 

     SecretKeySpec : 키를 복호화

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

byte[] keyBytes = cipher.doFinal(encryptedKeyBytes);

SecretKeySpec myKey = new SecretKeySpec(keyBytes, “Blowfish”);

 

     사이퍼 스트림(CipherStream)

가)    표준 입/출력 스트림을 암/복호화를 위한 래퍼 클래스를 제공

     CipherInputStream

     CipherOutputStream

 

나)    예제

 FileInputStream input = new FileInputStream(“plaintext_filename”);

FileOutputStream output = new FileOutputStream(“ciphertext_filename”);

CipherOutputStram cipherOutput = new CipherOutputStream(output, cipher);

int r = 0;

while((r=input.read()) != null)

   cipherOutput.write(r);

cipherOutput.close();

output.close();

input.close();

 


     IV로 사이퍼 초기화

초기화 백터의 바이트를 생성하기 위해 java.security.SecureRandom을 이용

가)    SecureRandom

    

 byte[] randomBytes = new byte[8];

SecureRandom random = new SecureRandom();

random.nextBytes(randomBytes);

 

 

          나) IV 생성과 사용

     생성

IVParameterSpec iv = new IVParameterSpec(randomBytes);

 

     사용

Cipher cipher = Cipher.getInstance(“Blowfish/CBC/PCS5PADDing”);

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

 

다)    IV 추적

     복호화 할 때에도 동일한 IV가 사용되어야 함

     salt와 매우 비슷하며 숨길 필요 없이 암호문에 붙여서 사용함

 

     사이퍼 스트림 예제 파일 인코더

가)    사이퍼 스트림을 이용해 파일을 암/복호화

나)    키는 패스워드 기반 암호화로 파일에 저장 및 복호화

다)    4개의 기능을 포함

     createKey() : AES 키를 생성 하고 패스워드를 이용하여 암호화하여 파일에 저장

/**

        * 1. 256bit AES(Rijndael)키를  생성

        * 2. PBE 이용하여 생성한 키를 암호화하여 파일에 저장

        */

       private static void createKey(char[] password) {

             System.out.println("Generating a RijnDael key...");

             // AES 대칭 생성기 객체 생성

             KeyGenerator keyGenerator = null;

             try {

                    keyGenerator = KeyGenerator.getInstance("Rijndael");

             } catch (NoSuchAlgorithmException e) {}

             // AES 생성

             keyGenerator.init(256);

             Key key = keyGenerator.generateKey();

             System.out.println("Done generating the key");

            

             // PBE 시작

             // salt 생성

             byte[] salt = new byte[8];

             SecureRandom random = new SecureRandom();

             random.nextBytes(salt);

            

             // password PBEKeySpec 생성

             PBEKeySpec pbeKeySpec = new PBEKeySpec(password);

             SecretKeyFactory keyFactory = null;;

             SecretKey pbeKey = null;

             try {

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

                    pbeKey = keyFactory.generateSecret(pbeKeySpec);

             } catch (NoSuchAlgorithmException e) {}

             catch (InvalidKeySpecException e) {}

             // PBEParameterSpec 생성

             PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, ITERATIONS);

             // Cipher 생성 초기화

             Cipher cipher = null;

             byte[] encryptedKeyBytes = null;

             try {

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

                    cipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

                   

                    // AES 암호화

                    encryptedKeyBytes = cipher.doFinal(key.getEncoded());

             } catch (NoSuchAlgorithmException e) {}

             catch (NoSuchPaddingException e) {}

             catch (InvalidKeyException e) {}

             catch (InvalidAlgorithmParameterException e) {}

             catch (IllegalBlockSizeException e) {}

             catch (BadPaddingException e) {}

            

             FileOutputStream fos;

             try {

                    fos = new FileOutputStream(KEY_FILENAME);

                    //salt 암호화된 바이트를 쓴다.

                    fos.write(salt);

                    fos.write(encryptedKeyBytes);

                    fos.close();

             } catch (FileNotFoundException e) {}

             catch (IOException e) {}

       }

 

     loadKey() : 키가 저장된 파일로부터 읽어들여 복호화하여 키를 생성

private static Key loadKey(char[] password) throws Exception {

             // 파일로부터 읽어들임

             FileInputStream fis = new FileInputStream(KEY_FILENAME);

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

             int i = 0;

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

                    baos.write(i);

             fis.close();

             byte[] saltAndKeyBytes = baos.toByteArray();

             baos.close();

             // salt 분리함. Base64 인코딩을 하지 않았기에 8byte 그대로 유지됨

             byte[] salt = new byte[8];

             System.arraycopy(saltAndKeyBytes, 0, salt, 0, 8);

            

             // key 분리함

             int length = saltAndKeyBytes.length - 8;

             byte[] encryptedKeyBytes = new byte[length];

             System.arraycopy(saltAndKeyBytes, 8, encryptedKeyBytes, 0, length);

            

             // PBE 시작

             PBEKeySpec pbeKeySpec = new PBEKeySpec(password);

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

             SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);

             PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, ITERATIONS);

             // Cipher 생성 초기화

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

             cipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);

             // 복호화

             byte[] decryptedKeyBytes = cipher.doFinal(encryptedKeyBytes);

             SecretKeySpec key = new SecretKeySpec(decryptedKeyBytes, "Rijndael");

            

             return key;

       }

 

     encrypt() : 사이퍼 스트림을 이용하여 암호화 수행

private static void encrypt(char[] passowrd, String fileInput, String fileOutput) throws Exception {

             // key 로드

             System.out.println("Loading the key.");

             Key key = loadKey(passowrd);

             System.out.println("Loaded the key.");

            

             // 사이퍼 생성

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

             System.out.println("Initializing SecureRandom...");

             // SecureRandom 생성하여 IV 초기화

             SecureRandom random = new SecureRandom();

             byte[] iv = new byte[16];

             random.nextBytes(iv);

             // 입력 파일과 출력 파일의 stream 연다

             FileInputStream fis = new FileInputStream(fileInput);

             FileOutputStream fos = new FileOutputStream(fileOutput);

            

             // 먼저 출력파일에 iv 쓴다.

             fos.write(iv);

             // IvParameterSpec 생성하고 사이퍼를 생성 초기화한다.

             IvParameterSpec spec = new IvParameterSpec(iv);

             System.out.println("Initializing the cipher...");

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

             // 출력 스트림과 사이퍼를 인자로 사이퍼 스트림을 생성한다.

             CipherOutputStream cos = new CipherOutputStream(fos, cipher);

            

             System.out.println("Encrypting the file");

             // 입력 파일로부터 읽어들여 사이퍼 스트림에다 쓴다.

             int theByte = 0;

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

                    cos.write(theByte);

             // 스트림을 모두 닫아준다.

             fis.close();

             cos.close();

       }

 

     decrypt() : 사이퍼 스트림을 이용하여 복호화 수행

private static void decrypt(char[] password, String fileInput, String fileOutput) throws Exception {

             // key 로드

             System.out.println("Loading the key");

             Key key = loadKey(password);

             System.out.println("Loaded the key.");

             // 사이퍼 생성

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

             // 입력 파일과 출력 파일의 stream 연다

             FileInputStream fis = new FileInputStream(fileInput);

             FileOutputStream fos = new FileOutputStream(fileOutput);

             // 입력파일에서 초기화 벡터 16byte 읽어들인다.

             // Base64인코딩을 하지 않았으므로 길이는 그대로다.

             byte[] iv = new byte[16];

             fis.read(iv);

             // IvParameterSpec 생성 사이퍼 초기화

             IvParameterSpec spec = new IvParameterSpec(iv);

             System.out.println("Initializing the cipher...");

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

             // 입력파일과 사이퍼를 인자로 사이퍼 스트림을 생성한다.

             CipherInputStream cis = new CipherInputStream(fis, cipher);

             System.out.println("Decrypting the file...");

             // 입력파일로 부터 읽어들여 출력파일에 쓴다.

             int theByte = 0;

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

                    fos.write(theByte);

             // 스트림을 모두 닫아준다.

             cis.close();

             fos.close();

       }

 

     봉인 객체

가)    사이퍼 또는 키로 객체를 암호화할 수 있는 방법을 제공

나)    암호화 객체 또는 봉인 객체라 불림

다)   

import java.io.IOException;

import java.security.InvalidKeyException;

import java.security.Key;

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.SealedObject;

 

public class SealedObjectExample {

 

       public static void main(String[] args) {

             String creatiCard = "1234567890";

            

             try {

                    KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");

                   

                    Key key = keyGenerator.generateKey();

                    Cipher cipher = Cipher.getInstance("DESede");

                    cipher.init(Cipher.ENCRYPT_MODE, key);

                   

                    System.out.println("Encrypting the Object");

                    SealedObject so = new SealedObject(creatiCard, cipher);

                    System.out.println("Decrypting the Object");

                    //String decryptedCrediteCard = (String) so.getObject(key);

                   

                    cipher.init(Cipher.DECRYPT_MODE, key);

                    String decryptedCrediteCard = (String) so.getObject(cipher);

                    System.out.println("Credit card Number : " + decryptedCrediteCard);

                   

             } catch (NoSuchAlgorithmException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

             } catch (NoSuchPaddingException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

             } catch (InvalidKeyException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

             } catch (IllegalBlockSizeException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

             } catch (IOException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

             } catch (ClassNotFoundException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

             } catch (BadPaddingException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

             }

 

       }

 

}

 

 

 

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

MessageDigest  (0) 2015.11.05
Session key  (0) 2015.11.05
패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
인증, 전자서명  (0) 2015.11.05
Posted by 으랏차
,

패스워드 기반 암호화(PBE : Password-Based Encryption)

 

1  설명

   가) 패스워드를 키로 사용하는 방법

   나) 키 스페이스가 TripleDES나 Blowfish보다 훨씬 작아 안전하지 못함

   다) 사전공격에 취약함

   라) 해쉬와 일반적인 대칭 암호화를 사용함

   마) 미리 패스워드 해쉬 목록을 만들어 놓고 복호화 할 수 있음

   바) salting와 iteration counts를 도입하여 보안성 강화

 

2  방법

   가) 패스워를 MD5로 해쉬를 구한 다음 이 값을 암호화 키 값으로 사용한다. 

 

3  Salt

   가) 패스워드를 해쉬하기 전에 랜덤값을 추가하여 키 스페이스를 늘린다.

   나) salt는 암호문과 함께 저장된다.

   다) 복호화할 때는 암호화된 데이터로부터 salt를 분리해야 한다.

   라) salt는 매번 다르게 생성되며 동일한 문장에 대해서도 다른 값이 생성된다.

 

4  Iteration count

   가) 해쉬의 횟수를 의미함

   나) Iteration count가 1000이면 1000번을 해쉬한다는 의미

 

5  암호화/복호화 방법

   가) 패스워드와 salt를 생성하여 보통문서를 암호화하고 생성된salt를 암호문서 앞에 붙인다.

 

   나) 암호화된 데이타를 salt와 암호문서로 나누어 패스워드와 salt로 암호 문서를 복호화 한다.

 

 

6  주요 클래스 사용법

   가) PBEKeySpec : SecretKeyFactory의 인스턴스를 이용해서 패스워드기반 키를 생성한다.

 char[] password = “iloveyou”.toCharArry();

PBEKeySpec keySpec = new PBEKeySpec(password)

 

   나) SecretKeyFactory : PBEKeySpec을 실제 키로 사용하기 위해 generateSecret()를 실행시켜 줘야 한다.

 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(“PBEWithShAAndTwoFish-CBC”);

SecretKey theKey = keyFactory.generateSecret(keySpec);

 

   다) PBEParameterSpec : salt와 interation count를 위한 레퍼런스

 PBEParameterSpec paramSpec = new PBEParameterSpec(salt, iterations);

Cipher cipher = Cipher.getInstance(“PBEWithShAAndTwoFish-CBC”);

Cipher.init(Cipher.ENCRYPT_MODE, theKey, paramSpec);

 

7  PBE 알고리즘

   가) PBEWithMD5AndDES 

   나) PBEWithSHAAndBlowfish

   다) PBEWithSHAAnd128BitRC4

   라) PBEWithSHAAndDEA-CBC

   마) PBEWithSHAAnd3-KeyTripleDES-CBC

 

8  PBE 예제

 

 import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import com.Ostermiller.util.Base64;

public class PBE {

 private static int ITERATIONS = 1000;
 
 public static void main(String[] args) {
  char[] password = "iloveyou".toCharArray();
  String text = "i love you! but you don't. i sad b.b";
  String output = null;
  
  System.out.println("평문 : " + text);
  try {
   output = encrypt(password, text);
   System.out.println("암호문 : " + output);
   System.out.println("복호문 : " + decrypt(password, output));
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 private static String encrypt(char[] password, String plaintext) throws Exception {
  // 1. salt를 8byte 랜덤 생성
  byte[] salt = new byte[8];
  Random random = new Random();
  random.nextBytes(salt);
  
  // 2. 패스워드를 이용하여 PBEKeySpec 생성
  PBEKeySpec keySpec = new PBEKeySpec(password);
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwoFish-CBC");
  
  // 3. 비밀키 생성
  SecretKey key = keyFactory.generateSecret(keySpec);
  
  // 4. salt, iteration count를 위한 PBEParameterSpec 생성
  PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);
  
  // 5. Cipher 생성 및 초기화
  Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwoFish-CBC");
  cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
  
  // 6. 암호문 생성
  byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
  
  // 7. salt와 암호문을 Base64 인코딩 후 결합하여 최종 결과물 생성
  String saltString = Base64.encodeToString(salt);
  String ciphertextString = Base64.encodeToString(ciphertext);
  
  return saltString+ciphertextString;
  
 }
 
 private static String decrypt(char[] password, String text) throws Exception {
  
  // 1. 8byte를 Base64인코딩하면 12byte가 생성된다.
  String salt = text.substring(0, 12);
  String ciphertext = text.substring(12, text.length());
  
  // 2. salt와 암호문을 Base64 디코딩하여 원래 상태로 되돌린다.
  byte[] saltArry = Base64.decodeToBytes(salt);
  byte[] ciphertextArry = Base64.decodeToBytes(ciphertext);
  
  // 3. 패스워드를 이용하여 PBEKeySpec 생성
  PBEKeySpec keySpec = new PBEKeySpec(password);
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwoFish-CBC");
  
  // 4. 비밀 키 생성
  SecretKey key = keyFactory.generateSecret(keySpec);
  
  // 5. salt, iteration count를 위한 PBEParameterSpec 생성
  PBEParameterSpec paramSpec = new PBEParameterSpec(saltArry, ITERATIONS);
  
  // 6. Cipher 생성 및 초기화
  Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwoFish-CBC");
  cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
  
  // 7. 평문생성
  byte[] plaintextArry = cipher.doFinal(ciphertextArry);
  
  return new String(plaintextArry);
 }

}

 

 

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

Session key  (0) 2015.11.05
대칭키 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
인증, 전자서명  (0) 2015.11.05
대칭 비대칭 암호화  (0) 2015.11.05
Posted by 으랏차
,

JCA, JCE

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

JCA & JCE

     설명

가)    JCA Runtime enviroment의 일부

나)  JCE JDK에 들어 있지 않은 JCA의 확장팩

나)    JDK JCA에 정의된 특정한 암호 함수만 사용 가능

 

     JCA

가)    전자 서명과 메시지 다이제스트 같은 기능에 대한 일반적인 API 제공

 

나)    주요 클래스들

     MessageDigest

     Signature

     KeyPaireGenerator

     KeyFactory

     CertificateFactory

     KeyStore

     AlgorithmParameters

     AlgorithmParameterGenerator

     SecureRandom

 

다)    암호 서비스 제공자 Sun Provider(Java 2 기준, sun.security.provider.Sun)

     MD5 메시지 다이제스트

     SHA-1 메시지 다이제스트

     DSA 전자 서명 사인과 검증

     DSA 키 쌍 생성

     DSA 키 변환

     X.509 인증서 생성

     Proprietary keystore 구현

     DSA 알고리즘 매개변수

     DSA 알고리즘 매개변수 생성

 

라)    암호 서비스 제공자 RSAJAC provider(com.sun.rsajca.Provider)

     RSA 키 쌍 생성

     RSA 키 변환

     SHA-1 또는 MD5 메시지 다이제스트를 이용한 RSA 서명

 

마)    JCA 접근

 MessageDigest myMessageDigest = MessageDigest.getInstance(“MD5”);

myMessageDigest.update(myData);

byte[] signatureBytes = myMessageDigest.digest();

 

 

     JCE(javax.crypto)

가)    주요 클래스와 인터페이스

     Cipher

     KeyAgreement

     KeyGenerator

     Mac

     SecretKey

     SecretKeyFactory

 

나)    JCE 접근 

KeyGenerator keyGenerator = KeyGenerator.getInstance(“Blowfish”);

Key key = keyGenerator.generatorKey();

Cipher cipher = Cipher.getInstance(“Blowfish/ECB/PKCS5Padding”);

cipher.init(Cipher.ENCRYPT_MODE, key);

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

  

다)    JCE 설치

이름

BouncyCastle

URL

http://www.bouncycastle.org

라이선스

오픈소스

참고문서

http://www.bouncycastle.org/docs/docs1.6/index.html

 

 

보통 썬의 JCE를 사용하기를 원하지만 일단 Sun JCE가 설치되고 나면 다른 것을 사용하지 못한다. Sun JCE DES, TripleDEs, Blowfish, Difie-Hellman외에는 사용할 수가 없다. 따라서 Bouncy Castle를 추천한다.

 

라)    Bouncy Castle 설치 (http://id0min.tistory.com/125 참조함)

     http://www.bouncycastle.org/latest_releases.html에서 자신의 JDK 버전에 해당되는 최신 버전을 다운로드 받는다. 다운받은 파일을 JDK JRE가 설치된 폴더에서 jre/lib/ext에 저장한다.

     양쪽 폴더에서 jre/lib/security 폴더에 있는 java.security 파일을 다음과 같이 수정한다. 숫자 10 provider 순서에 따라 수정한다.

security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider

     unrestricted policy 파일들을 다운로드 받아  양쪽 폴더에서 jre/lib/security 폴더에 local_policy.jar US_export_policy.jar 파일을 교체한다. 아래 URL에서 파일을 다운로드 받아서 풀어보면 위의 2개 파일 있다. 덮어 씌우면 된다.

     설치한 후에 동작하는지 검증한다.

 

       마)    테스트 소스

 public static void main(String[] args) {

String providerName = "BC";

KeyGenerator keyGenerator = null;

if(Security.getProvider(providerName) == null)

System.out.println(providerName + " provider not installed");

else

       System.out.println(providerName + " is installed");

// Blowfish 블록 암호화 방식

System.out.println("Attepting to get a Blowfish key...");

try {

keyGenerator = KeyGenerator.getInstance("Blowfish");

} catch (NoSuchAlgorithmException e) {

}

keyGenerator.init(128);

SecretKey key = keyGenerator.generateKey();

System.out.println("OK");

//암호화 한다

            

System.out.println("Attempting to get a Cipher and encrypt...");

Cipher cipher = null;

byte[] ciphertext = null;

try {

       cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");

} catch (NoSuchAlgorithmException e) {}

catch (NoSuchPaddingException e) {}

try {

       cipher.init(Cipher.ENCRYPT_MODE, key);

} catch (InvalidKeyException e) {}

try {

       ciphertext = cipher.doFinal("This is a test".getBytes("UTF8"));

} catch (IllegalBlockSizeException e) {}

catch (BadPaddingException e) {}

catch (UnsupportedEncodingException e) {}

System.out.println("OK");

System.out.println("Test completed successfully : " + ciphertext);

}

 

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

대칭키 암호화  (0) 2015.11.05
패스워드 기반 암호화  (0) 2015.11.05
인증, 전자서명  (0) 2015.11.05
대칭 비대칭 암호화  (0) 2015.11.05
블록 Padding  (0) 2015.11.05
Posted by 으랏차
,

인증, 전자서명

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

인증(Authentication)

 

메시지 다이제스트(Message Digest)

     기능

가)    해쉬 라고도 함

나)    메시지가 부당하게 변경되지 않았다는 것을 증명

다)    한 방향 함수

라)    패스워드 인증에도 사용됨

     방법

가)    파일과 다이제스트를 받음

나)    파일에 대해 메시지 다이제스트를 적용한 결과를 다이제스트와 비교함

     종류

가)    MD5

     RSA에서 개발

     128bit

나)    SHA, SHA-1

     Secure Hash Algorithm

     일반적으로 SHA SHA-1을 말함

     160bit

 

메시지 인증 코드(MAC:Message Authentication codes)

     기능

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

나)    ·수신 측 모두 비밀 키가 있어야 함

다)    동일한 메시지와 키는 언제나 동일한 메시지 인증 코드를 가짐

     사용

가)    보안 연결이 이미 설치된 곳에 보통 사용됨

나)    SSL은 받은 데이터를 검사하기 위해 세션을 시작할 때 교환한 비밀 키를 가지고 MAC을 사용함.

     종류

가)    HMAC(Hasing Message Authentication Codes)

     MD5 SHA-1과 같은 해시 알고리즘을 사용함

나)    HmacMD5

     키와 함께 MD5 다이제트스 알고리즘 사용

다)    HmacSHA1

     SHA-1 알고리즘 사용

 

전자서명

     기능

가)    데이터 원형에 대한 보증

나)    데이터가 변조 방지 보증

     방법

가)    서명해야 할 메시지에 대해 메시지 다이제스트 생성

나)    생성된 메시지 다이제스트를 송신자의 개인키로 암호화

다)    수신자는 전달받은 메시지에 대해 메시지 다이제스트 생성

라)    전자서명을 송신자의 공개키로 복호화한 후 다)에서 생성한 다이제스트와 비교

 

전자 인증서(Digital Certificates)

     문제점

가)    인증에 공개 키를 사용하는 것이 문제

나)    공개 키가 어떤 사람의 것인지 알 수가 없음

다)    전자서명은 수진자의 공개 키를 이용해서 서명해야 함

     기능

가)    승인된 기관의 개인 키로 서명된 개인의 공개 키와 신원을 확인하는 정보가 포함

나)    승인된 기관의 공개 키로 검증

다)    SSL 인증서는 URL을 포함하고 있어 접속 시 URL이 틀릴 경우 에러 메시지 발생

 

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

패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
대칭 비대칭 암호화  (0) 2015.11.05
블록 Padding  (0) 2015.11.05
base64 인코딩, 디코딩의 원리  (0) 2015.11.05
Posted by 으랏차
,
 

암호화(Encryption) : 메시지를 숨겨 그 메시지의 수신자 외에는 아무도 못 읽게 하는 것.

인증(Authentication) : 메시지가 바뀌지 않았는지, 혹은 발신자, 수신자가 맞는지 확인하는 것

JCA : Java Cryptography Architecture

JCE : Java Cryptography Extension

 

대칭 암호화 알고리즘

 

     블록암호와 스트림 암호

가)    블록암호화 방식

     한번에 정해진 크기의 데이터를 암호화 하는 방식

     64bit or 128 bit 크기 단위로 적용

나)    스트림 암호화 방식

     1bit or 1btye의 데이터를 암호화 하는 방식

     소켓 같은 정보의 일정한 스트림을 암호화할 때 적당

 

     대칭 암호화 깨는 방법에 대해

가)    단문 무식하게 모든 가능한 키를 시도

나)    키 스페이스 : 후보 키들의 집합이며  만큼의 후보 키가 존재한다.

 

     대칭 암호화에 사용되는 알고리즘

가)    DES(Data Encryption Standard)

     가장 널리 알려진 대칭 암호화 기법

     56bit 키 사용

     DES의 변형으로 TripleDES(DESede)가 고안됨.

나)    TripleDES(DESede)

     DES를 다른 키에 세 번 적용시키는 방식

     암호화 / 복호화 / 또 다른 암호화 -> ede(encryption, decryption, encryption)

     키는 2개 또는 3개가 사용될 수 있음

다)    Blowfish

     DES보다 더 빠르고 안전한 블록 암호

     448비트 키 사용 가능

라)    RC4(Rivest’s Code 4)

     스트림 암호의 일종으로 SSL 구현에 많이 사용됨

     40bit or 128bit

마)    AES(Advanced Encryption Standard)

     Rijndael 알고리즘 사용

     128, 192, 256 bit 사용 가능

 

     대칭 암호화의 한계

가)    암호화 복호화에 같은 키가 적용됨

나)    ·수신자 모두 동일한 키를 가지고 있어야 함

다)    키를 안전하게 전달할 수 있는 방법은 무엇인가?

 

 

비대칭 암호화

 

     기능

가)    암호화에 쓰이는 공개 키와 복호화에 쓰이는 개인 키 2개를 사용

 

     비대칭 암호화 알고리즘

가)    RSA

     키 교체가 가능 즉, 개인키로 암호화하면 공개키로 복호화 가능

나)    EIGamal

     PGP SSL에 사용

 

     약점

가)    개인 키가 쉽게 공격 받을 수 있다.

     공개 키를 다른 사람의 것으로 바꿔치기 하는 방법에 허점이 발생

     공개 키에 대한 증명서를 첨부해서 해결함

나)    속도가 느리다.

     대칭 암호화에 비해 1000배 느림

 

     세션 키 암호화

가)    세션 키를 암호화 하는데 사용하고 세션 키는 공개 키를 이용하여 암호화 함

나)    세션 키는 대칭 암호화 방법을 사용

다)    생성한 세션 키를 상대방에게 전달해야 함

라)    PGP : 이메일을 암호화하는데 사용됨

마)    S/MIME : 안전한 이메일 전송을 위해 RSA가 고안한 방법

바)    SSL/TLS : Secure Socket Layer Transport Layer Security TCP/IP 트래픽을 보안하기 위해 만들어짐

 

     키 일치(Key Agreement)

가)    상대방의 공개 키와 자신의 개인 키를 이용하여 암호화를 위한 키 생성

나)    공유 비밀 키(shared secret key)를 만들어 암호화와 복호화에 사용

다)    상대방에게 공유 비밀 키를 전달할 필요 없음

라)    Diffie-Hellman 키 일치 알고리즘

     공개-개인 키 쌍을 이용한 첫번째 알고리즘

  

암호화 알고리즘 요약

  

     암호화 알고리즘 요약

가)    알고리즘의 능력 판단 기준

     알고리즘 종류 및 키의 크기

 

나)    대칭 암호화

알고리즘

종류 

키의 크기 

참고 

 DES

블록 

56 

 가장 많이 사용되지만 너무 취약함

 TripleDES

블록

 158(유효 112)

 DES의 강화버전

 Blowfish

블록

 488까지 임의 길이

 훌륭한 보안 제공

 RC4

스트림

 보통 40 또는 128

 빠른 스트림 암호화, 대부분의 SSL 구현에 사용됨

 AES

블록

 128, 192, 256

 DES 대용의 비교적 최근 암호화 기법

 

다) 비대칭 암호화

 알고리즘

종류 

키의 크기 

참고 

 RSA

블록 

512, 1024, 2048 

가장 많이 사용되는 공개 키 알고리즘

2000년도 특허 만료 

 EL Gamal

 블록

512, 1024, 2048 

 PGP 같은 프로토콜에 널리 사용됨

 

라) 키 일치 알고리즘

 알고리즘

종류 

키의 크기 

참고 

 Diffie-Hellman

키 일치 

보통 512, 1024 

최초의 공개 키 암호 작성 알고리즘 

 

 

출처 : http://blog.naver.com/xxrcn11?Redirect=Log&logNo=20134786143

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

패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
인증, 전자서명  (0) 2015.11.05
블록 Padding  (0) 2015.11.05
base64 인코딩, 디코딩의 원리  (0) 2015.11.05
Posted by 으랏차
,