您的位置 首页 java

比特币勒索病毒加密算法原理,rsa文件加密

本文教你如何用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文件加密

文章地址:https://www.zhihuclub.com/196919.shtml

关于作者: 智云科技

热门文章

网站地图