在 Android 中的 iOS AES/CBC/PKCS7Padding 128 位算法中加密的解密字符串的问题

Posted

技术标签:

【中文标题】在 Android 中的 iOS AES/CBC/PKCS7Padding 128 位算法中加密的解密字符串的问题【英文标题】:Problem with decrypt String which is Encrypted in iOS AES/CBC/PKCS7Padding 128 bit Algorithm in Android 【发布时间】:2020-08-24 07:34:10 【问题描述】:

请指导我。我在解密由 ios“AES/CBC/PKCS7Padding”加密的字符串时遇到问题。它抛出异常。我想在android中解密字符串,在ios中加密。

在 Android 中,我遵循以下结构:

For Example: 
  String text = "rzp_test_DezQO1BVMXhkZY";
  String key = "5b0904cfada01b8182bcc029b928244d"; // secret key - 128 bit key
  String iv_key ="c999cbd1f130db1d";

我想加密和解密上面提到的“文本”字符串。如果我只从 Android 进行加密和解密。然后它工作正常。但是如果我试图解密在 ios 中加密的密钥,那么它会引发错误。

// Create key and cipher

Cipher dcipher, d1cipher;

      IvParameterSpec ivSpec = new IvParameterSpec(iv_key.getBytes());
      Key aesKey = new SecretKeySpec(key.getBytes(), "AES"); 

      ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
      dcipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

      ecipher.init(ENCRYPT_MODE, aesKey, ivSpec);
      dcipher.init(DECRYPT_MODE, aesKey, ivSpec);

加密算法:

  public String encrypt(String str) throws Exception 
        // Encode the string into bytes using utf-8
        byte[] utf8 = str.getBytes("UTF8");

        // Encrypt
        byte[] enc = ecipher.doFinal(utf8);

        // Encode bytes to base64 to get a string
        return Base64.encodeToString(enc, Base64.DEFAULT);
    

解密算法:

 public String decrypt(String str) throws Exception 
        // Decode base64 to get bytes
        String decrypted = "";
        try 
            byte[] dec = Base64.decode(str, Base64.DEFAULT);

            byte[] utf8 = dcipher.doFinal(dec);

            // Decode using utf-8
            decrypted = new String(utf8, "UTF8").trim();

         catch (Exception e) 


            e.printStackTrace();
        

        return decrypted;
    

它在 Android 中的加密和解密都可以正常工作。用这个检查:

String encrypted = encrypt(text);
System.out.println("Encrypted String: " + encrypted);

String decrypted = decrypt(encrypted);
System.out.println("Decrypted String: " + decrypted);

问题在于从 ios 解密以下加密字符串,这会引发错误:

   String decrypted1 = decrypt("c7076c78fc5d9d92c1d86c1500dcc0366ddf1b6e32df00ceadc911239935460d");
   System.out.println("Decrypted String1: " + decrypted1);

错误是:

W/System.err: javax.crypto.BadPaddingException: error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT
W/System.err:     at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
W/System.err:     at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:570)
W/System.err:     at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:351)
W/System.err:     at javax.crypto.Cipher.doFinal(Cipher.java:1741)
W/System.err:     at com.example.aesencryption.Activities.MainActivity1.decrypt(MainActivity1.java:178)

有人可以指导我吗??

在IOS中:

使用以下函数。

func aesEncrypt() -> String 

        let iv: [UInt8] = Array(AES_IV.utf8)
        let key: [UInt8] = Array(AES_SECRET.utf8)

        do
            let encrypted = try AES (key: key, blockMode: CBC(iv: iv)).encrypt([UInt8](self.data(using: .utf8)!))
            return Data(encrypted).base64EncodedString()
        
        catch
            print("error on encrypting data ")
            return ""
        

    

    func aesDecrypt() -> String 

        let iv: [UInt8] = Array(AES_IV.utf8)
        let key: [UInt8] = Array(AES_SECRET.utf8)
        do
            guard let data = Data(base64Encoded: self) else  return "" 
            let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt([UInt8](data))
            return String(bytes: decrypted, encoding: .utf8) ?? self
        
        catch
            print("error on encrypting data ")
            return ""
        

    

【问题讨论】:

iOS 是否使用相同的PKCS7Padding 进行加密? iOS 密文是十六进制编码的。但是,Android 代码中的 decrypt 需要 Base64 编码的字符串(因为 encrypt Base64 对密文进行编码)。所以你有两种可能性:要么将 iOS 密文转换为 Base64,例如Base64.encodeToString(hexStringToByteArray("c707...460d"), Base64.DEFAULT);hexStringToByteArray 来自 here 或者您相应地修改 Android 代码(以便也应用十六进制编码)。 另外,使用了 AES-256(而不是 AES-128)。 @RodrigoQueiroz 我添加了 iOS 算法。请看一看。 @topaco,我添加了 iOS 算法。请看一看。 【参考方案1】:

我通过以下方法得到了真正的字符串。

  public static String decryptKey(String key_id) 
            // Decode base64 to get bytes
            String decrypted = "";
            try 

                Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

                dcipher.init(DECRYPT_MODE, aesKey, ivSpec);

                byte[] utf8 = dcipher.doFinal(hexToBytes(key_id));

                // Decode using utf-8
                decrypted = new String(utf8, "UTF8").trim();

             catch (Exception e) 


                e.printStackTrace();
            

            return decrypted;
        

     public static byte[] hexToBytes(String str) 
            if (str == null) 
                return null;
             else if (str.length() < 2) 
                return null;
             else 
                int len = str.length() / 2;
                byte[] buffer = new byte[len];
                for (int i = 0; i < len; i++) 
                    buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
                
                return buffer;
            
        

【讨论】:

以上是关于在 Android 中的 iOS AES/CBC/PKCS7Padding 128 位算法中加密的解密字符串的问题的主要内容,如果未能解决你的问题,请参考以下文章

钛 AES/CBC/PKCS5Padding

iOS开发 --- 加密加盐(AES|CBC|PKCS7)

iOS开发 --- 加密加盐(AES|CBC|PKCS7)

AES/CBC/PKCS5 填充 |替代 PHP OpenSSL 中的 mcrypt_get_block_size()

如何使用Javascript中的AES CBC零填充进行加密并使用Java进行解密

AES (aes-cbc-128, aes-cbc-192, aes-cbc-256) 使用 openssl C 加密/解密