簡體   English   中英

Android Java AES加密

[英]Android Java AES Encryption

我目前正在制作一個Android應用,其中包括使用AES加密字符串。 但是由於某種原因,我的應用程序無法正確解密。 我試圖更改Base64格式,但無法解決。 該代碼類似於使用Android Cryptography API進行的Android加密示例。

有誰知道我的功能出了什么問題? 由於它不會解碼為與我的編碼字符串(“ pls”)相同的字符串。

非常感謝您的幫助。

byte[] a = encryptFIN128AES("pls");
String b = decryptFIN128AES(a);
Log.e("AES_Test", "b = " + b);


/**
 * Encrypts a string with AES (128 bit key)
 * @param fin 
 * @return the AES encrypted byte[]
 */
private byte[] encryptFIN128AES(String fin) {

    SecretKeySpec sks = null;

    try {
        sks = new SecretKeySpec(generateKey("Test1".toCharArray(), "Test2".getBytes()).getEncoded(),"AES");
    } catch (Exception e) {
        Log.e("encryptFIN128AES", "AES key generation error");
    }

    // Encode the original data with AES
    byte[] encodedBytes = null;
    try {
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.ENCRYPT_MODE, sks);
        encodedBytes = c.doFinal(fin.getBytes());
    } catch (Exception e) {
        Log.e("encryptFIN128AES", "AES encryption error");
    }

    return encodedBytes;

}


/**
 * Decrypts a string with AES (128 bit key)
 * @param encodedBytes
 * @return the decrypted String
 */
private String decryptFIN128AES(byte[] encodedBytes) {

    SecretKeySpec sks = null;

    try {
        sks = new SecretKeySpec(generateKey("Test1".toCharArray(), "Test2".getBytes()).getEncoded(),"AES");
    } catch (Exception e) {
        Log.e("decryptFIN128AES", "AES key generation error");
    }

    // Decode the encoded data with AES
    byte[] decodedBytes = null;
    try {
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, sks);
        decodedBytes = c.doFinal(encodedBytes);
    } catch (Exception e) {
        Log.e("decryptFIN128AES", "AES decryption error");
    }

    return Base64.encodeToString(decodedBytes, Base64.DEFAULT);
}


public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt)
        throws NoSuchAlgorithmException, InvalidKeySpecException {

    final int iterations = 1000;

    // Generate a 256-bit key
    final int outputKeyLength = 128;

    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
    SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
    return secretKey;
}

輸出:

E/AES_Test: b = cGxz

**

[編輯]修改了我的代碼,但是現在有一個NullPointerException

**

/**
     * Encrypts a string with AES (128 bit key)
     * @param fin
     * @return the AES encrypted string
     */
    private byte[] encryptFIN128AES(String fin) {

        SecretKeySpec sks = null;

        try {
            sks = new SecretKeySpec(generateKey(PASSPHRASE, SALT.getBytes(StandardCharsets.UTF_8)).getEncoded(), "AES");
        } catch (Exception e) {
            Log.e("encryptFIN128AES", "AES key generation error");
        }

        // Encode the original data with AES
        byte[] encodedBytes = null;
        try {
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
            c.init(Cipher.ENCRYPT_MODE, sks);
            encodedBytes = c.doFinal(fin.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            Log.e("encryptFIN128AES", "AES encryption error");
        }

        return encodedBytes;

    }


    /**
     * Decrypts a string with AES (128 bit key)
     * @param encodedBytes
     * @return the decrypted String
     */
    private String decryptFIN128AES(byte[] encodedBytes) {

        SecretKeySpec sks = null;

        try {
            sks = new SecretKeySpec(generateKey(PASSPHRASE, SALT.getBytes(StandardCharsets.UTF_8)).getEncoded(), "AES");
        } catch (Exception e) {
            Log.e("decryptFIN128AES", "AES key generation error");
        }

        // Decode the encoded data with AES
        byte[] decodedBytes = null;
        try {
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
            c.init(Cipher.DECRYPT_MODE, sks);
            decodedBytes = c.doFinal(encodedBytes);
        } catch (Exception e) {
            Log.e("decryptFIN128AES", "AES decryption error");
        }

        //return Base64.encodeToString(decodedBytes, Base64.DEFAULT);
        return new String(decodedBytes, StandardCharsets.UTF_8);
    }

// generateKey(char[] passphraseOrPin, byte[] salt) remains the same

錯誤:

E/decryptFIN128AES: AES decryption error
E/AndroidRuntime: FATAL EXCEPTION: Thread-176
                  Process: testapp.ttyi.nfcapp, PID: 2920
                  java.lang.NullPointerException: Attempt to get length of null array
                      at java.lang.String.<init>(String.java:371)
                      at testapp.ttyi.nfcapp.DisplayQRActivity.decryptFIN128AES(DisplayQRActivity.java:254)
                      at testapp.ttyi.nfcapp.DisplayQRActivity.access$100(DisplayQRActivity.java:29)
                      at testapp.ttyi.nfcapp.DisplayQRActivity$1.run(DisplayQRActivity.java:77)
                      at java.lang.Thread.run(Thread.java:818)

**

[EDIT2]已解決(但不允許填充/加密模式)

**

我設法解決了這個問題。 (使用Codo的return new String(decodedBytes, StandardCharsets.UTF_8);的解決方案)解碼(“ pls” return new String(decodedBytes, StandardCharsets.UTF_8);

盡管僅在使用以下算法時才起作用: Cipher c = Cipher.getInstance("AES");

當我輸入Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 如上所示,將發生“ NullPointerException”。 我的觀察表明,在解密期間:

 try {
                Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
                c.init(Cipher.DECRYPT_MODE, sks);
                decodedBytes = c.doFinal(encodedBytes);
            } catch (Exception e) {
                Log.e("decryptFIN128AES", "AES decryption error");
            }

某些操作將失敗,並且將始終打印出來:

E/decryptFIN128AES: AES decryption error

因此,NullPointerException將會發生,因為decodedBytes總是被初始化為NULL。

您的過程不平衡。 對於加密,您可以執行以下操作:

  1. 使用默認字符集( fin.getBytes() )編碼字符串以獲取二進制數據
  2. 加密二進制數據以獲取加密數據( doFinal

對於解密,您可以執行以下操作:

  1. 解密加密的數據以獲得未加密的二進制數據( doFinal
  2. 將二進制數據編碼為Base64字符串

代替Base64編碼,最后一步應該是加密中步驟1的相反步驟,即您應該將二進制數據解碼為字符串:

return String(decodedBytes);

強烈建議您不要使用默認字符集進行編碼和解碼,因為它取決於系統設置。 因此,在您進行加密和解密的系統之間可能有所不同。

因此使用:

fin.getBytes(StandardCharsets.UTF_8);

和:

return String(decodedBytes, StandardCharsets.UTF_8);

鹽也是如此。

還要注意,您應該指定填充和鏈接模式。 如果不這樣做,則將應用提供者特定的默認值。 有關更多詳細信息,請參見@Ryan的答案。

由於缺少AES安全性的一些基本基礎知識,因此您應該對如何正確使用AES進行更多研究:沒有IV(假設使用CBC),沒有指定模式(例如CBC)和未指定填充(例如PKCS5)。

看起來像char編碼問題。 稍作修改,它就可以工作。

在cryptoFIN128AES中:

encodedBytes = c.doFinal(Base64.getEncoder().encode(fin.getBytes()));

在cryptoFIN128AES中:

return new String(Base64.getDecoder().decode(decodedBytes));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM