本文主要通过RSA加解密实践,来讲述不对称秘钥的特点。
不对称秘钥和RSA
不对称秘钥算法,也叫公钥密码算法。
不对称秘钥算法图示:
不对称秘钥的重要特点是加密和解密用的秘钥不相同。
和对称秘钥算法的比较
不对称秘钥的优点
不对称秘钥有一个很大的好处是可以把公钥公开,比如Alice要传送敏感数据给Bob,Bob告诉Alice公钥,Alice用公钥加密数据,通过网络传送给Bob,在传送时被攻击者Eric捕获到,Eric拿到加密的数据和公钥,但不知道私钥仍无法破解敏感信息。
哦,这个看起来很不错,比对称加密好多了,完全可以取代对称加密呀?
等等!等等!小王同学,你先别激动,我们先了解下不对称秘钥的缺点再说。
不对称秘钥的缺点
不对称秘钥算法的原理并不复杂,可以从这篇文章对RSA算法的原理做大概的了解。
RSA等不对称秘钥算法都存在一个限制是——慢!这个从原理很容易知道。
慢会导致不对称秘钥算法另一个限制——只能加密少量数据。
RSA算法,一次加密的数据最多和秘钥长度相同。但实际上,RSA算法一般还需要有数据填充,比如常用的RSA_PKCS1_PADDING填充,还需要减去11个字节。
1024位秘钥,所能加密的数据长度为:1024 / 8 - 11 = 117字节。
不对称加密和对称加密同时用
如果你需要加密大量的数据,可以用对称加密,对称加密的秘钥用不对称加密算法加密保存。HTTPS就是这样做的。
不对称秘钥的其它用处
不对称秘钥除了可以用加密、解密还可以用于数字签名。本文不涉及数字签名的知识,主要讲述RSA加解密的使用。
RSA算法
生成秘钥
RSA的公钥和私钥需要配对,不能像对称加密的秘钥,可以随便写。
可以用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都是文本文件,看下内容
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-----
了解秘钥文件格式
你是否留意到这两个文件开头结尾的两行文字的区别了呢?比如:
public_key.pem的开头是
-----BEGIN PUBLIC KEY——
而rsa_private_key的开头是
-----BEGIN RSA PRIVATE KEY——
除了PUBLIC
和PRIVATE
区别外,后者还多了RSA
。
这表明这两个文件的格式不同。PKCS#1格式的RSA公钥、私钥文件开头和结束的两行带RSA
字样,而PKCS#8格式不带。
有些RSA库,解密时需要PKCS#8格式的私钥文件,可以用下面的命令转换
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'))
注意:对同样的公钥和明文进行RSA加密,秘文通常是不一样的,但这不影响解密。
2. iOS 前端加密,Python后端解密演示
私钥放在移动端是非常不安全的,攻击者可能破解你的iOS或Android程序找到私钥。很多时候,都是移动前端加密,后端解密。iOS 加密后用base64编码传送给后端,即使这个数据被攻击者捕获,也无法获取敏感数据。
iOS RSA加密可以借助Swift-RSAUtils开源库。
iOS代码中需要公钥需要去掉首行和末行内容。
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提交过来的字符串
cipher_text = base64.b64decode(cipher_text_base64)
plain_text = rsa_decrypt(cipher_text, private_key)