WEB개념

[암호화] Encryption/Decryption (대칭키, 공개키, 단방향) - AES, RSA, SHA

wooyeon06 2022. 3. 31. 10:19

 

 

 

 

AES (Adavanced Encryption Standard AES)

 

대칭형, 블럭 암호화 알고리즘이다.대칭형 암호화 알고리즘중 가장 유명하고, 128, 192, 256 bit 중 하나가 된다.

암호화 키의 길이에 따라 실행하는 라운드 수가 다른데, 각각 10(128), 12(192), 14(256) 라운드를 실행한다.

 

 

1.  AES모드

 

  1. ECB (Electronic Codebook): 평문 블록을 독립적으로 암호화하는 가장 기본적인 모드입니다. 하지만, 동일한 평문 블록이 동일한 암호문 블록으로 변환되기 때문에 패턴이 노출될 수 있습니다. 보안성이 약한 모드입니다.

  2. CBC (Cipher Block Chaining): 이전 블록의 암호문과 현재 평문 블록을 XOR하여 암호화하는 모드입니다. 초기화 벡터(IV)를 사용하여 암호문의 예측을 어렵게 합니다. 블록 간의 의존성으로 인해 병렬 처리가 어렵습니다.

  3. CFB (Cipher Feedback): 블록 암호를 스트림 암호처럼 사용하는 모드입니다. 이전 암호문 블록을 평문 블록과 XOR하여 스트림을 생성하고, 그 스트림을 평문과 XOR하여 암호문을 생성합니다. 피드백 사이즈에 따라 블록 또는 비트 CFB 모드가 있습니다.

  4. OFB (Output Feedback): CFB와 유사하지만, 스트림을 생성하기 위해 이전 암호문 블록을 사용하는 대신에 암호화 키로부터 생성된 스트림을 사용합니다. OFB 모드는 암호화와 복호화에 동일한 알고리즘을 사용할 수 있어서 유용합니다.

  5. CTR (Counter): 논스(Nonce) 또는 카운터 값을 사용하여 평문을 암호문으로 변환합니다. 병렬 처리가 가능하고, 블록 간의 의존성이 없어서 처리 속도가 빠릅니다. 스트림 암호와 유사한 동작을 하기 때문에 스트림 모드로도 볼 수 있습니다.

 

2. 패딩 (PCKS5, PKCS7)

:   AES 패딩은 AES 블록 암호화에서 마지막 블록이 블록 크기와 일치하지 않을 때 사용되는 추가 데이터입니다. 주로 마지막 블록이 부족한 경우에 사용됩니다.

 

  • 암복화 알고리즘 경우 input 데이터의 길이는 block size의 배수가 되어야 한다.

  • 하지만, 데이터의 길이가 block size의 배수가 아닌 경우 마지막 블록에 값을 추가해 block size의 배수로 맞춘다.

  • 이때, 추가 되는 행위 또는 값을 padding 이라고 한다.

  • PKCS5 : 8바이트 블록 사이즈에 맞추어져 패딩이 들어갑니다. 그리고 그 값으로 몇 바이트를 패딩으로 채웠는지 적혀 있습니다.
    • AA 07 07 07 07 07 07 07 [1 바이트 데이터 + 7 바이트 패딩]
    • AA BB CC DD 04 04 04 04 [4 바이트 데이터 + 4 바이트 패딩]
    • 08 08 08 08 08 08 08 08 [0 바이트 데이터 + 8 바이트 패딩]

 

public class AES256 {

    private static final String AES_ALGORITHM = "AES";
    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final int KEY_SIZE = 256;
    private static final int IV_SIZE = 16;

    // 예제용 키와 초기화 벡터(IV)
    private static final String KEY = "ThisIsASecretKey";
    private static final String IV = "InitializationVe";

    public static String encrypt(String plaintext) throws Exception {
        byte[] keyData = KEY.getBytes();
        byte[] ivData = IV.getBytes();

        SecretKeySpec secretKeySpec = new SecretKeySpec(keyData, AES_ALGORITHM);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));

        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    public static String decrypt(String ciphertext) throws Exception {
        byte[] keyData = KEY.getBytes();
        byte[] ivData = IV.getBytes();

        SecretKeySpec secretKeySpec = new SecretKeySpec(keyData, AES_ALGORITHM);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));

        return new String(decryptedBytes, "UTF-8");
    }

    public static void main(String[] args) {
        try {
            String plaintext = "Hello, AES256!";
            String ciphertext = encrypt(plaintext);
            System.out.println("암호화된 텍스트: " + ciphertext);

            String decryptedText = decrypt(ciphertext);
            System.out.println("복호화된 텍스트: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

 


 

 

RSA

 

:  Rivest, Shamir, Adleman의 이름에서 따온 암호화 알고리즘입니다. 공개키 암호화 방식의 하나로, 공개키와 개인키를 사용하여 데이터를 암호화 및 복호화합니다.

 

  1. 공개키 (Public Key):
    • 암호화에 사용되며, 누구에게나 공개될 수 있습니다..
  2. 개인키 (Private Key):
    • 복호화에 사용되며, 소유자만 알고 있어야 합니다.

 

RSA 알고리즘은 큰 소수를 사용하여 키를 생성합니다. 암호화와 복호화는 모듈러 연산을 사용하여 수행됩니다. 이러한 방식으로 RSA는 안전하고 강력한 암호화를 제공합니다.

 

RSA는 주로 인터넷 통신에서 사용되며, 전자 서명, SSL/TLS 프로토콜, 데이터 암호화 등 다양한 보안 응용 프로그램에 활용됩니다. 그러나 RSA는 계산량이 많아서 대량의 데이터를 처리하는 데는 적합하지 않을 수 있습니다. 따라서 대량의 데이터를 보호해야 하는 경우에는 대칭키 알고리즘과 결합하여 사용하는 것이 일반적입니다.

 

 

 

public class RSA {

    public static void main(String[] args) {
        try {
            // RSA 키 페어 생성
            KeyPair keyPair = generateKeyPair();

            // 공개키와 개인키 추출
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            // 원문
            String plaintext = "Hello, RSA!";

            // 암호화
            String encryptedText = encrypt(plaintext, publicKey);
            System.out.println("암호화된 텍스트: " + encryptedText);

            // 복호화
            String decryptedText = decrypt(encryptedText, privateKey);
            System.out.println("복호화된 텍스트: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048); // 키 크기 설정
        return keyPairGenerator.generateKeyPair();
    }

    public static String encrypt(String plaintext, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    public static String decrypt(String ciphertext, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(decryptedBytes);
    }
}

 


 

 

SHA256

 

 : SHA-2 (Secure Hash Algorithm 2)는 미국 국가안보국(NSA)가 설계한 암호화 해시 함수들의 집합이다.

일방향암호화로 복호화가 불가합니다.

 

"데이터의 위 변조 유무 확인"(정보의 무결성 확인)입니다. 통신 중인 메시지 내용이 위 변조가 발생했는지를

확인하기 위해서 사용하는 것을 말합니다.

 

 

public class SHA256 {

    public static void main(String[] args) {
        String originalString = "Hello, SHA-256!";
        try {
            String hashedString = hashString(originalString);
            System.out.println("해시된 문자열: " + hashedString);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static String hashString(String input) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = digest.digest(input.getBytes());
        StringBuilder hexString = new StringBuilder();

        for (byte hashByte : hashBytes) {
            String hex = Integer.toHexString(0xff & hashByte);
            if (hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }

        return hexString.toString();
    }
}

 

 

 



https://ojava.tistory.com/103

https://mike-tyson.tistory.com/11

https://m.blog.naver.com/doksg/221811748218