it-swarm.com.de

Java AES-Verschlüsselung und -Entschlüsselung

Ich möchte ein Kennwort mit 128-Bit-AES-Verschlüsselung mit 16-Byte-Schlüssel ver- und entschlüsseln. Beim Entschlüsseln des Werts erhalte ich einen javax.crypto.BadPaddingException-Fehler. Fehlt mir etwas beim Entschlüsseln?

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;
}  

Fehlermeldung

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)

Zum Schluss verwende ich folgende Lösung basierend auf @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;
}

}

24
Praneeth

Wenn Sie für eine Blockverschlüsselung keine Cipher-Transformation verwenden, die ein Auffüllschema enthält, muss die Anzahl der Bytes im Klartext ein ganzzahliges Vielfaches der Blockgröße der Verschlüsselung sein.

Füllen Sie Ihren Klartext also entweder mit einem Vielfachen von 16 Bytes (dies ist die AES-Blockgröße) aus, oder geben Sie ein Padding-Schema an, wenn Sie Ihre Cipher-Objekte erstellen. Sie könnten beispielsweise Folgendes verwenden:

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

Sofern Sie keinen triftigen Grund haben, dies nicht zu tun, verwenden Sie ein Auffüllschema, das bereits Bestandteil der JCE-Implementierung ist. Sie haben eine Reihe von Feinheiten und Eckfällen durchdacht, mit denen Sie sich sonst auseinandersetzen müssen.


Das zweite Problem ist, dass Sie String verwenden, um den Chiffretext zu speichern.

Im Algemeinen,

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

wird nicht someBytes und retrievedBytes identisch sein.

Wenn Sie den Chiffretext in einer String speichern möchten/müssen, müssen die Chiffretext-Bytes zuerst mit base64 codiert und die String aus den Base64-codierten Bytes erstellt werden. Wenn Sie dann entschlüsseln, werden Sie getBytes(), um die base64-codierten Bytes aus der String zu holen, dann base64-decodieren, um den echten Chiffretext zu erhalten, und dann entschlüsseln.

Der Grund für dieses Problem ist, dass die meisten (alle?) Zeichenkodierungen nicht in der Lage sind, beliebige Bytes gültigen Zeichen zuzuordnen. Wenn Sie also Ihre String aus dem Chiffretext erstellen, muss der String-Konstruktor (der eine Zeichencodierung verwendet, um die Bytes in Zeichen umzuwandeln) im Wesentlichen einige der Bytes wegwerfen, da er sie nicht verstehen kann. Wenn Sie also Bytes aus der Zeichenfolge erhalten, sind sie nicht die gleichen Byte, die Sie in die Zeichenfolge einfügen.

In Java (und in der modernen Programmierung im Allgemeinen) können Sie nicht davon ausgehen, dass ein Zeichen = ein Byte ist, es sei denn, Sie wissen absolut, dass Sie mit ASCII arbeiten. Aus diesem Grund müssen Sie base64 (oder ähnliches) verwenden, wenn Sie Zeichenfolgen aus beliebigen Bytes erstellen möchten.

26
QuantumMechanic

Hier ist die Implementierung, die oben erwähnt wurde:

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
Greg
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  
*/
5
user2362312

Versuchen Sie es mit einer einfacheren Lösung.

 byte [] salt = "ThisIsASecretKey" .getBytes (); 
 Schlüssel key = new SecretKeySpec (salt, 0, 16, "AES");. AES "); 
4
Kumar Bibek

Sie geben an, dass Sie ein Kennwort verschlüsseln/entschlüsseln möchten. Ich bin mir nicht sicher, was genau Ihr Anwendungsfall ist, aber Passwörter werden im Allgemeinen nicht in einer Form gespeichert, in der sie entschlüsselt werden können. Die übliche Praxis besteht darin, das Passwort zu salzen und einen entsprechend leistungsfähigen Einweg-Hash (wie z. B. PBKDF2) zu verwenden.

Weitere Informationen finden Sie unter folgendem Link.

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

1
the_new_mr

Vollständiges Beispiel für Verschlüsseln/Entschlüsseln a großes Video, ohne JavaOutOfMemoryException auszulösen und Java SecureRandom für die Initialisierungsvektorgenerierung zu verwenden. Dargestellt ist auch das Speichern der Schlüsselbytes in der Datenbank und das Wiederherstellen desselben Schlüssels aus diesen Bytes.

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

0
AZ_