本文主要通過(guò)RSA加解密實(shí)踐,來(lái)講述不對(duì)稱秘鑰的特點(diǎn)荔燎。
不對(duì)稱秘鑰和RSA
不對(duì)稱秘鑰算法撞芍,也叫公鑰密碼算法。
不對(duì)稱秘鑰算法圖示:
不對(duì)稱秘鑰的重要特點(diǎn)是加密和解密用的秘鑰不相同翩瓜。
和對(duì)稱秘鑰算法的比較
不對(duì)稱秘鑰的優(yōu)點(diǎn)
不對(duì)稱秘鑰有一個(gè)很大的好處是可以把公鑰公開(kāi)受扳,比如Alice要傳送敏感數(shù)據(jù)給Bob,Bob告訴Alice公鑰兔跌,Alice用公鑰加密數(shù)據(jù)勘高,通過(guò)網(wǎng)絡(luò)傳送給Bob,在傳送時(shí)被攻擊者Eric捕獲到坟桅,Eric拿到加密的數(shù)據(jù)和公鑰华望,但不知道私鑰仍無(wú)法破解敏感信息。
哦仅乓,這個(gè)看起來(lái)很不錯(cuò)赖舟,比對(duì)稱加密好多了,完全可以取代對(duì)稱加密呀方灾?
等等建蹄!等等!小王同學(xué)裕偿,你先別激動(dòng)洞慎,我們先了解下不對(duì)稱秘鑰的缺點(diǎn)再說(shuō)。
不對(duì)稱秘鑰的缺點(diǎn)
不對(duì)稱秘鑰算法的原理并不復(fù)雜嘿棘,可以從這篇文章對(duì)RSA算法的原理做大概的了解劲腿。
RSA等不對(duì)稱秘鑰算法都存在一個(gè)限制是——慢!這個(gè)從原理很容易知道鸟妙。
慢會(huì)導(dǎo)致不對(duì)稱秘鑰算法另一個(gè)限制——只能加密少量數(shù)據(jù)焦人。
RSA算法挥吵,一次加密的數(shù)據(jù)最多和秘鑰長(zhǎng)度相同。但實(shí)際上花椭,RSA算法一般還需要有數(shù)據(jù)填充忽匈,比如常用的RSA_PKCS1_PADDING填充,還需要減去11個(gè)字節(jié)矿辽。
1024位秘鑰丹允,所能加密的數(shù)據(jù)長(zhǎng)度為:1024 / 8 - 11 = 117字節(jié)。
不對(duì)稱加密和對(duì)稱加密同時(shí)用
如果你需要加密大量的數(shù)據(jù)袋倔,可以用對(duì)稱加密雕蔽,對(duì)稱加密的秘鑰用不對(duì)稱加密算法加密保存。HTTPS就是這樣做的宾娜。
不對(duì)稱秘鑰的其它用處
不對(duì)稱秘鑰除了可以用加密批狐、解密還可以用于數(shù)字簽名。本文不涉及數(shù)字簽名的知識(shí)前塔,主要講述RSA加解密的使用嚣艇。
RSA算法
生成秘鑰
RSA的公鑰和私鑰需要配對(duì),不能像對(duì)稱加密的秘鑰嘱根,可以隨便寫(xiě)髓废。
可以用OpenSSL生成RSA公鑰和私鑰
openssl genrsa -out private_key.pem 1024
openssl rsa -in private_key.pem -pubout -out public_key.pem
public_key.pem和privte_key.pem都是文本文件,看下內(nèi)容
public_key.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1t3KRf4oS3sH8PbABbXL1KBYC
nGq4C/yinpfQ2j2eUmZarHuwIMT9y5ns1lpZZTktGnypvnQjF8c0Rr/cYU53DJjg
lAgVEb3el6iU+WZ7nwLub/BNYS83zpzrhDE3Qy6qTM3evsUsekBR8x6f6Usl7KpE
I/0b+EfRSpXDdvU64wIDAQAB
-----END PUBLIC KEY-----
privte_key.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQD1t3KRf4oS3sH8PbABbXL1KBYCnGq4C/yinpfQ2j2eUmZarHuw
IMT9y5ns1lpZZTktGnypvnQjF8c0Rr/cYU53DJjglAgVEb3el6iU+WZ7nwLub/BN
YS83zpzrhDE3Qy6qTM3evsUsekBR8x6f6Usl7KpEI/0b+EfRSpXDdvU64wIDAQAB
AoGBAJK0odHfPTgBCf8pcaGYkG9xLJsIeutCNOd/GxOWif2yIux2WS8SkasaWd+/
J5iCSD32t4G9dafSNZyvtTPGYUqll4aGXlFqNW8pm16HPQXWrhv1D5LVEEu3zbj+
iNG+gHwB4bISQAOJbnvB6GoFUbDf8VYwkGGlSLGw5D5tulhRAkEA/XBLTfj+5j40
QPfuRIhcBsgxynKJDcmV0sLAIOTBIfSKs5nuYHEVEOcGaxS+nPY3w1ffSUPUdxm0
7L2s+9c0SQJBAPgzLLFvUjM58J/AtklkGyJ3KK5W+jLi/N1PIw7CGYGM2yfFiQLR
ibtJVjTFhLKqDz/BK4lZ9ffU/VNHSApOncsCQQCRBzSgnw9GtGv0jaxUnW+EFgWg
IyDYufW5kOafLCh1BNpmYnztxWhXrsyWdF2Ltr48U8mbxGwN57EIFJar2v+5AkA7
GkSMRAv48tUf1Y4Sz+m+PU3Mph2SPIcmVA/vFb1pIheV0u4bY7Y+iOokStychu52
qhMp8+gkie2BBTpcafgdAkBw8bAzLgmCV8SZEN60x8c2M2Y95CoYOoMLjvQdEfen
IeDmun3DtAPBuStwYNfeQnAHCwvcOJsgDiRLzhys3056
-----END RSA PRIVATE KEY-----
了解秘鑰文件格式
你是否留意到這兩個(gè)文件開(kāi)頭結(jié)尾的兩行文字的區(qū)別了呢该抒?比如:
public_key.pem的開(kāi)頭是
-----BEGIN PUBLIC KEY——
而rsa_private_key的開(kāi)頭是
-----BEGIN RSA PRIVATE KEY——
除了PUBLIC
和PRIVATE
區(qū)別外慌洪,后者還多了RSA
。
這表明這兩個(gè)文件的格式不同凑保。PKCS#1格式的RSA公鑰冈爹、私鑰文件開(kāi)頭和結(jié)束的兩行帶RSA
字樣,而PKCS#8格式不帶欧引。
有些RSA庫(kù)频伤,解密時(shí)需要PKCS#8格式的私鑰文件,可以用下面的命令轉(zhuǎn)換
openssl pkcs8 -topk8 -inform PEM -in private_key.pem -outform PEM -nocrypt>pkcs8_private_key.pem
加解密演示
1. Python RSA加解密演示
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
def rsa_encrypt(plaintext, key):
cipher = PKCS1_v1_5.new(RSA.importKey(key))
return cipher.encrypt(plaintext)
def rsa_decrypt(ciphertext, key):
cipher = PKCS1_v1_5.new(RSA.importKey(key))
return cipher.decrypt(ciphertext, '')
if __name__ == '__main__':
private_key = '''-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQD1t3KRf4oS3sH8PbABbXL1KBYCnGq4C/yinpfQ2j2eUmZarHuw
IMT9y5ns1lpZZTktGnypvnQjF8c0Rr/cYU53DJjglAgVEb3el6iU+WZ7nwLub/BN
YS83zpzrhDE3Qy6qTM3evsUsekBR8x6f6Usl7KpEI/0b+EfRSpXDdvU64wIDAQAB
AoGBAJK0odHfPTgBCf8pcaGYkG9xLJsIeutCNOd/GxOWif2yIux2WS8SkasaWd+/
J5iCSD32t4G9dafSNZyvtTPGYUqll4aGXlFqNW8pm16HPQXWrhv1D5LVEEu3zbj+
iNG+gHwB4bISQAOJbnvB6GoFUbDf8VYwkGGlSLGw5D5tulhRAkEA/XBLTfj+5j40
QPfuRIhcBsgxynKJDcmV0sLAIOTBIfSKs5nuYHEVEOcGaxS+nPY3w1ffSUPUdxm0
7L2s+9c0SQJBAPgzLLFvUjM58J/AtklkGyJ3KK5W+jLi/N1PIw7CGYGM2yfFiQLR
ibtJVjTFhLKqDz/BK4lZ9ffU/VNHSApOncsCQQCRBzSgnw9GtGv0jaxUnW+EFgWg
IyDYufW5kOafLCh1BNpmYnztxWhXrsyWdF2Ltr48U8mbxGwN57EIFJar2v+5AkA7
GkSMRAv48tUf1Y4Sz+m+PU3Mph2SPIcmVA/vFb1pIheV0u4bY7Y+iOokStychu52
qhMp8+gkie2BBTpcafgdAkBw8bAzLgmCV8SZEN60x8c2M2Y95CoYOoMLjvQdEfen
IeDmun3DtAPBuStwYNfeQnAHCwvcOJsgDiRLzhys3056
-----END RSA PRIVATE KEY-----'''
public_key = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1t3KRf4oS3sH8PbABbXL1KBYC
nGq4C/yinpfQ2j2eUmZarHuwIMT9y5ns1lpZZTktGnypvnQjF8c0Rr/cYU53DJjg
lAgVEb3el6iU+WZ7nwLub/BNYS83zpzrhDE3Qy6qTM3evsUsekBR8x6f6Usl7KpE
I/0b+EfRSpXDdvU64wIDAQAB
-----END PUBLIC KEY-----'''
message = 'RSA加解密演示'
cipher_text = rsa_encrypt(message.encode(encoding="utf-8"), public_key)
plain_text = rsa_decrypt(cipher_text, private_key)
print(str(plain_text, encoding='utf-8'))
注意:對(duì)同樣的公鑰和明文進(jìn)行RSA加密芝此,秘文通常是不一樣的憋肖,但這不影響解密。
2. iOS 前端加密婚苹,Python后端解密演示
私鑰放在移動(dòng)端是非常不安全的岸更,攻擊者可能破解你的iOS或Android程序找到私鑰。很多時(shí)候膊升,都是移動(dòng)前端加密怎炊,后端解密。iOS 加密后用base64編碼傳送給后端,即使這個(gè)數(shù)據(jù)被攻擊者捕獲评肆,也無(wú)法獲取敏感數(shù)據(jù)债查。
iOS RSA加密可以借助Swift-RSAUtils開(kāi)源庫(kù)。
iOS代碼中需要公鑰需要去掉首行和末行內(nèi)容瓜挽。
func demo() {
let text = "RSA加解密演示"
let pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1t3KRf4oS3sH8PbABbXL1KBYC" +
"nGq4C/yinpfQ2j2eUmZarHuwIMT9y5ns1lpZZTktGnypvnQjF8c0Rr/cYU53DJjg" +
"lAgVEb3el6iU+WZ7nwLub/BNYS83zpzrhDE3Qy6qTM3evsUsekBR8x6f6Usl7KpE" +
"I/0b+EfRSpXDdvU64wIDAQAB"
let encryptedData = RSAUtils.encryptWithRSAPublicKey(text.data(using: String.Encoding.utf8)!, pubkeyBase64: pubkey, keychainTag: "")
if encryptedData != nil {
let encryptedDataText = encryptedData!.base64EncodedString(options: NSData.Base64EncodingOptions())
print("\(encryptedDataText)")
} else {
print("error")
}
}
Python 解密
import base64
cipher_text_base64 = iOS提交過(guò)來(lái)的字符串
cipher_text = base64.b64decode(cipher_text_base64)
plain_text = rsa_decrypt(cipher_text, private_key)