2024 日本 PHP 研討會

openssl_private_encrypt

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

openssl_private_encrypt使用私钥加密資料

描述

openssl_private_encrypt(
    #[\SensitiveParameter] 字串 $data,
    字串 &$encrypted_data,
    #[\SensitiveParameter] OpenSSLAsymmetricKey|OpenSSLCertificate|陣列|字串 $private_key,
    整數 (int) $padding = OPENSSL_PKCS1_PADDING
): 布林值 (bool)

openssl_private_encrypt() 使用私鑰 private_key 加密 data 並將結果儲存到 encrypted_data 中。加密的資料可以使用 openssl_public_decrypt() 解密。

此函式可以用於例如簽署資料(或其雜湊值)以證明它不是由其他人編寫的。

參數

data

encrypted_data

private_key

private_key 必須是與將用於解密資料的公鑰相對應的私鑰。

padding

padding 可以是 OPENSSL_PKCS1_PADDINGOPENSSL_NO_PADDING 其中之一。

傳回值

成功時傳回 true,失敗時傳回 false

更新日誌

版本 描述
8.0.0 private_key 現在接受 OpenSSLAsymmetricKeyOpenSSLCertificate 實例;先前接受類型為 OpenSSL keyOpenSSL X.509資源

另請參閱

新增註解

使用者貢獻的註解 5 項註解

Hernanibus
8 年前
只是關於 [P.Peyremorte] 註解的一點補充。

“- openssl_private_encrypt 一次最多可以加密 117 個字元。”

這取決於 $key 的長度

- 對於 1024 位元金鑰長度 => 最大可加密字元數(位元組)= 1024/8 - 11(使用填充時)= 117 個字元(位元組)。
- 對於 2048 位元金鑰長度 => 最大可加密字元數(位元組)= 2048/8 - 11(使用填充時)= 245 個字元(位元組)。
... 依此類推

順帶一提,如果 openssl_private_encrypt 因資料大小而失敗,您只會得到 false 作為傳回值,解密時 openssl_public_decrypt() 也一樣。

“- 加密後的輸出字串長度始終為 129 個字元。如果您在加密的輸出上使用 base64_encode,它將始終提供 172 個字元,最後一個始終為“=”(填充字元)”

這同樣取決於 $key 的長度

- 對於 1024 位元金鑰長度 => 根據 RSA 設計,加密後的原始位元組數始終是一個 128 位元組(1024 位元)的區塊。
- 對於 2048 位元金鑰長度而言,根據 RSA 的設計,加密後的原始位元組數永遠是 256 位元組(2048 位元)的區塊。
... 依此類推

關於 base64_encode 輸出的長度,這取決於您編碼的內容(意思是取決於加密後的位元組結果),但通常編碼後的字串會增加約 33%(128 位元組約為 170 位元組,256 位元組約為 340 位元組)。

我會稍微概括一下 [P.Peyremorte] 的說明:
<?php
// 以常數形式給定變數:

//加密區塊密碼的區塊大小
private $ENCRYPT_BLOCK_SIZE = 200;// 例如,針對 2048 位元金鑰,留一些空間

//解密區塊密碼的區塊大小
private $DECRYPT_BLOCK_SIZE = 256;// 同樣針對 2048 位元金鑰

//加密時我們會使用:
function encrypt_RSA($plainData, $privatePEMKey)
{
$encrypted = '';
$plainData = str_split($plainData, $this->ENCRYPT_BLOCK_SIZE);
foreach(
$plainData as $chunk)
{
$partialEncrypted = '';

//例如使用 OPENSSL_PKCS1_PADDING 作為填充
$encryptionOk = openssl_private_encrypt($chunk, $partialEncrypted, $privatePEMKey, OPENSSL_PKCS1_PADDING);

if(
$encryptionOk === false){return false;}//您也可以返回錯誤訊息。如果太大,則會返回 false
$encrypted .= $partialEncrypted;
}
return
base64_encode($encrypted);//將整個二進位字串編碼為 MIME base 64
}

//解密時我們會使用:
protected function decrypt_RSA($publicPEMKey, $data)
{
$decrypted = '';

//解碼必須在分割之前完成,才能取得二進位字串
$data = str_split(base64_decode($data), $this->DECRYPT_BLOCK_SIZE);

foreach(
$data as $chunk)
{
$partial = '';

//確保填充方式相符
$decryptionOK = openssl_public_decrypt($chunk, $partial, $publicPEMKey, OPENSSL_PKCS1_PADDING);

if(
$decryptionOK === false){return false;}//這裡也處理解密錯誤。如果太大,則會返回 false
$decrypted .= $partial;
}
return
$decrypted;
}
?>
wfredkNOSPAM at L5DevelopmentNOSPAM dot com
22 年前
使用私鑰加密,使用公鑰解密。

用於發佈簽名訊息:任何有權限存取
您公鑰的人都可以讀取它,但他們無法建立
您的簽名。

<?php
echo "來源: $source";
$fp=fopen("/path/to/private.key","r");
$priv_key=fread($fp,8192);
fclose($fp);
// 如果您的金鑰已編碼(建議),則需要 $passphrase
$res = openssl_get_privatekey($priv_key,$passphrase);
/*
* 注意:這裡使用返回的資源值
*/
openssl_private_encrypt($source,$crypttext,$res);
echo
"已加密字串: $crypttext";

$fp=fopen ("/path/to/certificate.crt","r");
$pub_key=fread($fp,8192);
fclose($fp);
openssl_get_publickey($pub_key);
/*
* 注意:這裡使用 $pub_key 值(我猜是轉換後的)
*/
openssl_public_decrypt($crypttext,$newsource,$pub_key);
echo
"解密字串 : $newsource";
?>
adityasingh at techknowtrends dot com
12 年前
以下是一個簡化版的加密功能使用範例,方便入門

$res = openssl_pkey_new();

// 取得私鑰
openssl_pkey_export($res, $privkey);

// 取得公鑰
$pubkey = openssl_pkey_get_details($res);
$pubkey = $pubkey["key"];
var_dump($privkey);
var_dump($pubkey);

// 從命令列取得一些文字來操作
$tocrypt = trim(fgets(STDIN));

// 一些要使用的變數
$encryptedviaprivatekey = ""; // 存放使用私鑰加密的文字
$decryptedviapublickey = ""; // 存放使用私鑰加密後,再用公鑰解密的文字,應該與 $tocrypt 相同
$encryptedviapublickey = ""; // 存放使用公鑰加密的文字
$decryptedviaprivatekey = ""; // 存放使用公鑰加密後,再用私鑰解密的文字,應該與 $tocrypt 相同

openssl_private_encrypt($tocrypt, $encryptedviaprivatekey, $privkey);
echo $tocrypt . "->" . $encryptedviaprivatekey;
echo "\n\n";
openssl_public_decrypt($encryptedviaprivatekey, $decryptedviapublickey, $pubkey);
echo $encryptedviaprivatekey . "->" . $decryptedviapublickey;
echo "\n\n";

openssl_public_encrypt($tocrypt,$encryptedviapublickey, $pubkey);
echo $tocrypt . "->" . $encryptedviapublickey;
echo "\n\n";
openssl_private_decrypt($encryptedviapublickey, $decryptedviaprivatekey, $privkey);
echo $encryptedviapublickey . "->" . $decryptedviaprivatekey;

輸出

字串(887) "-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCy745x8AqGKlTWBu2Ub80boPaQxo/midZ4LHZ0zbPpiCAfkADN
VYSe8OckPKutdjPX7SNAx66PgQRH1xrz1gysbRrf8K/mA0LQ00MKBFaFottWt5cC
IaUS9zvCgPw7prwng3hkGShnvTSMXiKFyt1E3RTvpXRk0u46D6hKiy+TSQIDAQAB
AoGBAJe1jjNCDtoz19vi4doBdIhhT8vt3iHbafBX2lMr+MceeAXqpRNy10+e9op9
uh0G4+vGDialZnYbMBLs6Ngl+nVnzn+cN1MMJ18brgf3biZKzVzK9wmOW4eycWaR
9eLa7/+ns8Cw5GsLJdG+OHR2gXRXU4hzUFdf90UUbP+kuqK1AkEA2X04XznFDNmT
NuhyCixwinlziazJBp/81jjaBhYj3cG0nTF0Gactc/yD0yudbrMqjLBfts+FbG3Z
yFHKrAB/cwJBANKetll3M3aCGsermEK+9hbB8yMihCju6pAwClUNkrAgrm9zU4LP
WkC81RDzXbz+pfIqpopfn34F3+U2iMiOe1MCQCXpTgpLZ631v1Oy8S4U0QlSYnF9
TQ16lfhBsL+e3GGrgnBkTniqS6IMQm5tC+RgFuqvU//p7LgZ7fydRVb2P0ECQFp9
YADuKskmutTAj6lVnCtI5upYgQmJJHQQf8/tBfHwCKHPnbic17zqpGwk80go7Ckw
U98tmDuv0HMNTBVGygsCQALck7VNBRjL9iFzJMFis+alcP1ZC88wOLPvIxYbevUH
c8rZwRqt1aHwaWOoxcVom+tyzRC6gEYoBarmU1bX4No=
-----END RSA PRIVATE KEY-----
"
字串(272) "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCy745x8AqGKlTWBu2Ub80boPaQ
xo/midZ4LHZ0zbPpiCAfkADNVYSe8OckPKutdjPX7SNAx66PgQRH1xrz1gysbRrf
8K/mA0LQ00MKBFaFottWt5cCIaUS9zvCgPw7prwng3hkGShnvTSMXiKFyt1E3RTv
pXRk0u46D6hKiy+TSQIDAQAB
-----END PUBLIC KEY-----
"
這是一個加密測試
( ¦E@n¥u?7Fëµ¥+-M¼ìk?7¥;t?8[j¼ñrƒ¦ª-TÜ++ßYG?-úö¦}9+k8OJn_?¦x?¦
dó+aév.cå?-ï`,¦?·5u¦p%Z²¤ÜI?û ¼

( ¦E@n¥u?7Fëµ¥+-M¼ìk?7¥;t?8[j¼ñrƒ¦ª-TÜ++ßYG?-úö¦}9+k8OJn_?¦x?¦
dó+aév.cå?-ï`,¦?·5u¦p%Z²¤ÜI?û ¼->這是一個加密測試

這是一個加密測試->hT!¡_
#+£-íßÿo»¢äSs+üSnäÖ-(¦ëIkl[¤¦=?í?Ç+Uy·N,=b=+¦TàmeNo¦A~ùÑtü¦@ÿ½»¦SV5Ѫ*¦?·UÿoPÖFq
-? O{²¦á|,äIN)+_-öF+*¦{|??G-??£/?¬±"PFL

hT!¡_
#+£-íßÿo»¢äSs+üSnäÖ-(¦ëIkl[¤¦=?í?Ç+Uy·N,=b=+¦TàmeNo¦A~ùÑtü¦@ÿ½»¦SV5Ѫ*¦?·UÿoPÖFq
-? O{²¦á|,äIN)+_-öF+*¦{|??G-??£/?¬±"PFL->這是一個加密測試
P.Peyremorte
8 年前
手冊中未提及的一個技巧

- openssl_private_encrypt 一次最多可以加密 117 個字元。
- 加密後的輸出字串長度始終為 129 個字元。如果您對加密後的輸出使用 base64_encode,它將始終提供 172 個字元,最後一個始終為“=”(填充字元)。

因此,要編碼較長的串流輸入,您必須使用類似以下的程式碼
<?php
$RawData
= ... ; //您要編碼的輸入資料

$PartialData = '';
$EncodedData = '';
$Split = str_split($RawData , 117);
ForEach(
$Split as $Part)
{
openssl_private_encrypt($Part, $PartialData, $PrivateKey);
$EncodedData .= base64_encode($PartialData);
}
?>

然後,要解碼

<?php
$OriginalData
= '';
$Split = str_split($EncodedData, 172);
foreach(
$Split as $Part)
{
openssl_private_decrypt(base64_decode($Part), $PartialData, $PublicKey);
$OriginalData .= $PartialData;
}
?>
billnet at tiscalinet dot it
22 年前
<?php
$fp
= fopen("/path/to/key.pem", "r");
$priv_key = fread($fp, 8192);
fclose($fp);
openssl_get_privatekey($priv_key);
openssl_private_encrypt($source, $finaltext, $priv_key);
echo
"已加密字串: $finaltext";
?>

掰掰!
To Top