项目中用到了一些加密的算法,算法不太好,但是基于这些都是常用的加密算法,于是记录一下。不写具体原理了,在末尾加入一些链接,别人写的,写的很不错,把原理写的都特别清楚。
根据自己的使用特点来确定,由于非对称加密算法的运行速度比对称加密算法的速度慢很多,当我们需要加密大量的数据时,建议采用对称加密算法,提高加解密速度。
对称加密算法不能实现签名,因此签名只能非对称算法。
由于对称加密算法的密钥管理是一个复杂的过程,密钥的管理直接决定着他的安全性,因此当数据量很小时,我们可以考虑采用非对称加密算法。
在实际的操作过程中,我们通常采用的方式是:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。
如果在选定了加密算法后,那采用多少位的密钥呢?一般来说,密钥越长,运行的速度就越慢,应该根据的我们实际需要的安全级别来选择,一般来说,RSA建议采用1024位的数字,ECC建议采用160位,AES采用128为即可。
基本的单向加密算法:
-
BASE64 严格地说,属于编码格式,而非加密算法
/**
* Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。
* 使用Apache的Commons-codec的base64来做加密解密
*
*/
public class MyBase64 {
public static void main(String[] args) throws UnsupportedEncodingException {
String aa = "test";
String encodeStr = Base64.encodeBase64String(new String(aa.getBytes(), "UTF-8").getBytes());
//BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充。加密后: dGVzdA==
System.out.println("加密后: " + encodeStr);
String decodeStr = new String(Base64.decodeBase64(encodeStr));
if (aa.equals(decodeStr)) {
System.out.println("加密解密成功");
}
}
}
这里用到了apache的包,maven需要加入引用
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> </dependency>
-
MD5(Message Digest algorithm 5,信息摘要算法)
public class MD5Test {
public static void main(String[] args) throws UnsupportedEncodingException {
MessageDigest md5 = null;
try {
// md5 = MessageDigest.getInstance("SHA");
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
String aa = new String("测试信息".getBytes(), "UTF-8");
byte[] md5Bytes = null;
try {
md5Bytes = md5.digest(aa.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
System.out.println(hexValue.toString());
}
}
- SHA(Secure Hash Algorithm,安全散列算法)
写法和md5类似。
-
HMAC(Hash Message Authentication Code,散列消息鉴别码)
复杂的对称加密(DES、PBE)、非对称加密算法:
-
DES(Data Encryption Standard,数据加密算法) 数据加密标准,速度较快,适用于加密大量数据的场合。
package com.xizheng.test.xizhneg;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class DESUtil {
//算法名称
public static final String KEY_ALGORITHM = "DES";
//算法名称/加密模式/填充方式
//DES共有四种工作模式-->>ECB:电子密码本模式、CBC:加密分组链接模式、CFB:加密反馈模式、OFB:输出反馈模式
public static final String CIPHER_ALGORITHM = "DES/ECB/NoPadding";
/**
*
* 生成密钥key对象
* @param KeyStr 密钥字符串
* @return 密钥对象
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws Exception
*/
private static SecretKey keyGenerator(String keyStr) throws Exception {
byte input[] = HexString2Bytes(keyStr);
DESKeySpec desKey = new DESKeySpec(input);
//创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
return securekey;
}
private static int parse(char c) {
if (c >= 'a') return (c - 'a' + 10) & 0x0f;
if (c >= 'A') return (c - 'A' + 10) & 0x0f;
return (c - '0') & 0x0f;
}
// 从十六进制字符串到字节数组转换
public static byte[] HexString2Bytes(String hexstr) {
byte[] b = new byte[hexstr.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = hexstr.charAt(j++);
char c1 = hexstr.charAt(j++);
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
}
/**
* 加密数据
* @param data 待加密数据
* @param key 密钥
* @return 加密后的数据
*/
public static String encrypt(String data, String key) throws Exception {
Key deskey = keyGenerator(key);
// 实例化Cipher对象,它用于完成实际的加密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecureRandom random = new SecureRandom();
// 初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
byte[] results = cipher.doFinal(data.getBytes());
// 该部分是为了与加解密在线测试网站(http://tripledes.online-domain-tools.com/)的十六进制结果进行核对
for (int i = 0; i < results.length; i++) {
System.out.print(results[i] + " ");
}
System.out.println();
// 执行加密操作。加密后的结果通常都会用Base64编码进行传输
return Base64.encodeBase64String(results);
}
/**
* 解密数据
* @param data 待解密数据
* @param key 密钥
* @return 解密后的数据
*/
public static String decrypt(String data, String key) throws Exception {
Key deskey = keyGenerator(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, deskey);
// 执行解密操作
return new String(cipher.doFinal(Base64.decodeBase64(data)));
}
public static void main(String[] args) throws Exception {
String source = "amigoxie";
System.out.println("原文: " + source);
String key = "A1B2C3D4E5F60708";
String encryptData = encrypt(source, key);
System.out.println("加密后: " + encryptData);
String decryptData = decrypt(encryptData, key);
System.out.println("解密后: " + decryptData);
}
}
TripleDES 是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高。
package com.xizheng.test.xizhneg;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
//import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
public class ThreeDESUtil {
// 算法名称
public static final String KEY_ALGORITHM = "desede";
// 算法名称/加密模式/填充方式
public static final String CIPHER_ALGORITHM = "desede/CBC/NoPadding";
/**
* CBC加密
* @param key 密钥
* @param keyiv IV
* @param data 明文
* @return Base64编码的密文
* @throws Exception
*/
public static byte[] des3EncodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception {
// Security.addProvider(new BouncyCastleProvider());
Key deskey = keyGenerator(new String(key));
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ips = new IvParameterSpec(keyiv);
cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
byte[] bOut = cipher.doFinal(data);
for (int k = 0; k < bOut.length; k++) {
System.out.print(bOut[k] + " ");
}
System.out.println("");
return bOut;
}
/**
*
* 生成密钥key对象
* @param KeyStr 密钥字符串
* @return 密钥对象
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws Exception
*/
private static Key keyGenerator(String keyStr) throws Exception {
byte input[] = HexString2Bytes(keyStr);
DESedeKeySpec KeySpec = new DESedeKeySpec(input);
SecretKeyFactory KeyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
return ((Key) (KeyFactory.generateSecret(((java.security.spec.KeySpec) (KeySpec)))));
}
private static int parse(char c) {
if (c >= 'a') return (c - 'a' + 10) & 0x0f;
if (c >= 'A') return (c - 'A' + 10) & 0x0f;
return (c - '0') & 0x0f;
}
// 从十六进制字符串到字节数组转换
public static byte[] HexString2Bytes(String hexstr) {
byte[] b = new byte[hexstr.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = hexstr.charAt(j++);
char c1 = hexstr.charAt(j++);
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
}
/**
* CBC解密
* @param key 密钥
* @param keyiv IV
* @param data Base64编码的密文
* @return 明文
* @throws Exception
*/
public static byte[] des3DecodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception {
Key deskey = keyGenerator(new String(key));
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ips = new IvParameterSpec(keyiv);
cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
byte[] bOut = cipher.doFinal(data);
return bOut;
}
public static void main(String[] args) throws Exception {
byte[] key = "6C4E60E55552386C759569836DC0F83869836DC0F838C0F7".getBytes();
byte[] keyiv = { 1, 2, 3, 4, 5, 6, 7, 8 };
byte[] data = "amigoxie".getBytes("UTF-8");
System.out.println("data.length=" + data.length);
System.out.println("CBC加密解密");
byte[] str5 = des3EncodeCBC(key, keyiv, data);
System.out.println(new sun.misc.BASE64Encoder().encode(str5));
byte[] str6 = des3DecodeCBC(key, keyiv, str5);
System.out.println(new String(str6, "UTF-8"));
}
}
AES: 高级加密标准,是下一代的加密算法标准,速度快,安全级别高;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesUtils {
// 初始向量 16byte
private static final byte[] IV ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
public static final String AES_ECB_NOPadding = "AES/ECB/NOPadding";
public static final String AES_ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";
public static final String AES_CBC_NOPadding = "AES/CBC/NOPadding";
public static final String AES_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
public static final String CHARSET_UTF8 = "UTF-8";
/**
* AES/CBC/PKCS5Padding
* @param hexData 十六进制
* @param hexKey 十六进制
* @return
* @throws UnsupportedEncodingException
*/
public static String encrypt(String transformation,String hexData,String hexKey) throws UnsupportedEncodingException {
byte[] data = DataConvert.hex2byte(hexData);
byte[] k = DataConvert.hex2byte(hexKey);
byte[] resp = encrypt(transformation,data, k);
return DataConvert.ByteArraytoHexString(resp);
}
/**
* AES/CBC/PKCS5Padding
* @param srcData 明文字符串
* @param hexKey 十六进制
* @param charset 编码
* @return
* @throws UnsupportedEncodingException
*/
public static String encrypt(String transformation,String srcData,String hexKey,String charset) throws UnsupportedEncodingException {
byte[] data = srcData.getBytes(charset==null?CHARSET_UTF8:charset);
byte[] k = DataConvert.hex2byte(hexKey);
byte[] resp = encrypt(transformation,data, k);
return DataConvert.ByteArraytoHexString(resp);
}
/**
* AES/CBC/PKCS5Padding
* @param src
* @param key
* @return
*/
public static byte[] encrypt(String transformation,byte[] src,byte[] key) {
try {
Cipher cipher = Cipher.getInstance(transformation);
if(AES_ECB_NOPadding.equals(transformation) || AES_ECB_PKCS5Padding.equals(transformation)){
cipher.init(Cipher.ENCRYPT_MODE, makeKey(key));
}else{
cipher.init(Cipher.ENCRYPT_MODE, makeKey(key), makeIv());
}
return cipher.doFinal(src);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* AES/CBC/PKCS5Padding
* @param hexData 十六进制
* @param hexKey 十六进制
* @return
* @throws UnsupportedEncodingException
*/
public static String decrypt(String transformation,String hexData,String hexKey) throws UnsupportedEncodingException {
byte[] data = DataConvert.hex2byte(hexData);
byte[] k = DataConvert.hex2byte(hexKey);
byte[] resp = decrypt(transformation,data, k);
return new String(resp,CHARSET_UTF8);
}
/**
* AES/CBC/PKCS5Padding
* @param eData
* @param key
* @return
*/
public static byte[] decrypt(String transformation,byte[] eData,byte[] key) {
try {
Cipher cipher = Cipher.getInstance(transformation);
if(AES_ECB_NOPadding.equals(transformation) || AES_ECB_PKCS5Padding.equals(transformation)){
cipher.init(Cipher.DECRYPT_MODE, makeKey(key));
}else{
cipher.init(Cipher.DECRYPT_MODE, makeKey(key), makeIv());
}
return cipher.doFinal(eData);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* MAC算法:采用AES-CBC算法,初始向量全0。如果最后一个数据块长度为16字节,则在此数据块后附加16字节’0x80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00’。如果最后一个数据块长度小于16字节,则该数据块的最后填补’0x80’,如果填补之后的数据块长度仍小于16字节,则在数据块后填充’0x00’,至数据块长度为16字节。MAC值为最后一块密文数据的前4字节
* @param hexData
* @param key
* @return
*/
public static byte[] encryptMac(byte[] hexData,byte[] key) {
System.out.println("src:"+DataConvert.ByteArraytoHexString(hexData));
byte[] mac = new byte[4];
int maxLen = hexData.length + (16-(hexData.length%16));
ByteBuffer buff = ByteBuffer.allocate(maxLen);
buff.put(hexData);
buff.put((byte) 0x80);
System.out.println("padding:"+DataConvert.ByteArraytoHexString(buff.array()));
byte[] eData = encrypt(AES_CBC_NOPadding,buff.array(),key);
buff = ByteBuffer.wrap(eData);
buff.position(buff.capacity()-16);
buff.get(mac);
return mac;
}
/**
* 计算MAC
* @param hexData
* @param hexKey
* @return
* @throws UnsupportedEncodingException
*/
public static String encryptMac(String data,String hexKey) throws UnsupportedEncodingException {
byte[] srcData = data.getBytes(CHARSET_UTF8);
byte[] key = DataConvert.hex2byte(hexKey);
return DataConvert.ByteArraytoHexString(encryptMac(srcData,key));
}
static AlgorithmParameterSpec makeIv() {
IvParameterSpec ips = new IvParameterSpec(IV);
return ips;
}
static Key makeKey(byte[] encodedKey) {
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");
return aesKey;
}
public static void main(String[] args) throws UnsupportedEncodingException{
//秘钥长度为24byte
String ENCRYPTION_KEY = "6C6F67696E41434D452D31326C6F67696E41434D452D3132";
String src = "ED7182AECBC7D5700A34BB682E0E13EE769A692E2EA3936ED33A52E639CA0AA4F06ED47F66AC0B9FD270BBF123DBEE2B2F4E16D36C782B2C4DECECA8E08EF2DD";
System.out.println("src: " + src);
String encrypted = AesUtils.encrypt(AES_CBC_PKCS5Padding,src,ENCRYPTION_KEY,CHARSET_UTF8);
System.out.println("encrypted: " + encrypted);
String decrypted = AesUtils.decrypt(AES_CBC_PKCS5Padding,encrypted,ENCRYPTION_KEY);
System.out.println("decrypted: " + decrypted);
}
}
public class DataConvert {
public DataConvert() {
}
/**
* print Hex byteArray
* @param b byte[]
*/
public static void PrintByteArray(byte[] b) {
char[] hex =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
'e', 'f' };
for (int i = 0; i < b.length; i++) {
if (i % 8 == 0)
System.out.println("");
System.out
.print("0x" + hex[(b[i] >> 4 & 0x0f)] + hex[b[i] & 0x0f] + "; ");
}
}
public static String getBytePrintString(byte[] b) {
char[] hex =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F' };
StringBuffer sb=new StringBuffer();
for (int i = 0; i < b.length; i++) {
sb.append( ""+hex[(b[i] >> 4 & 0x0f)] + hex[b[i] & 0x0f] );
}
return sb.toString();
}
/**
* This method convert byte array to String
* @author sgc
* @return String
* @param byte[] b,int bLen is :b' availability length
*/
public static String ByteArraytoHexString(byte[] b, int bLen) {
int iLen = bLen;
//每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
StringBuffer sb = new StringBuffer(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = b[i];
//把负数转换为正数
while (intTmp < 0) {
intTmp = intTmp + 256;
}
//小于0F的数需要在前面补0
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString().toUpperCase();
}
/**
* This method convert byte array to String
* @author sgc
* @return String
* @param byte[] b,int bLen is :b' availability length
*/
public static String ByteArraytoHexString(byte[] b) {
int iLen = b.length;
//每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
StringBuffer sb = new StringBuffer(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = b[i];
//把负数转换为正数
while (intTmp < 0) {
intTmp = intTmp + 256;
}
//小于0F的数需要在前面补0
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString().toUpperCase();
}
/**
* Int (or) long to ByteArray
* @param number long
* @return byte[]
*/
public static
byte[] LongtoByteArray(long number) {
long temp = number;
StringBuffer s = new StringBuffer(Long.toString(temp, 16));
if (s.length() % 2 == 1) {
return StringToBytes("0" + s.toString());
} else {
return StringToBytes(s.toString());
}
}
/**
* ByteArray to int or long
* @param b byte[]
* @return int
*/
public static int ByteArraytoInteger(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b[i] > 0) {
s = s + b[i];
} else {
s = s + 256 + b[i];
}
s = s * 256;
}
if (b[3] > 0) {
s = s + b[3];
} else {
s = s + 256 + b[3];
}
return s;
}
public static long ByteArraytoLong(byte[] b) {
long l = 0;
for (int i = 0; i < b.length; i++) {
l += (long)(b[b.length - i - 1]&0xff) << (8 * i);
}
return l;
}
public static long ByteArraytoLong(byte[] b,int start ,int len) {
long l = 0;
for (int i = 0; i < len; i++) {
l += (long)(b[start+len - i - 1]&0xFF) << (8 * i);
}
return l;
}
/**
* ByteArray to Double
* @param b byte[]
* @return double
*/
public static double ByteArraytoDouble(byte[] b) {
long l = 0;
Double D = new Double(0.0);
l = b[0];
l = ((long)b[1] << 8);
l = ((long)b[2] << 16);
l = ((long)b[3] << 24);
l = ((long)b[4] << 32);
l = ((long)b[5] << 40);
l = ((long)b[6] << 48);
l = ((long)b[7] << 56);
return Double.longBitsToDouble(l);
}
public static final byte[] StringToBytes(String s) {
int temp[] = new int[s.length()];
byte b[] = new byte[s.length() / 2];
for (int i = 0; i < s.length(); i++) {
temp[i] = Integer.parseInt(String.valueOf(s.charAt(i)), 16);
}
int k = 0;
for (int j = 0; j < s.length(); j += 2) {
b[k] = (byte)(temp[j] * 16 + temp[j + 1]);
k++;
}
return b;
}
/*
Integer和Long提供了toBinaryString, toHexString和toOctalString方 法,可以方便的将数据转换成二进制、十六进制和八进制字符串。功能更加强大的是其toString(int/long i, int radix)方法,可以将一个十进制数转换成任意进制的字符串形式。
*/
public static String getRandom(int len, int radix) {
StringBuffer buf = new StringBuffer("1");
for (int i = 0; i < len; i++) {
buf.append("0");
}
int div = Integer.parseInt(buf.toString());
int value = (int)(Math.random() * div);
if (radix == 10)
return strPadding(value, len);
else
return hexStrPadding(Integer.toHexString(value), len);
}
/**
*
* @param in
* @param outlen
* @return
*/
public static final String strPadding(long in, int outlen) {
String str = String.valueOf(in);
int padlen = outlen - str.length();
StringBuffer zeroBuf = new StringBuffer("");
for (int i = 0; i < padlen; i++) {
zeroBuf.append("0");
}
return zeroBuf.append(str).toString();
}
public static final String hexStrPadding(String in, int outlen) {
int padlen = outlen - in.length();
StringBuffer zeroBuf = new StringBuffer("");
for (int i = 0; i < padlen; i++) {
zeroBuf.append("0");
}
return zeroBuf.append(in).toString();
}
public static byte[] hex2byte(String hex) throws IllegalArgumentException {
if (hex.length() % 2 != 0) {
throw new IllegalArgumentException();
}
char[] arr = hex.toCharArray();
byte[] b = new byte[hex.length() / 2];
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
String swap = "" + arr[i++] + arr[i];
int byteint = Integer.parseInt(swap, 16) & 0xFF;
b[j] = new Integer(byteint).byteValue();
}
return b;
}
public static String decimal2Hex(String str){
return Integer.toHexString(Integer.parseInt(str));
}
public static byte[] LongtoByteArray(long number, int len) {
long temp = number;
StringBuffer s = new StringBuffer(Long.toString(temp, 16));
StringBuffer tmp = new StringBuffer();
if (s.length() % 2 == 1) {
tmp.append("0" + s.toString());
} else {
tmp.append(s.toString());
}
while (tmp.length() < len * 2) {
tmp.insert(0, "00");
}
return StringToBytes(tmp.toString());
}
}
AES加密的时候可能遇到以下错误
默认 Java 中仅支持 128 位密钥,当使用 256 位密钥的时候,会报告密钥长度错误Invalid AES key length。
你需要下载一个支持更长密钥的包。这个包叫做 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6,可以从这里下载,下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
下载之后,解压后,可以看到其中包含两个包:
local_policy.jar
US_export_policy.jar
看一下你的 JRE 环境,将 JRE 环境中 jre\lib\security 中的同名包替换掉。对于jdk来说就是以下目录:Java\jdk1.6.0_45\jre\lib\security。
-
PBE(Password-based encryption,基于密码验证)
-
RSA(算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman)由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的
package com.xizheng.test.xizhneg;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;
import javax.crypto.Cipher;
public class RSAUtils {
/**
* 生成公钥和私钥
* @throws NoSuchAlgorithmException
*
*/
public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException{
HashMap<String, Object> map = new HashMap<String, Object>();
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
map.put("public", publicKey);
map.put("private", privateKey);
return map;
}
/**
* 使用模和指数生成RSA公钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA/None/NoPadding】
*
* @param modulus 模
* @param exponent 指数
* @return
*/
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 使用模和指数生成RSA私钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA/None/NoPadding】
*
* @param modulus 模
* @param exponent 指数
* @return
*/
public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 公钥加密
*
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 模长
int key_len = publicKey.getModulus().bitLength() / 8;
// 加密数据长度 <= 模长-11
String[] datas = splitString(data, key_len - 11);
String mi = "";
//如果明文长度大于模长-11则要分组加密
for (String s : datas) {
mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
}
/**
* 私钥解密
*
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey)
throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//模长
int key_len = privateKey.getModulus().bitLength() / 8;
byte[] bytes = data.getBytes();
byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
System.out.println(bcd.length);
//如果密文长度大于模长则要分组解密
String ming = "";
byte[][] arrays = splitArray(bcd, key_len);
for(byte[] arr : arrays){
ming += new String(cipher.doFinal(arr));
}
return ming;
}
/**
* ASCII码转BCD码
*
*/
public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
byte[] bcd = new byte[asc_len / 2];
int j = 0;
for (int i = 0; i < (asc_len + 1) / 2; i++) {
bcd[i] = asc_to_bcd(ascii[j++]);
bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
}
return bcd;
}
public static byte asc_to_bcd(byte asc) {
byte bcd;
if ((asc >= '0') && (asc <= '9'))
bcd = (byte) (asc - '0');
else if ((asc >= 'A') && (asc <= 'F'))
bcd = (byte) (asc - 'A' + 10);
else if ((asc >= 'a') && (asc <= 'f'))
bcd = (byte) (asc - 'a' + 10);
else
bcd = (byte) (asc - 48);
return bcd;
}
/**
* BCD转字符串
*/
public static String bcd2Str(byte[] bytes) {
char temp[] = new char[bytes.length * 2], val;
for (int i = 0; i < bytes.length; i++) {
val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
val = (char) (bytes[i] & 0x0f);
temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
}
return new String(temp);
}
/**
* 拆分字符串
*/
public static String[] splitString(String string, int len) {
int x = string.length() / len;
int y = string.length() % len;
int z = 0;
if (y != 0) {
z = 1;
}
String[] strings = new String[x + z];
String str = "";
for (int i=0; i<x+z; i++) {
if (i==x+z-1 && y!=0) {
str = string.substring(i*len, i*len+y);
}else{
str = string.substring(i*len, i*len+len);
}
strings[i] = str;
}
return strings;
}
/**
*拆分数组
*/
public static byte[][] splitArray(byte[] data,int len){
int x = data.length / len;
int y = data.length % len;
int z = 0;
if(y!=0){
z = 1;
}
byte[][] arrays = new byte[x+z][];
byte[] arr;
for(int i=0; i<x+z; i++){
arr = new byte[len];
if(i==x+z-1 && y!=0){
System.arraycopy(data, i*len, arr, 0, y);
}else{
System.arraycopy(data, i*len, arr, 0, len);
}
arrays[i] = arr;
}
return arrays;
}
public static void main(String[] args) throws Exception {
HashMap<String, Object> map = RSAUtils.getKeys();
//生成公钥和私钥
RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
//模
String modulus = publicKey.getModulus().toString();
//公钥指数
String public_exponent = publicKey.getPublicExponent().toString();
//私钥指数
String private_exponent = privateKey.getPrivateExponent().toString();
//明文
String mingWen = "测试用例";
//使用模和指数生成公钥和私钥
RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
RSAPrivateKey priKey = RSAUtils.getPrivateKey(modulus, private_exponent);
//加密后的密文
String mi = RSAUtils.encryptByPublicKey(mingWen, pubKey);
System.out.println(mi);
//解密后的明文
mingWen = RSAUtils.decryptByPrivateKey(mi, priKey);
System.out.println(mingWen);
}
}
-
DH(Diffie-Hellman算法,密钥一致协议)
-
DSA(Digital Signature Algorithm,数字签名)数字签名算法,是一种标准的 DSS(数字签名标准);
-
ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)
参考链接:
http://www.blogjava.net/amigoxie/archive/2014/06/01/414299.html
http://www.blogjava.net/amigoxie/archive/2014/07/06/415503.html
http://www.open-open.com/lib/view/open1397274257325.html
http://www.cnblogs.com/shoubianxingchen/p/5305617.html