RSA 非对称加密/解密/签名

RSA 是一种非对称加密算法,可以对交互的数据进行加密和加签。

非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。
公开密钥与私有密钥是一对,如果用私有密钥对数据进行加签,只有用对应的公开密钥才能验签;如果用公开密钥对数据进行加密,那么只有用对应的私有密钥才能解密。

如何生成公私钥?

通过openssl工具生成RSA的公钥和私钥(opnssl工具可在互联网中下载到)

下载:
  1. 通过官网途径下载
  2. 从github上克隆源码
linux 下安装方式(已处在该目录下):
  1. sudo ./config
  2. sudo make
  3 sudo make test
  4. sudo make install

*我在编译的过程中出现了一个错误给忽略了导致安装完成后无法正常使用报错:(openssl: error while loading shared libraries:libssl.so.1.1: cannot open shared object file: No such file or directory)这是由于安装库的位置不正确导致的,
解决方法是建立一个软链接:
ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
ln -s /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1*

生成私钥:

genrsa -out key.pem 1024,并回车
系统终端生成
此时,我们可以在bin文件夹中看到一个文件名为key.pem的文件,打开它,
密钥
可以看到—–BEGIN RSA PRIVATE KEY—–开头,—–END RSA PRIVATE KEY—–结尾的
没有换行的字符串,这个就是原始的私钥。

生成公钥:

输入命令rsa -in key.pem -pubout -out pubkey.pem,并回车
公钥
此时,我们可以在bin文件夹中看到一个文件名为pubkey.pem的文件,打开它,
这里写图片描述
可以看到—–BEGIN PUBLIC KEY—–开头, —–END PUBLIC KEY—–结尾的没有换行的
字符串,这个就是公钥。

ACTION 如果因为openssl太大不想下载的话

我们也可以使用python自带的模块来生成公私钥,不只是因为功能强大。项目中使用的一般都是openssl生成的,这是独立于某一语言之外的

使用python中的crypto来生成公私钥:

In [1]: from Crypto import Random
In [2]: from Crypto.PublicKey import RSA
#伪随机数
In [3]: random_generator = Random.new().read
In [4]: rsa = RSA.generate(1024,random_generator)
In [5]: myprivate = rsa.exportKey()
In [6]: myprivate

Out[6]: '-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQCUzbANLEEENoLBzZjXIFkWj41OL73o7GLEVlsgsALKEyJDQ1iz\n+nrzrojQ/4B3tBwi5AJBVf+rd/CUHMDtq16OV6QiDPHB49b2w2Zn8O6+dkok6IvE\nKfHhBv8Es2ZRvtWeaMW98M8cO13WegzWoeA12CJlvGK6bW5zk4U5WRX+GwIDAQAB\nAoGASXZ+uxIlCxJqXYnGMjbrJKM8bORPCsZhQHMtzCZ5ShBGMxT1nu1DdDivnRb2\n8qH93g/ZOS5e6eVt5YGIkg2vwS+wtx0SlLQg7IRgFfk3uimeNPcLxUP2bjWmcxwX\nrcPdDCPjetx0GDd/vvKUozmzREAON0EhB0PvViM6BdsVHpkCQQDAS37X17hiVuhU\nliii13ZDMM/BQMCKZyk1cSPjow90Cptmmqy8HGWs6+5mV7jgBf558oZATIfxSNEf\nBTuLWKjnAkEAxhmwfmUiQfG77gN12XmctRP6tvspWc5Rl41pyqcyBztlnngkZL3R\nCrbx8OGTmWa2yq8DFkUdEyOdzFkeNhgWrQJBAJPvAIwopu7wkRfR1T1BqPeT66Bu\nojFXn7o/ai7L2S2ao2bSA6VL62SWtPcC8XVW5ykFzQZWWhbjwA2vRtmywW0CQAHN\nMgG0Qb9/x0m+1k+H/5jV+a24UwPyEGPkcVXad2YBcEckqJAR+dizGTgrlQAMIxVs\nygZl0oHeDQ1SsiejyHECQATZLWxB5E1rumQHUKqFftDNwFHVGTLB9+r6V6IgimFq\nO83UgcpSIfiaFN/DR7gTi+R8iUTa7SCTUZ3mUlNMeC0=\n-----END RSA PRIVATE KEY-----'

In [7]: mypublic = rsa.publickey()
# 生成公钥
In [8]: mypublic = mypublic.exportKey()
In [9]: mypublic

Out[14]: '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUzbANLEEENoLBzZjXIFkWj41O\nL73o7GLEVlsgsALKEyJDQ1iz+nrzrojQ/4B3tBwi5AJBVf+rd/CUHMDtq16OV6Qi\nDPHB49b2w2Zn8O6+dkok6IvEKfHhBv8Es2ZRvtWeaMW98M8cO13WegzWoeA12CJl\nvGK6bW5zk4U5WRX+GwIDAQAB\n-----END PUBLIC KEY-----'

需要保存的话可以用python的文件操作:

with open ('/home/private.pem',wb) as f:
    f.write(myprivate)

开始数据的加密与签名等操作

在开始操作前再回顾一下必要的常识:
通常在项目中是双向验证双向加密的,也就是说可能会有两对公私钥
这里写图片描述

from Crypto.Cipher import PKCS1_v1_5
from Crypto import Random
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
# 加密函数
def encrypt(message, public_key):
    """
    功能:对参数使用公钥进行加密 
    参数:
    message:待加密数据
    public_key: str, 公钥字符串
    返回值:
    str,加密后的字符串
    """
    message_length = len(message)
    block_size = message_length / 117
    if message_length % 117 != 0:
        block_size += 1
    cipher = get_cipher(public_key)
    encrypted_message = []
    for i in range(0, block_size):
        if message_length > i * 117:
            part_message = message[(i * 117):((i + 1) * 117)]
        else:
            part_message = message[i * 117:]
   # 以上部分是为了处理加密数据太长进行的分段操作
        part_encrypted_message = cipher.encrypt(part_message)
        encrypted_message.append(part_encrypted_message)
    ret = base64.b64encode(''.join(encrypted_message))
    return ret
# 解密函数
def decrypt(encrypted_data, private_key):
    """ 
    功能:使用私钥对参数进行解密,RSA ECB PKCS1Padding 解密。
    1024密钥,对应最大的加密块大小117,最大密码块大小为128
    参数:
    encrypted_data: 加密后的参数
    private_key: 自己的私钥
    返回值:
    str,解密后的字符串
    """
    raw_data = base64.b64decode(encrypted_data)
    assert len(raw_data) % 128 == 0, u'加密字符串长度不正确'
    block_size = len(raw_data) / 128
    cipher = get_cipher(private_key)
    dsize = SHA.digest_size
    sentinel = Random.new().read(15+dsize)
    decrypted_messages = []
    for i in range(0, block_size):
        if len(raw_data) > i * 128:
            part = raw_data[i * 128: (i + 1) * 128]
        else:
            part = raw_data[i * 128:]
        part_decrypt_message = cipher.decrypt(part, sentinel)
        decrypted_messages.append(part_decrypt_message)
    return ''.join(decrypted_messages)

# 签名函数
def sign(data, key):
    h = SHA.new(data)
    # 首先生成RSA实例
    rsa_private = RSA.importKey(key)
    from Crypto.Signature import PKCS1_v1_5 as PKCS1V15
    signer = PKCS1V15.new(rsa_private)
    signature = signer.sign(h)
    signature = base64.b64encode(signature)
    return signature

# 验签函数
def check_sign(params, sign, public_key):
    """
    功能:使用公钥验证签名内容
    参数:
    params dict, 待验证参数
    sign str, 签名
    public_key str, 公钥字符串
    返回值:
    true/false true表示验证通过;false表示验证失败;
    """
    from Crypto.Signature import PKCS1_v1_5 as PKCS1V15
    rsa_public = RSA.importKey(public_key)
    verifier = PKCS1V15.new(rsa_public)
    h = SHA.new(params)
    return verifier.verify(h, base64.b64decode(sign))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Java提供的`java.security`包中的`KeyPairGenerator`、`Cipher`和`Signature`类来实现RSA非对称加密签名。 以下是一个简单的示例代码,其中使用RSA算法生成密钥对、使用公钥加密、使用私钥解密、使用私钥签名、使用公钥验证签名: ```java import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import javax.crypto.Cipher; public class ZipRSAEncryption { public static void main(String[] args) throws Exception { String zipFile = "path/to/your/zip/file.zip"; String publicKeyFile = "path/to/your/public/key/file.pem"; String privateKeyFile = "path/to/your/private/key/file.pem"; String encryptedZipFile = "path/to/your/encrypted/zip/file.zip"; String decryptedZipFile = "path/to/your/decrypted/zip/file.zip"; String signatureFile = "path/to/your/signature/file.sig"; // 生成RSA密钥对 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(2048); // 密钥长度为2048位 KeyPair keyPair = kpg.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); // 加密Zip文件 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] buffer = new byte[1024]; FileOutputStream fos = new FileOutputStream(encryptedZipFile); ZipOutputStream zos = new ZipOutputStream(fos); FileInputStream fis = new FileInputStream(zipFile); ZipInputStream zis = new ZipInputStream(fis); ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { zos.putNextEntry(new ZipEntry(entry.getName())); int len; while ((len = zis.read(buffer)) > 0) { byte[] encryptedData = cipher.doFinal(buffer, 0, len); zos.write(encryptedData, 0, encryptedData.length); } zos.closeEntry(); } zis.close(); zos.close(); fis.close(); fos.close(); // 解密Zip文件 cipher.init(Cipher.DECRYPT_MODE, privateKey); fos = new FileOutputStream(decryptedZipFile); zos = new ZipOutputStream(fos); fis = new FileInputStream(encryptedZipFile); zis = new ZipInputStream(fis); while ((entry = zis.getNextEntry()) != null) { zos.putNextEntry(new ZipEntry(entry.getName())); int len; while ((len = zis.read(buffer)) > 0) { byte[] decryptedData = cipher.doFinal(buffer, 0, len); zos.write(decryptedData, 0, decryptedData.length); } zos.closeEntry(); } zis.close(); zos.close(); fis.close(); fos.close(); // 对Zip文件进行签名 Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); fis = new FileInputStream(zipFile); while ((len = fis.read(buffer)) > 0) { signature.update(buffer, 0, len); } fis.close(); byte[] signatureData = signature.sign(); FileOutputStream signatureFos = new FileOutputStream(signatureFile); signatureFos.write(signatureData); signatureFos.close(); // 验证Zip文件的签名 signature.initVerify(publicKey); fis = new FileInputStream(zipFile); while ((len = fis.read(buffer)) > 0) { signature.update(buffer, 0, len); } fis.close(); FileInputStream signatureFis = new FileInputStream(signatureFile); byte[] signatureBytes = new byte[signatureFis.available()]; signatureFis.read(signatureBytes); signatureFis.close(); boolean isValid = signature.verify(signatureBytes); if (isValid) { System.out.println("签名验证通过"); } else { System.out.println("签名验证失败"); } } } ``` 在上面的代码中,我们首先使用`KeyPairGenerator`类生成一个2048位的RSA密钥对,并将其分别保存为PEM格式的公钥和私钥文件。然后,我们使用公钥加密Zip文件,使用私钥解密Zip文件,使用私钥对Zip文件进行签名,使用公钥验证Zip文件的签名。 在加密和解密Zip文件时,我们使用`Cipher`类进行加密和解密操作。在签名和验证签名时,我们使用`Signature`类进行签名和验证签名操作。需要注意的是,签名算法通常是基于哈希函数的,因此我们需要先使用哈希函数对Zip文件进行摘要计算,再对摘要进行签名操作。在示例代码中,我们使用的哈希函数是SHA-256,签名算法是SHA256withRSA
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值