PGP加密檔案和解密檔案
阿新 • • 發佈:2019-01-22
首先,需要jar包如下:
cryptix-jce-api.jar
cryptix-jce-provider.jar
cryptix-message-api.jar
cryptix-openpgp-provider.jar
cryptix-pki-api.jar
然後需要寫兩個class,一個是PGP加密解密功能的類,一個是給其他類使用的工具類。
使用的時候呼叫工具類PGPEncryptDecrypt就好了。
工具類PGPEncryptDecrypt :
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import cryptix.pki.KeyBundle;
public class PGPEncryptDecrypt {
//解密檔案路徑
private static String decryptFilePath = "";
//解密後新生成的檔案
private static String decrypt_New = "";
//解密後生成的新檔案
private static File decryptFile_New = null;
//須解密檔案
private static File decryptFile = null;
//須解密檔名
private static String decryptFileName = "" ;
//須加密檔案
private static File encryptFile = null;
//加密後生成的新檔案
private static File encryptFile_New = null;
//公鑰證書
private static File pubKey = null;
// 私鑰證書
private static File prikey = null;
// 證書密碼
private static String password = "";
//原始檔案路徑
private static String plaintextPath = "" ;
//原始檔案檔名
private static String plaintextFileName = "";
//加密檔案路徑
private static String encryptFilePath = "";
//加密後新生成的檔案
private static String encrypt_newFileName = "";
//證書檔案路徑
private static String certFilePath = "";
//公鑰名
private static String publicKeyFileName = "";
//私鑰名
private static String privateKeyFileName = "";
//將日期以 yyyyMMdd 的格式輸出
private static final SimpleDateFormat compactDateFormatter = new SimpleDateFormat("yyyyMMdd");
private static String formatCompactDate(Date date) {
if(date==null){
return "";
}
return compactDateFormatter.format(date);
}
///////////////////////////////////////////加密用////////////////////////////////////////////////
//簽名並加密檔案,並且將簽名加密後的檔案內容寫入到新的檔案中
public static void signEncrypt(String pswd,String orifilepath,String orifilename,String encryfilepath,String encryptnewFileName,String certpath,String pubkeyname,String prikeyname){
System.out.println("encrypt--------------------");
password = pswd;
plaintextPath = orifilepath;
plaintextFileName = orifilename;
encryptFilePath = encryfilepath;
encrypt_newFileName = encryptnewFileName;
certFilePath = certpath;
publicKeyFileName = pubkeyname;
privateKeyFileName = prikeyname;
encryptFile = new File(plaintextPath,plaintextFileName);
pubKey = new File(certFilePath,publicKeyFileName);
prikey = new File(certFilePath,privateKeyFileName);
encryptFile_New = new File(encryptFilePath,encrypt_newFileName);
if(!encryptFile.exists()){
System.out.println("Encrypt file is not exists!");
throw new RuntimeException("Encrypt file is not exists!");
}
String encode = getFilecharset(new File(plaintextPath,plaintextFileName));
System.out.println("encode=>"+encode);
System.out.println("++++++++++++++++++"+plaintextPath+plaintextFileName);
System.out.println("++++++++++++++++++"+encryptFilePath+encrypt_newFileName);
byte [] encrypts = pgpEncryptAndSign(IOUtil.read((plaintextPath+plaintextFileName) ,encode), pubKey, prikey, password);
IOUtil.writeAsText( (encryptFilePath+encrypt_newFileName), new String(encrypts),encode);
}
/** 使用PGP證書籤名和加密原始檔案
*
* @param plain
* 原始檔案
* @param publicFile
* 公鑰
* @param privateFile
* 私鑰
* @param password
* 私鑰密碼
* @return 返回簽名加密後的密文
*/
private static byte[] pgpEncryptAndSign(byte[] plain, File publicKeyFile,File privateKeyFile, String password) {
try {
InputStream pubInputStream = new FileInputStream(publicKeyFile);
InputStream priInputStream = new FileInputStream(privateKeyFile);
// 將公鑰檔案轉換為PGP的KeyBundle(加密需要使用KeyBundle)
KeyBundle publicKey = PGPUtil.streamToKeyBundle(pubInputStream);
// 將私鑰檔案轉換為PGP的KeyBundle(簽名需要使用KeyBundle)
KeyBundle privateKey = PGPUtil.streamToKeyBundle(priInputStream);
// 返回加密後的密文
return PGPUtil.signAndEncrypt(plain, privateKey, password,
publicKey);
} catch (Exception e) {
System.out.println("Use PGP Sign And Encrypt Fail! excepted:"+ e);
throw new RuntimeException();
}
}
///////////////////////////////////////////加密用////////////////////////////////////////////////
///////////////////////////////////////////解密用////////////////////////////////////////////////
/**
* 解密並驗籤檔案
* 並且將解密的內容寫入到指定的檔案中
*/
public static void decryptVerify(String decrypt_pswd,String decrypt_filepath , String decrypt_filename , String decryptnewfilename,String decrypt_certpath,String decrypt_pubkeyname,String decrypt_prikeyname){
System.out.println("decrypt--------------------");
password = decrypt_pswd;
certFilePath = decrypt_certpath;
publicKeyFileName = decrypt_pubkeyname;
privateKeyFileName = decrypt_prikeyname;
decryptFilePath = decrypt_filepath;
decryptFileName = decrypt_filename;
decrypt_New = decryptnewfilename;
decryptFile = new File(decryptFilePath,decryptFileName);
decryptFile_New = new File(decryptFilePath,decrypt_New);
pubKey = new File(certFilePath,publicKeyFileName);
prikey = new File(certFilePath,privateKeyFileName);
if(!decryptFile.exists()){
System.out.println("Decrypt file is not exists!");
throw new RuntimeException("Decrypt file is not exists!");
}
String encode = getFilecharset(new File(plaintextPath,plaintextFileName));
System.out.println("++++++++++++++++++"+plaintextPath+plaintextFileName);
System.out.println("++++++++++++++++++"+decryptFilePath+decryptFileName);
byte [] decrypts = pgpDecryptCryptograph(IOUtil.read((decryptFilePath+decryptFileName),encode), pubKey, prikey, password);
IOUtil.writeAsText( (decryptFilePath+decrypt_New), new String(decrypts),encode);
}
/**
* 使用PGP私鑰對密文解密
*
* @param cryptograph
* 密文內容
* @param publicFile
* 公鑰檔案
* @param privateFile
* 私鑰檔案
* @param password
* 私鑰密碼
* @return 返回解密驗籤後明文
*/
private static byte[] pgpDecryptCryptograph(byte [] cryptograph,File publicKeyFile,File privateKeyFile,String password){
try {
InputStream pubInputStream = new FileInputStream(publicKeyFile);
InputStream priInputStream = new FileInputStream(privateKeyFile);
//將私鑰檔案轉換為PGP的KeyBundle(簽名需要使用KeyBundle)
KeyBundle privateKey = PGPUtil.streamToKeyBundle(priInputStream);
//將公鑰檔案轉換為PGP的KeyBundle(加密需要使用KeyBundle)
KeyBundle publicKey = PGPUtil.streamToKeyBundle(pubInputStream);
return PGPUtil.decryptVerify(cryptograph, privateKey, password, publicKey);
} catch (Exception e) {
System.out.println("Use PGP Decrypt Verify Fail! exception:"+e);
e.printStackTrace();
throw new RuntimeException();
}
}
///////////////////////////////////////////解密用////////////////////////////////////////////////
//判斷編碼格式方法
private static String getFilecharset(File sourceFile) {
String charset = "GBK";
byte[] first3Bytes = new byte[3];
try {
boolean checked = false;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
bis.mark(0);
int read = bis.read(first3Bytes, 0, 3);
if (read == -1) {
return charset; //檔案編碼為 ANSI
} else if (first3Bytes[0] == (byte) 0xFF
&& first3Bytes[1] == (byte) 0xFE) {
charset = "UTF-16LE"; //檔案編碼為 Unicode
checked = true;
} else if (first3Bytes[0] == (byte) 0xFE
&& first3Bytes[1] == (byte) 0xFF) {
charset = "UTF-16BE"; //檔案編碼為 Unicode big endian
checked = true;
} else if (first3Bytes[0] == (byte) 0xEF
&& first3Bytes[1] == (byte) 0xBB
&& first3Bytes[2] == (byte) 0xBF) {
charset = "UTF-8"; //檔案編碼為 UTF-8
checked = true;
}
bis.reset();
if (!checked) {
int loc = 0;
while ((read = bis.read()) != -1) {
loc++;
if (read >= 0xF0)
break;
if (0x80 <= read && read <= 0xBF) // 單獨出現BF以下的,也算是GBK
break;
if (0xC0 <= read && read <= 0xDF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF) // 雙位元組 (0xC0 - 0xDF)
// (0x80
// - 0xBF),也可能在GB編碼內
continue;
else
break;
} else if (0xE0 <= read && read <= 0xEF) {// 也有可能出錯,但是機率較小
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
charset = "UTF-8";
break;
} else
break;
} else
break;
}
}
}
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
return charset;
}
}
功能類PGPUtil:
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import cryptix.message.EncryptedMessage;
import cryptix.message.EncryptedMessageBuilder;
import cryptix.message.KeyBundleMessage;
import cryptix.message.LiteralMessage;
import cryptix.message.LiteralMessageBuilder;
import cryptix.message.Message;
import cryptix.message.MessageException;
import cryptix.message.MessageFactory;
import cryptix.message.NotEncryptedToParameterException;
import cryptix.message.SignedMessage;
import cryptix.message.SignedMessageBuilder;
import cryptix.openpgp.PGPArmouredMessage;
import cryptix.pki.KeyBundle;
public class PGPUtil {
//這個一定要有 不然會報這個錯java.security.NoSuchAlgorithmException: Algorithm not found.
static{
Security.addProvider(new cryptix.jce.provider.CryptixCrypto());
Security.addProvider(new cryptix.openpgp.provider.CryptixOpenPGP() );
}
///////////////////////////////////////////加密用////////////////////////////////////////////////
/**
* 流轉換為PGP KeuBundle 物件
* @param inputStream Key
* @return 轉換後的 KeuBundle
* @throws MessageException
* @throws IOException
*/
public static KeyBundle streamToKeyBundle(InputStream inputStream) throws MessageException, IOException {
MessageFactory messageFactory = null;
try {
messageFactory = MessageFactory.getInstance("OpenPGP");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Collection msgs = messageFactory.generateMessages(inputStream);
KeyBundleMessage keybm = (KeyBundleMessage)msgs.iterator().next();
return keybm.getKeyBundle();
}
/**
* 簽名加密
* @param plain 明文
* @param privateKey 私鑰
* @param keypass 私鑰密碼
* @param recipientKeys 公鑰
* @return 返回簽名加密後的資料
* @throws UnrecoverableKeyException
* @throws MessageException
*/
public static byte [] signAndEncrypt(byte[] plain,KeyBundle privateKey,String keypass,List<KeyBundle> recipientKeys) throws UnrecoverableKeyException, MessageException{
return PGPUtil.encrypt(PGPUtil.sign(plain, privateKey, keypass),recipientKeys);
}
/**
* 簽名加密
* @param plain 明文
* @param privateKey 私鑰
* @param keypass 私鑰密碼
* @param recipientKeys 公鑰
* @return 返回簽名加密後的資料
* @throws UnrecoverableKeyException
* @throws MessageException
*/
public static byte [] signAndEncrypt(byte[] plain,KeyBundle privateKey,String keypass,KeyBundle publicKey) throws UnrecoverableKeyException, MessageException{
return PGPUtil.encrypt(PGPUtil.sign(plain, privateKey, keypass),publicKey);
}
/**
* 使用多個公鑰對明文加密
* @param plain 明文
* @param recipientKeys 公鑰集合
* @return 加密後的明文
* @throws MessageException
*/
public static byte[] encrypt(byte[] plain,List<KeyBundle> recipientKeys) throws MessageException{
LiteralMessage literal = buildLiteralMessage(plain);
EncryptedMessageBuilder emb = null;
try {
emb = EncryptedMessageBuilder.getInstance("OpenPGP");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
emb.init(literal);
//新增接受者
for(KeyBundle key : recipientKeys){
emb.addRecipient(key);
}
//壓縮
emb.setAttribute("compressed", "true");
//得到加密資訊
Message msg = emb.build();
PGPArmouredMessage pgpMsg = new PGPArmouredMessage(msg);
return pgpMsg.getEncoded();
}
/**
* 使用單張公鑰加密
* @param plain 明文
* @param publicKey 公鑰
* @return 返回加密後的密文
* @throws MessageException
*/
public static byte[] encrypt(byte[] plain,KeyBundle publicKey) throws MessageException{
List<KeyBundle> list = new ArrayList<KeyBundle>();
list.add(publicKey);
return encrypt(plain,list);
}
/**
* 使用私鑰和密碼對明文簽名
* @param plain 明文
* @param privateKey 私鑰
* @param keypass 私鑰密碼
* @return 簽名後的明文
* @throws MessageException
* @throws UnrecoverableKeyException
*/
public static byte[] sign(byte[] plain,KeyBundle privateKey,String keypass)throws MessageException,UnrecoverableKeyException{
SignedMessageBuilder smb = null;
try {
smb = SignedMessageBuilder.getInstance("OpenPGP");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// SignedMessageBuilder smb = SignedMessageBuilder.getInstance("OpenPGP/V3");
LiteralMessage literal = buildLiteralMessage(plain);
smb.init(literal);
smb.addSigner(privateKey, keypass.toCharArray());
Message msg = smb.build();
PGPArmouredMessage armoured = new PGPArmouredMessage(msg);
return armoured.getEncoded();
}
private static LiteralMessage buildLiteralMessage(byte[] message) throws MessageException{
LiteralMessageBuilder lmb = null;
try {
lmb = LiteralMessageBuilder.getInstance("OpenPGP");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
lmb.init(message);
LiteralMessage literal = (LiteralMessage)lmb.build();
return literal;
}
///////////////////////////////////////////加密用////////////////////////////////////////////////
///////////////////////////////////////////解密用////////////////////////////////////////////////
/**
* 解密驗籤
* @param encrypted 密文
* @param privateKey 私鑰
* @param keypass 私鑰密碼
* @param publicKey 公鑰
* @return 返回明文
* @throws UnrecoverableKeyException
* @throws MessageException
* @throws IOException
* @throws NotEncryptedToParameterException
*/
public static byte[] decryptVerify(byte[] encrypted,KeyBundle privateKey,String keypass,KeyBundle publicKey) throws UnrecoverableKeyException, MessageException, IOException, NotEncryptedToParameterException{
return PGPUtil.verify(PGPUtil.decrypt(encrypted, privateKey, keypass), publicKey);
}
/**
* 使用私鑰和密碼解密加密後的資料
* @param encrypted PGP加密過的資料
* @param privateKey 私鑰
* @param keypass 私鑰密碼
* @return 解密後的明文
* @throws MessageException
* @throws IOException
* @throws UnrecoverableKeyException
* @throws NotEncryptedToParameterException
*/
public static byte[] decrypt(byte[] encrypted,KeyBundle privateKey,String keypass) throws MessageException, IOException, UnrecoverableKeyException, NotEncryptedToParameterException{
MessageFactory mf = null;
try {
mf = MessageFactory.getInstance("OpenPGP");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Collection msgs = mf.generateMessages(new ByteArrayInputStream(encrypted));
//得到集合中的EncryptedMessage物件
Message message = (Message)msgs.iterator().next();
if (!(message instanceof EncryptedMessage)) {
throw new MessageException("Not a encrypted message.");
}
EncryptedMessage em = (EncryptedMessage)message;
Message msg = em.decrypt(privateKey,keypass.toCharArray());
return ((LiteralMessage)msg).getBinaryData();
}
/**
* 驗證Message
* @param signed 驗證的內容
* @param publickey 公鑰
* @return 返回驗證後的內容
* @throws MessageException
* @throws IOException
*/
public static byte[] verify(byte[] signed,KeyBundle publickey) throws MessageException, IOException{
MessageFactory mf = null;
try {
mf = MessageFactory.getInstance("OpenPGP");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Message msg = (Message)mf.generateMessages(new ByteArrayInputStream(signed)).iterator().next();
if (!(msg instanceof SignedMessage)) {
throw new MessageException(" Not a signed message.");
}
SignedMessage sm = (SignedMessage)msg;
if (sm.verify(publickey)) {
} else {
throw new MessageException(" Signature verify fail. ");
}
if (!(sm.getContents() instanceof LiteralMessage)){
throw new MessageException(" Not a signed message.");
}
LiteralMessage lm = (LiteralMessage)sm.getContents();
return lm.getBinaryData();
}
///////////////////////////////////////////解密用////////////////////////////////////////////////
}
功能類IOUtil
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class IOUtil {
public static byte[] read(String fileName,String encode) {
String fileContent = "";
try {
File f = new File(fileName);
if (f.isFile() && f.exists()) {
InputStreamReader read = new InputStreamReader(new FileInputStream(f), encode);
BufferedReader reader = new BufferedReader(read);
String line;
while ((line = reader.readLine()) != null) {
fileContent += line + "\n";
}
read.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return fileContent.getBytes();
}
public static void writeAsText(String fileName, String fileContent,String encode) {
System.out.println("write path:"+fileName);
System.out.println("write encode:"+encode);
try {
File f = new File(fileName);
if (!f.exists()) {
System.out.println("notexist");
f.createNewFile();
} else {
System.out.println("exist");
}
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f), encode);
BufferedWriter writer = new BufferedWriter(write);
writer.write(fileContent);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
最後是呼叫:
//------------------------PGP encrypt decrypt------------------------
String PGPpassword = "PGP私鑰密碼";
String filepath = "存放檔案的路徑";
String oripath = "存放原始檔的資料夾";
String encryptpath = "存放加密後文件的資料夾";
String decryptpath = "存放解密後文件的資料夾";
String orifilename = "原始檔檔名";
String encryptfilename = "加密檔案檔名";
String decryptfilename = "解密檔案檔名";
String keypath = "PGP私鑰存放路徑";
String publicPGPkey = "公鑰檔名";
String privatePGPkey = "私鑰檔名";
//------------------------PGP encrypt decrypt------------------------
/*執行加密*/
PGPEncryptDecrypt.signEncrypt(PGPpassword, filepath+oripath, orifilename, filepath+encryptpath, encryptfilename, keypath, publicPGPkey, privatePGPkey);
/*執行解密操作*/
PGPEncryptDecrypt.decryptVerify(PGPpassword,filepath,encryptpath+encryptfilename,decryptpath+decryptfilename, keypath, publicPGPkey, privatePGPkey);