Java의 구성 파일에서 비밀번호 암호화

Rashmi Patidar 2023년10월12일
Java의 구성 파일에서 비밀번호 암호화

암호화는암호화 키라는 매개 변수와 결합 된 암호화 알고리즘을 사용하여 일반 텍스트 정보를 읽을 수없는 형식으로 변환하는 프로세스입니다. 읽을 수없는 형식은 종종ciphertext형식으로 알려져 있습니다. 해독 키를 소유 한 사람 만 데이터를 해독하고 원본 일반 텍스트를 복구 할 수 있습니다.

구성 파일의 암호 암호화 문제를 다음 두 가지 하위 작업으로 나눌 수 있습니다.

  1. 파일에있는 일반 텍스트 암호를 암호화합니다.
  2. 파일에서 읽은 암호화 된 암호를 해독합니다.

먼저src/conf/경로에config.properties파일이라는 구성 파일을 만들어 보겠습니다.

password = TestPassword123

이제 구성 파일을 읽으려면Properties클래스를 인스턴스화하십시오. 생성자를 사용하여FileInputStream클래스의 인스턴스를 만들 수 있습니다. 구성 파일의 경로를 입력으로 사용합니다. 이제 속성 클래스의 인스턴스가 속성을로드하는 데 사용됩니다. 클래스에서 속성 파일을로드하기 위해load메소드를 사용하면InputStreamReader인스턴스를 매개 변수로 사용합니다. 이 입력 스트림에 잘못된 유니 코드 이스케이프 시퀀스가 ​​포함 된 경우IllegalArgumentException이 발생하고 입력 스트림에서 읽을 때 오류가 발생하면IOException이 발생합니다.

속성이 성공적으로로드되면getProperty()메서드를 사용하여 속성 목록에서 지정된 키로 속성을 검색합니다. 속성을 찾을 수없는 경우 메서드는null을 반환합니다. 이러한 상황을 처리하기위한 외부 검사를 수행하고 파일에서 암호가 널인 경우IllegalArgumentException을 발생시킵니다.

salt는 비밀번호 문자열에 추가 할 임의의 문자열로 생성됩니다.

createSecretKeySecretKeySpec 키를 반환하는 사용자 정의 메소드이며 키의 용도는 비밀번호를 암호화 및 복호화하는 것입니다. encryptdecrypt 메서드는Encryption 클래스에서 제공된 사용 정의정적메서드입니다.

다음은 동일한 내용을 보여주는 샘플 코드입니다.

package fileDataEncryption;

import static fileDataEncryption.Encryption.*;

import java.io.FileInputStream;
import java.util.Properties;
import javax.crypto.spec.SecretKeySpec;

public class ConfigFileEncryption {
  public static void main(String[] args) throws Exception {
    Properties properties = new Properties();
    FileInputStream inputStream = new FileInputStream("src/conf/config.properties");
    properties.load(inputStream);
    String password = properties.getProperty("password");

    if (password == null) {
      throw new IllegalArgumentException("No such parameter present in config file");
    }

    byte[] salt = new String("12345678").getBytes();
    int iterationCount = 40000;
    int keyLength = 128;
    SecretKeySpec key = createSecretKey(password.toCharArray(), salt, iterationCount, keyLength);

    String originalPassword = password;
    System.out.println("Original password: " + originalPassword);
    String encryptedPassword = encrypt(originalPassword, key);
    System.out.println("Encrypted password: " + encryptedPassword);
    String decryptedPassword = decrypt(encryptedPassword, key);
    System.out.println("Decrypted password: " + decryptedPassword);
  }
}

Encryption클래스의 사용자 정의 메소드에 대한 자세한 설명은 다음과 같습니다.

  1. createSecretKeypassword,salt,iterationCountkeyLength와 같은 매개 변수를 사용하는 함수입니다. password는 구성 파일의 실제 비밀번호입니다. 암호화에서salt는 데이터, 암호 또는 암호를 해시하는 추가 입력으로 사용하는 임의의 데이터입니다. salts의 사용은 스토리지에서 비밀번호를 보호하는 것입니다. 알고리즘이 수행해야하는 반복 횟수로iterationCount변수를 사용합니다. 변수 값을 줄이면 시작 시간이 단축되므로 테스트 중에 도움이되지만 무차별 대입 공격자가 더 쉽게 사용할 수 있습니다. keyLength변수는 궁극적으로 파생해야하는 키의 길이입니다. 사용 된 메서드에서 throw 된 예외를 throw합니다.
  2. getInstance메소드는 가장 선호되는 제공자부터 시작하여 등록 된 보안 제공자 목록을 탐색합니다. 요청 된 비밀 키 알고리즘의 표준 이름을 취하고 새로운SecretKeyFactory객체를 반환합니다. 지정된 알고리즘이 null이면NullPointerException을, 지정된 알고리즘에 대해SecretKeyFactorySpi구현을 지원하는 Provider가 없으면NoSuchAlgorithmException을 발생시킵니다.
  3. PBEKeySpec은 가변 키 크기 PBE 암호의PBEKey를 생성하기 위해 암호, 솔트, 반복 횟수 및 파생 키 길이를 사용하는 클래스 생성자입니다. saltnull이면NullPointerException이 발생하고 salt가 비어 있으면IllegalArgumentException이 발생합니다.
  4. generateSecret은 제공된 키 사양 또는 키 자료에서SecretKey개체를 생성합니다. 비밀 키의 사양을 사용합니다. 지정된 사양이이 비밀 키 팩토리가 분류 된 키 값을 생성하는 데 적합하지 않은 경우InvalidKeySpecException이 발생합니다.

Encryption클래스의encrypt메소드에 대한 세부 사항입니다.

  1. encrypt방법은 암호화 할 데이터와 키의 두 가지 매개 변수를 사용합니다. 이 메서드는 자식 메서드에서 throw 된 예외를 throw합니다.
  2. getInstance메소드는 가장 선호되는 제공자부터 시작하여 등록 된 보안 제공자 목록을 탐색합니다. 변환 이름, 즉 AES / CBC / PKCS5Padding을 사용합니다. 변경 사항이 유효하지 않은 형식으로 null이고 비어 있으면NoSuchAlgorithmException이 발생하고 변경에 사용할 수없는 패딩 스키마가 포함 된 경우NoSuchPaddingException이 발생합니다.
  3. init메소드는 작동 모드 값에 따라 암호화, 복호화, 키 래핑 또는 키 풀기의 네 가지 작업 중 하나에 대해Cipher를 초기화합니다. 우리의 경우ENCRYPT_MODE. 이 메소드는 작동 모드가 유효하지 않은 경우UnsupportedOperationException을, 지정된 키가 부적절한 경우InvalidKeyException을 발생시킵니다.
  4. getParameters는이 암호와 함께 사용되는 매개 변수를 리턴합니다.
  5. getParameterSpec은 매개 변수 개체의 사양을 반환합니다. paramSpec매개 변수는 매개 변수가 반환해야하는 사양 클래스를 식별합니다. 예를 들어, 매개 변수가DSAParameterSpec클래스의 인스턴스에서 반환되어야 함을 나타 내기 위해DSAParameterSpec.class가 될 수 있습니다.
  6. doFinal메소드는 단일 파트 작업에서 데이터를 암호화 또는 복호화하거나 다중 파트 작업을 완료합니다. 데이터는 암호를 초기화하는 방법에 따라 암호화되거나 해독됩니다.
  7. base64EncodeBase64인코딩 체계를 사용하여 지정된 바이트 배열을 문자열로 인코딩하는 개인 메서드입니다. decrypt메소드에서 사용되는 기능은 위에서 언급 한 메소드와 유사합니다. 유일한 차이점은 작동 모드로DECRYPT_MODE기능에 지정된mode에 따라 다르게 작동한다는 것입니다.
package fileDataEncryption;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class Encryption {
  public static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount,
      int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
    PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
    SecretKey keyTmp = keyFactory.generateSecret(keySpec);
    return new SecretKeySpec(keyTmp.getEncoded(), "AES");
  }

  public static String encrypt(String dataToEncrypt, SecretKeySpec key)
      throws GeneralSecurityException, UnsupportedEncodingException {
    Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    pbeCipher.init(Cipher.ENCRYPT_MODE, key);
    AlgorithmParameters parameters = pbeCipher.getParameters();
    IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
    byte[] cryptoText = pbeCipher.doFinal(dataToEncrypt.getBytes("UTF-8"));
    byte[] iv = ivParameterSpec.getIV();
    return base64Encode(iv) + ":" + base64Encode(cryptoText);
  }

  private static String base64Encode(byte[] bytes) {
    return Base64.getEncoder().encodeToString(bytes);
  }

  public static String decrypt(String string, SecretKeySpec key)
      throws GeneralSecurityException, IOException {
    String iv = string.split(":")[0];
    String property = string.split(":")[1];
    Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
    return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
  }

  private static byte[] base64Decode(String property) throws IOException {
    return Base64.getDecoder().decode(property);
  }
}

다음은 구성 파일에서 암호를 암호화하고 해독하기 위해 작성된 코드의 출력입니다.

Original password: TestPassword123
Encrypted password: Hy7fbIwpyKgp0oileu+oLg==:WNRknMJz/8u8GmWlCZFPFA==
Decrypted password: TestPassword123
Rashmi Patidar avatar Rashmi Patidar avatar

Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.

LinkedIn

관련 문장 - Java Encryption