涉及敏感資料的傳輸,雙方最好約定使用加密解密。那RSA非對稱加密就大有作為了。
服務端可以保留自己的私鑰,發給用戶端對應的公鑰。這樣就可以互相加解密了。php中rsa加解密實作:
首先要生成一對公鑰私鑰。前提是linux機器上安裝了openssl指令。
生成私鑰檔案:
openssl genrsa -out rsa_private_key.pem 1024
利用私鑰,生成公鑰:
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
生成了一對鑰匙。php代碼:
<?php
ini_set('error_reporting', -1);
ini_set('display_errors', -1);
header('Content-Type: text/html; charset=utf-8');
# openssl genrsa -out rsa_private_key.pem 1024
# openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
$private_key = file_get_contents("/home/users/xx/test/rsa_private_key.pem");
$public_key = file_get_contents("/home/users/xx/test/rsa_public_key.pem");
$pi_key = openssl_pkey_get_private($private_key);// 可用傳回資源id
$pu_key = openssl_pkey_get_public($public_key);
// 加密資料
$data = array(
'id' => '1234567890',
'name' => '小明',
'mobile' => '123456',
);
$data = json_encode($data);
$encrypted = '';
$decrypted = '';
openssl_public_encrypt($data, $encrypted, $pu_key);//公鑰加密
$encrypted = base64_encode($encrypted);// base64傳輸
echo $encrypted,"<br/>";
openssl_private_decrypt(base64_decode($encrypted), $decrypted, $pi_key);//私鑰解密
echo $decrypted,"<br/>";
print_r(json_decode($decrypted, true));
公鑰加密(openssl_public_encrypt),私鑰解密(openssl_private_decrypt)。私鑰加密(openssl_private_encrypt),公鑰解密(openssl_public_decrypt)。都是一個道理,代碼類似。
RSA加密解密有個填充方式padding的參數,不同程式設計語言之間互動,需要注意這個。
padding
can be one of
OPENSSL_PKCS1_PADDING
,
OPENSSL_SSLV23_PADDING
,
OPENSSL_PKCS1_OAEP_PADDING
,
OPENSSL_NO_PADDING
值得注意的是,如果選擇密鑰是1024bit長的(openssl genrsa -out rsa_private_key.pem 1024),那麼支援加密的明文長度位元組最多隻能是1024/8=128byte;
如果加密的padding填充方式選擇的是OPENSSL_PKCS1_PADDING(這個要占用11個位元組),那麼明文長度最多隻能就是128-11=117位元組。如果超出,那麼這些openssl加解密函數會傳回false。
這時有個解決辦法,把需要加密的源字元串按少于117個長度分開為幾組,在解密的時候以172個位元組分為幾組。
其中的『少于117』(隻要不大于117即可)和『172』兩個數字是怎麼來的,值得一說。
為什麼少于117就行,因為rsa encrypt後的位元組長度是固定的,就是密鑰長1024bit/8=128byte。是以隻要encrypt不傳回false,即隻要不大于117個位元組,那麼傳回加密後的都是128byte。
172是因為什麼?因為128個位元組base64_encode後的長度固定是172。
這裡順便普及下base64_encode。encode的長度是和原文長度有個計算公式:
$len2 = $len1%3 >0 ? (floor($len1/3)*4 + 4) : ($len1*4/3);
明文超出長度的代碼(前提是1024bit的密鑰長,OPENSSL_PKCS1_PADDING的填充方式,否則數字要變化)
<?php
$pi_key = openssl_pkey_get_private($private_key);// 資源類型
$pu_key = openssl_pkey_get_public($public_key);
$data = array(
'username' => '張三1',
'mobile' => '13321995977',
'info' => '14bMitESqD4PYwODWmy7rrrvyFPEnJJTECLjvKB7IkrVxVDkp1XiJnGKH
2h5syHQ5qslPSGYJ1M/XkDnGINwaLVHVD3BoKKgKg1bZn7ao5pXT+herqxaVwWs6
ga63yVSIC8jcODxiuvxJnUMQRLaqoF6aUb/2VWc2T5MDmxLhAkEA3pwGpvXgLiWL
3h7QLYZLrLrbFRuRN4CYl4UYaAKokkAvZly04Glle8ycgOc2DzL4eiL4l/+x/gaq
deJU/cHLRQJBANOZY0mEoVkwhU4bScSdnfM6usQowYBEwHYY',
);
$str = json_encode($data);
$en = encrypt_rsa($str, $pu_key);
$de = decrypt_rsa($en, $pi_key);
echo $de;
function encrypt_rsa($data, $pu_key){
$split = str_split($data, 100);// 1024bit && OPENSSL_PKCS1_PADDING 不大于117即可
foreach ($split as $part) {
$isOkay = openssl_public_encrypt($part, $en_data, $pu_key);
if(!$isOkay){
return false;
}
// echo strlen($en_data),'<br/>';
$encode_data .= base64_encode($en_data);
}
return $encode_data;
}
function decrypt_rsa($data, $pi_key){
$split = str_split($data, 172);// 1024bit 固定172
foreach ($split as $part) {
$isOkay = openssl_private_decrypt(base64_decode($part), $de_data, $pi_key);// base64在這裡使用,因為172位元組是一組,是encode來的
if(!$isOkay){
return false;
}
$decode_data .= $de_data;
}
return $decode_data;
}
base64建議參考這篇文章:http://www.ruanyifeng.com/blog/2008/06/base64.html
轉載于:https://www.cnblogs.com/firstForEver/p/5803940.html