-> 블로그 이전

[HW] Java 기반의 AES 복호화 프로그램

2022. 3. 26. 21:36Major`/정보보호개론

<문제>

아래의 key, IV, Ciphertext를 통해서 plaintext 구하기

"각 값들은 Base64 인코딩되어 제공된다"

 

## key ##
8iE3bf1se6N76HGPP8S0Xw==

## IV ##
cHml3oX848/0uBwDJtChOA==

## Ciphertext ##
QDr9NZNG9Bgc3TTnfRuqjjzf/kVSYwbP7F9mR4GQZ/IneIh7HTc/xnwzEeVBc
H3pPlIbLFySKZruedJc9X87CGNDJ1f2Dat8BR3Ypbei5Q42xc306/AkSuGsjfqb
X9/ELxmdKn7MyvY/Jbc0v0AJHV6odgNzygKRRrFJcUIF/50=

## 암호화 모드 ##
AES/CBC/PKCS5PADDING

Base64 인코딩?

Base64 Encoding이란 Binary Data → Text로 변경하는 Encoding이다

 

변경 방식은 Binary Data를 6bit씩 자른 뒤 6bit에 해당하는 문자를 아래 Base64 색인표에서 찾아서 치환을 해준다

  • 실제로 Padding을 더해주는 과정이 추가된다

Example 1) 문자열 : Man

77 97 110

→ 01001101 01100001 01101110

 

6bit씩 묶기

→ 010011 010110 000101 101110

→ 19 21 5 46

→ TWFu

 

"문자열 → ASCII binary → 6bit cut → base64_encoding"

하지만 여기서 문제는 모든 문자열이 깔끔하게 6bit씩 끊어지지 않는다는 것이다

이를 해결하기 위해서 padding을 한다

6bit가 안된다면 빈 공간에 padding문자인 "="을 넣어준다

 

 

Example 2) 문자열 : Many

→ 77 97 110 121

→ 01001101 01100001 01101110 01111001

 

6bit씩 묶기

→ 010011 010110 000101 101110 011110 01

→ 여기서 마지막이 6bit가 안되기 때문에 6bit를 채워준다

→ 010011 010110 000101 101110 011110 010000

TWFueQ==

 


PKCS5PADDING?

유명한 패딩 방식 중 하나이다

- PKCS5는 8byte block의 암호 알고리즘을 가정한다

 

>> plaintext의 길이가 L byte이면, 마지막 block은 "L mod 8"의 크기를 갖게 된다. 그러면 패딩의 크기는 8 - (L mod 8)이 된다

 

1) 1byte Data + 7byte Padding

"AA __ __ __ __ __ __ __"

  • 7byte가 부족하기 떄문에 "07"을 7번 padding한다

"AA 07 07 07 07 07 07 07"

 

2) 2byte Data + 6byte Padding

"AA BB __ __ __ __ __ __"

  • 6byte가 부족하기 때문에 "06"을 6번 padding한다

"AA BB 06 06 06 06 06 06"

 

 

3) 원본 데이터의 길이가 Block의 배수일 경우 (8, 16, 24, ...)

8byte가 block일 경우 08을 8번 패딩한다

"AA BB CC DD EE FF GG HH

 08 08 08 08 08 08 08 08"

 


Java JCA/JCE

javax.crypto package에 존재하는 Cipher 클래스가 핵심적인 역할을 수행한다 : 암호화 & 복호화 기능 제공

 


Cipher 객체 인스턴스화

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

- AES 암호화 & CBC Operation Mode & PKCS5 Paddign Scheme로 초기화를 요청

  • secretKey length : 32bit = AES-256
  • secretKey length : 24bit = AES-192
  • secretKey length : 16bit = AES-128

 

Keys

- 암호화 작업을 위한 키들을 나타낸다

SecretKey sk = new SecretKeySpec(keyBytes, "AES");

- keyBytes로부터 양방향 키를 생성

 

 

IV

- 초기화 벡터를 생성

byte [] iv = new byte[] {0, 0, 0, 0, 0, 0, 0, 0};
IvParameterSpec iv = new IvParameterSpec(iv);

 

 

 

Cipher 초기화

- key & 증명서 & opmode와 함께 init()를 호출할 수 있다

  • ENCRYPT_MODE : cipher 객체를 "암호화 모드"로 초기화
  • DECRYPT_MODE : cipher 객체를 "복호화 모드"로 초기화
  • WRAP_MODE : cipher 객체를 key-wrapping mode로 초기화
  • UNWRAP_MODE : chiper 객체를 key-unwrapping mode로 초기화
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey sk = new SecretKey(keyBytes, "AES);
IvParameterSpec iv = new IvParameterSpec(iv);

cipher.init(Cipher.DECRYPT_MODE, sk, iv);

 

Encryption/Decryption

Cipher 객체를 초기화하고, 암호화 & 복호화를 하기 위해서 doFinal()를 호출할 수 있다

doFinal()은 암호화 or 복호화된 메시지를 포함한 byte 배열을 return한다

cipher.doFinal([CipherText]);

 


Full Code

package HW_2;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AES_Decryption {
    static String key = "8iE3bf1se6N76HGPP8S0Xw==";
    static String IV = "cHml3oX848/0uBwDJtChOA==";
    static byte [] key_decode = Base64.getDecoder().decode(key);
    static byte [] IV_decode = Base64.getDecoder().decode(IV);

    public static void main(String[] args)
            throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
        String CipherText = "QDr9NZNG9Bgc3TTnfRuqjjzf/kVSYwbP7F9mR4GQZ/IneIh7HTc/xnwzEeVBc" +
                "H3pPlIbLFySKZruedJc9X87CGNDJ1f2Dat8BR3Ypbei5Q42xc306/AkSuGsjfqb" +
                "X9/ELxmdKn7MyvY/Jbc0v0AJHV6odgNzygKRRrFJcUIF/50=";

        byte [] CipherText_decode = Base64.getDecoder().decode(CipherText.getBytes());
        String plaintext = decode_cipherText(CipherText_decode);

        System.out.println("## AES 복호화 ##\n" + plaintext);
    }

    static String decode_cipherText(byte [] CipherText_decode)
            throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKey sk = new SecretKeySpec(key_decode, "AES");
        IvParameterSpec iv = new IvParameterSpec(IV_decode);

        cipher.init(Cipher.DECRYPT_MODE, sk, iv);

        return new String(cipher.doFinal(CipherText_decode));
    }
}