簡單理解rsa的加密和簽名-PHP實現

咱們先動手在linux上生成一下rsa

Ps:openssl是一堆加密算法和安全協議的開源集合,像RSA,DES,MD5,RC4等等,都能在openssl裏面找到源代碼.php

用openssl指定生成test.key文件,其中包含公鑰+私鑰,1024爲生成密鑰長度linux

tb@tb:~/mimi$ openssl genrsa -out test.key 1024
Generating RSA private key, 1024 bit long modulus
.++++++
....................................................++++++
e is 65537 (0x10001)

能夠簡單查看下,注意這裏包括私鑰+公鑰android

vim test.key
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCpS7mxdU6svbDcs10qbq9f9t5D4yfqC1jLmZD3GDD4D/8TbNkf
vcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yulXZyvPurfN/1AJt4JYDxnN/q
u1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UWy8ezLy6UWFQCrnUHEQIDAQAB
AoGAQCQeoKtvOWdNIPEb9T2mWFdx8oqXzsapx8nQ8K1LsFBvNe7hfHMsGLLOjzhI
G7223eiEm07mMaJF2XvOaEpSYX/qQ1LZRSdBrzCec1lcDbB95dcRg9NmgBuCpUxE
3SGYm3VB8rurfsrRUUYoIbjWz8qyuIGdMbaNkHG/CpnUYpkCQQDfWYDYtQ3DxCt+
JBoLfuCykk8+nIV12CIYb023naoR2s/aQQRk9BkGCkDrdOAgZAN3BGOHYseKAfTP
nARDzfiDAkEAwgtYfgCDTOfW5/kJK1lZO21CdCCZnePwGYmWDLPzNiJIn8k0U6Ig
9GmxG+0GKzY71XO8W3Nh18ilZbX9dYel2wJASQ+AJGNlc0pyZ7rrgiMo4YEWxwZw
adIfpRqTs6KxhVGseFqYU2W94cns3pjG0BGnSIF5BUp8t1pYeKkyg/OWfQJBAK1w
mq41IycQaoR5kfqPKDT32dgWc3gvDqKk2duM1KzkQ+meXAkM90u/VLDTURo6pYyK
oCdVoHTRQRUCcAQnNNUCQQCO/zDRaY+5ssjPqj77eJqWfAhtbSDRRw+NurmUSas1
FT1cD5nil+uT48bIRoC5nk/XWfvAvMg/Yw5bslGUNx7f
-----END RSA PRIVATE KEY-----

~
經過下面命令生成公鑰出來ios

tb@tb:~/mimi$ openssl rsa -in test.key -pubout -out test_pub.key
writing RSA key

此時咱們有公鑰test_pub.key和公鑰+私鑰test.key算法

tb@tb:~/mimi$ ls
test.key  test_pub.key

能夠查看下公鑰,短了點數據庫

tb@tb:~/mimi$ vim test_pub.key 

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpS7mxdU6svbDcs10qbq9f9t5D
4yfqC1jLmZD3GDD4D/8TbNkfvcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yu
lXZyvPurfN/1AJt4JYDxnN/qu1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UW
y8ezLy6UWFQCrnUHEQIDAQAB
-----END PUBLIC KEY-----
tb@tb:~/mimi$

咱們爲了測試,新建了一個demo.php

tb@tb:~/mimi$ cat demo.php 
<?php
    echo 'tb';
tb@tb:~/mimi$

咱們加密下demo.php,-in指定加密文件,-inkey 指定密鑰,-pubin 意思用公鑰加密-out輸出文件vim

tb@tb:~/mimi$ openssl rsautl -encrypt -in demo.php -inkey test_pub.key  -pubin -out demo.en
tb@tb:~/mimi$ ls
demo.en  demo.php  test.key  test_pub.key

咱們看加密後的demo.php,徹底看不懂。。看來加密成功。安全

tb@tb:~/mimi$ cat demo.en
z0?!1I¢+i2?Y?    縏,°?¨IB?}?¤9§???stBI
             ??]〢sk膷j-???1日T-′.)
                                       J?qz+{°Qˉ3

tb@tb:~/mimi$

而後咱們須要把加密後的demo.php解密回來,-inkey指定解密文件,服務器

tb@tb:~/mimi$ openssl rsautl -decrypt -in demo.en -inkey test.key -out demo.cn

下面的demo.cn就是解密後的文件,app

tb@tb:~/mimi$ ls
demo.cn  demo.php  test_pub.key
demo.en  test.key
tb@tb:~/mimi$ cat demo.cn 
<?php
    echo 'tb';
tb@tb:~/mimi$

應用:

1、服務端/移動端(ios,android)加密:流程

一、生成rsa公鑰,私鑰
二、移動端保留私鑰,經過http將公鑰傳輸給服務端(如http,須要base64_e(d)ncode函數對,由於會有特殊字符)
三、服務端接受公鑰後,用公鑰把對稱加密aes的key加密,
四、服務端把須要給移動端的數據data用對稱加密算法aes 加密
五、服務端把加密的data和加密的aes key給移動端
六、移動端經過私鑰把服務端用公鑰加密的key解密,而後用aes解密data數據

可是這個怎麼交互,怎麼識別,包括怎麼不影響傳輸效率,最小減輕服務器壓力。本人尚未概念。。不知道支付寶啥的怎麼作的。但願大神指教

2、驗證簽名

1
發送方用一個hash算法對數據生成數據的摘要,而後用私鑰對摘要進行簽名,將此摘要和總體數據給接收方。接收方收到摘要和總體數據,用公鑰解密,獲得摘要。到此只能證實消息確實由發送方發出,可是怎麼肯定中途有沒有被篡改呢?

2
接收方在對消息進行文件hash,生成摘要,若是接收方生成的摘要和用公鑰解密後的摘要相等。那麼就證實了文件確實爲發送方發送,並且沒有被篡改。

3
簡而言之:
一-->公鑰加密,私鑰解密。
二-->私鑰簽名,公鑰驗證。

EXAMPLE WITH PHP

<?php

 $private_key = "-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCpS7mxdU6svbDcs10qbq9f9t5D4yfqC1jLmZD3GDD4D/8TbNkf
vcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yulXZyvPurfN/1AJt4JYDxnN/q
u1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UWy8ezLy6UWFQCrnUHEQIDAQAB
AoGAQCQeoKtvOWdNIPEb9T2mWFdx8oqXzsapx8nQ8K1LsFBvNe7hfHMsGLLOjzhI
G7223eiEm07mMaJF2XvOaEpSYX/qQ1LZRSdBrzCec1lcDbB95dcRg9NmgBuCpUxE
3SGYm3VB8rurfsrRUUYoIbjWz8qyuIGdMbaNkHG/CpnUYpkCQQDfWYDYtQ3DxCt+
JBoLfuCykk8+nIV12CIYb023naoR2s/aQQRk9BkGCkDrdOAgZAN3BGOHYseKAfTP
nARDzfiDAkEAwgtYfgCDTOfW5/kJK1lZO21CdCCZnePwGYmWDLPzNiJIn8k0U6Ig
9GmxG+0GKzY71XO8W3Nh18ilZbX9dYel2wJASQ+AJGNlc0pyZ7rrgiMo4YEWxwZw
adIfpRqTs6KxhVGseFqYU2W94cns3pjG0BGnSIF5BUp8t1pYeKkyg/OWfQJBAK1w
mq41IycQaoR5kfqPKDT32dgWc3gvDqKk2duM1KzkQ+meXAkM90u/VLDTURo6pYyK
oCdVoHTRQRUCcAQnNNUCQQCO/zDRaY+5ssjPqj77eJqWfAhtbSDRRw+NurmUSas1
FT1cD5nil+uT48bIRoC5nk/XWfvAvMg/Yw5bslGUNx7f
-----END RSA PRIVATE KEY-----";

$public_key = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpS7mxdU6svbDcs10qbq9f9t5D
4yfqC1jLmZD3GDD4D/8TbNkfvcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yu
lXZyvPurfN/1AJt4JYDxnN/qu1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UW
y8ezLy6UWFQCrnUHEQIDAQAB
-----END PUBLIC KEY-----";


//獲取全部支持算法,cipher 就是密碼,算法計算的意思
$methods=openssl_get_cipher_methods();

// var_dump($methods);


$data="原始數據爲: 用私鑰加密origin data1";
$method="AES-128-CBC";

//經過私鑰加密,生成$crypted;
openssl_private_encrypt($data, $crypted, $private_key);

// 因爲php 進行openssl_public_encrypt 加密後返回的是二進制數據,須要對其返回的加密後的數據進行二進制16進制編碼base64_encode才能夠顯示,$crypted爲加密後的串
$crypted=base64_encode($crypted);

echo "私鑰加密後的結果爲:".$crypted."\n";

//相應的:加密後生產的16進制加密字符串須要進行base64_decode進行解密後在進行openssl_private_decrypt
$crypted=base64_decode($crypted);


openssl_public_decrypt($crypted, $decrypted , $public_key);

echo "用公鑰解密的結果爲".($decrypted)."\n";
echo"===================我是分割線==============\n";
$data="用公鑰加密origin data2\n";
$method="AES-128-CBC";

//經過公鑰加密,生成$crypted;
openssl_public_encrypt($data, $crypted, $public_key);

// 因爲php 進行openssl_public_encrypt 加密後返回的是二進制數據,須要對其返回的加密後的數據進行二進制16進制編碼base64_encode才能夠顯示,$crypted爲加密後的串
$crypted=base64_encode($crypted);

echo "公鑰加密後的結果爲:".$crypted."\n";

//相應的:加密後生產的16進制加密字符串須要進行base64_decode進行解密後在進行openssl_private_decrypt
$crypted=base64_decode($crypted);


openssl_private_decrypt($crypted, $decrypted , $private_key);

echo "用私鑰解密的結果爲".($decrypted)."\n";

大php執行結果:

圖片描述

HELP

不知道具體參數有哪些,能夠這樣簡單看一下。
openssl rsa --h
unknown option --h
rsa [options] <infile >outfile
where options are
-inform arg input format - one of DER NET PEM
-outform arg output format - one of DER NET PEM
-in arg input file
-sgckey Use IIS SGC key format
-passin arg input file pass phrase source
-out arg output file
-passout arg output file pass phrase source
-des encrypt PEM output with cbc des
-des3 encrypt PEM output with ede cbc des using 168 bit key
-seed encrypt PEM output with cbc seed
-aes128, -aes192, -aes256 encrypt PEM output with cbc aes
-camellia128, -camellia192, -camellia256 encrypt PEM output with cbc camellia
-text print the key in text
-noout don't print key out
-modulus print the RSA key modulus
-check verify key consistency
-pubin expect a public key in input file
-pubout output a public key
-engine e use engine e, possibly a hardware device.

2018-02-26補充

  1. 服務端生成一對非對稱加密key ServerPublicKey ServerPrivateKey
  2. app端編碼中寫入服務端告知的 ServerPublicKey,同時app端能夠本身生成一對 AppPublicKey 和 AppPrivateKey
  3. app1第一次請求服務端時,app端用ServerPublicKey 加密 對稱加密aes的 keyRandom (可每端同樣,也能夠徹底隨機。如下稱爲aeskey)
    ,app1的硬件uuid,app1的publickey(須要base64) ,以及額外的這次消息的datamsg等自定義字段。
    app2第一次請求服務端時,app端用ServerPublicKey 加密 對稱加密aes的 keyRandom (可每端同樣,也能夠徹底隨機。如下稱爲aeskey),app2的硬件uuid,app2的publickey(須要base64) ,以及額外的這次消息的datamsg等自定義字段。
  4. 服務端收到app各端的請求,用ServerPrivateKey能夠解開每一個端的app1,app2的
    aeskey,以及每一個app的uuid,AppPublicKey,能夠存儲再如下表中爲之後驗證(保證每一個uuid的key是同樣的,若是不一樣就異常錯誤)及做弊統計黑名單等工做
appuuid    AppPublicKey      aeskey

xxoo        asdfasd!#@       rrrr

ddeef        ujoi!@#!@¥      rrrr

至此第一次aeskey算是握手部分完成。這樣的好處是隻有反編譯以後,才能拿到ServerPublicKey。

6.下次app再向服務端發送請求,將數據用約定好的(固然用如下5,6的步驟能夠隨機生成)aeskey加密,。

7.服務端用步驟4中的已知aeskey解密app端的發送過來的數據後,再用一樣的aes能夠解開便可。

8.另外服務端主動推送的時候,也能夠用那個共有的aeskey加密後推送數據

若是要作到更好(有必要嗎):
從第5步應該這樣:

5.客戶端傳遞三個自定義字段:一個爲用ServerPublicKey 加密的aeskey,另外一個爲uuid,另外爲真正的data

6,服務端用ServerPrivateKey能夠解開uuid,而後去數據庫中查到到每一個uuid對應的不一樣aeskey,而後用這個數據aes去加密數據

另外若是須要驗證一致性仍然能夠用hash簽名。

相關文章
相關標籤/搜索