'암호화'에 해당되는 글 4건

  1. 2015.11.05 Session key
  2. 2015.11.05 대칭키 암호화
  3. 2015.11.05 대칭 비대칭 암호화
  4. 2015.11.05 블록 Padding

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

암호화(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 으랏차
,

블록 Padding

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

출처 : http://dxdy2x.comze.com/content/util_pad_mode.htm

출처 : http://blog.daum.net/coy486/2

 

위의 두 곳에 있는 내용을 기반으로 나름 정리한 내용임을 밝혀 둡니다.

Padding

데이터를 블럭으로 암호화 할때 평문이 항상 블럭 크기(일반적으로 64비트 또는 128비트)의 배수가 되지 않는다. 패딩은 어떻게 평문의 마지막 블록이 암호화 되기 전에 데이터로 채워지는가를 확실히 지정하는 방법이다. 복호화 과정에서는 패딩을 제거하고 평문의 실제 길이를 지정하게 된다.

 

PKCS#5
PKCS#5는 공개키 암호화의 표준이며, RSA 회사에 의해 발표되 독립적으로 규정된 표준이다.
패딩기법은 블럭의 나머지 부분을 바이트(정확히 otect) 수로 채운다. 예를 들어 128비트의 블록에서, 만약 블럭에 남는 다섯 개의 남은 평문 바이트가 있다면, 11의 값을 가진 11 바이트가 블록에 패딩된다. 블럭에 채워진 데이터는 16바이트(128비트)로 나누어지게 된다. 이 방법은 패딩이 복호화 뒤에 명백하게 제거되도록 하고, 평문의 원래 크기가 다시 저장 되도록 한다. 추가적으로 64비트의 블럭인 경우는 다섯개의 남은 평문이 있다면, 3의 값을 가진 3바이트가 블럭에 패딩된다. 블럭에 채워진 데이터는 8바이트(64비트)로 나누어지게 된다.
만약 평문이 블럭(64 또는 128비트 외 기타)으로 나누어지면, 패딩을 추가하지 않아도 되는 것 처럼 보이지만, 암호화를 수행 할때는 패딩이 항상 추가 된다.

 

 


Mode

암호 모드는 평문의 블럭이 암호문의 블럭으로 암호화되는 방법을 결정하며, 그 역 또한 성립한다.
아래는 내용은 DES 암호 알고리즘의 이용하여 64비트(8바이트) 블럭암호를 했을 때 나타 낸것이다. 만약 128비트 암호(16바이트)를 사용 한다면 크기만 변경해 주면된다.

 

ECB Mode (Electronic Code Book)
가장 일반적인 형태이며 암호문 각각의 8바이트 블럭이 독립적이라는 것이다. 만약 암호문 한 블럭 에러가 발생했다면 에러가 발생한 블럭을 제외한 나머지 암호문 블럭은 복호화 할 수 있다. 아래그림에서 보면 만약 Block C2가 에러가 났더라도 Block C1과 그 외 Block Cn은 복호화 할 수 있다는 것이다. 단점은 보통 정형화 된 형식의 평문(인사말, 전송되는 데이터의 형식의 헤더 정보 등...) 또는 반복되는 평문이 있을 경우 암호문에서 반복되는 형식이 출력된다. 이것은 악의적이 누군가에 정보를 추측 할 수 있도록 하게 해준다. 

 

CBC Mode (Cipher Block Chaining)
평문의 첫번째 블럭(P1)이 초기화 벡터(IV: Initalization Vector)와 XOR을 수행하하고 나서 암호화를 수행하게 된다. 암호문(C1)은 평문의 다음 블럭(P2)의 XOR를 수행하게 되며 이것이 반복된다. 그리고 마지막 블럭에서는 패딩이 추가되어져서 수행된다. 복호화는 역으로 수행하면 된다. CBC 특징은 현재 생성된 암호문 블럭이 다음 생성된 암호문 브럭에 영향을 미치기 때문에 특정 암호문 블럭에 에러가 발생하면 그 다음 암호문에도 그 영향을 받게 된다. IV는 송신자가 값을 가지고 암호화를 수행하면 복호화하는 수신자도 IV값을 알고 있어야한다. 깨진 암호문의 해당블록과 다음블록의 평문까지 영향을 받는다.

문서를 전송하는데 적합하지만, 한번에 모든 블록을 전송해야 한다.(보통 8캐릭터). 전제 메시지에는 좋지만, 한번에 한 글자씩 보내는 방식에는 적합하지 않다.



 

PCBC Mode (Propagating Cipher Block Chaining)
PCBC는 CBC 모드와 유사하다. 아래 그림에서 보면 평문 블럭(P2)이 암호화 할 때, 이전의 평문 블럭(P1)과 암호문 블럭(C1)이 동시에 XOR 연산을 수행하고 암호화를 수행하게 된다. 그리고 마지막 블럭에서는 패딩이 추가되어져서 수행된다. 복호화는 역으로 수행하면 된다.


 

CFB Mode (Cipher FeedBack)
CFB는 블록암호가 스트림 암호처럼 한 바이트(8비트)를 암호화 하거나 복호화하는데 CFB8이라고 한다.

스트림 암호화처럼 동작하기 때문에 평문과 암호문의 길이가 같아져 패딩이 필요 없다.

스트림의 기본단위를 Bit단위로 설정할 수 있으며 Bit 단위에 따라 CFB8~CFB128로 쓰인다.

한번에 한 바이트 데이타를 암호화 해서 보내는 방식에 적합하다.
다음은 아래 그림처럼 작동 방법을 설명하고 있다.
Step 1. 8bytes 초기화 벡터(IV)에 값을 채우고, IV값을 암호화를 수행하여 Shift register값을 출력한다.
Step 2. 평문의 첫 8비트(Byte P1)와 shift register의 최좌단 8비트와 XOR를 수행하여 첫번째 암호문(Byte C1)을 출력한다.
Step 3. Shift register값을 왼쪽으로 8비트 이동시키고, 암호문의 8비트를 shift register에 값의 오른쪽에 채운다.
Step 4. shift register는 암호화를 수행한다.
Step 5. 평문의 다음 8비트(Byte P2)와 shift register의 최좌단 8비트를 XOR를 수행하여 다음 암호문(Byte C2)을 출력한다.
Step 6. 모든 평문의 길이만큼 Step 3~6까지 반복 수행하여 처리한다.

 

 

또 다른 그림

 

OFB Mode (Output FeedBack)
OFB는 암호문이 shift register값에 피드백 되지 않는 것을 제외하고는 CFB와 유사하다. shift register 출력 값 그 자체가 피드백 된다. 이것은 평문도 암호문도 암호화 되지 않는다. 단지 암호문은 shift register의 출력 값과 평문이 XOR 수행하여 출력 된다는 것이다.

스트림 암호화처럼 동작하기 때문에 평문과 암호문의 길이가 같아져 패딩이 필요 없다.

스트림의 기본단위를 Bit단위로 설정할 수 있으며 Bit 단위에 따라 CFB8~CFB128로 쓰인다.

 


또 다른 그림

 

 

 CRT Mode (CounTeR)
블록을 암호화할 때마다 1씩 증가해 가는 카운터를 암호화 해서 키 스트림을 만든다. 즉 카운터를 암호화환 비트열과 평문블록과의 XOR을 취한 결과가 암호문 블록이 된다. CRT는 OFB와 같은 스트림 암호의 일종이며 암복호화는 완전히 같은 구조를 가지므로 구현이 간단하다. 비표와 블록번호로부터 카운터를 구할수 있기 때문에 블록의 순서를 임의로 암/복호화 할 수 있다.

 

출처 : 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
대칭 비대칭 암호화  (0) 2015.11.05
base64 인코딩, 디코딩의 원리  (0) 2015.11.05
Posted by 으랏차
,