<cite id="1ndtl"></cite>
<ruby id="1ndtl"></ruby>
<strike id="1ndtl"></strike>
<span id="1ndtl"><dl id="1ndtl"></dl></span><span id="1ndtl"><dl id="1ndtl"></dl></span>
<strike id="1ndtl"></strike>
<strike id="1ndtl"><dl id="1ndtl"><del id="1ndtl"></del></dl></strike>
<span id="1ndtl"></span>
<span id="1ndtl"><dl id="1ndtl"></dl></span>
<strike id="1ndtl"></strike>
<strike id="1ndtl"></strike><span id="1ndtl"><dl id="1ndtl"></dl></span>
<strike id="1ndtl"></strike><strike id="1ndtl"></strike>
<strike id="1ndtl"></strike>
<span id="1ndtl"></span>
<span id="1ndtl"><dl id="1ndtl"></dl></span>
<th id="1ndtl"><noframes id="1ndtl"><span id="1ndtl"><video id="1ndtl"><strike id="1ndtl"></strike></video></span> <strike id="1ndtl"></strike>
<strike id="1ndtl"></strike>
<span id="1ndtl"><dl id="1ndtl"></dl></span>
  1. 首頁
  2. 比特幣的加密算法(比特幣勒索病毒加密算法原理,rsa文件加密)

比特幣的加密算法(比特幣勒索病毒加密算法原理,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 rsafrom rsa.key import PublicKey, PrivateKeyfrom Crypto.Random import get_random_bytesfrom Crypto.Cipher import AESn = 125720733811994291169610359480915027242498332835983573581162897380161904809997273335081454438575169422082365180940876618145332064877333466150617673634912674691272686174191003876154229771482350657467474462371208540453058063685991322556840489981457202800248228247442801463255542794487793252246277195836743728807e = 65537d = 19137129262988160103575582437121142435130740930646384943553733986366406188634401922437288699196269132775282283977999986917585984698968195955239969973936686417032907212206649527011774897714725474886031049229542718237754549863294574561095602754592205273482485305289414428603551207636838864047226576028764734081p = 12485487274433155882855920331622116862134407135211164113507239786605989655388750120598556263544308444761407796178741288699689788828502980217890667645001833q = 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);	}}
相關文章
美女网站色