【问题标题】:Java decrypt error: data not block size alignedJava解密错误:数据未对齐块大小
【发布时间】:2011-09-26 16:39:59
【问题描述】:

我正在尝试加密我的 android 应用程序和 PHP 网络服务之间的数据。

我在这个网站找到了下一段代码:http://schneimi.wordpress.com/2008/11/25/aes-128bit-encryption-between-java-and-php/

但是当我尝试解密时,我得到标题“数据未对齐块大小”的异常

这是我的 MCrypt 类

中的方法
public String encrypt(String text) throws Exception
{
    if(text == null || text.length() == 0)
        throw new Exception("Empty string");

    Cipher cipher;
    byte[] encrypted = null;

    try {
        cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);

        encrypted = cipher.doFinal(padString(text).getBytes());
    } catch (Exception e)
    {           
        throw new Exception("[encrypt] " + e.getMessage());
    }

    return new String( encrypted );
}

public String decrypt(String code) throws Exception
{
    if(code == null || code.length() == 0)
        throw new Exception("Empty string");

    Cipher cipher;
    byte[] decrypted = null;

    try {
        cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
        decrypted = cipher.doFinal(hexToBytes(code));
    } catch (Exception e)
    {
        throw new Exception("[decrypt] " + e.getMessage());
    }
    return new String( decrypted );
}


private static byte[] hexToBytes(String hex) {
  String HEXINDEX = "0123456789abcdef";
  int l = hex.length() / 2;
  byte data[] = new byte[l];
  int j = 0;

  for (int i = 0; i < l; i++) {
    char c = hex.charAt(j++);
    int n, b;

    n = HEXINDEX.indexOf(c);
    b = (n & 0xf) << 4;
    c = hex.charAt(j++);
    n = HEXINDEX.indexOf(c);
    b += (n & 0xf);
    data[i] = (byte) b;
  }

  return data;
}

private static String padString(String source)
{
  char paddingChar = ' ';
  int size = 16;
  int x = source.length() % size;
  int padLength = size - x;

  for (int i = 0; i < padLength; i++)
  {
      source += paddingChar;
  }

  return source;
}

这就是我在我的活动中使用它进行测试的方式:

String encrypted = mcrypt.encrypt(jsonUser.toString());
String decrypted = mcrypt.decrypt(encrypted);

加密方法工作正常,但第二个抛出异常。

【问题讨论】:

    标签: java php android mcrypt


    【解决方案1】:

    终于!我让它工作了!感谢您的所有建议。我想分享代码以防有人像我一样被卡住:

    JAVA

    import java.security.NoSuchAlgorithmException;
    
    import javax.crypto.Cipher;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public class MCrypt {
    
        private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!)
        private IvParameterSpec ivspec;
        private SecretKeySpec keyspec;
        private Cipher cipher;
    
        private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!)
    
        public MCrypt()
        {
            ivspec = new IvParameterSpec(iv.getBytes());
    
            keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
    
            try {
                cipher = Cipher.getInstance("AES/CBC/NoPadding");
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        public byte[] encrypt(String text) throws Exception
        {
            if(text == null || text.length() == 0)
                throw new Exception("Empty string");
    
            byte[] encrypted = null;
    
            try {
                cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
    
                encrypted = cipher.doFinal(padString(text).getBytes());
            } catch (Exception e)
            {           
                throw new Exception("[encrypt] " + e.getMessage());
            }
    
            return encrypted;
        }
    
        public byte[] decrypt(String code) throws Exception
        {
            if(code == null || code.length() == 0)
                throw new Exception("Empty string");
    
            byte[] decrypted = null;
    
            try {
                cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
    
                decrypted = cipher.doFinal(hexToBytes(code));
            } catch (Exception e)
            {
                throw new Exception("[decrypt] " + e.getMessage());
            }
            return decrypted;
        }
    
    
    
        public static String bytesToHex(byte[] data)
        {
            if (data==null)
            {
                return null;
            }
    
            int len = data.length;
            String str = "";
            for (int i=0; i<len; i++) {
                if ((data[i]&0xFF)<16)
                    str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
                else
                    str = str + java.lang.Integer.toHexString(data[i]&0xFF);
            }
            return str;
        }
    
    
        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;
            }
        }
    
    
    
        private static String padString(String source)
        {
          char paddingChar = ' ';
          int size = 16;
          int x = source.length() % size;
          int padLength = size - x;
    
          for (int i = 0; i < padLength; i++)
          {
              source += paddingChar;
          }
    
          return source;
        }
    }
    

    如何使用它(JAVA)

    mcrypt = new MCrypt();
    /* Encrypt */
    String encrypted = MCrypt.bytesToHex( mcrypt.encrypt("Text to Encrypt") );
    /* Decrypt */
    String decrypted = new String( mcrypt.decrypt( encrypted ) );
    

    ================================================ =====

    PHP

    <?php 
    
    class MCrypt
    {
        private $iv = 'fedcba9876543210'; #Same as in JAVA
        private $key = '0123456789abcdef'; #Same as in JAVA
    
    
        function __construct()
        {
        }
    
        function encrypt($str) {
    
          //$key = $this->hex2bin($key);    
          $iv = $this->iv;
    
          $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
    
          mcrypt_generic_init($td, $this->key, $iv);
          $encrypted = mcrypt_generic($td, $str);
    
          mcrypt_generic_deinit($td);
          mcrypt_module_close($td);
    
          return bin2hex($encrypted);
        }
    
        function decrypt($code) {
          //$key = $this->hex2bin($key);
          $code = $this->hex2bin($code);
          $iv = $this->iv;
    
          $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
    
          mcrypt_generic_init($td, $this->key, $iv);
          $decrypted = mdecrypt_generic($td, $code);
    
          mcrypt_generic_deinit($td);
          mcrypt_module_close($td);
    
          return utf8_encode(trim($decrypted));
        }
    
        protected function hex2bin($hexdata) {
          $bindata = '';
    
          for ($i = 0; $i < strlen($hexdata); $i += 2) {
            $bindata .= chr(hexdec(substr($hexdata, $i, 2)));
          }
    
          return $bindata;
        }
    
    }
    

    如何使用它(PHP)

    <?php 
    
    $mcrypt = new MCrypt();
    #Encrypt
    $encrypted = $mcrypt->encrypt("Text to encrypt");
    #Decrypt
    $decrypted = $mcrypt->decrypt($encrypted);
    

    【讨论】:

      【解决方案2】:

      我猜你的keyspecivspec 对解密无效。我通常将它们转换为PublicKeyPrivateKey 实例,然后使用私钥解密。

      【讨论】:

      • 这是我的 ivspec 和 keyspec: ivspec = new IvParameterSpec(iv.getBytes()); keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
      • 啊。您使用的是 AES,而不是 RSA。我的错。您收到的异常是什么?
      • 这是一个例外:javax.crypto.IllegalBlockSizeException:数据未对齐块大小
      • @Femi,我们无法使用 RSA 加密大数据
      • @Femi,我认为我们可以使用 RSA 加密最大大小为 256 字节的数据
      【解决方案3】:

      我查看了另一个答案中的 cmets。我在尝试使用 php 中的开放 SSL 加密大块文本时遇到了类似的问题(双方)。我想 Java 也会出现同样的问题。

      如果您有 1024 位 RSA 密钥,则必须将传入的文本分成 117 个字节的块(一个字符就是一个字节)并加密每个块(您可以将它们连接在一起)。另一方面,您必须将加密数据拆分为 128 字节的块并分别解密。这应该会给你你的原始信息。

      另外请注意,http 可能对非 ASCII 加密数据不友好。我在传输之前和之后对其进行 base64 编码/解码(另外,您必须担心 base64 更改的额外 urlencoding,但这很容易)。

      我不确定您的 AES 密钥长度,但如果它是 1024 位,则块长度可能相同。如果不是,则必须将这些位除以 8 才能找到输出的字节块长度。不幸的是,我实际上不确定如何获得它(可能乘以 117/128 ?)

      这是一些php代码:

      class Crypto {
         public function encrypt($key, $data) {
            $crypto = '';
            foreach (str_split($data, 117) as $chunk) {
               openssl_public_encrypt($chunk, $encrypted, $key);
               $crypto .= $encrypted;
            }
            return $crypto;
         }
      
         //Decrypt omitted.  Basically the same, change 117 to 128.
      
         /**#@+
          * Update data for HTTP transmission and retrieval
          * Must be used on encrypted data, but also useful for any binary data
          * (e.g. zip files).
          */
         public function base64_encode($value) {
            return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
         }
         //String length must be padded for decoding for some reason
         public function base64_decode($value) {
            return base64_decode(str_pad(strtr($value, '-_', '+/')
               , strlen($value) % 4, '=', STR_PAD_RIGHT));
         }
         /**#@-*/
      }
      

      【讨论】:

        猜你喜欢
        • 2023-04-06
        • 2011-05-02
        • 1970-01-01
        • 1970-01-01
        • 2014-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-15
        相关资源
        最近更新 更多