密码学基础之RSA与不对称秘钥

本文主要通过RSA加解密实践,来讲述不对称秘钥的特点。

不对称秘钥和RSA

不对称秘钥算法,也叫公钥密码算法。
不对称秘钥算法图示:

密码学基础之RSA与不对称秘钥_第1张图片
不对称秘钥

不对称秘钥的重要特点是加密和解密用的秘钥不相同。

和对称秘钥算法的比较

不对称秘钥的优点
不对称秘钥有一个很大的好处是可以把公钥公开,比如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
密码学基础之RSA与不对称秘钥_第2张图片
RSA公钥和私钥生成

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——

除了PUBLICPRIVATE区别外,后者还多了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)

相关文章

密码学基础之对称加密(一)
密码学基础系列

你可能感兴趣的:(密码学基础之RSA与不对称秘钥)