项目中用到了一些加密的算法,算法不太好,但是基于这些都是常用的加密算法,于是记录一下。不写具体原理了,在末尾加入一些链接,别人写的,写的很不错,把原理写的都特别清楚。
根据自己的使用特点来确定,由于非对称加密算法的运行速度比对称加密算法的速度慢很多,当我们需要加密大量的数据时,建议采用对称加密算法,提高加解密速度。
对称加密算法不能实现签名,因此签名只能非对称算法。
由于对称加密算法的密钥管理是一个复杂的过程,密钥的管理直接决定着他的安全性,因此当数据量很小时,我们可以考虑采用非对称加密算法。
在实际的操作过程中,我们通常采用的方式是:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。
如果在选定了加密算法后,那采用多少位的密钥呢?一般来说,密钥越长,运行的速度就越慢,应该根据的我们实际需要的安全级别来选择,一般来说,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