Android Java AES加密 [英] Android Java AES Encryption

查看:177
本文介绍了Android Java AES加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在制作Android应用程序,其中包括使用AES加密字符串。但是由于某种原因,我的应用程序没有正确解密。我试图改变Base64格式,但它不能解决它。代码与 Android加密与Android Cryptography API



有谁知道我的功能出了什么问题?因为它不会解码为与我编码的字符串(pls)相同的字符串。



您的帮助非常感谢。

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


/ **
*使用AES加密字符串(128位密钥)
* @param fin
* @返回AES加密字节[ ]
* /
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);
}

//用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);
}

返回encodedBytes;

}


/ **
*使用AES解密一个字符串(128位密钥)
* @param encodedBytes
* @返回解密的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);
}

//用AES
byte []解码编码数据decodeBytes = null;
try {
Cipher c = Cipher.getInstance(AES);
c.init(Cipher.DECRYPT_MODE,sks);
decodedBytes = c.doFinal(encodedBytes);
} catch(Exception e){
Log.e(decryptFIN128AES,AES decrypt error);
}

返回Base64.encodeToString(decodedBytes,Base64.DEFAULT);
}


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

final int iterations = 1000;

//生成256位密钥
final int outputKeyLength = 128;

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

输出:

  E / AES_Test:b = cGxz 

**



修改了我的代码,但现在有一个NullPointerException



**

  / ** 
*使用AES加密字符串(128位密钥)
* @param fin
* @返回AES加密字符串
* /
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);
}

//用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);
}

返回encodedBytes;

}


/ **
*使用AES解密一个字符串(128位密钥)
* @param encodedBytes
* @返回解密的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);
}

//用AES
byte []解码编码数据decodeBytes = 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 decrypt error);
}

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

// generateKey(char [] passphraseOrPin,byte [] salt)保持不变

错误:

  E / decryptFIN128AES:AES解密错误
E / AndroidRuntime:致命的例外:Thread-176
进程:testapp.ttyi.nfcapp,PID:2920
java.lang.NullPointerException:尝试获取null数组的长度
在java.lang.String。< ; init>(String.java:371)
在testapp.ttyi.nfcapp.DisplayQRActivity.decryptFIN128AES(DisplayQRActivity.java:254)
在testapp.ttyi.nfcapp.DisplayQRActivity.access $ 100(DisplayQRActivity.java :29)
at testapp.ttyi.nfcapp.DisplayQRActivity $ 1.run(DisplayQRActivity.java:77)
在java.lang.Thread.run(Thread.java:818)

**



已解决(但无填充/加密模式允许)



**



我设法解决了这个问题。 (解码到pls)使用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 decrypt error);
}

某些东西会失败,它总是打印出来:

  E / decryptFIN128AES:AES解密错误

因此,NullPointerException将发生为 decodingBytes 始终为NULL。

解决方案

您的流程不均衡。要进行加密,请执行以下操作:


  1. 使用默认字符集编码字符串( fin.getBytes())获取二进制数据

  2. 加密二进制数据以获取加密数据( doFinal



    1. 对于解密,您可以执行以下操作:


      1. 解密加密数据以获取未加密的二进制数据( doFinal

      2. 将二进制数据编码为Base64字符串

      代替Base64编码,最后一步应与加密中的步骤1相反,即应将二进制数据解码为字符串:

        return String(decodedBytes); 

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



      所以使用:

        fin.getBytes(StandardCharsets.UTF_8); 

      和:

       code> return String(decodedBytes,StandardCharsets.UTF_8); 

      同样适用于盐。



      另请注意,您应该指定填充和链接模式。如果没有,则提供者特定的默认值适用。详见@ Ryan的答案。


      I am currently making an Android app that includes encrypting a String with AES. But for some reason my app does not decrypt properly. I tried to change the Base64 format but it does not fix it. The code is similar to the example on Android Encryption with the Android Cryptography API

      Does anyone know where did I go wrong with my functions? Since it does not decode to the same string as my encoded string ("pls").

      Your help is much appreciated.

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

      Output:

      E/AES_Test: b = cGxz
      

      **

      [EDIT] Modified my code but now there is a 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
      

      Error:

      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] Resolved (But no Padding/Encryption Mode allowed)

      **

      I managed to resolve the issue. (Decodes to "pls") using Codo's solution ofreturn new String(decodedBytes, StandardCharsets.UTF_8);

      Though it only works when the algorithm used is: Cipher c = Cipher.getInstance("AES");

      When I put Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); The "NullPointerException" as seen above will happen. My observation shows that during decryption:

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

      something will fail and it will always print out:

      E/decryptFIN128AES: AES decryption error
      

      And thus the NullPointerException will occur as decodedBytes is always initiated to NULL.

      解决方案

      Your process is not balanced. For encryption you do:

      1. Encode string using default charset (fin.getBytes()) to get binary data
      2. Encrypt binary data to get encrypted data (doFinal)

      For the decryption, you do:

      1. Decrypt encrypted data to get unencrypted binary data (doFinal)
      2. Encode binary data as a Base64 string

      Instead of Base64 encoding, the last step should be the reverse of step 1 in the encryption, i.e. you should decode the binary data into a string:

      return String(decodedBytes);
      

      It strongly recommend, you do not use the default charset for encoding and decoding as it depends on the system's setting. So it could be different between the system where you encrypt and decyrpt.

      So use:

      fin.getBytes(StandardCharsets.UTF_8);
      

      and:

      return String(decodedBytes, StandardCharsets.UTF_8);
      

      The same applies for the salt.

      Also note that you should specify the padding and chaining mode. If you don't, provider-specific default values apply. See @Ryan's answer for more details.

      这篇关于Android Java AES加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆