C++客户端和java服务端互相加解密

5 篇文章 0 订阅

这段时间在公司做一个APP和移动网关通信加密的项目,本来是想采用https或者openssl来加密通道,但考虑到数据本身的安全性问题,还是打算自己编写加解密算法。

一、流程

1、客户端生成AES密钥和RSA密钥对

2、服务端生成RSA密钥对,并公开公钥,保存私钥

3、客户端获取服务端公钥,同时将客户端公钥发送到服务端

4、客户端用服务端公钥加密AES密钥,同时用客户端私钥对加密后的AES密钥进行签名,然后将结果通过http协议发送到

服务端

5、服务端接收到数据后,先用客户端公钥验证签名,然后用服务端私钥解密,获得AES密钥

6、客户端和服务端通过AES密钥进行加解密

二、客户端代码

客户端用C++语言编写,因为在linux上开发,用cryptopp库进行开发,详细如下:

1、AesEncryption.h

#ifndef ENCRYPTIONSO_AESENCRYPTION_H
#define ENCRYPTIONSO_AESENCRYPTION_H


#include <cryptopp/aes.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>


using namespace std;
using namespace CryptoPP;

#ifdef WIN32
#ifdef MYDLL_EXPORTS
#define MYDLLCLASS _declspec(dllexport)
#else
#define MYDLLCLASS _declspec(dllimport)
#endif
#else
#define MYDLLCLASS
#endif


class MYDLLCLASS AesEncryption {


public:
    void initKV(byte *nKey,byte *nIv);


    string encrypt(string plainText);


    void writeCipher(string output);


    string decrypt(string cipherTextHex);


    string readCipher();


    void generateKey(byte* nKey);
private:
    byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ], iv[ CryptoPP::AES::BLOCKSIZE];
};

#endif //ENCRYPTIONSO_AESENCRYPTION_H

2、 AesEncryption.cpp

#include <fstream>
#include <iostream>
#include <sstream>
#include "AesEncryption.h"


void AesEncryption::initKV(byte *nKey,byte *nIv)
{
    //memset( key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH );
    //memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
    memcpy(key,nKey,CryptoPP::AES::DEFAULT_KEYLENGTH);
    memcpy(iv,nIv,CryptoPP::AES::BLOCKSIZE);
}


void AesEncryption::generateKey(byte* nKey)
{
    CryptoPP::AES::Encryption aesEncryption(nKey, CryptoPP::AES::DEFAULT_KEYLENGTH);
}


string AesEncryption::encrypt(string plainText)
{
    string cipherText;


    //
    CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, iv );
    CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( cipherText ));
    stfEncryptor.Put( reinterpret_cast<const unsigned char*>( plainText.c_str() ), plainText.length() + 1 );
    stfEncryptor.MessageEnd();


    string cipherTextHex;
    for( int i = 0; i < cipherText.size(); i++ )
    {
        char ch[3] = {0};
        sprintf(ch, "%02x",  static_cast<byte>(cipherText[i]));
        cipherTextHex += ch;
    }


    return cipherTextHex;
}
void AesEncryption::writeCipher(string output)
{
    ofstream out("cipher.data");
    out.write(output.c_str(), output.length());
    out.close();


    cout<<"writeCipher finish "<<endl<<endl;
}


string AesEncryption::decrypt(string cipherTextHex)
{
    string cipherText;
    string decryptedText;


    int i = 0;
    while(true)
    {
        char c;
        int x;
        stringstream ss;
        ss<<hex<<cipherTextHex.substr(i, 2).c_str();
        ss>>x;
        c = (char)x;
        cipherText += c;
        if(i >= cipherTextHex.length() - 2)break;
        i += 2;
    }


    //
    CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );
    CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedText ));
    stfDecryptor.Put( reinterpret_cast<const unsigned char*>( cipherText.c_str() ), cipherText.size());


    stfDecryptor.MessageEnd();


    return decryptedText;
}


string AesEncryption::readCipher()
{
    ifstream in("cipher.data");


    string line;
    string decryptedText;
    while(getline(in, line))
    {
        if(line.length() > 1)
        {
            decryptedText += decrypt(line) + "\n";
        }
        line.clear();
    }


    cout<<"readCipher finish "<<endl;
    in.close();


    return decryptedText;
}

3、RsaEncryption.h

#ifndef ENCRYPTIONSO_RSAENCRYPTION_H
#define ENCRYPTIONSO_RSAENCRYPTION_H


#include <cryptopp/randpool.h>
#include <cryptopp/rsa.h>
#include <cryptopp/hex.h>
#include <cryptopp/osrng.h>
#include <cryptopp/files.h>
#include <iostream>


using namespace std;
using namespace CryptoPP;


#ifdef WIN32
#ifdef MYDLL_EXPORTS
#define MYDLLCLASS _declspec(dllexport)
#else
#define MYDLLCLASS _declspec(dllimport)
#endif
#else
#define MYDLLCLASS
#endif


class MYDLLCLASS RsaEncryption {
public:
    RsaEncryption();
    virtual ~RsaEncryption();


/**
init rsa use public key.
@params N N factor in RSA, aslo called the modulus, big integer in string format.
@params e e factor in RSA, aslo called public exponent, big integer in string format.
*/
public: void initPublicKey(const char * N, const char * e);
/**
init ras use private key.
@params N N factor in RSA, aslo called the modulus, big integer in string format.
@params e e factor in RSA, aslo called public exponent, big integer in string format.
@params d d factor in RSA, aslo called private exponent, big integer in string format.
*/
public: void initPrivateKey(const char * N, const char * e, const char * d);




/**
the maximal cipher length after encrypted.
fixed and always is the key bit size/8, e.g. 1024 bits key, this value is 128.
@param len the plain data length will be encrypted.
@return the maximal cipher length.
*/
public: int getCipherLen(int len);
/**
encrypt indata to outdata.
@param indata input data.
@param len the input data length.
@param outdata the output data length.
*/
public: int encrypt(const char * indata, int len, char * outdata);


/**
the maximal plain data length after decrypted.
@param len the cipher data length that will be decrypted.
@return the maximal plain data length.
*/
public: int getPlainLen(int len);
/**
decrypt indata to outdata.
@param indata input data.
@param len the input data length.
@param outdata the output data length.
*/
public: int decrypt(const char * indata, int len, char * outdata);
/**
sign message.
@param message input data.
@return string signed message.
 */
public: std::string signMessage(const std::string& message);
/**
verify signed.
@param message input data.
@param signedMessage signed message.
@return bool verify result.
 */
public: bool verifyMessage(const std::string& message, std::string& signedMessage);


public: std::string encrypt(std::string message);


public: std::string decrypt(std::string encryptMessage);


private: CryptoPP::RSAFunction pk;  // public key.
private: CryptoPP::InvertibleRSAFunction sk;    // private key.
private: CryptoPP::RSAES_PKCS1v15_Encryptor * enc;    // encryptor.
private: CryptoPP::RSAES_PKCS1v15_Decryptor * dec;    // decryptor.
private: CryptoPP::AutoSeededRandomPool rng;        // auto seeded randomor.
};
#endif //ENCRYPTIONSO_RSAENCRYPTION_H

4、RsaEncryption.cpp

#include "RsaEncryption.h"


RsaEncryption::RsaEncryption()
{
    enc = NULL;
    dec = NULL;
}


RsaEncryption::~RsaEncryption()
{
    if (NULL != enc)
    {
        delete enc;
    }
    if (NULL != dec)
    {
        delete dec;
    }
}


void RsaEncryption::initPublicKey(const char * N, const char * e)
{
    CryptoPP::Integer big_N(N);
    CryptoPP::Integer big_e(e);


    pk.Initialize(big_N, big_e);
    if (NULL != enc)
    {
        delete enc;
    }
    enc = new CryptoPP::RSAES_PKCS1v15_Encryptor(pk);
}


void RsaEncryption::initPrivateKey(const char * N, const char * e, const char * d)
{
    CryptoPP::Integer big_N(N);
    CryptoPP::Integer big_e(e);
    CryptoPP::Integer big_d(d);


    sk.Initialize(big_N, big_e, big_d);
    if (NULL != dec)
    {
        delete dec;
    }
    dec = new CryptoPP::RSAES_PKCS1v15_Decryptor(sk);
}


int RsaEncryption::getCipherLen(int len)
{
    return (int)enc->CiphertextLength(len);
}




int RsaEncryption::encrypt(const char * indata, int len, char * outdata)
{
    enc->Encrypt(rng, (const unsigned char *)indata, len, (unsigned char *)outdata);
    return (int)enc->FixedCiphertextLength();
}


int RsaEncryption::getPlainLen(int len)
{
    return (int)dec->MaxPlaintextLength(len);
}


int RsaEncryption::decrypt(const char * indata, int len, char * outdata)
{
    CryptoPP::DecodingResult res = dec->Decrypt(rng, (const unsigned char *)indata, len, (unsigned char *)outdata);


    return (int)res.messageLength;
}


std::string RsaEncryption::encrypt(std::string message)
{
    std::string result = "";


    RSA::PublicKey  publicKey(pk);
    RSAES_PKCS1v15_Encryptor pub(publicKey);


    StringSource( message, true, new PK_EncryptorFilter(rng, pub, new HexEncoder(new StringSink(result))) );


    return result;
}


std::string RsaEncryption::decrypt(std::string encryptMessage) {


    std::string result = "";


    RSA::PrivateKey privateKey(sk);


    RSAES_PKCS1v15_Decryptor pri(privateKey);


    StringSource(encryptMessage, true, new HexDecoder(new PK_DecryptorFilter(rng, pri, new StringSink(result))) );


    return result;


}


std::string RsaEncryption::signMessage(const std::string& message)
{


    RSA::PrivateKey privateKey(sk);


    CryptoPP::RSASSA_PKCS1v15_SHA_Signer signer(privateKey);


    size_t length = signer.MaxSignatureLength();
    CryptoPP::SecByteBlock signature(length);


    std::string signedMessage = "";


    StringSource s1(message, true, new SignerFilter(rng, signer, new HexEncoder(new StringSink(signedMessage))));
    //StringSource s1(message, true, new SignerFilter(rng, signer, new Base64Encoder(new StringSink(signedMessage))));


    return signedMessage;


}
bool RsaEncryption::verifyMessage(const std::string& message, std::string& signedMessage)
{
    RSA::PublicKey  publicKey(pk);


    RSASSA_PKCS1v15_SHA_Verifier verifier(publicKey);


    StringSource signatureFile( signedMessage, true, new HexDecoder);
    //StringSource signatureFile( signedMessage, true, new Base64Decoder);
    if (signatureFile.MaxRetrievable() != verifier.SignatureLength())
    { throw std::string( "Signature Size Problem" ); }
    SecByteBlock signature(verifier.SignatureLength());
    signatureFile.Get(signature, signature.size());
    VerifierFilter *verifierFilter = new VerifierFilter(verifier);
    verifierFilter->Put(signature, verifier.SignatureLength());
    StringSource s(message, true, verifierFilter);
    return verifierFilter->GetLastResult();
}

5、Cencryption.h 导出类

#ifndef ENCRYPTIONSO_CENCRYPTION_H
#define ENCRYPTIONSO_CENCRYPTION_H


#include <array>
#include <iostream>
#include "AesEncryption.h"
#include "RsaEncryption.h"


#ifdef WIN32
#ifdef MYDLL_EXPORTS
#define MYDLLCLASS _declspec(dllexport)
#else
#define MYDLLCLASS _declspec(dllimport)
#endif
#else
#define MYDLLCLASS
#endif


using namespace std;




class MYDLLCLASS Cencryption {
private:
    AesEncryption aesEncryption;  //AES加解密
    RsaEncryption rsaEncryption;  //RSA加解密


    byte m_key[ CryptoPP::AES::DEFAULT_KEYLENGTH ]; //AES密钥


    byte m_iv[ CryptoPP::AES::BLOCKSIZE];


    string m_Module;
    string m_PubExpond;
    string m_PriExpond;


private:
    const string &getM_Module() const;
    const string &getM_PubExpond() const;
    const string &getM_PriExpond() const;




private:
    /*******AES加密*************
     * @param plainText 明文
     * @return
     */
    string AesEncrtypt(string plainText);


    /*******AES解密*************
    * @param cipherTextHex 密文
    * @return
    */
    string AesDecrypt(string cipherTextHex);




    /*******生成AES密钥*************
    * @param nAesKey 密钥
    * @return
    */
    void GenerateAesKey();




    /*******RSA加密*************
     * @param plainText 明文
     * @return
     */
    string RsaEncrtypt(string plainText,RsaEncryption &nrsaEncryption);




    /*******RSA解密*************
   * @param cipherTextHex 密文
   * @return
   */
    string RsaDecrtypt(string cipherTextHex);


public:
    Cencryption();
    virtual ~Cencryption();




public:
    /*****************
    * 获取-----客户端公钥,发送到远程服务端
    * * @return string 客户端公钥
    */
    string getPublicKey();


    /*****************
     * 初始化-----生成对称密钥,然后用非对称算法加密后传到后台
     * * @param serPubKey 服务端公钥
     * * @return string 加密后的对称密钥
     */
    string Initialize(string serPubKey);


    /*******加密*************
     * @param plainText 明文
     * @return string 密文
     */
    string Encrypt(string plainText);


    /*******解密*************
    * @param cipherTextHex 密文
    * @return string 明文
    */
    string Decrypt(string cipherTextHex);
};
#endif //ENCRYPTIONSO_CENCRYPTION_H

6、Cencryption.cpp

#include "Cencryption.h"
Cencryption::Cencryption() {    m_Module = "90755611487566208138950675092879865387596685014726501531250157258482495478524769456222913843665634824684037468817980814231054856125127115894189385717148934026931120932481402379431731629550862846041784305274651476086892165805223719552575599962253392248079811268061946102234935422772131475340988882825043233323";
    // e factor in RSA, aslo called public exponent.
    m_PubExpond = "65537";
    // d factor in RSA, aslo called private exponent
    m_PriExpond = "17790520481266507102264359414044396762660094486842415203197747383916331528947124726552875080482359744765793816651732601742929364124685415229452844016482477236658413327331659722342187036963943428678684677279032263501011143882814728160215380051287503219732737197808611144507720521201393129692996926599975297921";

    rsaEncryption.initPublicKey(m_Module.c_str(),m_PubExpond.c_str());
    rsaEncryption.initPrivateKey(m_Module.c_str(),m_PubExpond.c_str(),m_PriExpond.c_str());

}

Cencryption::~Cencryption() {

}
/*************************************************
 *
 *使用服务端传回来的公钥加密AES密钥
 * @param serPubKey 服务端公钥
 * @return string 加密后的对称密钥
 */
string Cencryption::Initialize(string serPubKey) {


    if (serPubKey.empty() || serPubKey == "")
        return "errno:server publicKey is null!";


    GenerateAesKey();


    string strKey((char*)m_key);


    int idx = serPubKey.find(";");
    if (idx <= 0)
        return "errno:the server publickey must contain ;";


    string strN = serPubKey.substr(0,idx);
    string strE = serPubKey.substr(idx+1);


    cout<<"Server Module is:"<<strN<<endl;
    cout<<"Server PubExpond is:"<<strE<<endl;


    RsaEncryption rsaEncrypt;


    rsaEncrypt.initPublicKey(strN.c_str(),strE.c_str());


    string cipherKey = RsaEncrtypt(strKey,rsaEncrypt);  //用服务端传回的公钥加密


    /***********************签名********************************/
    string signedMessage = rsaEncryption.signMessage(cipherKey);


    cout<<"cipherKey is:"<<cipherKey<<endl;


    cout<<"signedMessage is:"<<signedMessage<<endl;


    cipherKey += ";";
    cipherKey += signedMessage;


    cout<<"cipherKey + signedMessage is:"<<cipherKey<<endl;
    return cipherKey;
}
string Cencryption::AesEncrtypt(string plainText) {
    aesEncryption.initKV(m_key,m_iv);
    return aesEncryption.encrypt(plainText);
}
string Cencryption::AesDecrypt(string cipherTextHex) {
    return aesEncryption.decrypt(cipherTextHex);
}
void Cencryption::GenerateAesKey() {
    memcpy(m_key,"longzhungaga1234",CryptoPP::AES::DEFAULT_KEYLENGTH);
    memset( m_iv, 0x00, CryptoPP::AES::BLOCKSIZE );
}
string Cencryption::RsaEncrtypt(string plainText,RsaEncryption &nrsaEncryption) {
    cout<<"加密"<<endl;
    string strOut = nrsaEncryption.encrypt(plainText);
    return strOut;
}

string Cencryption::RsaDecrtypt(string cipherTextHex) {
    cout<<"解密"<<endl;
    //return rsaEncryption.RSADecryptString(rsaEncryption.getPrikey(),cipherTextHex.c_str());
}
string Cencryption::Encrypt(string plainText) {
    string strCipher = AesEncrtypt(plainText);
    return strCipher;
}
string Cencryption::Decrypt(string cipherTextHex) {
   string strPlainText = AesDecrypt(cipherTextHex);
   return strPlainText;
}

const string &Cencryption::getM_Module() const {
    return m_Module;
}

const string &Cencryption::getM_PubExpond() const {
    return m_PubExpond;
}
string Cencryption::getPublicKey() {
    string strModule = getM_Module();
    strModule += ";";
    strModule += getM_PubExpond();
    return strModule;
}
const string &Cencryption::getM_PriExpond() const {
    return m_PriExpond;
}

三、服务端代码

服务端代码用JAVA语言编写,采用crypt库

1、 SymmetricEncoder.java 对称加密算法

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Scanner;


/**
 * Created by wenzhuqing1 on 2017/11/13.
 */
/*
 * AES对称加密和解密
 */
public class SymmetricEncoder {


    private SymmetricEncoder()
    {
        encodeKey = "";
    }


    public String getEncodeKey() {
        return encodeKey;
    }


    public void setEncodeKey(String encodeKey) {
        this.encodeKey = encodeKey;
    }


    private  String encodeKey;  //密钥


    private static class LazyHolder {
        private static final SymmetricEncoder INSTANCE = new SymmetricEncoder();
    }


    public static final SymmetricEncoder getInstance() {
        return LazyHolder.INSTANCE;
    }


    /*
   * 加密
   * 1.构造密钥生成器
   * 2.根据ecnodeRules规则初始化密钥生成器
   * 3.产生密钥
   * 4.创建和初始化密码器
   * 5.内容加密
   * 6.返回字符串
   */
    public  String AESEncode(String encodeRules,String content){
        try {
            //1.构造密钥生成器,指定为AES算法,不区分大小写
            KeyGenerator keygen=KeyGenerator.getInstance("AES");
            //2.根据ecnodeRules规则初始化密钥生成器
            //生成一个128位的随机源,根据传入的字节数组
            keygen.init(128, new SecureRandom(encodeRules.getBytes()));
            //3.产生原始对称密钥
            SecretKey original_key=keygen.generateKey();
            //4.获得原始对称密钥的字节数组
            byte [] raw=original_key.getEncoded();
            //5.根据字节数组生成AES密钥
            SecretKey key=new SecretKeySpec(raw, "AES");
            //6.根据指定算法AES自成密码器
            Cipher cipher=Cipher.getInstance("AES");
            //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY
            cipher.init(Cipher.ENCRYPT_MODE, key);
            //8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
            byte [] byte_encode=content.getBytes("utf-8");
            //9.根据密码器的初始化方式--加密:将数据加密
            byte [] byte_AES=cipher.doFinal(byte_encode);
            //10.将加密后的数据转换为字符串
            //这里用Base64Encoder中会找不到包
            //解决办法:
            //在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。
            String AES_encode=new String(new BASE64Encoder().encode(byte_AES));
            //11.将字符串返回
            return AES_encode;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }


        //如果有错就返加nulll
        return null;
    }
    /*
     * 解密
     * 解密过程:
     * 1.同加密1-4步
     * 2.将加密后的字符串反纺成byte[]数组
     * 3.将加密内容解密
     */
    public  String AESDncode(String encodeRules,String content){
        try {
            //1.构造密钥生成器,指定为AES算法,不区分大小写
            KeyGenerator keygen=KeyGenerator.getInstance("AES");
            //2.根据ecnodeRules规则初始化密钥生成器
            //生成一个128位的随机源,根据传入的字节数组
            keygen.init(128, new SecureRandom(encodeRules.getBytes()));
            //3.产生原始对称密钥
            SecretKey original_key=keygen.generateKey();
            //4.获得原始对称密钥的字节数组
            byte [] raw=original_key.getEncoded();
            //5.根据字节数组生成AES密钥
            SecretKey key=new SecretKeySpec(raw, "AES");
            //6.根据指定算法AES自成密码器
            Cipher cipher=Cipher.getInstance("AES");
            //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY
            cipher.init(Cipher.DECRYPT_MODE, key);
            //8.将加密并编码后的内容解码成字节数组
            byte [] byte_content= new BASE64Decoder().decodeBuffer(content);
            /*
             * 解密
             */
            byte [] byte_decode=cipher.doFinal(byte_content);
            String AES_decode=new String(byte_decode,"utf-8");
            return AES_decode;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }


        //如果有错就返加nulll
        return null;
    }


    public static void main(String[] args) {
        SymmetricEncoder se=new SymmetricEncoder();
        Scanner scanner=new Scanner(System.in);
        /*
         * 加密
         */
        System.out.println("使用AES对称加密,请输入加密的规则");
        String encodeRules=scanner.next();
        System.out.println("请输入要加密的内容:");
        String content = scanner.next();
        System.out.println("根据输入的规则"+encodeRules+"加密后的密文是:"+se.AESEncode(encodeRules, content));


        /*
         * 解密
         */
        System.out.println("使用AES对称解密,请输入加密的规则:(须与加密相同)");
        encodeRules=scanner.next();
        System.out.println("请输入要解密的内容(密文):");
        content = scanner.next();
        System.out.println("根据输入的规则"+encodeRules+"解密后的明文是:"+se.AESDncode(encodeRules, content));
    }
}

2、RsaEncoder.java 非对称加密算法

import com.jd.gw.encoding.Base16;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import javax.crypto.*;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;


public class RsaEncoder {


    public static final String KEY_ALGORITHM = "RSA";


    public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";


    private static Logger LOGGER = LoggerFactory.getLogger(RsaEncoder.class);


    public static void dump(String label, byte[] data)
    {
        String hex_str = Base16.encode(data);
        System.out.println(label+"="+hex_str);
    }


    public static byte[] decryptBASE64(String key) {
        return Base64.decodeBase64(key);
    }


    public static String encryptBASE64(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }


    /**
     * the example.
     * @param args
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeySpecException
     * @throws UnsupportedEncodingException
     * @throws ShortBufferException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws InvalidKeyException
     */
    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, UnsupportedEncodingException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException
    {




        System.out.println("=======================RSA PKCS #1=====================");
        // key
        // N factor in RSA, aslo called modulus.
        String N = "90755611487566208138950675092879865387596685014726501531250157258482495478524769456222913843665634824684037468817980814231054856125127115894189385717148934026931120932481402379431731629550862846041784305274651476086892165805223719552575599962253392248079811268061946102234935422772131475340988882825043233323";
        // e factor in RSA, aslo called public exponent.
        String e = "65537";
        // d factor in RSA, aslo called private exponent
        String d = "17790520481266507102264359414044396762660094486842415203197747383916331528947124726552875080482359744765793816651732601742929364124685415229452844016482477236658413327331659722342187036963943428678684677279032263501011143882814728160215380051287503219732737197808611144507720521201393129692996926599975297921";


        byte[] indata = "bsmith is a good guy.".getBytes("UTF-8");
        dump("indata", indata);


        // init RSA public key encryptor.
        RsaEncoder enc = new RsaEncoder();


        enc.initPublicKey(N, e);


        String outdata = enc.encryptBase16(indata);
        //dump("outdata", outdata);
        LOGGER.info(outdata);


        // init private for RSA decryptor.
        RsaEncoder dec = new RsaEncoder();
        dec.initPrivateKey(N, e, d);
        //dec.initPublicKey(N,e);




        byte[] indata1 = dec.decryptBase16(outdata);
        dump("indata1", indata1);
        /*try
        {
            String signedData = dec.sign(indata);
            //String signedData = "5590B62904C53AF1153DD60A99BFABFC5DC25954093402DFCCA3A99BB41C8B728228928DD1E6793DBFAD9E2B2D963226BDE697754011B0EDD022FBD14BCC1880DD35D877464C182B275031087B472CEFEA3E17F49E7342214DAF960B8B8BC24AA514663C562F9F9696CD02AA02EDFECBE7A1C1F27BE06CAA9586C219BD8BBB06";


            boolean bVerify = dec.verify(indata,signedData);


            if (bVerify)
                LOGGER.info("success!");
            else
                LOGGER.info("failure!");
        }
        catch (Exception exception)
        {
            exception.printStackTrace();
        }*/


    }


    private Cipher enc;     // encryptor.
    private Cipher dec;     // decryptor.
    //private Key key;        // the enc/dec key.
    private PrivateKey privateKey;   //private key
    private PublicKey publicKey;    //public key
    private int KEY_BYTE_LEN;       // RSA key bytes length.


    private String modules;     //RSA KEY yinzi
    private String publicExpond;
    private String privateExpond;


    public String getModules() {
        return modules;
    }


    public void setModules(String modules) {
        this.modules = modules;
    }


    public String getPublicExpond() {
        return publicExpond;
    }


    public void setPublicExpond(String publicExpond) {
        this.publicExpond = publicExpond;
    }


    public String getPrivateExpond() {
        return privateExpond;
    }


    public void setPrivateExpond(String privateExpond) {
        this.privateExpond = privateExpond;
    }


    public  String sign(byte[] data) throws Exception {


        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data);
        return Base16.encode(signature.sign());
    }


    public  boolean verify(String data,  String sign)
            throws Exception {


        byte[] localData = Base16.decode(data);


        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(localData);
        // 验证签名是否正常
        byte[] signes = Base16.decode(sign);
        return signature.verify(signes);
    }








    private void GenerateRsaKeys() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException
    {


        KeyPairGenerator keyPairGen = KeyPairGenerator
                    .getInstance(KEY_ALGORITHM);


        keyPairGen.initialize(1024);


        KeyPair keyPair = keyPairGen.generateKeyPair();
        PublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
        PrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();


        //将公钥和模进行Base64编码
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        RSAPublicKeySpec publicSpec= keyFactory.getKeySpec(publicKey,RSAPublicKeySpec.class);
        BigInteger modulus = publicSpec.getModulus();
        BigInteger exponent=publicSpec.getPublicExponent();


        RSAPrivateKeySpec privateSpec = keyFactory.getKeySpec(privateKey,RSAPrivateKeySpec.class);
        BigInteger primodulus = privateSpec.getModulus();
        BigInteger priexponent=privateSpec.getPrivateExponent();


        modules = modulus.toString();
        publicExpond = exponent.toString();
        privateExpond = priexponent.toString();


        LOGGER.info("module is :" + modules);
        LOGGER.info("publicExpond is :" + publicExpond);
        LOGGER.info("privateExpond is :" + privateExpond);


    }


    public RsaEncoder()
    {
        try {
            GenerateRsaKeys();
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        catch (NoSuchPaddingException e)
        {
            e.printStackTrace();
        }
        catch (InvalidKeySpecException e)
        {
            e.printStackTrace();
        }
    }


    /**
     * init public key to encrypt/decrypt, all operations use this key.
     * @param N N factor in RSA, aslo called modulus.
     * @param e e factor in RSA, aslo called publicExponent.
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeySpecException
     */
    public void initPublicKey(String N, String e) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException
    {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        BigInteger big_N = new BigInteger(N);
        KEY_BYTE_LEN = (big_N.bitLength())>>3;
        BigInteger big_e = new BigInteger(e);
        KeySpec keySpec = new RSAPublicKeySpec(big_N, big_e);
        //key = keyFactory.generatePublic(keySpec);
        publicKey = keyFactory.generatePublic(keySpec);
    }


    /**
     * init private key to encrypt/decrypt, all operations use this key.
     * @param N N factor in RSA, aslo called modulus.
     * @param e e factor in RSA, aslo called publicExponent, ignored, just keep compatible with C++ interface.
     * @param d d factor in RSA, aslo called privateExponent.
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeySpecException
     */
    public void initPrivateKey(String N, String e, String d) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException
    {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        BigInteger big_N = new BigInteger(N);
        KEY_BYTE_LEN = (big_N.bitLength())>>3;
        BigInteger big_d = new BigInteger(d);
        KeySpec keySpec = new RSAPrivateKeySpec(big_N, big_d);
        //key = keyFactory.generatePrivate(keySpec);
        privateKey = keyFactory.generatePrivate(keySpec);
    }


    /**
     * get maxim plain bytes length that RSA can encrypt.
     * @return the maxim length.
     */
    public int getMaxPlainLen()
    {
        return KEY_BYTE_LEN-11;
    }


    /**
     * get cipher length that return by RSA encryption.
     * in RSA, this length is fixed, and equals the key bytes length - 11.
     * e.g. 1024 bits RSA key, this value is 128-11 = 117.
     * @return the cipher length.
     */
    public int getCipherLen()
    {
        return KEY_BYTE_LEN;
    }


    /**
     * encrypt indata to outdata use the key.
     * @param indata input data.
     * @param inoff input data offset.
     * @param inlen input data length.
     * @param outdata output data.
     * @param outoff output data offset.
     * @return the actual cipher length.
     * @throws ShortBufferException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     */
    public int encrypt(byte[] indata, int inoff, int inlen, byte[] outdata, int outoff) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException
    {
        initEncryptor();
        return enc.doFinal(indata, inoff, inlen, outdata, outoff);
    }


    /**
     * encrypt indata to outdata use the key.
     * @param indata input data.
     * @param inoff input data offset.
     * @param inlen input data length.
     * @return the actual cipher data.
     * @throws ShortBufferException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     */
    public byte[] encrypt(byte[] indata, int inoff, int inlen) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException
    {
        initEncryptor();
        return enc.doFinal(indata, inoff, inlen);
    }


    /**
     * encrypt indata to outdata use the key.
     * @param indata input data.
     * @return the actual cipher data.
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public byte[] encrypt(byte[] indata) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
    {
        initEncryptor();
        return enc.doFinal(indata);
    }


    /**
     * get the maxim plain data length after decryption.
     * the actual plain data length may be shorter than this value.
     * @param len the cipher data length.
     * @return the maxim plain data length.
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     */
    public int getPlainLen(int len) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException
    {
        initDecryptor();
        return dec.getOutputSize(len);
    }


    /**
     * decrypt input data to output data.
     * @param indata input data.
     * @param inoff input data offset.
     * @param inlen input data length.
     * @param outdata output data.
     * @param outoff output data offset.
     * @return the actual plain length.
     * @throws InvalidKeyException
     * @throws ShortBufferException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     */
    public int decrypt(byte[] indata, int inoff, int inlen, byte[] outdata, int outoff) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException
    {
        initDecryptor();
        return dec.doFinal(indata, inoff, inlen, outdata, outoff);
    }


    /**
     * decrypt input data to output data.
     * @param indata input data.
     * @param inoff input data offset.
     * @param inlen input data length.
     * @return the actual plain data.
     * @throws InvalidKeyException
     * @throws ShortBufferException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     */
    public byte[] decrypt(byte[] indata, int inoff, int inlen) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException
    {
        initDecryptor();
        return dec.doFinal(indata, inoff, inlen);
    }


    /**
     * decrypt input data to output data.
     * @param indata input data.
     * @return the actual plain data.
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public byte[] decrypt(byte[] indata) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
    {
        initDecryptor();
        return dec.doFinal(indata);
    }


    private void initEncryptor() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException
    {
        if (null == enc)
        {
            enc = Cipher.getInstance("RSA");
            //enc.init(Cipher.ENCRYPT_MODE, key);
            enc.init(Cipher.ENCRYPT_MODE, publicKey);
        }
    }


    private void initDecryptor() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException
    {
        if (null == dec)
        {
            dec = Cipher.getInstance("RSA");
            //dec.init(Cipher.DECRYPT_MODE, key);
            dec.init(Cipher.DECRYPT_MODE, privateKey);
        }
    }


    /*****************************
     * base16加密
     * @param indata 明文
     * @return String base16编码
     */
    public String encryptBase16(byte[] indata) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
    {
        initEncryptor();
        return Base16.encode(enc.doFinal(indata));


    }


    /*****************************
     * base16加密
     * @param indata 明文
     * @return String base16编码
     */
    public byte[] decryptBase16(String indata) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
    {
        initDecryptor();
        return dec.doFinal(Base16.decode(indata));
    }
}


众所周知,Java编译后的Jar包和Class文件,可以轻而易举的使用反编译工具(如JD-GUI)进行反编译,拿到源码。为了保护自己发布的Jar包和Class文件,采用的方式大多是混淆方式,这种方式对于Class文件的加密是不彻底的,还是能够通过分析得出核心算法。本工具是采用jvmti方式对Class文件进行加密,使用C++生成加密和解密库,先用加密库对Jar包进行加密,将加密后的Jar包及解密库文件发布出去,执行时候需要JVM引入解密库文件,解密后执行。c++的.dll文件和.so文件的破解难度是很大的,这就能有效的保护软件和代码的知识产权. 使用方法: 1.打开windows命令行(运行=>cmd=>回车),在命令行中 进入 EncryptJar目录 2.执行 java -jar encrypt.jar 3.输入h,然后回车,可以看到帮助菜单 4.输入3,然后按回车键,进入加入jar文件功能 5.输入要加密的jar文件的路径 6.提示输入秘钥(key)的时候,直接回车,不要输入任何字符(否则后面classhook将不可解密加密后的jar包) 7.输入目标路径(加密后的jar文件路径,此处要注意:jar文件名要保持相同,将加密后的文件保存到不同的目录) 8.将加密后的jar包,替换原来的没有加密的jar包,与要发布的程序一起进行发布.(一般替换lib目录下对应的jar包即可) 9.加密后的jar包运行方法: windows下: 拷贝libClassHook.dll文件到程序的根目录(通常为要执行的jar程序的根目录) 使用以下命令启动程序: java -agentlib:libClassHook -jar xxxxxxxxxxx.jar 则在运行过程中会自动进行解密操作(解密过程是运行过程中用c++的dll进行解密的,可以有效防止破解class文件) 如果执行过程报错,可将程序根目录添加到环境变量path中去 Linux下: 拷贝libClassHook.so到程序的根目录(通常为要执行的jar程序的根目录) 使用以下命令启动程序: java -agentlib:ClassHook -jar xxxxxxxxxxx.jar (这里要删除掉lib,linux系统下会自动补全) 则在运行过程中会自动进行解密操作(解密过程是运行过程中用c++的dll进行解密的,可以有效防止破解class文件) 如果执行过程报错,可以在程序根目录下执行以下语句:export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH 或将libClassHook.so 拷贝到/usr/lib目录中去。 支持操作系统:加密请在windows64位系统并安装了64位jdk环境下进行。 需要解密运行的程序支持LINUX(64位)和windows(64位)安装了JDK1.8以上的系统。 测试程序: (t_lib目录下的jar包为经过加密的jar包) java -agentlib:libClassHook -jar test.jar
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值