Один и тот же пароль приводит к различным ключам AES в Java - PullRequest
0 голосов
/ 26 сентября 2018

Я пытаюсь реализовать базовый пример шифрования AES на двух устройствах в Java.Однако использование одного и того же пароля (128 бит) на обоих устройствах для генерации ключа AES приводит к разным ключам на обоих устройствах при каждом запуске приложения.Поэтому мы не можем расшифровать текст, который мы отправляем между устройствами.

Ниже приведены методы, которые я использую, они являются слегка измененными версиями кода, который я нашел в другом месте:

public String encryptMessage(String message, String password) throws Exception {

    // Creating key and cipher
    SecretKeySpec aesKey = new SecretKeySpec(password.getBytes("UTF-8"), "AES");


    byte[] iv = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
    IvParameterSpec ivspec = new IvParameterSpec(iv);
    //AES cipher
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

    // encrypt the text
    cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivspec);

    byte[] encrypted;

    encrypted = cipher.doFinal(message.getBytes());

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

public String decryptMessage(String encryptedMessage, String password) throws Exception {

    // Creating key and cipher
    byte[] passwordBytes = password.getBytes("UTF-8");

    SecretKeySpec aesKey = new SecretKeySpec(passwordBytes, "AES");

    byte[] iv = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
    IvParameterSpec ivspec = new IvParameterSpec(iv);
    //AES cipher
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

    // decrypting the text
    cipher.init(Cipher.DECRYPT_MODE, aesKey, ivspec);
    String decrypted = new String(cipher.doFinal(encryptedMessage.getBytes(Charset.forName("UTF-8"))));

    //returning decrypted text
    return decrypted;
}

Каждый раз, когда я запускаю этот код и распечатываю aesKey, он отличается.

Мое понимание AES и симметричного шифрования заключается в том, что при наличии одного и того же пароля он должен генерировать один и тот же ключ, иначе как он может расшифроватьартефакт?У меня неправильный конец клюшки по AES или кто-то может подсказать, что может происходить?

1 Ответ

0 голосов
/ 26 сентября 2018

Ваше понимание верно, и ключ в вашем коде тот же.

Вы не можете "напечатать" aesKey, так как SecretKeySpec не имеет toString() метода.Таким образом, будет вызван встроенный Object.toString(), который просто печатает адрес объекта в памяти

javax.crypto.spec.SecretKeySpec@14c7f    // <--- useless info //

Есть только несколько проблем с вашим кодом:

  • Не преобразовывать зашифрованные байты в строку UTF-8.Могут быть комбинации, которые недопустимы в UTF-8, а также 00 байтов.Для печати зашифрованных данных используйте кодировку Base64 или Hex.

  • Не следует использовать байты ASCII в качестве ключа, что значительно снижает безопасность ключа. Получите ключ от пароля, по крайней мере, с SHA-256, но предпочтительно PBKDF2 или scrypt.

  • Используйте случайный IV с высокой энтропией и сохраните его с зашифрованным текстом.

Вот обновленная версия, демонстрирующая, что она работает:

public static String encryptMessageGH(String message, String password) throws Exception {
    MessageDigest sha = MessageDigest.getInstance("SHA-256");
    byte[] key = sha.digest(password.getBytes("UTF-8"));
    SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
    byte[] iv = new byte[16];
    new SecureRandom().nextBytes(iv);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    cipher.init(Cipher.ENCRYPT_MODE, aesKey, new IvParameterSpec(iv));
    byte[] ciphertext = cipher.doFinal(message.getBytes());
    byte[] encrypted = new byte[iv.length + ciphertext.length];
    System.arraycopy(iv, 0, encrypted, 0, iv.length);
    System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
    return Base64.getEncoder().encodeToString(encrypted);
}

public static String decryptMessageGH(String encryptedMessage, String password) throws Exception {
    MessageDigest sha = MessageDigest.getInstance("SHA-256");
    byte[] key = sha.digest(password.getBytes("UTF-8"));
    SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
    byte[] encrypted = Base64.getDecoder().decode(encryptedMessage);
    byte[] iv = new byte[16];
    System.arraycopy(encrypted, 0, iv, 0, iv.length);
    byte[] ciphertext = new byte[encrypted.length - iv.length];
    System.arraycopy(encrypted, iv.length, ciphertext, 0, ciphertext.length);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));
    return new String(cipher.doFinal(ciphertext), "UTF-8");
}

public static void main(String[] args) throws Exception {
    String orig = "Test message";
    String enc = encryptMessageGH(orig, "abcdef123");
    System.out.println("Encrypted: " + enc);
    String dec = decryptMessageGH(enc, "abcdef123");
    System.out.println("Decrypted: " + dec);
}

Вывод:

Encrypted: lcqcd9UZpjLSY9SsQ/N7kV/cpdzL3c7HQcCSiIs6p/k=
Decrypted: Test message
...