PHP Conference Japan 2024

openssl_verify

(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)

openssl_verify驗證簽章

說明

openssl_verify(
    字串 $data,
    字串 $signature,
    OpenSSLAsymmetricKey|OpenSSLCertificate|陣列|字串 $public_key,
    字串|整數 $algorithm = OPENSSL_ALGO_SHA1
): 整數 (int)|false

openssl_verify() 使用與 public_key 相關聯的公鑰,驗證 signature 對於指定的 data 是否正確。這必須是用於簽名的私鑰對應的公鑰。

參數

data

先前用於產生簽名的字串數據

signature

openssl_sign() 或類似方法產生的原始二進位字串

public_key

OpenSSLAsymmetricKey - 由 openssl_get_publickey() 返回的密鑰

字串 (string) - PEM 格式的密鑰(例如 -----BEGIN PUBLIC KEY----- MIIBCgK...

algorithm

整數 (int) - 其中一種簽名演算法

字串 (string) - 由 openssl_get_md_methods() 返回的有效字串,例如 "sha1WithRSAEncryption" 或 "sha512"。

返回值

如果簽名正確,則返回 1;如果不正確,則返回 0;如果發生錯誤,則返回 -1 或 false

更新日誌

版本 說明
8.0.0 public_key 現在接受 OpenSSLAsymmetricKeyOpenSSLCertificate 實例;以前接受類型為 OpenSSL keyOpenSSL X.509資源

範例

範例 #1 openssl_verify() 範例

<?php
// 假設 $data 和 $signature 包含數據和簽名

// 從憑證中取得公鑰並準備好
$pubkeyid = openssl_pkey_get_public("file://src/openssl-0.9.6/demos/sign/cert.pem");

// 說明簽名是否正確
$ok = openssl_verify($data, $signature, $pubkeyid);
if (
$ok == 1) {
echo
"good";
} elseif (
$ok == 0) {
echo
"bad";
} else {
echo
"ugly, 檢查簽名時發生錯誤";
}
// 從記憶體中釋放密鑰
openssl_free_key($pubkeyid);
?>

範例 #2 openssl_verify() 範例

<?php
//您要簽署的資料
$data = 'my data';

//建立新的私鑰和公鑰
$private_key_res = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
$details = openssl_pkey_get_details($private_key_res);
$public_key_res = openssl_pkey_get_public($details['key']);

//建立簽章
openssl_sign($data, $signature, $private_key_res, "sha256WithRSAEncryption");

//驗證簽章
$ok = openssl_verify($data, $signature, $public_key_res, OPENSSL_ALGO_SHA256);
if (
$ok == 1) {
echo
"有效";
} elseif (
$ok == 0) {
echo
"無效";
} else {
echo
"錯誤: ".openssl_error_string();
}
?>

另請參閱

新增註釋

使用者貢獻的註釋 8 個註釋

Stiv
18 年前
我終於找到驗證簽章的方法了。 文件中的範例無法運作。 下面的程式碼可以運作 :)

<?php
// $data 假設包含要簽署的資料

// 從檔案取得憑證並準備
$fp = fopen("path/file.pem", "r");
$cert = fread($fp, 8192);
fclose($fp);

// 判斷簽章是否正確
// 使用憑證,而不是公鑰
$ok = openssl_verify($data, $signature, $cert);
if (
$ok == 1) {
echo
"good";
} elseif (
$ok == 0) {
echo
"bad";
} else {
echo
"ugly, 簽章檢查錯誤";
}
?>
mikey at badpenguins dot com
14 年前
我花了好多天仔細研究 PHP 的 OpenSSL 文件,試圖弄清楚如何完成一個看似簡單的任務:給定兩個 PEM 編碼的憑證,其中一個是另一個的簽署者嗎? openssl_verify() 的文件或註釋中沒有任何地方說明如何取得現有憑證的簽章。 openssl_x509_parse() 函數看起來很有希望,但它是一個不穩定的 API,可能會改變。

我必須編寫自己的程式碼來判斷一個憑證是否簽署了另一個憑證,程式碼位於:http://badpenguins.com/source/misc/isCertSigner.php?viewSource

簡而言之,以下是我的心得...

已簽署 X.509 憑證中的簽章資料包含以簽署者的公鑰加密的 DER 格式資料。 這些資料包含原始主體憑證的雜湊值,以及用於建立簽章的加密演算法資訊。

因此,您需要取得此簽章資料和原始憑證的副本(移除簽發者和簽章序列)。 使用簽發者使用的相同演算法對原始憑證的副本(不含簽發者/簽章序列)進行雜湊,如果雜湊值相符,則您就擁有簽署憑證的簽發者憑證。
meint dot post at bigfoot dot com
23 年前
任何嘗試讓基於 Win32 CryptoAPI 的數位簽章元件與 openssl_verify() 函數一起使用的人都應該注意,CryptoAPI PKCS1 (RSA) 方法使用反向位元組順序,而 openssl_verify() 方法需要格式正確的 PKCS1 數位簽章(理應如此)。 我是透過慘痛的教訓才學到這一點,而且花了我一些時間才挖掘出來。 以下是用 VBScript 反轉位元組順序的簡單解決方案:

N = Len(Blob.Hex)

' 使用十六進位格式反轉簽章中的位元組
For i = 1 To N - 1 Step 2
s = Mid(Blob, i, 2) & s
Next

s 包含反向順序的數位簽章。 Blob 是一個任意的二進位容器。

以十六進位格式傳送簽章,並在 PHP 中使用 hex2bin 方法轉換為 openssl_verify() 的正確格式,例如:

function hex2bin($data) {

$len = strlen($data);
return pack("H" . $len, $data);

}

就是這樣,希望對您有所幫助。 順帶一提,我使用 ASPEncrypt 在 Win32 平台上進行測試。 它僅適用於 Internet Explorer,但您也可以使用 Java 小程式,這樣就沒有上述任何問題 :-)
peter dot labos at gmail dot com
6 年前
即使 openssl_verify() 返回 false,openssl_error_string() 也會被填入值。

當 openssl_verify() 返回 0 時,openssl_error_string() 會被填入 1。
我花了很多時間才理解這點,因為我下一次呼叫 openssl 時,因為錯誤檢查而失敗。

<?php
$c
= file_get_contents($filename);
$publicKey = openssl_pkey_get_public($c);
$result = openssl_verify('freedom', 'someirrelevantnosign', $publicKey);

$error = "";

while (
$msg = openssl_error_string() !== false) {
$error .= $msg;
}

if (!empty(
$error)) {
echo
$error; // 1
}
steve dot venable at lmco dot com
22 年前
關於 openssl_verify()(以及其他一些函式)的注意事項。公鑰來自任何支援格式的憑證(如範例所示,使用 openssl_get_publickey() 取得資源 ID)。但經過一些嘗試和錯誤後,我發現簽章字串**必須是二進位格式**。雖然傳遞 base64 編碼的簽章字串(PEM 格式?)不會發生錯誤,但只會得到不匹配的結果。當我自己進行 base64 解碼時,驗證返回了匹配(返回值 1)。您可以直接捨棄開頭/結尾行,並使用 `base64_decode()` 函式的輸出。
phpdev at fpierrat dot fr
3 年前
如文件中所述:「如果簽章正確,則返回 1;如果不正確,則返回 0;如果發生錯誤,則返回 -1 或 false。」

在第二個範例以及 Stiv 的說明中,以下條件會同時匹配 0 或 false,它們具有不同的含義
elseif ($ok == 0) {
echo "bad";
}

這裡應該使用嚴格比較 (===) 而不是一般比較 (==)
elseif ($ok === 0) {
echo "bad";
}
---
var_dump(0==false); //==> true
var_dump(0===false);//==> false
attila dot m dot magyar at gmail dot com
10 年前
mikey at badpenguins dot com -- 使用 openssl_x509_checkpurpose() 似乎可以在 PHP 中驗證 X509 憑證鏈。
jeremie dot gomez at gmail dot com
13 年前
您實際上可以使用公鑰作為第三個參數,而不是憑證。

如果無法運作,請確保

1) 您的公鑰格式正確。它似乎必須包含 ----BEGIN PUBLIC KEY---- 和 ----END PUBLIC KEY----

2) 您的簽名是二進制格式。您可以使用 PHP 的 base64_decode 函式來解碼。
To Top