
本文教你如何用Python与Java对文件进行不对称加密,并且Python与Java共用一套密钥,可以相互加解密对方的密文。本文仅作技术交流,请不要用于任何违法用途。一、引言最近有个项目需要做文件加密......
本文教你如何用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代码中我使用的是模块。python中使用的是的AES模块,以及RSA模块(也可以直接使用的RSA模块)
问题1Python与Java生成的RSA密钥无法相互导入
JAVA的RSAKeyPairGenerator并没有公开,因此我无法确定JAVA是如何导入相关的key。根据网上的一些方法,踩坑两小时依旧无果。最后解决方法:在对JAVA代码生成密钥debug过程中找到相应的n,e,d,p,q参数的值,也可以使用反射的方法找到这些值(私有属性,无法直接获取)。在python的函数源码中,发现可以通过(PublicKey(n,e),PrivateKey(n,e,d,p,q))这种方式导入相应的key。在的RSA模块中可以根据函数的源码找到RsaKey(n=n,e=e,d=d,p=p,q=q,u=u)这段代码导入相应的key。通过这种方式就可以python与Java使用同一套密钥了。
问题2Python使用AES加密后的内容,python可以解密但是Java无法解密。后发现是数据进行padding时两边不一致导致的,后将函数改为以下得到解决
这里是将文件最终搞成AES加密cipher_session=(session_key,pubkey)aes加密mode=_ECBcryptos=(session_key,mode)AES加密后的密文字节数组cipher_text=(padding(data))out_(cipher_text)defrsa_decrypt_file(file_path):"""私钥解密文件"""withopen(file_path,'rb')asf:因为rsa加密是128位,所以前128位为aes密钥enc_session_key,cipher_text=[(x)forxin(128,-1)]aes对文件内容解密cipher_aes=(session_key,_ECB)data=cipher_(cipher_text)'''去除内容末尾的相同的字符,因为加密过程中对未满16位的做了补充具体可以参考lambdas:s+(16-len(s)%16)*chr(16-len(s)%16).encode()这段代码下面代码应该还要校验c是否等于16-len(s)%16'''c=data[-1]index=0ifc16:fori,dinenumerate(data[::-1]):ifd==c:index=ielse:breakdata=data[:-1-index]withopen(file_path,'wb')asf:(data)if__name__=='__main__':rsa_encrypt_file(r'd:\1.txt')rsa_decrypt_file(r'd:\1.txt')四、java相关代码
最近写python代码写得比较多,函数及属性的命名都没有按照Java的驼峰命名方式,大家随意看看哈。
;;;publicclassMain{publicstaticvoidmain(String[]args)throwsException{rsa_encrypt_file("d:\\1.txt");rsa_decrypt_file("d:\\1.txt");}/***字节数组复制*@paramoriginal原始的字节数组*@paramstart要复制的开始位置下标*@param要复制的结束位置下标*@return*/publicstaticbyte[]copy_array(byte[]original,intstart,int){intnewLength=-start;byte[]copy=newbyte[newLength];(original,start,copy,0,(,newLength));returncopy;}/***rsa对文件解密,先解密aes密钥,再解密文件**@paramfile_path*@throwsException*/publicstaticvoidrsa_decrypt_file(Stringfile_path)throwsException{//读取数据Filef=newFile(file_path);intlength=(int)();byte[]data=newbyte[length];FileInputStreamfis=newFileInputStream(f);(data);();//解密byte[]enc_session_key=copy_array(data,0,128);byte[]session_key=(enc_session_key,);byte[]cipher_text=copy_array(data,128,);byte[]text=_decrypt(cipher_text,session_key);//写入文件FileOutputStreamfos=newFileOutputStream(f);(text);();();}/***rsa对文件加密,先加密aes密钥,再加密文件**@paramfile_path*@throwsException*/publicstaticvoidrsa_encrypt_file(Stringfile_path)throwsException{//读取数据Filef=newFile(file_path);intlength=(int)();byte[]data=newbyte[length];FileInputStreamfis=newFileInputStream(f);(data);();//aes的随机密钥byte[]session_key=_aes_Key();//使用rsa对aes的密钥加密byte[]cipher_session=(session_key,);//使用aes算法对文件内容加密byte[]cipher_data=_encrypt(data,session_key);//将密钥写入文件FileOutputStreamfos=newFileOutputStream(f);(cipher_session);(cipher_data);();();}};;;;;;publicclassAESUtil{/***创建128位的随机密钥**@return*@throwsNoSuchAlgorithmException*/publicstaticbyte[]create_aes_Key()throwsNoSuchAlgorithmException{//生成keyKeyGeneratorkeyGenerator;//构造密钥生成器,指定为AES算法,不区分大小写keyGenerator=("AES");//生成一个128位的随机源,根据传入的字节数组(128);//产生原始对称密钥SecretKeysecretKey=();//获得原始对称密钥的字节数组byte[]keyBytes=();//key转换,根据字节数组生成AES密钥//Keykey=newSecretKeySpec(keyBytes,"AES");returnkeyBytes;}/***AES解密**@paramcipherText加密后的密文byte数组*@paramkey_byte解密用密钥*/publicstaticbyte[]aes_decrypt(byte[]cipherText,byte[]key_byte){Ciphercipher;byte[]result=null;try{Keykey=newSecretKeySpec(key_byte,"AES");cipher=("AES/ECB/PKCS5Padding");//初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的(_MODE,key);result=(cipherText);}catch(Exceptione){();}returnresult;}/***AES加密**@paramcontext需要加密的明文KEYSTR加密用密钥*@return*/publicstaticbyte[]aes_encrypt(byte[]context,byte[]key_byte){try{Keykey=newSecretKeySpec(key_byte,"AES");Ciphercipher=("AES/ECB/PKCS5Padding");(_MODE,key);//将加密并编码后的内容解码成字节数组(context);}catch(Exceptione){();returnnull;}}}此处密钥是通过【内容三】中的问题1获取得到的。生成的密钥步骤可以参考genKeyPair函数
;;;;;;;;;;;publicclassRSAUtils{=();=();//预先得到的公钥和私钥publicstaticStringpublicKeyString="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzCEKyIaoSOCd+8XG/u6X9fGGlgmqygZPAWAYpSaPebX4kUm2yloxLdTAwYbCQmMhcgyOvxdo9H9Qjc/uw1SY43mvIAqXaRNQ9FYbzMCcV167ebjJF4xFjPICf5bQqBh4mt5vuf0CM1lpZazI7rsI2R5/pdVwmVXKFEVmqpuu+pwIDAQAB";publicstaticStringprivateKeyString="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=";publicstaticvoidmain(String[]args)throwsException{genKeyPair();//加密字符串//Stringmessage="df723820";//StringmessageEn=encrypt(message,publicKeyString);//(message+"\t加密后的字符串为:"+messageEn);//StringmessageDe=decrypt(messageEn,privateKeyString);//("还原后的字符串为:"+messageDe);}/***随机生成密钥对**@throwsNoSuchAlgorithmException*/publicstaticvoidgenKeyPair()throwsNoSuchAlgorithmException{//KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象KeyPairGeneratorkeyPairGen=("RSA");//初始化密钥对生成器,密钥大小为96-1024位(1024,newSecureRandom());//生成一个密钥对,保存在keyPair中KeyPairkeyPair=();RSAPrivateKeyprivateKey=(RSAPrivateKey)();//得到私钥RSAPublicKeypublicKey=(RSAPublicKey)();//得到公钥(());(());publicKeyString=newString(().encodeToString(()));//得到私钥字符串privateKeyString=newString(().encodeToString(()));("生成的公钥:"+publicKeyString);("生成的私钥:"+privateKeyString);}/***RSA公钥加密**@paramstr加密字符串*@parampublicKey公钥*@return密文*@throwsException加密过程中的异常信息*/publicstaticStringencrypt(Stringstr,StringpublicKey)throwsException{//base64编码的公钥byte[]decoded=(publicKey);RSAPublicKeypubKey=(RSAPublicKey)("RSA").generatePublic(newX509EncodedKeySpec(decoded));//RSA加密Ciphercipher=("RSA");(_MODE,pubKey);StringoutStr=((("UTF-8")));returnoutStr;}/***RSA私钥解密**@paramstr加密字符串*@paramprivateKey私钥*@return铭文*@throwsException解密过程中的异常信息*/publicstaticStringdecrypt(Stringstr,StringprivateKey)throwsException{//64位解码加密后的字符串byte[]inputByte=(("UTF-8"));//base64编码的私钥byte[]decoded=(privateKey);RSAPrivateKeypriKey=(RSAPrivateKey)("RSA").generatePrivate(newPKCS8EncodedKeySpec(decoded));//RSA解密Ciphercipher=("RSA");(_MODE,priKey);StringoutStr=newString((inputByte));returnoutStr;}publicstaticbyte[]decrypt(byte[]inputByte,StringprivateKey)throwsException{//base64编码的私钥byte[]decoded=(privateKey);//base64编码的私钥RSAPrivateKeypriKey=(RSAPrivateKey)("RSA").generatePrivate(newPKCS8EncodedKeySpec(decoded));//RSA解密Ciphercipher=("RSA");(_MODE,priKey);(inputByte);}publicstaticbyte[]encrypt(byte[]inputByte,StringpublicKey)throwsException{//base64编码的公钥byte[]decoded=(publicKey);RSAPublicKeypubKey=(RSAPublicKey)("RSA").generatePublic(newX509EncodedKeySpec(decoded));//RSA加密Ciphercipher=("RSA");(_MODE,pubKey);(inputByte);}}