Java引用到的包:
commons-lang
bouncycastle
slf4j
commons-codec
commons-io
package
my.tools.security;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileOutputStream;
import
java.io.ObjectInputStream;
import
java.io.ObjectOutputStream;
import
java.math.BigInteger;
import
java.security.KeyPair;
import
java.security.KeyFactory;
import
java.security.KeyPairGenerator;
import
java.security.Provider;
import
java.security.PublicKey;
import
java.security.PrivateKey;
import
java.security.SecureRandom;
import
java.security.NoSuchAlgorithmException;
import
java.security.InvalidParameterException;
import
java.security.interfaces.RSAPublicKey;
import
java.security.interfaces.RSAPrivateKey;
import
java.security.spec.RSAPublicKeySpec;
import
java.security.spec.RSAPrivateKeySpec;
import
java.security.spec.InvalidKeySpecException;
import
javax.crypto.Cipher;
import
org.apache.commons.io.IOUtils;
import
org.apache.commons.io.FileUtils;
import
org.apache.commons.codec.DecoderException;
import
org.apache.commons.codec.binary.Hex;
import
org.bouncycastle.jce.provider.BouncyCastleProvider;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.apache.commons.lang.StringUtils;
import
org.apache.commons.lang.time.DateFormatUtils;
/**
*
RSA算法加密/解密工具類。
*
*
@author fuchun
*
@version 1.0.0, 2010-05-05
*/
public
abstract
class
RSAUtils {
private
static
final
Logger LOGGER = LoggerFactory.getLogger(RSAUtils.
class
);
/**
算法名稱 */
private
static
final
String ALGORITHOM =
"RSA"
;
/**保存生成的密鑰對的文件名稱。
*/
private
static
final
String RSA_PAIR_FILENAME =
"/__RSA_PAIR.txt"
;
/**
密鑰大小 */
private
static
final
int
KEY_SIZE =
1024
;
/**
默認的安全服務提供者 */
private
static
final
Provider DEFAULT_PROVIDER =
new
BouncyCastleProvider();
private
static
KeyPairGenerator keyPairGen =
null
;
private
static
KeyFactory keyFactory =
null
;
/**
緩存的密鑰對。 */
private
static
KeyPair oneKeyPair =
null
;
private
static
File rsaPairFile =
null
;
static
{
try
{
keyPairGen
= KeyPairGenerator.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
keyFactory
= KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
}
catch
(NoSuchAlgorithmException ex) {
LOGGER.error(ex.getMessage());
}
rsaPairFile
=
new
File(getRSAPairFilePath());
}
private
RSAUtils() {
}
/**
*
生成並返回RSA密鑰對。
*/
private
static
synchronized
KeyPair generateKeyPair() {
try
{
keyPairGen.initialize(KEY_SIZE,
new
SecureRandom(DateFormatUtils.format(
"yyyyMMdd"
).getBytes()));
oneKeyPair
= keyPairGen.generateKeyPair();
saveKeyPair(oneKeyPair);
return
oneKeyPair;
}
catch
(InvalidParameterException ex) {
LOGGER.error(
"KeyPairGenerator
does not support a key length of "
+ KEY_SIZE +
"."
,
ex);
}
catch
(NullPointerException ex) {
LOGGER.error(
"RSAUtils#KEY_PAIR_GEN
is null, can not generate KeyPairGenerator instance."
,
ex);
}
return
null
;
}
/**
*
返回生成/讀取的密鑰對文件的路徑。
*/
private
static
String getRSAPairFilePath() {
String
urlPath = RSAUtils.
class
.getResource(
"/"
).getPath();
return
(
new
File(urlPath).getParent() + RSA_PAIR_FILENAME);
}
/**
*
若需要創建新的密鑰對文件,則返回 {@code true},否則 {@code false}。
*/
private
static
boolean
isCreateKeyPairFile() {
//
是否創建新的密鑰對文件
boolean
createNewKeyPair =
false
;
if
(!rsaPairFile.exists() || rsaPairFile.isDirectory()) {
createNewKeyPair
=
true
;
}
return
createNewKeyPair;
}
/**
*
將指定的RSA密鑰對以文件形式保存。
*
*
@param keyPair 要保存的密鑰對。
*/
private
static
void
saveKeyPair(KeyPair keyPair) {
FileOutputStream
fos =
null
;
ObjectOutputStream
oos =
null
;
try
{
fos
= FileUtils.openOutputStream(rsaPairFile);
oos
=
new
ObjectOutputStream(fos);
oos.writeObject(keyPair);
}
catch
(Exception ex) {
ex.printStackTrace();
}
finally
{
IOUtils.closeQuietly(oos);
IOUtils.closeQuietly(fos);
}
}
/**
*
返回RSA密鑰對。
*/
public
static
KeyPair getKeyPair() {
//
首先判斷是否需要重新生成新的密鑰對文件
if
(isCreateKeyPairFile()) {
//
直接強制生成密鑰對文件,並存入緩存。
return
generateKeyPair();
}
if
(oneKeyPair !=
null
)
{
return
oneKeyPair;
}
return
readKeyPair();
}
//
同步讀出保存的密鑰對
private
static
KeyPair readKeyPair() {
FileInputStream
fis =
null
;
ObjectInputStream
ois =
null
;
try
{
fis
= FileUtils.openInputStream(rsaPairFile);
ois
=
new
ObjectInputStream(fis);
oneKeyPair
= (KeyPair) ois.readObject();
return
oneKeyPair;
}
catch
(Exception ex) {
ex.printStackTrace();
}
finally
{
IOUtils.closeQuietly(ois);
IOUtils.closeQuietly(fis);
}
return
null
;
}
/**
*
根據給定的係數和專用指數構造一個RSA專用的公鑰對象。
*
*
@param modulus 係數。
*
@param publicExponent 專用指數。
*
@return RSA專用公鑰對象。
*/
public
static
RSAPublicKey generateRSAPublicKey(
byte
[]
modulus,
byte
[]
publicExponent) {
RSAPublicKeySpec
publicKeySpec =
new
RSAPublicKeySpec(
new
BigInteger(modulus),
new
BigInteger(publicExponent));
try
{
return
(RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
}
catch
(InvalidKeySpecException ex) {
LOGGER.error(
"RSAPublicKeySpec
is unavailable."
,
ex);
}
catch
(NullPointerException ex) {
LOGGER.error(
"RSAUtils#KEY_FACTORY
is null, can not generate KeyFactory instance."
,
ex);
}
return
null
;
}
/**
*
根據給定的係數和專用指數構造一個RSA專用的私鑰對象。
*
*
@param modulus 係數。
*
@param privateExponent 專用指數。
*
@return RSA專用私鑰對象。
*/
public
static
RSAPrivateKey generateRSAPrivateKey(
byte
[]
modulus,
byte
[]
privateExponent) {
RSAPrivateKeySpec
privateKeySpec =
new
RSAPrivateKeySpec(
new
BigInteger(modulus),
new
BigInteger(privateExponent));
try
{
return
(RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
}
catch
(InvalidKeySpecException ex) {
LOGGER.error(
"RSAPrivateKeySpec
is unavailable."
,
ex);
}
catch
(NullPointerException ex) {
LOGGER.error(
"RSAUtils#KEY_FACTORY
is null, can not generate KeyFactory instance."
,
ex);
}
return
null
;
}
/**
*
根據給定的16進制係數和專用指數字符串構造一個RSA專用的私鑰對象。
*
*
@param modulus 係數。
*
@param privateExponent 專用指數。
*
@return RSA專用私鑰對象。
*/
public
static
RSAPrivateKey getRSAPrivateKey(String hexModulus, String hexPrivateExponent) {
if
(StringUtils.isBlank(hexModulus)
|| StringUtils.isBlank(hexPrivateExponent)) {
if
(LOGGER.isDebugEnabled())
{
LOGGER.debug(
"hexModulus
and hexPrivateExponent cannot be empty. RSAPrivateKey value is null to return."
);
}
return
null
;
}
byte
[]
modulus =
null
;
byte
[]
privateExponent =
null
;
try
{
modulus
= Hex.decodeHex(hexModulus.toCharArray());
privateExponent
= Hex.decodeHex(hexPrivateExponent.toCharArray());
}
catch
(DecoderException
ex) {
LOGGER.error(
"hexModulus
or hexPrivateExponent value is invalid. return null(RSAPrivateKey)."
);
}
if
(modulus
!=
null
&& privateExponent !=
null
)
{
return
generateRSAPrivateKey(modulus, privateExponent);
}
return
null
;
}
/**
*
根據給定的16進制係數和專用指數字符串構造一個RSA專用的公鑰對象。
*
*
@param modulus 係數。
*
@param publicExponent 專用指數。
*
@return RSA專用公鑰對象。
*/
public
static
RSAPublicKey getRSAPublidKey(String hexModulus, String hexPublicExponent) {
if
(StringUtils.isBlank(hexModulus)
|| StringUtils.isBlank(hexPublicExponent)) {
if
(LOGGER.isDebugEnabled())
{
LOGGER.debug(
"hexModulus
and hexPublicExponent cannot be empty. return null(RSAPublicKey)."
);
}
return
null
;
}
byte
[]
modulus =
null
;
byte
[]
publicExponent =
null
;
try
{
modulus
= Hex.decodeHex(hexModulus.toCharArray());
publicExponent
= Hex.decodeHex(hexPublicExponent.toCharArray());
}
catch
(DecoderException
ex) {
LOGGER.error(
"hexModulus
or hexPublicExponent value is invalid. return null(RSAPublicKey)."
);
}
if
(modulus
!=
null
&& publicExponent !=
null
)
{
return
generateRSAPublicKey(modulus, publicExponent);
}
return
null
;
}
/**
*
使用指定的公鑰加密數據。
*
*
@param publicKey 給定的公鑰。
*
@param data 要加密的數據。
*
@return 加密後的數據。
*/
public
static
byte
[]
encrypt(PublicKey publicKey,
byte
[]
data)
throws
Exception {
Cipher
ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
ci.init(Cipher.ENCRYPT_MODE,
publicKey);
return
ci.doFinal(data);
}
/**
*
使用指定的私鑰解密數據。
*
*
@param privateKey 給定的私鑰。
*
@param data 要解密的數據。
*
@return 原數據。
*/
public
static
byte
[]
decrypt(PrivateKey privateKey,
byte
[]
data)
throws
Exception {
Cipher
ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
ci.init(Cipher.DECRYPT_MODE,
privateKey);
return
ci.doFinal(data);
}
/**
*
使用給定的公鑰加密給定的字符串。
*
<p />
*
若 {@code publicKey} 爲 {@code null},或者 {@code plaintext} 爲 {@code null} 則返回 {@code
*
null}。
*
*
@param publicKey 給定的公鑰。
*
@param plaintext 字符串。
*
@return 給定字符串的密文。
*/
public
static
String encryptString(PublicKey publicKey, String plaintext) {
if
(publicKey ==
null
|| plaintext ==
null
)
{
return
null
;
}
byte
[]
data = plaintext.getBytes();
try
{
byte
[]
en_data = encrypt(publicKey, data);
return
new
String(Hex.encodeHex(en_data));
}
catch
(Exception ex) {
LOGGER.error(ex.getCause().getMessage());
}
return
null
;
}
/**
*
使用默認的公鑰加密給定的字符串。
*
<p />
*
若{@code plaintext} 爲 {@code null} 則返回 {@code null}。
*
*
@param plaintext 字符串。
*
@return 給定字符串的密文。
*/
public
static
String encryptString(String plaintext) {
if
(plaintext
==
null
)
{
return
null
;
}
byte
[]
data = plaintext.getBytes();
KeyPair
keyPair = getKeyPair();
try
{
byte
[]
en_data = encrypt((RSAPublicKey)keyPair.getPublic(), data);
return
new
String(Hex.encodeHex(en_data));
}
catch
(NullPointerException
ex) {
LOGGER.error(
"keyPair
cannot be null."
);
}
catch
(Exception
ex) {
LOGGER.error(ex.getCause().getMessage());
}
return
null
;
}
/**
*
使用給定的私鑰解密給定的字符串。
*
<p />
*
若私鑰爲 {@code null},或者 {@code encrypttext} 爲 {@code null}或空字符串則返回 {@code null}。
*
私鑰不匹配時,返回 {@code null}。
*
*
@param privateKey 給定的私鑰。
*
@param encrypttext 密文。
*
@return 原文字符串。
*/
public
static
String decryptString(PrivateKey privateKey, String encrypttext) {
if
(privateKey ==
null
|| StringUtils.isBlank(encrypttext)) {
return
null
;
}
try
{
byte
[]
en_data = Hex.decodeHex(encrypttext.toCharArray());
byte
[]
data = decrypt(privateKey, en_data);
return
new
String(data);
}
catch
(Exception ex) {
LOGGER.error(String.format(
"\"%s\"
Decryption failed. Cause: %s"
,
encrypttext, ex.getCause().getMessage()));
}
return
null
;
}
/**
*
使用默認的私鑰解密給定的字符串。
*
<p />
*
若{@code encrypttext} 爲 {@code null}或空字符串則返回 {@code null}。
*
私鑰不匹配時,返回 {@code null}。
*
*
@param encrypttext 密文。
*
@return 原文字符串。
*/
public
static
String decryptString(String encrypttext) {
if
(StringUtils.isBlank(encrypttext))
{
return
null
;
}
KeyPair
keyPair = getKeyPair();
try
{
byte
[]
en_data = Hex.decodeHex(encrypttext.toCharArray());
byte
[]
data = decrypt((RSAPrivateKey)keyPair.getPrivate(), en_data);
return
new
String(data);
}
catch
(NullPointerException
ex) {
LOGGER.error(
"keyPair
cannot be null."
);
}
catch
(Exception ex) {
LOGGER.error(String.format(
"\"%s\"
Decryption failed. Cause: %s"
,
encrypttext, ex.getMessage()));
}
return
null
;
}
/**
*
使用默認的私鑰解密由JS加密(使用此類提供的公鑰加密)的字符串。
*
*
@param encrypttext 密文。
*
@return {@code encrypttext} 的原文字符串。
*/
public
static
String decryptStringByJs(String encrypttext) {
String
text = decryptString(encrypttext);
if
(text
==
null
)
{
return
null
;
}
return
StringUtils.reverse(text);
}
/**
返回已初始化的默認的公鑰。*/
public
static
RSAPublicKey getDefaultPublicKey() {
KeyPair
keyPair = getKeyPair();
if
(keyPair
!=
null
)
{
return
(RSAPublicKey)keyPair.getPublic();
}
return
null
;
}
/**
返回已初始化的默認的私鑰。*/
public
static
RSAPrivateKey getDefaultPrivateKey() {
KeyPair
keyPair = getKeyPair();
if
(keyPair
!=
null
)
{
return
(RSAPrivateKey)keyPair.getPrivate();
}
return
null
;
}
}
服務端Action中調用RSAUtils工具類
//
Struts2 Action方法中:
//
將公鑰的 modulus 和 exponent 傳給頁面。
//
Hex -> apache commons-codec
RSAPublicKey
publicKey = RSAUtils.getDefaultPublicKey();
ActionContext.getContext().put(
"modulus"
,
new
String(Hex.encodeHex(publicKey.getModulus().toByteArray())));
ActionContext.getContext().put(
"exponent"
,
new
String(Hex.encodeHex(publicKey.getPublicExponent().toByteArray())));
//
頁面裏,Javascript對明文進行加密:
var
modulus = $(
'#hid_modulus'
).val(),
exponent = $(
'#hid_exponent'
).val();
var
key = RSAUtils.getKeyPair(exponent,
''
,
modulus);
pwd1
= RSAUtils.encryptedString(key, pwd1);
pwd2
= RSAUtils.encryptedString(key, pwd2);
//
服務器端,使用RSAUtils工具類對密文進行解密
RSAUtils.decryptStringByJs(password1);