2013-10-05 51 views
15

我一直试图使用AES-128 CBC解密一个字符串,该字符串最初使用JAVA AES加密进行了加密。在java中使用PKCS7填充。我试图使用类似的PHP代码进行加密和解密。但我得到不同的结果。Java中的AES 128加密解密PHP中的

我的Java代码

import java.security.MessageDigest; 
import java.security.spec.AlgorithmParameterSpec; 

import javax.crypto.Cipher; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 

import android.util.Base64; 

/** 
* @author vipin.cb , [email protected] <br> 
*   Sep 27, 2013, 5:18:34 PM <br> 
*   Package:- <b>com.veebow.util</b> <br> 
*   Project:- <b>Veebow</b> 
*   <p> 
*/ 
public class AESCrypt { 

    private final Cipher cipher; 
    private final SecretKeySpec key; 
    private AlgorithmParameterSpec spec; 
    public static final String SEED_16_CHARACTER = "U1MjU1M0FDOUZ.Qz"; 

    public AESCrypt() throws Exception { 
     // hash password with SHA-256 and crop the output to 128-bit for key 
     MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
     digest.update(SEED_16_CHARACTER.getBytes("UTF-8")); 
     byte[] keyBytes = new byte[32]; 
     System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length); 

     cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); 
     key = new SecretKeySpec(keyBytes, "AES"); 
     spec = getIV(); 
    } 

    public AlgorithmParameterSpec getIV() { 
     byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 
     IvParameterSpec ivParameterSpec; 
     ivParameterSpec = new IvParameterSpec(iv); 

     return ivParameterSpec; 
    } 

    public String encrypt(String plainText) throws Exception { 
     cipher.init(Cipher.ENCRYPT_MODE, key, spec); 
     byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8")); 
     String encryptedText = new String(Base64.encode(encrypted, 
       Base64.DEFAULT), "UTF-8"); 

     return encryptedText; 
    } 

    public String decrypt(String cryptedText) throws Exception { 
     cipher.init(Cipher.DECRYPT_MODE, key, spec); 
     byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT); 
     byte[] decrypted = cipher.doFinal(bytes); 
     String decryptedText = new String(decrypted, "UTF-8"); 

     return decryptedText; 
    } 

} 

,我使用了相当于PHP代码。

<?php 

class MCrypt { 

    private $iv = '0000000000000000'; #Same as in JAVA    
    private $key = 'U1MjU1M0FDOUZ.Qz'; #Same as in JAVA 

    function __construct() { 
     $this->key = hash('sha256', $this->key, true); 
    } 

    function encrypt($str) { 
     $iv = $this->iv; 
     $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); 
     mcrypt_generic_init($td, $this->key, $iv); 
     $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); 
     $pad = $block - (strlen($str) % $block); 
     $str .= str_repeat(chr($pad), $pad); 
     $encrypted = mcrypt_generic($td, $str); 
     mcrypt_generic_deinit($td); 
     mcrypt_module_close($td); 
     return base64_encode($encrypted); 
    } 

    function decrypt($code) { 
     $iv = $this->iv; 
     $td = mcrypt_module_open('rijndael-128', '', 'cbc', ''); 
     mcrypt_generic_init($td, $this->key, $iv); 
     $str = mdecrypt_generic($td, base64_decode($code)); 
     $block = mcrypt_get_block_size('rijndael-128', 'cbc'); 
     mcrypt_generic_deinit($td); 
     mcrypt_module_close($td); 
     return $str; 
     //return $this->strippadding($str);    
    } 

    /* 
     For PKCS7 padding 
    */ 
    private function addpadding($string, $blocksize = 16) { 
     $len = strlen($string); 
     $pad = $blocksize - ($len % $blocksize); 
     $string .= str_repeat(chr($pad), $pad); 
     return $string; 
    } 

    private function strippadding($string) { 
     $slast = ord(substr($string, -1)); 
     $slastc = chr($slast); 
     $pcheck = substr($string, -$slast); 
     if (preg_match("/$slastc{" . $slast . "}/", $string)) { 
      $string = substr($string, 0, strlen($string) - $slast); 
      return $string; 
     } else { 
      return false; 
     } 
    } 

} 

$encryption = new MCrypt(); 
echo $encryption->encrypt('123456') . "<br/>"; 
echo $encryption->decrypt('tpyxISJ83dqEs3uw8bN/+w=='); 

在Java
明文= 123456
密文= tpyxISJ83dqEs3uw8bN/+ W ==

在PHP

明文= 123456
密文= IErqfTCktrnmWndOpq3pnQ ==

当我尝试使用PHP解密对Java加密文本“tpyxISJ83dqEs3uw8bN/+ w =​​=”进行解密时,我是ge如果我删除了填充,则为空数组。没有删除填充,我得到“::::::::::”

我认为在PHP和Java中使用的IV字节有一些错误 任何人都可以帮助我解决这个问题。我尝试了很多组合。仍然没有结果。我对Java概念非常陌生。

------解决方案-------

我已经根据owlstead给出的意见修改我的PHP类。可能有更好的办法。我在这里发布它,以便有人可能会在未来发现它有帮助,并且欢迎您的意见以进一步改进。

<?php 

class MCrypt { 

    private $hex_iv = '00000000000000000000000000000000'; # converted Java byte code in to HEX and placed it here    
    private $key = 'U1MjU1M0FDOUZ.Qz'; #Same as in JAVA 

    function __construct() { 
     $this->key = hash('sha256', $this->key, true); 
     //echo $this->key.'<br/>'; 
    } 

    function encrypt($str) {  
     $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); 
     mcrypt_generic_init($td, $this->key, $this->hexToStr($this->hex_iv)); 
     $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); 
     $pad = $block - (strlen($str) % $block); 
     $str .= str_repeat(chr($pad), $pad); 
     $encrypted = mcrypt_generic($td, $str); 
     mcrypt_generic_deinit($td); 
     mcrypt_module_close($td);   
     return base64_encode($encrypted); 
    } 

    function decrypt($code) {   
     $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); 
     mcrypt_generic_init($td, $this->key, $this->hexToStr($this->hex_iv)); 
     $str = mdecrypt_generic($td, base64_decode($code)); 
     $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); 
     mcrypt_generic_deinit($td); 
     mcrypt_module_close($td);   
     return $this->strippadding($str);    
    } 

    /* 
     For PKCS7 padding 
    */ 

    private function addpadding($string, $blocksize = 16) { 
     $len = strlen($string); 
     $pad = $blocksize - ($len % $blocksize); 
     $string .= str_repeat(chr($pad), $pad); 
     return $string; 
    } 

    private function strippadding($string) { 
     $slast = ord(substr($string, -1)); 
     $slastc = chr($slast); 
     $pcheck = substr($string, -$slast); 
     if (preg_match("/$slastc{" . $slast . "}/", $string)) { 
      $string = substr($string, 0, strlen($string) - $slast); 
      return $string; 
     } else { 
      return false; 
     } 
    } 
function hexToStr($hex) 
{ 
    $string=''; 
    for ($i=0; $i < strlen($hex)-1; $i+=2) 
    { 
     $string .= chr(hexdec($hex[$i].$hex[$i+1])); 
    } 
    return $string; 
} 
} 

$encryption = new MCrypt(); 
echo $encryption->encrypt('123456') . "<br/>"; 
echo $encryption->decrypt('tpyxISJ83dqEs3uw8bN/+w=='); 
+0

谢谢。这正是我所期待的。在我的钥匙中修正了一个错字,然后马上放弃! – ssdscott

+0

@ssdscott我很高兴它帮助你,甚至在发布2年后:) – shanavascet

回答

9

你的IV不同的是,具有值零的字节是从字符'0'这将转化为与小数以十六进制值30或48字节不同(如果假设ASCII或UTF-8编码)。

+0

什么应该是IV ..我给了16空间没有运气。我试图将字节iv转换为java中的字符串,并得到了长度为16的空字符串。我尝试在php中使用它进行加密,但没有任何运气。 – shanavascet

+2

比较两个平台上IV的字节值。请记住,对称密码的输入和输出是以字节为单位的,并且已经为密码预定义了字节的顺序。你应该总是得到与平台无关的相同结果。因此,请确保您输入算法的值在两个平台上都相同。执行此操作的最佳方法是在执行密码操作之前以十六进制形式输出输入值。谨防(字符)编码/解码问题!如果可能的话,使用相同的*字节数组*来测试算法本身的输入/输出。 –

+0

非常感谢猫头鹰..我遵循你提到的步骤..感谢您的耐心回答我的问题和评论在这里...爱你。 – shanavascet