当前位置:首页 > 经验 >

rsa加密使用方法(rsa非对称加密流程)

来源:原点资讯(www.yd166.com)时间:2022-10-30 01:54:10作者:YD166手机阅读>>

本文教你如何用Python与Java对文件进行不对称加密,并且Python与java共用一套密钥,可以相互加解密对方的密文。本文仅作技术交流,请不要用于任何违法用途。

一、引言

最近有个项目需要做文件加密,并且要求python与JAVA能够相互加解密。对于文件加密,我第一时间想到了比特币勒索病毒。于是收集了相关的信息,参考瑞星官网的《又一使用.net开发的勒索病毒出现——Prodecryptor勒索病毒》这篇文章,大致了解到程序先使用rsa对AES算法的密钥进行加密,然后使用AES算法对文件进行加密。

二、RSA与AES简介

RSA加密算法属于非对称加密算法,AES加密算法属于对称加密算法。这里我们不聊RSA与AES算法的具体实现,我们先聊下对称加密与非对称基本情况。

1、对称加密速度快,但是只有一个密钥进行加密和解密。当你的程序加密时,别人能反编译你的程序获取密钥,导致密钥泄露。

2、非对称加密速度慢,在加密中采用两个密钥,使用公钥进行加密,私钥进行解密。在程序中使用公钥进行加密,别人即使拿到了你的公钥也无法对文件进行解密。但是每次加密有长度限制,如果加密信息较多,需分段加解密(不建议对大量信息rsa加密,效率低效)。

因此在比特币勒索病毒程序中加密过程如下:1读取文件字节数组(加密算法都是对字节数组进行加密)2创建一个随机AES密钥,作为session密钥。3使用RSA算法对AES的session密钥加密覆盖写入文件。4然后使用AES的session密钥对文件内容进行加密写入文件。

解密过程:1读取加密后的文件字节数组,2使用私钥对AES的密钥进行解密,3使用AES对文件内容解密,4将解密后的文件内容覆盖写入文件中。

三、python与java交互遇到的一些问题

根据网上的例子,如果单独使用python或者java按上述方式进行文件加解密都很容易找到实现方案,但是如果python和java进行交互可能会出现一些问题。由于我学艺不精,采用了一些投机取巧的方法。

在java代码中我使用的是javax.crypto.Cipher模块。python中使用的是Crypto.Cipher的AES模块,以及RSA模块(也可以直接使用Crypto.Cipher的RSA模块)

问题1 Python与Java生成的RSA密钥无法相互导入

JAVA的RSAKeyPairGenerator并没有公开,因此我无法确定JAVA是如何导入相关的key。根据网上的一些方法,踩坑两小时依旧无果。最后解决方法:在对JAVA代码生成密钥debug过程中找到相应的n ,e ,d ,p ,q参数的值,也可以使用反射的方法找到这些值(私有属性,无法直接获取)。在python的rsa.newkeys函数源码中,发现可以通过 ( PublicKey(n, e), PrivateKey(n, e, d, p, q) )这种方式导入相应的key。在Crypto.PublicKey的RSA模块中可以根据RSA.generate函数的源码找到RsaKey(n=n, e=e, d=d, p=p, q=q, u=u)这段代码导入相应的key。通过这种方式就可以python与Java使用同一套密钥了。

问题2 python使用AES加密后的内容,python可以解密但是Java无法解密。 后发现是数据进行padding时两边不一致导致的,后将函数改为以下得到解决

# 数据补空格 padding = lambda s: s (16 - len(s) % 16) * chr(16 - len(s) % 16).encode()四、python相关代码

以下为python加密模块内容,相应的密钥是通过【内容三】中的问题1获取得到。在实际项目中应该只保留公钥部分,私钥及解密部分应该剔除,下面java相关内容中也是如此。

"""信息加密模块""" import rsa from rsa.key import PublicKey, PrivateKey from Crypto.Random import get_random_bytes from Crypto.Cipher import AES n = 125720733811994291169610359480915027242498332835983573581162897380161904809997273335081454438575169422082365180940876618145332064877333466150617673634912674691272686174191003876154229771482350657467474462371208540453058063685991322556840489981457202800248228247442801463255542794487793252246277195836743728807 e = 65537 d = 19137129262988160103575582437121142435130740930646384943553733986366406188634401922437288699196269132775282283977999986917585984698968195955239969973936686417032907212206649527011774897714725474886031049229542718237754549863294574561095602754592205273482485305289414428603551207636838864047226576028764734081 p = 12485487274433155882855920331622116862134407135211164113507239786605989655388750120598556263544308444761407796178741288699689788828502980217890667645001833 q = 10069349401319384440381523925066814369492626716870156920501823163204449469801788824691171814613081997769220084438138226773387889070138894859614591998248079 (pubkey, privkey) = (PublicKey(n, e), PrivateKey(n, e, d, p, q)) def rsa_encrypt_file(file_path): """公钥加密文件""" with open(file_path, 'rb') as f: data = f.read() with open(file_path, 'wb') as out_file: session_key = get_random_bytes(16) # 这里是将文件最终搞成AES加密 cipher_session = rsa.encrypt(session_key, pubkey) # aes的临时密钥 out_file.write(cipher_session) # aes加密 mode = AES.MODE_ECB cryptos = AES.new(session_key, mode) # 数据补空格 padding = lambda s: s (16 - len(s) % 16) * chr(16 - len(s) % 16).encode() # AES加密后的密文字节数组 cipher_text = cryptos.encrypt(padding(data)) out_file.write(cipher_text) def rsa_decrypt_file(file_path): """私钥解密文件""" with open(file_path, 'rb') as f: # 此处可以加passphrase, 类似盐值,但通过rsa模块生成的时候不支持此参数 # 因为rsa加密是128位,所以前128位为aes密钥 enc_session_key, cipher_text = [f.read(x) for x in (128, -1)] # rsa解密aes密钥 session_key = rsa.decrypt(enc_session_key, privkey) # aes对文件内容解密 cipher_aes = AES.new(session_key, AES.MODE_ECB) data = cipher_aes.decrypt(cipher_text) ''' 去除内容末尾的相同的字符,因为加密过程中对未满16位的做了补充 具体可以参考lambda s: s (16 - len(s) % 16) * chr(16 - len(s) % 16).encode()这段代码 下面代码应该还要校验c是否等于16 - len(s) % 16 ''' c = data[-1] index = 0 if c < 16: for i, d in enumerate(data[::-1]): if d == c: index = i else: break data = data[:- 1 - index] with open(file_path, 'wb') as f: f.write(data) if __name__ == '__main__': rsa_encrypt_file(r'd:\1.txt') rsa_decrypt_file(r'd:\1.txt')四、java相关代码

最近写python代码写得比较多,函数及属性的命名都没有按照Java的驼峰命名方式,大家随意看看哈。

main.java

import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; public class Main { public static void main(String[] args) throws Exception { rsa_encrypt_file("d:\\1.txt"); rsa_decrypt_file("d:\\1.txt"); } /** * 字节数组复制 * @param original 原始的字节数组 * @param start 要复制的开始位置下标 * @param end 要复制的结束位置下标 * @return */ public static byte[] copy_array(byte[] original, int start, int end) { int newLength = end - start; byte[] copy = new byte[newLength]; System.arraycopy(original, start, copy, 0, Math.min(original.length, newLength)); return copy; } /** * rsa对文件解密,先解密aes密钥,再解密文件 * * @param file_path * @throws Exception */ public static void rsa_decrypt_file(String file_path) throws Exception { // 读取数据 File f = new File(file_path); int length = (int) f.length(); byte[] data = new byte[length]; FileInputStream fis = new FileInputStream(f); fis.read(data); fis.close(); // 解密 byte[] enc_session_key = copy_array(data, 0, 128); byte[] session_key = RSAUtils.decrypt(enc_session_key, RSAUtils.privateKeyString); byte[] cipher_text = copy_array(data, 128, data.length); byte[] text = AESUtil.aes_decrypt(cipher_text, session_key); // 写入文件 FileOutputStream fos = new FileOutputStream(f); fos.write(text); fos.flush(); fos.close(); } /** * rsa对文件加密,先加密aes密钥,再加密文件 * * @param file_path * @throws Exception */ public static void rsa_encrypt_file(String file_path) throws Exception { // 读取数据 File f = new File(file_path); int length = (int) f.length(); byte[] data = new byte[length]; FileInputStream fis = new FileInputStream(f); fis.read(data); fis.close(); // aes的随机密钥 byte[] session_key = AESUtil.create_aes_Key(); // 使用rsa对aes的密钥加密 byte[] cipher_session = RSAUtils.encrypt(session_key, RSAUtils.publicKeyString); // 使用aes算法对文件内容加密 byte[] cipher_data = AESUtil.aes_encrypt(data, session_key); // 将密钥写入文件 FileOutputStream fos = new FileOutputStream(f); fos.write(cipher_session); fos.write(cipher_data); fos.flush(); fos.close(); } }

AESUtil.java

import java.security.Key; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; public class AESUtil { /** * 创建128位的随机密钥 * * @return * @throws NoSuchAlgorithmException */ public static byte[] create_aes_Key() throws NoSuchAlgorithmException { // 生成key KeyGenerator keyGenerator; // 构造密钥生成器,指定为AES算法,不区分大小写 keyGenerator = KeyGenerator.getInstance("AES"); // 生成一个128位的随机源,根据传入的字节数组 keyGenerator.init(128); // 产生原始对称密钥 SecretKey secretKey = keyGenerator.generateKey(); // 获得原始对称密钥的字节数组 byte[] keyBytes = secretKey.getEncoded(); // key转换,根据字节数组生成AES密钥 // Key key = new SecretKeySpec(keyBytes, "AES"); return keyBytes; } /** * AES解密 * * @param cipherText 加密后的密文byte数组 * @param key_byte 解密用密钥 */ public static byte[] aes_decrypt(byte[] cipherText, byte[] key_byte) { Cipher cipher; byte[] result = null; try { Key key = new SecretKeySpec(key_byte, "AES"); cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY cipher.init(Cipher.DECRYPT_MODE, key); result = cipher.doFinal(cipherText); } catch (Exception e) { e.printStackTrace(); } return result; } /** * AES加密 * * @param context 需要加密的明文 KEYSTR 加密用密钥 * @return */ public static byte[] aes_encrypt(byte[] context, byte[] key_byte) { try { Key key = new SecretKeySpec(key_byte, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); // 将加密并编码后的内容解码成字节数组 return cipher.doFinal(context); } catch (Exception e) { e.printStackTrace(); return null; } } }

RSAUtils.java

此处密钥是通过【内容三】中的问题1获取得到的。生成的密钥步骤可以参考genKeyPair函数

import javax.crypto.Cipher; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class RSAUtils { private static Base64.Decoder decoder = Base64.getDecoder(); private static Base64.Encoder encoder = Base64.getEncoder(); // 预先得到的公钥和私钥 public static String publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzCEKyIaoSOCd 8XG/u6X9fGGlgmqygZPAWAYpSaPebX4kUm2yloxLdTAwYbCQmMhcgyOvxdo9H9Qjc/uw1SY43mvIAqXaRNQ9FYbzMCcV167ebjJF4xFjPICf5bQqBh4mt5vuf0CM1lpZazI7rsI2R5/pdVwmVXKFEVmqpuu pwIDAQAB"; public static String privateKeyString = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALMIQrIhqhI4J37xcb 7pf18YaWCarKBk8BYBilJo95tfiRSbbKWjEt1MDBhsJCYyFyDI6/F2j0f1CNz 7DVJjjea8gCpdpE1D0VhvMwJxXXrt5uMkXjEWM8gJ/ltCoGHia3m 5/QIzWWllrMjuuwjZHn l1XCZVcoURWaqm676nAgMBAAECgYAbQI6mfulcjJ 2expNjUrfIyfaAdgsA/1xsfR JG FVDV3YfTA0pnYgqYrNzOhTyBwtKWiBAQMeePY4bbWXBvNGsCSd7pwP4Io2B24fm4yKSIUbjJKx2jQMbLn kvNu9Tw508ogmEfnHzUmVy0h2ePN 6hTUCZ7jjaNFlK2oACgQJBAO5jymEpoTdqFluIt2ETc6ElW9yPg1IrIJNT2QSPMS1i2xd/BmPP9PQMcV4hHv7knLFeLAjVaf0QFJ0SetlqYGkCQQDAQfRiii7xbt0sYMIrSWe4ygjSvxC9Job1dtgyI1Q2EjfO6wZzd 7Iu pbC2sA2fCk40YMmxSmvCQoOuO/RESPAkEA1IjZfOi9mAcYKcFpJL5P38LL9IdqoA5dO5yMpjj3siwpgvg3/TMBg7e4NyC2Xq/5V1TLU5DZrsnwZt1782yYyQJBAL 4hcZGWm20yqZYjwivmNlzz7ypgD2/z9G0g//rryyEmlajlLlNHjfa/OdxyXD95LXpVo93ju5 q faYgb4Qw0CQG6d0blzJS9qmnkP61Q49bBfiOPLF5MF9T VyXe7zyjGKdrnT6WUucGTjjdVW1FX1mkMBtUdu9VPnbGiYzvoyuM="; public static void main(String[] args) throws Exception { genKeyPair(); // 加密字符串 // String message = "df723820"; // String messageEn = encrypt(message, publicKeyString); // System.out.println(message "\t加密后的字符串为:" messageEn); // String messageDe = decrypt(messageEn, privateKeyString); // System.out.println("还原后的字符串为:" messageDe); } /** * 随机生成密钥对 * * @throws NoSuchAlgorithmException */ public static void genKeyPair() throws NoSuchAlgorithmException { // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); // 初始化密钥对生成器,密钥大小为96-1024位 keyPairGen.initialize(1024, new SecureRandom()); // 生成一个密钥对,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥 System.out.println(publicKey.getModulus()); System.out.println(publicKey.getPublicExponent()); publicKeyString = new String(Base64.getEncoder().encodeToString(publicKey.getEncoded())); // 得到私钥字符串 privateKeyString = new String(Base64.getEncoder().encodeToString(privateKey.getEncoded())); System.out.println("生成的公钥:" publicKeyString); System.out.println("生成的私钥:" privateKeyString); } /** * RSA公钥加密 * * @param str 加密字符串 * @param publicKey 公钥 * @return 密文 * @throws Exception 加密过程中的异常信息 */ public static String encrypt(String str, String publicKey) throws Exception { // base64编码的公钥 byte[] decoded = decoder.decode(publicKey); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA") .generatePublic(new X509EncodedKeySpec(decoded)); // RSA加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); String outStr = encoder.encodeToString(cipher.doFinal(str.getBytes("UTF-8"))); return outStr; } /** * RSA私钥解密 * * @param str 加密字符串 * @param privateKey 私钥 * @return 铭文 * @throws Exception 解密过程中的异常信息 */ public static String decrypt(String str, String privateKey) throws Exception { // 64位解码加密后的字符串 byte[] inputByte = decoder.decode(str.getBytes("UTF-8")); // base64编码的私钥 byte[] decoded = decoder.decode(privateKey); RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA") .generatePrivate(new PKCS8EncodedKeySpec(decoded)); // RSA解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, priKey); String outStr = new String(cipher.doFinal(inputByte)); return outStr; } public static byte[] decrypt(byte[] inputByte, String privateKey) throws Exception { // base64编码的私钥 byte[] decoded = decoder.decode(privateKey); // base64编码的私钥 RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA") .generatePrivate(new PKCS8EncodedKeySpec(decoded)); // RSA解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, priKey); return cipher.doFinal(inputByte); } public static byte[] encrypt(byte[] inputByte, String publicKey) throws Exception { // base64编码的公钥 byte[] decoded = decoder.decode(publicKey); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA") .generatePublic(new X509EncodedKeySpec(decoded)); // RSA加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); return cipher.doFinal(inputByte); } }

栏目热文

rsa加密原理总结(rsa加密解密用法)

rsa加密原理总结(rsa加密解密用法)

密码学是研究编制密码和破译密码的技术科学。研究密码变化的客观规律,应用于编制密码以保守通信秘密的,称为编码学;应用于破...

2022-10-30 02:20:01查看全文 >>

rsa加密和解密过程(rsa加密解密的实际例子)

rsa加密和解密过程(rsa加密解密的实际例子)

1. RSA加密与解密 -- 使用公钥加密、私钥解密public class RSATool{public string...

2022-10-30 02:08:52查看全文 >>

非对称密钥加密解密过程(对称式加密解密过程图解)

非对称密钥加密解密过程(对称式加密解密过程图解)

2022年在合肥举办的国家网络安全宣传周网络全博览会上,国盾量子和科大讯飞还联合推出了一种让保障我们老百姓切身利益的黑科...

2022-10-30 02:25:04查看全文 >>

rsa加密原理图解(rsa加密解密的实际例子)

rsa加密原理图解(rsa加密解密的实际例子)

加密和解密使用的是两个不同的秘钥,这种算法叫做非对称加密。非对称加密又称为公钥加密,RSA只是公钥加密的一种。 数字签...

2022-10-30 02:24:59查看全文 >>

rsa加密模式(rsa加密过程图)

rsa加密模式(rsa加密过程图)

接口数据使用了 RSA 加密和签名?一篇文章带你搞定!1、前言 很多童鞋在工作中,会遇到一些接口使用RSA加密和签名来...

2022-10-30 02:22:00查看全文 >>

rsa的加密和解密原理(rsa算法的加密和解密步骤)

rsa的加密和解密原理(rsa算法的加密和解密步骤)

数据信息安全对我们每个人都有很重要的意义,特别是一些敏感信息,可能一些类似于收货地址、手机号还没引起大家的注意。但是最直...

2022-10-30 02:19:20查看全文 >>

rsa加密和解密教程(rsa加密解密结果分析)

rsa加密和解密教程(rsa加密解密结果分析)

RSA加密验签是对安全性要求比较高的机构间通信常用的方式,密钥足够长的情况下,当前的计算能力还不足以解密(不过量子计算机...

2022-10-30 02:06:55查看全文 >>

rsa加密的流程(rsa加密算法主要步骤)

rsa加密的流程(rsa加密算法主要步骤)

目前常用的加密/解密算法主要有两类:对称加密算法和非对称加密算法。两者的主要区别在于加密和解密的密钥是否一致,一致的就是...

2022-10-30 02:09:13查看全文 >>

RSA加密算法(rsa加密算法实例代码)

RSA加密算法(rsa加密算法实例代码)

说到加密,目前比较常见的有对称加密和非对称加密,那什么是对称加密和非对称加密呢,如图对称加密假如 一个人A想把信息m发给...

2022-10-30 02:02:51查看全文 >>

rsa加密算法安全吗(rsa加密算法详解)

rsa加密算法安全吗(rsa加密算法详解)

RSA算法由来RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shami...

2022-10-30 02:12:12查看全文 >>

文档排行