1. 程式人生 > >PGP加密檔案和解密檔案

PGP加密檔案和解密檔案

首先,需要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);