Вопрос по encryption, java – Java AES шифрование и дешифрование

24

Я хотел бы зашифровать и расшифровать пароль, используя 128-битное шифрование AES с 16-байтовым ключом. я получаюjavax.crypto.BadPaddingException ошибка при расшифровке значения. Я что-то упускаю при расшифровке?

public static void main(String args[]) {
    Test t = new Test();
    String encrypt = new String(t.encrypt("mypassword"));
    System.out.println("decrypted value:" + t.decrypt("ThisIsASecretKey", encrypt));
}

public String encrypt(String value) {
    try {
        byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        System.out.println("encrypted string:" + (new String(encrypted)));
        return new String(skeySpec.getEncoded());
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

public String decrypt(String key, String encrypted) {
    try {
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(skeySpec.getEncoded(), "AES"));
        //getting error here
        byte[] original = cipher.doFinal(encrypted.getBytes());
        return new String(original);
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}  

Сообщение об ошибке

encrypted string:�Bj�.�Ntk�F�`�
encrypted key:ThisIsASecretKey
decrypted value:null
May 25, 2012 12:54:02 PM bean.Test decrypt
SEVERE: null
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at bean.Test.decrypt(Test.java:55)
at bean.Test.main(Test.java:24)

Finally I am using following Solution based on @QuantumMechanic answer

public class Test {

public String encryptionKey;

public static void main(String args[]) {
    Test t = new Test();
    String encrypt = t.encrypt("mypassword");
    System.out.println("decrypted value:" + t.decrypt(t.encryptionKey, encrypt));
}

public String encrypt(String value) {
    try {
        // Get the KeyGenerator
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(256);
        // Generate the secret key specs.
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        String key = new Base64().encodeAsString(raw);
        this.encryptionKey = key;
        System.out.println("------------------Key------------------");
        System.out.println(key);
        System.out.println("--------------End of Key---------------");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        String encrypt = (new Base64()).encodeAsString(cipher.doFinal(value.getBytes()));
        System.out.println("encrypted string:" + encrypt);
        return encrypt;
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

public String decrypt(String key, String encrypted) {
    try {
        Key k = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, k);
        byte[] decodedValue = Base64.getDecoder().decode(encrypted);
        byte[] decValue = c.doFinal(decodedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

}

Ваш Ответ

6   ответов
1

что хотите зашифровать / расшифровать пароль. Я не уверен точно, каков ваш конкретный вариант использования, но, как правило, пароли не хранятся в форме, где их можно расшифровать. Общая практика заключается в том, чтобы посолить пароль и использовать достаточно мощный односторонний хеш (такой как PBKDF2).

Взгляните на следующую ссылку для получения дополнительной информации.

http://crackstation.net/hashing-security.htm

4

byte[] salt = "ThisIsASecretKey".getBytes();
Key key = new SecretKeySpec(salt, 0, 16, "AES");

Cipher cipher = Cipher.getInstance("AES");
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Praneeth
Error: User Rate Limit Exceeded Praneeth
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededThisIsASecretKey Praneeth
5

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;

try
{
    String passEncrypt = "my password";
    byte[] saltEncrypt = "choose a better salt".getBytes();
    int iterationsEncrypt = 10000;
    SecretKeyFactory factoryKeyEncrypt = SecretKeyFactory
            .getInstance("PBKDF2WithHmacSHA1");
    SecretKey tmp = factoryKeyEncrypt.generateSecret(new PBEKeySpec(
            passEncrypt.toCharArray(), saltEncrypt, iterationsEncrypt,
            128));
    SecretKeySpec encryptKey = new SecretKeySpec(tmp.getEncoded(),
            "AES");

    Cipher aesCipherEncrypt = Cipher
            .getInstance("AES/ECB/PKCS5Padding");
    aesCipherEncrypt.init(Cipher.ENCRYPT_MODE, encryptKey);

    // get the bytes
    byte[] bytes = StringUtils.getBytesUtf8(toEncodeEncryptString);

    // encrypt the bytes
    byte[] encryptBytes = aesCipherEncrypt.doFinal(bytes);

    // encode 64 the encrypted bytes
    String encoded = Base64.encodeBase64URLSafeString(encryptBytes);

    System.out.println("e: " + encoded);

    // assume some transport happens here

    // create a new string, to make sure we are not pointing to the same
    // string as the one above
    String encodedEncrypted = new String(encoded);

    //we recreate the same salt/encrypt as if its a separate system
    String passDecrypt = "my password";
    byte[] saltDecrypt = "choose a better salt".getBytes();
    int iterationsDecrypt = 10000;
    SecretKeyFactory factoryKeyDecrypt = SecretKeyFactory
            .getInstance("PBKDF2WithHmacSHA1");
    SecretKey tmp2 = factoryKeyDecrypt.generateSecret(new PBEKeySpec(passDecrypt
            .toCharArray(), saltDecrypt, iterationsDecrypt, 128));
    SecretKeySpec decryptKey = new SecretKeySpec(tmp2.getEncoded(), "AES");

    Cipher aesCipherDecrypt = Cipher.getInstance("AES/ECB/PKCS5Padding");
            aesCipherDecrypt.init(Cipher.DECRYPT_MODE, decryptKey);

    //basically we reverse the process we did earlier

    // get the bytes from encodedEncrypted string
    byte[] e64bytes = StringUtils.getBytesUtf8(encodedEncrypted);

    // decode 64, now the bytes should be encrypted
    byte[] eBytes = Base64.decodeBase64(e64bytes);

    // decrypt the bytes
    byte[] cipherDecode = aesCipherDecrypt.doFinal(eBytes);

    // to string
    String decoded = StringUtils.newStringUtf8(cipherDecode);

    System.out.println("d: " + decoded);

}
catch (Exception e)
{
    e.printStackTrace();
}
5
import javax.crypto.*;    
import java.security.*;  
public class Java {

private static SecretKey key = null;         
   private static Cipher cipher = null; 

   public static void main(String[] args) throws Exception
   {

      Security.addProvider(new com.sun.crypto.provider.SunJCE());

      KeyGenerator keyGenerator =
         KeyGenerator.getInstance("DESede");
      keyGenerator.init(168);
      SecretKey secretKey = keyGenerator.generateKey();
      cipher = Cipher.getInstance("DESede");

      String clearText = "I am an Employee";
      byte[] clearTextBytes = clearText.getBytes("UTF8");

      cipher.init(Cipher.ENCRYPT_MODE, secretKey);
      byte[] cipherBytes = cipher.doFinal(clearTextBytes);
      String cipherText = new String(cipherBytes, "UTF8");

      cipher.init(Cipher.DECRYPT_MODE, secretKey);
      byte[] decryptedBytes = cipher.doFinal(cipherBytes);
      String decryptedText = new String(decryptedBytes, "UTF8");

      System.out.println("Before encryption: " + clearText);
      System.out.println("After encryption: " + cipherText);
      System.out.println("After decryption: " + decryptedText);
   }
}


// Output

/*
Before encryption: I am an Employee  
After encryption: }?ス?スj6?スm?スZyc?ス?ス*?ス?スl#l?スdV  
After decryption: I am an Employee  
*/
26

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

Так что либо добавьте ваш открытый текст к кратному 16 байтам (что является размером блока AES), либо укажите схему заполнения при созданииCipher объекты. Например, вы можете использовать:

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

Если у вас нет веских оснований этого не делать, используйте схему заполнения, которая уже является частью реализации JCE. Они продумали ряд тонкостей и угловых случаев, которые вам придется осознать и решить самостоятельно, в противном случае.

Хорошо, ваша вторая проблема в том, что вы используетеString держать зашифрованный текст.

В общем,

String s = new String(someBytes);
byte[] retrievedBytes = s.getBytes();

будутnot иметьsomeBytes а такжеretrievedBytes быть идентичным

Если вы хотите / должны держать зашифрованный текст вString, base64-кодировать сначала зашифрованные байты и создатьString из байтов в кодировке base64. Затем, когда вы расшифруетеgetBytes() чтобы получить base64-закодированные байты изStringзатем base64-декодируйте их, чтобы получить настоящий зашифрованный текст, затем расшифруйте его.

Причиной этой проблемы является то, что большинство (все?) Кодировки символов не способны отображать произвольные байты в допустимые символы. Поэтому, когда вы создаете свойString из зашифрованного текста,String Конструктор (который применяет кодировку символов для преобразования байтов в символы), по сути, должен отбрасывать некоторые байты, потому что он не может их понять. Таким образом, когда вы получаете байты из строки, они не совпадают с байтами, которые вы помещаете в строку.

В Java (и в современном программировании в целом) вы не можете предполагать, что один символ = один байт, если вы абсолютно не знаете, что имеете дело с ASCII. Вот почему вам нужно использовать base64 (или что-то подобное), если вы хотите создавать строки из произвольных байтов.

Error: User Rate Limit Exceeded Praneeth
Error: User Rate Limit ExceededBASE64EncoderError: User Rate Limit ExceededBASE64DecoderError: User Rate Limit Exceeded Praneeth
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceedednError: User Rate Limit ExceedednError: User Rate Limit ExceededthisError: User Rate Limit Exceeded
Error: User Rate Limit ExceededmypasswordError: User Rate Limit Exceeded1234567890123456Error: User Rate Limit Exceeded Praneeth
0

encrypting/Decrypting huge video without throwing Java OutOfMemoryException и с помощью JavaSecureRandom для генерации вектора инициализации. Также изображено хранение байтов ключа в базе данных и затем восстановление того же ключа из этих байтов.

https://stackoverflow.com/a/18892960/185022

Похожие вопросы