Подтвердить что ты не робот

Шифровать и дешифровать значение файла свойства в java

Я ищу способ зашифровать пароль в файле конфигурации который читается программой Java. В настоящее время я читаю пароль из текстового файла, но при этом пароль остается сильным если кто-то должен посмотреть файл конфигурации.

Я думал о создании простого класса, в котором пользователь мог бы ввести их желаемый пароль, получить зашифрованную версию пароля, затем вставьте зашифрованную версию в текстовый файл конфигурации. Затем приложение будет читать зашифрованный пароль, расшифровать пароль назад в строку и двигаться дальше.

У меня возникают проблемы с строкой → encrytped bytes → string преобразования.

Я использую встроенные классы безопасности Java для реализации этого кода. Вот пример тестового кода:

    // Reads password from config file
String password = ScriptConfig.getString( "password" );

// Generate Key
KeyGenerator kg = KeyGenerator.getInstance("DES");
Key key = kg.generateKey();

// Create Encryption cipher
Cipher cipher = Cipher.getInstance( "DES" );
cipher.init( Cipher.ENCRYPT_MODE, key );

// Encrypt password
byte[] encrypted = cipher.doFinal( password.getBytes() );

// Create decryption cipher
cipher.init( Cipher.DECRYPT_MODE, key );
byte[] decrypted = cipher.doFinal( encrypted );

// Convert byte[] to String
String decryptedString = new String(decrypted);

System.out.println("password: " + password);
System.out.println("encrypted: " + encrypted);
System.out.println("decrypted: " + decryptedString);

// Read encrypted string from config file
String encryptedPassword = ScriptConfig.getString( "encryptedPassword"
);

// Convert encryptedPassword string into byte[]
byte[] encryptedPasswordBytes = new byte[1024];
encryptedPasswordBytes = encryptedPassword.getBytes();

// Decrypt encrypted password from config file
byte[] decryptedPassword = cipher.doFinal( encryptedPasswordBytes );//error here

System.out.println("encryptedPassword: " + encryptedPassword);
System.out.println("decryptedPassword: " + decryptedPassword);


The config file has the following variables:
password=password
encryptedPassword=[[email protected]


When I run the code, I get the following output:
password: passwd
encrypted: [[email protected]
decrypted: passwd
javax.crypto.IllegalBlockSizeException: Input length must be multiple
of 8 when decrypting with padded cipher
at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
at com.sun.crypto.provider.DESCipher.engineDoFinal(Da shoA12275)
at javax.crypto.Cipher.doFinal(DashoA12275)
at com.sapient.fbi.uid.TestEncryption.main(TestEncryp tion.java:4

Любая помощь в отношении ошибки, структуры или процесса, которые я использую для этого было бы замечательно. Спасибо.

4b9b3361

Ответ 1

На самом деле простым решением было бы использовать кодировку Base64, см. фрагмент кода ниже: -

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

...

private String encode(String str) {
    BASE64Encoder encoder = new BASE64Encoder();
    str = new String(encoder.encodeBuffer(str.getBytes()));
    return str;
}

private String decode(String str) {
    BASE64Decoder decoder = new BASE64Decoder();
    try {
        str = new String(decoder.decodeBuffer(str));
    } catch (IOException e) {
        e.printStackTrace();
    }       
    return str;
}

...

Ответ 2

Посмотрите Jasypt. Он уже сделал тяжелый подъем для вас. В частности, классы org.jasypt.encryption.pbe.StandardPBEStringEncryptor и org.jasypt.properties.PropertyValueEncryptionUtils.

Создайте шифр:

SimplePBEConfig config = new SimplePBEConfig(); 
config.setAlgorithm("PBEWithMD5AndTripleDES");
config.setKeyObtentionIterations(1000);
config.setPassword("propertiesFilePassword");

StandardPBEStringEncryptor encryptor = new org.jasypt.encryption.pbe.StandardPBEStringEncryptor();
encryptor.setConfig(config);
encryptor.initialize();

Затем используйте PropertyValueEncryptionUtils для шифрования/дешифрования значений:

PropertyValueEncryptionUtils.encrypt(value, encryptor);
PropertyValueEncryptionUtils.decrypt(encodedValue, encryptor)

Обратите внимание, что закодированное значение начинается с ENC( и заканчивается на ), поэтому легко определить, зашифровано ли свойство из файла.

Также обратите внимание, что пароль, используемый для config.setPassword(), не является паролем, который вы кодируете для хранения в файле свойств. Вместо этого это пароль для шифрования/дешифрования значения, которое вы храните. Что такое этот пароль и как его установить, зависит от вас. Я по умолчанию полностью квалифицированное имя класса, которое читает файл свойств.

Наконец, если вы используете Spring, Jasypt имеет класс EncryptablePropertyPlaceholderConfigurer, который вы можете использовать для загрузки файла свойств и использовать синтаксис ${foo} в ваших XML файлах Spring для подстановки переменных для таких вещей, как DB пароли.

Ответ 3

Вот некоторые помощники для шифрования или дешифрования с использованием AES в Java:

public static final String AES = "AES";

/**
 * Encrypt a value and generate a keyfile.
 * If the keyfile is not found, then a new one will be created.
 * 
 * @throws GeneralSecurityException
 * @throws IOException if an I/O error occurs
 */
public static String encrypt(String value, File keyFile)
        throws GeneralSecurityException, IOException {
    if (!keyFile.exists()) {
        KeyGenerator keyGen = KeyGenerator.getInstance(CryptoUtils.AES);
        keyGen.init(128);
        SecretKey sk = keyGen.generateKey();
        FileWriter fw = new FileWriter(keyFile);
        fw.write(byteArrayToHexString(sk.getEncoded()));
        fw.flush();
        fw.close();
    }

    SecretKeySpec sks = getSecretKeySpec(keyFile);
    Cipher cipher = Cipher.getInstance(CryptoUtils.AES);
    cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters());
    byte[] encrypted = cipher.doFinal(value.getBytes());
    return byteArrayToHexString(encrypted);
}

/**
 * Decrypt a value.
 * 
 * @throws GeneralSecurityException
 * @throws IOException if an I/O error occurs
 */
public static String decrypt(String message, File keyFile)
        throws GeneralSecurityException, IOException {
    SecretKeySpec sks = getSecretKeySpec(keyFile);
    Cipher cipher = Cipher.getInstance(CryptoUtils.AES);
    cipher.init(Cipher.DECRYPT_MODE, sks);
    byte[] decrypted = cipher.doFinal(hexStringToByteArray(message));
    return new String(decrypted);
}

private static SecretKeySpec getSecretKeySpec(File keyFile)
        throws NoSuchAlgorithmException, IOException {
    byte[] key = readKeyFile(keyFile);
    SecretKeySpec sks = new SecretKeySpec(key, CryptoUtils.AES);
    return sks;
}

private static byte[] readKeyFile(File keyFile)
        throws FileNotFoundException {
    Scanner scanner = new Scanner(keyFile).useDelimiter("\\Z");
    String keyValue = scanner.next();
    scanner.close();
    return hexStringToByteArray(keyValue);
}

private static String byteArrayToHexString(byte[] b) {
    StringBuffer sb = new StringBuffer(b.length * 2);
    for (int i = 0; i < b.length; i++) {
        int v = b[i] & 0xff;
        if (v < 16) {
            sb.append('0');
        }
        sb.append(Integer.toHexString(v));
    }
    return sb.toString().toUpperCase();
}

private static byte[] hexStringToByteArray(String s) {
    byte[] b = new byte[s.length() / 2];
    for (int i = 0; i < b.length; i++) {
        int index = i * 2;
        int v = Integer.parseInt(s.substring(index, index + 2), 16);
        b[i] = (byte) v;
    }
    return b;
}

Просто вызовите подходящий метод.

Ответ 4

У меня возникают проблемы с строкой → encrytped bytes → string conversion.

Я бы поместил массив байтов через base64 en/decoder, таким образом вам придется упорствовать в строках, содержащих только символы (A подмножество) ASCII, что должно ограничивать ваши проблемы. Посмотрите, например. в общедоступные кодеки и замените ваш new String(decrypted) вызовом одного из статических методов в классе org.apache.commons.codec.binary.Base64.

Кроме того, я думаю, что то, что вы в конечном итоге хотите сделать, это не строго "шифровать" пароль, а хранить только хэш пароля, который уже обсуждался в fooobar.com/info/1760/....