2016-06-01 77 views
0

我需要加密一個unix時間戳以調用第三方API。在他們的文件,他們規定我必須使用:加密PHP中的時間戳並使用Java解密

  • 算法:128位AES,模式:CBC
  • 填充:PKCS5Padding
  • 初始化向量: 「0000000000000000」

然後他們給一個例子:

客戶端必須使用時間戳1464284796測試它們的實現,初始化向量:'0000000000000000 '並導致AUTH_TOKEN 6BH3hg1cqQJOK6sG8gw7Xw ==以base64密鑰b35901b480ca658c8be4341eefe21a80

他們甚至給示例代碼來生成加密的時間戳,問題是,他們使用的是Java,我們正在使用PHP。我在PHP中嘗試的所有內容都與期望的輸出不匹配,即6BH3hg1cqQJOK6sG8gw7Xw ==。

這裏是他們的Java示例:

import java.io.UnsupportedEncodingException; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import javax.crypto.Cipher; 
import javax.crypto.NoSuchPaddingException; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 
import org.apache.commons.codec.DecoderException; 
import org.apache.commons.codec.binary.Base64; 
import org.apache.commons.codec.binary.Hex; 
import com.google.common.primitives.Longs; 
class Encryptor { 
    private String initialVector; 
    private static final String TRANFORMATION = "AES/CBC/PKCS5Padding"; 
    private static final String ALGORITHM = "AES"; 
    String encrypt(SecretKeySpec key, long timestamp) throws Exception { 
     byte[] encryptedBytes = 
      getEncryptingCipher(key).doFinal(Longs.toByteArray(timestamp)); 
     return Base64.encodeBase64String(encryptedBytes); 
    } 
    private Cipher getEncryptingCipher(SecretKeySpec key) throws 
    NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, 
    InvalidKeyException, 
    InvalidAlgorithmParameterException { 
     Cipher encryptingCipher = Cipher.getInstance(TRANFORMATION); 
     encryptingCipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(initialVector.getBytes())); 
     return encryptingCipher; 
    } 
    private SecretKeySpec getSecretKeySpec(String key) throws DecoderException { 
     byte[] keyBytes = Hex.decodeHex(key.toCharArray()); 
     return new SecretKeySpec(keyBytes, ALGORITHM); 
    } 
    void setInitialVector(String initialVector) { 
     this.initialVector = initialVector; 
    } 
} 

用法:

Encryptor encryptor = new Encryptor(); 
encryptor.setInitialVector("0000000000000000"); 
//Expensive operation so only performed once, re-use the key spec instance 
SecretKeySpec keySpec = 
encryptor.getSecretKeySpec("b35901b480ca658c8be4341eefe21a80"); 
long timestamp = System.currentTimeMillis()/1000; 
String authToken = encryptor.encrypt(keySpec, timestamp); 

我試圖在PHP中:

[[email protected] ~]$ php -a 
Interactive shell 

php > echo openssl_encrypt('1464284796','AES-128-CBC','b35901b480ca658c8be4341eefe21a80',null,'0000000000000000'); 
8PM7LQM7Xmb2NCBE3Hp00g== 
php > 

然後:

<?php 

function encrypt($message, $initialVector, $secretKey) { 
    return base64_encode(
     mcrypt_encrypt(
      MCRYPT_RIJNDAEL_128, 
      $secretKey, 
      $message, 
      MCRYPT_MODE_CBC, 
      $initialVector 
     ) 
    ); 
} 

function encrypt_something($input) 
{ 
    $size = mcrypt_get_block_size('rijndael-128', 'cbc'); 
    $input = pkcs5_pad($input, $size); 

    $key = 'b35901b480ca658c8be4341eefe21a80'; 
    $td = mcrypt_module_open('rijndael-128', '', 'cbc', ''); 
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND); 
    mcrypt_generic_init($td, $key, '0000000000000000'); 
    $data = mcrypt_generic($td, $input); 
    mcrypt_generic_deinit($td); 
    mcrypt_module_close($td); 
    $data = base64_encode($data); 
    return $data; 
} 

function pkcs5_pad ($text, $blocksize) 
{ 
    $pad = $blocksize - (strlen($text) % $blocksize); 
    return $text . str_repeat(chr($pad), $pad); 
} 

function pkcs5_unpad($text) 
{ 
    $pad = ord($text{strlen($text)-1}); 
    if ($pad > strlen($text)) return false; 
    if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false; 
    return substr($text, 0, -1 * $pad); 
} 

echo encrypt_something('1464284796'); 

//echo encrypt('1464284796','0000000000000000','b35901b480ca658c8be4341eefe21a80'); 



[[email protected] ~]$ php -f api.php 
UXRvTOIPiiYfBUoDFRaC5w== 

老實說,我不知道我在做什麼,特別是在JAVA中。我甚至不知道如何運行示例代碼。

UPDATE

第三方伸出我們自己的樣品進行修訂:

注:客戶必須使用時間戳 1464284796,初始化向量測試及其履行情況:「0000000000000000」並導致 的base64 AUTH_TOKEN ZnNmKbcdxRrYTDBgQKI9aQ ==的 密鑰b35901b480ca658c8be4341eefe21a80

的解決方案是revome pack功能:

$ts = '1464284796'; 
$key = "b35901b480ca658c8be4341eefe21a80"; 
$authToken = openssl_encrypt($ts, 'AES-128-CBC', hextobin($key), null, '0000000000000000'); 

function hextobin($hexstr) 
{ 
    $n = strlen($hexstr); 
    $sbin =""; 
    $i =0; 
    while($i<$n) 
    { 
     $a =substr($hexstr,$i,2); 
     $c = pack("H*",$a); 
     if ($i==0){$sbin=$c;} 
     else {$sbin.=$c;} 
     $i+=2; 
    } 
    return $sbin; 
} 
+0

能系統調用運行準備Java代碼的方法嗎?這可以得到答案,並且可能比在PHP中實現所有這些東西更容易。 –

回答

1

數字不是簡單的十進制字符串。您必須將它們編碼爲二進制表示。這可以通過pack完成。由於Longs.toByteArray(timestamp)編碼時間戳64位大端表示法,你一定要配合這個編碼:

$ts = "\0\0\0\0" . pack('N', '1464284796'); 
echo openssl_encrypt($ts, 'AES-128-CBC', hex2bin('b35901b480ca658c8be4341eefe21a80'), 
     null, '0000000000000000')); 
+0

它輸出'6BH3hg1cqQJOK6sG8gw7Xw =='!非常感謝!!! –

0

看一看你使用的Java API。他們真的期望十六絃?這在Java中非常罕見。這裏

你的代碼說「initialVector.getBytes()」,這表明API想要一個字節數組,而不是一個十六進制字符串:)

原因的破字節數組表示的是PHP或JS代碼通常使用十六進制字符串是不支持這些語言中的字節數組(至少傳統上,現代JS中實際上有字節數組)。