这段时间在公司做一个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));
}
}