【问题标题】:Android Java AES EncryptionAndroid Java AES 加密
【发布时间】:2017-05-31 03:23:37
【问题描述】:

我目前正在制作一个包含使用 AES 加密字符串的 Android 应用程序。但由于某种原因,我的应用程序无法正确解密。我试图更改 Base64 格式,但它没有修复它。代码类似于Android Encryption with the Android Cryptography API上的例子

有谁知道我的功能哪里出错了?因为它不会解码为与我的编码字符串(“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

**

[EDIT] 修改了我的代码,但现在有一个 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);解决方案

虽然它只在使用的算法是: 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。

【问题讨论】:

    标签: java android encryption base64 aes


    【解决方案1】:

    您的流程不平衡。对于加密,您可以:

    1. 使用默认字符集 (fin.getBytes()) 对字符串进行编码以获取二进制数据
    2. 加密二进制数据得到加密数据 (doFinal)

    为了解密,你这样做:

    1. 解密加密数据得到未加密的二进制数据 (doFinal)
    2. 将二进制数据编码为 Base64 字符串

    最后一步应该与加密中的第 1 步相反,而不是 Base64 编码,即您应该将二进制数据解码为字符串:

    return String(decodedBytes);
    

    强烈建议您不要使用默认字符集进行编码和解码,因为它取决于系统的设置。因此,您加密和解密的系统之间可能会有所不同。

    所以使用:

    fin.getBytes(StandardCharsets.UTF_8);
    

    和:

    return String(decodedBytes, StandardCharsets.UTF_8);
    

    盐也是如此。

    还请注意,您应该指定填充和链接模式。如果您不这样做,则应用特定于提供商的默认值。有关更多详细信息,请参阅@Ryan 的答案。

    【讨论】:

    • 您好,感谢您的回复。我试图放入您的解决方案,但现在它在 decryptFIN128AES 的最后一行给了我一个 NullPointerException:return new String(decodedBytes, StandardCharsets.UTF_8);
    【解决方案2】:

    您应该更多地研究如何正确使用 AES,因为您缺少 AES 安全性的一些基本原理:没有 IV(假设使用 CBC)、没有指定模式(例如 CBC)和没有指定填充(例如 PKCS5) .

    【讨论】:

      【解决方案3】:

      看起来像字符编码问题。稍作修改即可使用。

      在加密FIN128AES中:

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

      在解密FIN128AES:

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

      【讨论】:

      • Base64 编码和解码对这里的过程没有任何影响。它只会增加加密数据的长度。可以直接跳过。
      猜你喜欢
      • 1970-01-01
      • 2016-09-22
      • 2011-06-05
      • 2011-11-22
      • 1970-01-01
      • 2017-04-16
      • 2012-03-28
      • 2012-06-01
      • 1970-01-01
      相关资源
      最近更新 更多