生成公钥私钥配对加解密
注意:
RSA加密或签名后的结果是不可读的二进制,使用时经常会转为BASE64码再传输。
RSA加密时,对要加密数据的大小有限制,最大不大于密钥长度。例如在使用1024bit的密钥时(genrsa-outrsa_private_key.pem1024),最大可以加密1024/8=128Bytes的数据。数据大于128Bytes时,需要对数据进行分组加密(如果数据超限,加解密时会失败,openssl函数会返回false),分组加密后的加密串拼接成一个字符串后发送给客户端。
为了保证每次加密的结果都不同,RSA加密时会在待加密数据后拼接一个随机字符串,再进行加密。不同的填充方式Padding表示这个字符串的不同长度,在对超限数据进行分组后,会按照这个Padding指定的长度填入随机字符串。例如如果Padding填充方式使用默认的OPENSSL_PKCS1_PADDING(需要占用11个字节用于填充),那么明文长度最多只能就是128-11=117Bytes。
一般默认使用OPENSSL_PKCS1_PADDING。PHP支持的Padding有OPENSSL_PKCS1_PADDING、OPENSSL_SSLV23_PADDING、OPENSSL_PKCS1_OAEP_PADDING和OPENSSL_NO_PADDING。
接收方解密时也需要分组。将加密后的原始二进制数据(对于经过BASE64的数据,需要解码),每128Bytes分为一组,然后再进行解密。解密后,根据Padding的长度丢弃随机字符串,把得到的原字符串拼接起来,就得到原始报文。
importjava.io.IOException;
importjava.security.KeyFactory;
importjava.security.NoSuchAlgorithmException;
importjava.security.PrivateKey;
importjava.security.PublicKey;
importjava.security.spec.InvalidKeySpecException;
importjava.security.spec.PKCS8EncodedKeySpec;
importjava.security.spec.X509EncodedKeySpec;
importjavax.crypto.BadPaddingException;
importjavax.crypto.Cipher;
importjavax.crypto.IllegalBlockSizeException;
importorg.apache.commons.io.output.ByteArrayOutputStream;
importorg.springframework.util.Base64Utils;
importcom.bessky.hrmis.common.uconfig.UConfigHelper;
importcom.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
importcom.sun.org.apache.xml.internal.security.utils.Base64;
publicclassRSAHelper
{
privatestaticfinalStringpublicKeyBase64="";
privatestaticfinalStringprivateKeyBase64="";
/**
*RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024
*/
publicstaticfinalintKEY_SIZE=2048;
/**
*获取公钥对象
*
*@parampublicKeyBase64
*@return
*@throwsInvalidKeySpecException
*@throwsNoSuchAlgorithmException
*/
publicstaticPublicKeygetPublicKey(StringpublicKeyBase64)throwsInvalidKeySpecException,NoSuchAlgorithmException,Base64DecodingException
{
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
X509EncodedKeySpecpublicpkcs8KeySpec=newX509EncodedKeySpec(Base64.decode(publicKeyBase64));
PublicKeypublicKey=keyFactory.generatePublic(publicpkcs8KeySpec);
returnpublicKey;
}
/**
*获取私钥对象
*
*@paramprivateKeyBase64
*@return
*@throwsNoSuchAlgorithmException
*@throwsInvalidKeySpecException
*/
publicstaticPrivateKeygetPrivateKey(StringprivateKeyBase64)throwsNoSuchAlgorithmException,InvalidKeySpecException,Base64DecodingException
{
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpecprivatekcs8KeySpec=newPKCS8EncodedKeySpec(Base64.decode(privateKeyBase64));
PrivateKeyprivateKey=keyFactory.generatePrivate(privatekcs8KeySpec);
returnprivateKey;
}
/**
*使用工钥加密
*
*@paramcontent 待加密内容
*@parampublicKeyBase64公钥base64编码
*@return经过base64编码后的字符串
*/
publicstaticStringencipher(Stringcontent)
{
returnencipher(content,publicKeyBase64,KEY_SIZE/8-11);
}
/**
*使用公司钥加密(分段加密)
*
*@paramcontent 待加密内容
*@parampublicKeyBase64公钥base64编码
*@paramsegmentSize 分段大小,一般小于keySize/8(段小于等于0时,将不使用分段加密)
*@return经过base64编码后的字符串
*/
publicstaticStringencipher(Stringcontent,StringpublicKeyBase64,intsegmentSize)
{
try
{
PublicKeypublicKey=getPublicKey(publicKeyBase64);
returnencipher(content,publicKey,segmentSize);
}
catch(Exceptione)
{
e.printStackTrace();
returnnull;
}
}
/**
*分段加密
*
*@paramciphertext 密文
*@paramkey 加密秘钥
*@paramsegmentSize分段大小,<=0不分段
*@return
*/
publicstaticStringencipher(Stringciphertext,java.security.Keykey,intsegmentSize)
{
try
{
//用公钥加密
byte[]srcBytes=ciphertext.getBytes();
//Cipher负责完成加密或解密工作,基于RSA
Ciphercipher=Cipher.getInstance("RSA");
//根据公钥,对Cipher对象进行初始化
cipher.init(Cipher.ENCRYPT_MODE,key);
byte[]resultBytes=null;
if(segmentSize>0)
resultBytes=cipherDoFinal(cipher,srcBytes,segmentSize);//分段加密
else
resultBytes=cipher.doFinal(srcBytes);
Stringbase64Str=Base64Utils.encodeToString(resultBytes);
returnbase64Str;
}
catch(Exceptione)
{
e.printStackTrace();
returnnull;
}
}
/**
*分段大小
*
*@paramcipher
*@paramsrcBytes
*@paramsegmentSize
*@return
*@throwsIllegalBlockSizeException
*@throwsBadPaddingException
*@throwsIOException
*/
publicstaticbyte[]cipherDoFinal(Ciphercipher,byte[]srcBytes,intsegmentSize)throwsIllegalBlockSizeException,BadPaddingException,IOException
{
if(segmentSize<=0)
thrownewRuntimeException("分段大小必须大于0");
ByteArrayOutputStreamout=newByteArrayOutputStream();
intinputLen=srcBytes.length;
intoffSet=0;
byte[]cache;
inti=0;
//对数据分段解密
while(inputLen-offSet>0)
{
if(inputLen-offSet>segmentSize)
{
cache=cipher.doFinal(srcBytes,offSet,segmentSize);
}
else
{
cache=cipher.doFinal(srcBytes,offSet,inputLen-offSet);
}
out.write(cache,0,cache.length);
i++;
offSet=i*segmentSize;
}
byte[]data=out.toByteArray();
out.close();
returndata;
}
/**
*使用私钥解密
*
*@paramcontentBase64 待加密内容,base64编码
*@paramprivateKeyBase64私钥base64编码
*@return
*@segmentSize分段大小
*/
publicstaticStringdecipher(StringcontentBase64)
{
returndecipher(contentBase64,privateKeyBase64,KEY_SIZE/8);
}
/**
*使用私钥解密(分段解密)
*
*@paramcontentBase64 待加密内容,base64编码
*@paramprivateKeyBase64私钥base64编码
*@return
*@segmentSize分段大小
*/
publicstaticStringdecipher(StringcontentBase64,StringprivateKeyBase64,intsegmentSize)
{
try
{
PrivateKeyprivateKey=getPrivateKey(privateKeyBase64);
returndecipher(contentBase64,privateKey,segmentSize);
}
catch(Exceptione)
{
e.printStackTrace();
returnnull;
}
}
/**
*分段解密
*
*@paramcontentBase64密文
*@paramkey 解密秘钥
*@paramsegmentSize 分段大小(小于等于0不分段)
*@return
*/
publicstaticStringdecipher(StringcontentBase64,java.security.Keykey,intsegmentSize)
{
try
{
//用私钥解密
byte[]srcBytes=Base64Utils.decodeFromString(contentBase64);
//Cipher负责完成加密或解密工作,基于RSA
CipherdeCipher=Cipher.getInstance("RSA");
//根据公钥,对Cipher对象进行初始化
deCipher.init(Cipher.DECRYPT_MODE,key);
byte[]decBytes=null;//deCipher.doFinal(srcBytes);
if(segmentSize>0)
decBytes=cipherDoFinal(deCipher,srcBytes,segmentSize);//分段加密
else
decBytes=deCipher.doFinal(srcBytes);
StringdecrytStr=newString(decBytes);
returndecrytStr;
}
catch(Exceptione)
{
e.printStackTrace();
} }}