首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 與 PHP HMAC-SHA1 跨語言加密結果不一致排查

     編輯:程式設計綜合問答

問題核心

Java 使用 new BigInteger(bytes).toString() 將 HMAC-SHA1 位元組陣列轉為帶符號十進位字串(如 -653068794747578802236590292838260814592085857640),PHP 需產出相同字串。

根本差異

  • Java BigInteger:預設有符號解析,最高位為 1 視為負數,輸出帶負號十進位。
  • PHP 無原生對應:mhash() 返回原始位元組,需手動實現有符號大整數轉換。

PHP 正確實現

function hmacSha1ToBigIntegerString($data, $keyBase64) {
    $key = base64_decode($keyBase64);
    $hash = hash_hmac('sha1', $data, $key, true); // 原始二進位
    // 轉為有符號大整數字串(模擬 Java BigInteger)
    $hex = bin2hex($hash);
    // 判斷最高位
    $firstByte = hexdec($hex[0].$hex[1]);
    $isNegative = ($firstByte & 0x80) !== 0;
    
    if ($isNegative) {
        // 取反加一(補碼轉正數)
        $bytes = array_map('ord', str_split($hash));
        for ($i = count($bytes)-1; $i >= 0; $i--) {
            $bytes[$i] = (~$bytes[$i]) & 0xFF;
            if ($bytes[$i] !== 0xFF) break; // 處理進位
        }
        $hash = implode('', array_map('chr', $bytes));
        $hex = bin2hex($hash);
        return '-' . gmp_strval(gmp_init($hex, 16));
    } else {
        return gmp_strval(gmp_init($hex, 16));
    }
}
// 使用
$sig = hmacSha1ToBigIntegerString($param, $appkey);

更佳建議:統一輸出格式

雙方協議改用 Base64 或十六進位輸出,避免大整數符號位陷阱:

  • Java:Base64.getEncoder().encodeToString(bytes) 或 Hex.encodeHexString(bytes)。
  • PHP:base64_encode($hash) 或 bin2hex($hash)。

此為業界標準做法,跨語言零歧義、可讀性強、無大數庫依賴。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved