最近公司有個業務,需要對接第三方接口,但是參數是需要加密的,對方也只提供了一個java的demo,在網上到處搜索,沒有找到直接就能用的方法,后來還是跟公司的Android工程師對接出來的,在這里記錄一下大致的流程。
首先說明一下對方要求的接口請求方式,格式為:http://ip:port/interface/method?data=摘要@@16進制字符串
說明:
1. 請求參數需要組合成a=1&b=2&c=3格式的參數串;
2. 摘要的生成方法為md5('a=1&b=2&c=3');
3. 16進制字符串的生成方法是將參數串進行**對稱加密(DES-ECB)**后再轉成16進制字符串(bin2hex函數);
對方提供的demo(java版本)如下:
public class DesUtils {
/** 默認密鑰 */
private static String strDefaultKey = "seeyonssokey";
/** 加密工具 */
private Cipher encryptCipher;
/** 解密工具 */
private Cipher decryptCipher;
/**
* 加密字符串
* @param strIn 需加密的字符串
* @return 加密后的字符串
* @throws Exception
*/
public String encrypt(String strIn) throws Exception {
return byteArr2HexStr(encryptCipher.doFinal(strIn.getBytes()));
}
/**
* 解密字符串
* @param strIn 需解密的字符串
* @return 解密后的字符串
* @throws Exception
*/
public String decrypt(String strIn) throws Exception {
return new String(decryptCipher.doFinal(hexStr2ByteArr(strIn)));
}
/**
* 將 byte 數組轉換為表示 16 進制值的字符串, 如: byte[]{8,18} 轉換為: 0813 , 和 public static
* byte[] hexStr2ByteArr(String strIn) 互為可逆的轉換過程
* @param arrB 需要轉換的 byte 數組
* @return 轉換后的字符串
* @throws Exception 本方法不處理任何異常,所有異常全部拋出
*/
public static String byteArr2HexStr(byte[] arrB) throws Exception {
int iLen = arrB.length;
// 每個byte用兩個字符才能表示,所以字符串的長度是數組長度的兩倍
StringBuffer sb = new StringBuffer(iLen * 2);
for(int i = 0; i < iLen; i++) {
int intTmp = arrB[i];
// 把負數轉換為正數
while(intTmp < 0) {
intTmp = intTmp + 256;
}
// 小於0F的數需要在前面補0
if(intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
}
/**
* 將 表 示 16 進 制 值 的 字 符 串 轉 換 為 byte 數 組 , 和 public static String
* byteArr2HexStr(byte[] arrB) 互為可逆的轉換過程
* @param strIn 需要轉換的字符串
* @return 轉換后的 byte 數組
* @throws Exception 本方法不處理任何異常,所有異常全部拋出
* @author <a href="mailto:leo841001@163.com">LiGuoQing</a>
*/
public static byte[] hexStr2ByteArr(String strIn) throws Exception {
byte[] arrB = strIn.getBytes();
int iLen = arrB.length;
// 兩個字符表示一個字節,所以字節數組長度是字符串長度除以2
byte[] arrOut = new byte[iLen / 2];
for(int i = 0; i < iLen; i = i + 2) {
String strTmp = new String(arrB, i, 2);
arrOut[i / 2] = (byte)Integer.parseInt(strTmp, 16);
}
return arrOut;
}
/**
* 從指定字符串生成密鑰,密鑰所需的字節數組長度為 8 位 不足 8 位時后面補 0 , 超出 8 位只取前 8 位
* @param arrBTmp 構成該字符串的字節數組
* @return 生成的密鑰
* @throws java.lang.Exception
*/
private static Key getKey(byte[] arrBTmp) throws Exception {
// 創建一個空的8位字節數組(默認值為0)
byte[] arrB = new byte[8];
// 將原始字節數組轉換為8位
for(int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB[i] = arrBTmp[i];
}
// 生成密鑰
Key key = new SecretKeySpec(arrB, "DES");
return key;
}
public static String encrypt(String strIn, String secretkey) throws Exception {
Key key = getKey(secretkey.getBytes("utf-8"));
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
return byteArr2HexStr(cipher.doFinal(strIn.getBytes("utf-8")));
}
public static String decrypt(String strIn, String secretkey) throws Exception {
Key key = getKey(secretkey.getBytes("utf-8"));
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] param = cipher.doFinal(hexStr2ByteArr(strIn));
return new String(param, "utf-8");
}
}
PHP實現加密功能的的方法有兩種:
- mcrypt方式(適用於php7.0以前的版本):
<?php
$text = 'a=1&b=2&c=3'; //參數串
$key = 'abcd1234'; // 密鑰
echo $ret = self::encryptForDES($text , $key); //加密
/**
* 字符串加密(加密方法:DES-ECB)
* @param string $input 待加密字符串
* @param string $key 對稱加密密鑰
* @return string
*/
function encryptData($input, $key)
{
$size = mcrypt_get_block_size('des','ecb'); // 計算加密算法的分組大小
$input = self::pkcs5_pad($input, $size); // 對字符串進行補碼
$td = mcrypt_module_open('des', '', 'ecb', '');
$iv = @mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
@mcrypt_generic_init($td, $key, $iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$data = bin2hex($data); // 將加密后的字符串轉化為16進制
return $data;
}
/**
- 對字符串進行補碼
- @param string $text 原字符串
- @param string $blockSize 加密算法的分組大小
- @return string
*/
function pkcs5_pad($text, $blockSize)
{
$pad = $blockSize - (strlen($text) % $blockSize);
return $text . str_repeat(chr($pad), $pad);
}
輸出為:990389f0aad8d12014ca6a45cd72cdf7
- openssl方式(適用於php7.0以后的版本):
<?php
$text = 'a=1&b=2&c=3'; // 參數串
$key = 'abcd1234'; // 密鑰
echo encryptData($text, $key); // 加密
/**
* 字符串加密(加密方法:DES-ECB)
* @param string $input 待加密字符串
* @param string $key 對稱加密密鑰
* @return string
*/
function encryptData($input, $key)
{
$ivlen = openssl_cipher_iv_length('DES-ECB'); // 獲取密碼iv長度
$iv = openssl_random_pseudo_bytes($ivlen); // 生成一個偽隨機字節串
$data = openssl_encrypt($input, 'DES-ECB', $key, $options=OPENSSL_RAW_DATA, $iv); // 加密
return bin2hex($data);
}
輸出為:990389f0aad8d12014ca6a45cd72cdf7
