java python rsa加密_实现Java加密,Python解密的RSA非对称加密算法功能
摘要
因為最近業(yè)務需要使用到openssl的rsa非對稱加密算法,研究了下它的使用方式,但是特殊在于前端分IOS和android兩端,所以前端部門要求使用java給他們做一個加密工具包,但是因為服務端是python做的,所以需要兩端的數(shù)據(jù)能夠共通。研究了幾天終于搞定了,下面是一些重要的代碼以及一些我踩過的坑,分享一下。
歡迎訪問我的Github
OpenSSL官網(wǎng)
一. 編譯
make
Perl 5
an ANSI C compiler
a development environment in form of development libraries and C
header files
a supported Unix operating system
二. 安裝
$ ./config
$ make
$ make test
$ make install
三. 生成密鑰
生成的密鑰的路徑是你當前執(zhí)行命令的路徑
這里默認生成1024長度密鑰
公鑰是基于私鑰來生成的,所以必須先生成私鑰
# 進入openssl
root@VM-0-15-ubuntu:/home/ubuntu# openssl
# 生成一個1024位的私鑰文件rsa_private_key.pem
OpenSSL> genrsa -out rsa_private_key.pem 1024
# 從私鑰中提取公鑰rsa_public_key.pem
OpenSSL> rsa -in rsa_private_key.pem -out rsa_public_key.pem -outform PEM -pubout
# 將私鑰轉(zhuǎn)換成 DER 格式
OpenSSL> rsa -in rsa_private_key.pem -out rsa_private_key.der -outform der
# 將公鑰轉(zhuǎn)換成 DER 格式
OpenSSL> rsa -in rsa_public_key.pem -out rsa_public_key.der -pubin -outform der
# 把RSA私鑰轉(zhuǎn)換成PKCS8格式
OpenSSL> pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt
# 從私鑰創(chuàng)建公鑰證書請求
OpenSSL> req -new -key rsa_private_key.pem -out rsa_public_key.csr
# 生成證書并簽名(有效期10年)
OpenSSL> x509 -req -days 3650 -in rsa_public_key.csr -signkey rsa_private_key.pem -out rsa_public_key.crt
# 把crt證書轉(zhuǎn)換為der格式
OpenSSL> x509 -outform der -in rsa_public_key.crt -out rsa_public_key.der
# 把crt證書生成私鑰p12文件
OpenSSL> pkcs12 -export -out rsa_private_key.p12 -inkey rsa_private_key.pem -in rsa_public_key.crt
1.JAVA端加密
其實單一語言的加解密都還是比較簡單的,關(guān)鍵在于跨語言的兼容問題上。
而且需要特別注意的是我使用的RSA長度是1024的,也就是說我單個需要加密的數(shù)據(jù)的長度不能超過 1024/8-11=117,實際測試單條數(shù)據(jù)最大長度是 116 bytes。
如果需要擴大需要加密的單條數(shù)據(jù)的長度,只需要在生成公鑰的時候設(shè)置對應的長度即可。((數(shù)據(jù)長度+12)*8=密鑰長度)
其中RSA_ALGORITHM 設(shè)置的是算法的使用模式,因為Python端使用的是OAEP所以這里用的是RSA/ECB/OAEPWithSHA-256AndMGF1Padding
在Java端我們使用的公鑰格式是DER,如果使用PEM則會出現(xiàn)異常
package site.cnkj.util;
import org.apache.commons.io.FileUtils;
import sun.misc.BASE64Decoder;
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
/*
* @version 1.0 created by Carol on 2019/4/15 15:31
*/
public class FileEncryptDecrypt {
private static final String RSA_ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
private static final Charset UTF8 = Charset.forName("UTF-8");
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
/**
* 加密文件
* @param keyPath 公鑰路徑,DER
* @param input 輸入文件地址
* @param output 輸出文件地址
*/
public static boolean encrypt(String keyPath, String input, String output){
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
List list = new ArrayList();
try {
byte[] buffer = Files.readAllBytes(Paths.get(keyPath));
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
File inputFile = new File(input);
File outputFile = new File(output);
fileInputStream = new FileInputStream(inputFile);
fileOutputStream = new FileOutputStream(outputFile);
byte[] inputByte = new byte[116];
int len;
while((len = fileInputStream.read(inputByte)) != -1){
list.add(new String(inputByte, 0, len));
}
for (String s : list) {
byte [] encrypted = encrypt(publicKey, s);
fileOutputStream.write(encrypted);
fileOutputStream.flush();
}
fileOutputStream.close();
fileInputStream.close();
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static byte[] encrypt(PublicKey publicKey, String message) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM,"BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encode(cipher.doFinal(message.getBytes(UTF8)));
}
/**
* 從字符串中加載公鑰
*
*/
private static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
try {
byte[] buffer = new BASE64Decoder().decodeBuffer(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
public static void main(String [] args) throws Exception {
encrypt("F:\\dls\\chunk\\config\\rsa_public_key.der", "C:\\Users\\Carol\\Desktop\\file\\868663032830438_migu$user$login$_1554947856915.log","F:\\868663032830438_migu$user$login$_1554947856915.log");
}
}
2.Python端解密
Python端可以使用的模塊是很多的,通常可以用rsa、Crypto、PyCryptodome、PyCrypt等,需要注意的是其中PyCrypt已經(jīng)停止維護了不建議使用,但是幸運的是PyCrypt有一個分支叫PyCryptodome
為了便于閱讀,Java端對加密后的數(shù)據(jù)進行了Base64的格式轉(zhuǎn)換,因此在Python端也同樣需要對獲取的加密后的數(shù)據(jù)進行Base64的轉(zhuǎn)換后再進行解密。
通過觀察,發(fā)現(xiàn)加密后進行Base64轉(zhuǎn)換后的數(shù)據(jù)結(jié)束符為“==”,因此我在這里是直接根據(jù)結(jié)束符進行拆分數(shù)據(jù)的,拆分后的數(shù)據(jù)分別解密后放在同一個字符串集合里面,這里你不需要但是如果出現(xiàn)換行的情況是否還需要自己手動設(shè)置換行,當解密后原有的換行符依然可用。
但是需要注意的是在windows環(huán)境下文件的換行符是"\r\n",加密后依然加密的是"\r\n",但是,但我們解密后寫入文件的時候應當替換"\r\n"為"\n",否則你會發(fā)現(xiàn)多了一行換行,因為當Python重寫寫入文件的時候認為"\r\n"為“回車換行”,所以體現(xiàn)在文件中就是兩次換行的效果了。
在 _init()方法中獲取私鑰的位置只需要把os.path.join(os.path.dirname(os.getcwd()), "config", "rsa_private_key.pem")替換成你自己的私鑰路徑即可
在Python端我們使用的私鑰格式是PEM
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2019/4/12
@Author : Carol
@Site :
@File : FileDecryptEncrypt.py
@Software: PyCharm
@Description:
"""
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
import base64
import traceback
import os
class FileDecryptEncrypt():
def __init__(self):
try:
self.private_key = RSA.import_key(open(os.path.join(os.path.dirname(os.getcwd()), "config", "rsa_private_key.pem")).read())
except Exception as e:
traceback.print_exc()
print("加載密鑰出現(xiàn)異常")
def decrypt(self, root_path, res_path):
"""
RSA的文件解密
:param root_path: 加密后的文件
:param res_path: 解密后的文件
:return: 解密結(jié)果
"""
new_line = b""
cipher = PKCS1_OAEP.new(self.private_key, hashAlgo=SHA256)
try:
with open(root_path, "r") as rootf:
lines = rootf.read().split("==")
for line in lines:
if len(line) > 0:
line = line + "=="
b64_decoded_message = base64.b64decode(line)
cipherContent = cipher.decrypt(b64_decoded_message)
new_line = new_line + cipherContent
if not os.path.exists(os.path.dirname(res_path)):
os.makedirs(os.path.dirname(res_path))
with open(res_path, "w") as resf:
resf.write(str(new_line, encoding="UTF-8").replace("\r\n", "\n"))
return True
except Exception as e:
traceback.print_exc()
return False
if __name__ == '__main__':
FileDecryptEncrypt().decrypt("F:\\868663032830438_1554947856915.log","D:\\\\868663032830438_1554947856915.log")
總結(jié)
以上是生活随笔為你收集整理的java python rsa加密_实现Java加密,Python解密的RSA非对称加密算法功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java搜索文件_Java如何在目录中搜
- 下一篇: java socket 二次发送_发过2