对称与非对称加密算法的区别。
对称加密算法
加密(encryption)与解密(decryption)用的是同样的密钥(secret key),这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。
非对称加密算法
非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。非对称加密使用这对密钥中的一个进行加密,而解密则需要另一个密钥。比如,你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人--银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。
常见的非对称加密算法为RSA、ECC和EIGamal。
一、Hex编码与解码
Hex 全称是Intel HEX。Hex文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制编码数字组成。
如下:
99、105、224,7
编码之后的数据为:“6369e007”,是一个字符串。
pom依赖
编码与解码测试如下:
/**
* Hex编码
*/
public static String encodeHex(byte[] input) {
return Hex.encodeHexString(input);
}
/**
* Hex解码
*/
public static byte[] decodeHex(String input) {
try {
return Hex.decodeHex(input.toCharArray());
} catch (DataBindingException e) {
throw new RuntimeException();
} catch (DecoderException e) {
throw new RuntimeException();
}
}
二、Base64编码与解码
/**
* Base64编码
*/
public static String encodeBase64(byte[] input) {
return Base64.encodeBase64String(input);
}
/**
* Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548)
*/
public static String encodeUrlSafeBase64(byte[] input) {
return Base64.encodeBase64URLSafeString(input);
}
/**
* Base64解码.
*/
public static byte[] decodeBase64(String input) {
return Base64.decodeBase64(input);
}
测试如下:
public class Base64Test {
public static void main(String[] args){
String str = "Hello World";
try{
System.out.println("RESULT: " + encodeStr(str));
} catch(UnsupportedEncodingException e){
e.printStackTrace();
}
}
}
输出结果为:
1. RESULT: SGVsbG8gV29ybGQ=
上面输出的字符串是“Hello world”字符串的8位二进制值被连接在一起,然后以6位分组。随后每个组都被转换成一个单独的数字并映射到Base64的索引。
binary dec Base64
010010 18 S
000110 6 G
010101 21 V
101100 44 s
011011 27 b
000110 6 G
111100 60 8
100000 32 g
010101 29 d
110110 54 2
111101 61 9
110010 50 y
011011 27 b
000110 6 G
010000 16 Q
注意:字符串最后加上了“=”,其意思表示字符串编码的结束。
三、URL编码与解码
当URL地址里包含非西欧字符的字符串时,浏览器都会将这些非西欧字符串转换成application/x-www-form-urlencoded MIME 字符串。在开发过程中,我们可能涉及将普通字符串和这种特殊字符串的相关转换,这就需要使用 URLDecoder 和 URLEncoder类进行实现,其中:
· URLDecoder类包含一个decode(String s,String enc)静态方法,它可以将application/x-www-form-urlencoded MIME字符串转成普通字符串;
· URLEncoder类包含一个encode(String s,String enc)静态方法,它可以将普通字符串转换成application/x-www-form-urlencoded MIME字符串。
普通字符串转与 application/x-www-form-urlencoded MIME 字符串之间的转化:
public class URLDecoderTest {
public static void main(String[] args) throws Exception {
// 将application/x-www-form-urlencoded字符串转换成普通字符串
// 其中的字符串直接从上图所示窗口复制过来,chrome 默认用 UTF-8 字符集进行编码,所以也应该用对应的字符集解码
System.out.println("采用UTF-8字符集进行解码:");
String keyWord = URLDecoder.decode("%E5%A4%A9%E6%B4%A5%E5%A4%A7%E5%AD%A6+Rico", "UTF-8");
System.out.println(keyWord);
System.out.println("\n 采用GBK字符集进行解码:");
System.out.println(URLDecoder.decode("%E5%A4%A9%E6%B4%A5%E5%A4%A7%E5%AD%A6+Rico", "GBK"));
// 将普通字符串转换成application/x-www-form-urlencoded字符串
System.out.println("\n 采用utf-8字符集:");
String urlStr = URLEncoder.encode("天津大学", "utf-8");
System.out.println(urlStr);
System.out.println("\n 采用GBK字符集:");
String urlStr2 = URLEncoder.encode("天津大学", "GBK");
System.out.println(urlStr2);
}
}
/*
Output:
采用UTF-8字符集进行解码:
天津大学 Rico
采用GBK字符集进行解码:
澶╂触澶у Rico
采用utf-8字符集:
%E5%A4%A9%E6%B4%A5%E5%A4%A7%E5%AD%A6
采用GBK字符集:
%CC%EC%BD%F2%B4%F3%D1%A7
*/
四、AES加密或解密
高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法。对称加密算法也就是加密和解密用相同的密钥
密钥K:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
1、密钥
就是把明文转换为密文,密文转换为明文的一把钥匙。接下来我们会用ASE加密技术生成一把密钥。
/**
* 生成AES密钥,可选长度为128,192,256位.
*/
public static byte[] generateAesKey(int keysize) {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
keyGenerator.init(keysize);
SecretKey secretKey = keyGenerator.generateKey();
return secretKey.getEncoded();
} catch (GeneralSecurityException e) {
throw unchecked(e);
}
}
2、加密,将明文和密钥一起,作为参数传入。
/**
* ASE 加密
* @param str 明文
* @param key 秘钥
* @return
*/
public static String enStr(String str, byte[] key) {
Cipher cipher = null;
SecretKey generateKey = null;
try {
generateKey = new SecretKeySpec(key, "AES");
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, generateKey);
byte[] resultBytes = cipher.doFinal(str.getBytes());
return Hex.encodeHexString(resultBytes);
} catch (Exception e) {
logger.error("AES加密出错", e);
}
return null;
}
3、解密,解密就是加密的互逆过程,所以代码很类似。
/**
* 解密
* @param key 秘钥
* @param str 密文
* @return
*/
public static String deStr(String str, byte[] key) {
Cipher cipher = null;
SecretKey generateKey = null;
try {
generateKey = new SecretKeySpec(key, "AES");
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, generateKey);
byte[] result = Hex.decodeHex(str.toCharArray());
return new String(cipher.doFinal(result));
} catch(Exception e) {
logger.error("ASE解密出错", e);
}
return null;
}
通用公共抽取:
/**
* 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.
*
* @param input 原始字节数组
* @param key 符合AES要求的密钥
* @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE
*/
private static byte[] aes(byte[] input, byte[] key, int mode) {
try {
SecretKey secretKey = new SecretKeySpec(key, AES);
Cipher cipher = Cipher.getInstance(AES);
cipher.init(mode, secretKey);
return cipher.doFinal(input);
} catch (GeneralSecurityException e) {
throw unchecked(e);
}
}
五、DES加密与解密(3DES)
数据加密标准(DES Data Encryption Standard)
DES算法的入口参数有三个:Key、Data、Mode。
其中Key为8个字节共64位,是DES算法的工作密钥;
Data也为8个字节64位,是要被加密或被解密的数据;
Mode为DES的工作方式,有两种:加密或解密。
DES算法是这样工作的:
如Mode为加密,则用Key 去把数据Data进行加密,生成Data的密码形式(64位)作为DES的输出结果;
如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。
3DES加密:
3DES是DES加密算法的一种模式,它使用3条64位的密钥对数据进行三次加密。数据加密标准(DES)是美国的一种由来已久的加密标准,它使用对称密钥加密法。
3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。
设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,P代表明文,C代表密表,这样,
3DES加密过程为:C=Ek3(Dk2(Ek1(P)))
3DES解密过程为:P=Dk1((EK2(Dk3(C)))
K1、K2、K3决定了算法的安全性,若三个密钥互不相同,本质上就相当于用一个长为168位的密钥进行加密。多年来,它在对付强力攻击时是比较安全的。若数据对安全性要求不那么高,K1可以等于K3。在这种情况下,密钥的有效长度为112位。
五、RSA加密与解密
非对称加密,公钥加密,私钥解密,反之亦然。由于需要大数的乘幂求模等算法,运行速度慢,不易于硬件实现。
通常私钥长度有512bit,1024bit,2048bit,4096bit,长度越长,越安全,但是生成密钥越慢,加解密也越耗时。
既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;
同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。
六、MD5加密(不可逆)
MD5即Message-Digest Algorithm 5(信息-摘要算法5), 非对称的加密算法
public static String MD5(String key) {
char hexDigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
try {
byte[] btInput = key.getBytes();
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
charstr[] = newchar[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
returnnull;
}
}
总结
哈希函数,比如MD5,SHA,这些都不是加密算法。要注意他们的区别和用途,很多网友都把md5说成是加密算法,这是严重不正确的啊。
哈希函数:MD5,SHA 是没有密钥的,相当与指纹的概念,因此也是不可逆的;
md5是128位的,SHA有不同的算法,有128,256等位。。。如SHA-256,SHA-384
然后就是 Base64,这更加不属于加密算法的范围了,它只是将byte[]数组进行了转换,为什么要转换呢?就是因为很多加密后的密文后者一些特殊的byte[]数组需要显示出来,或者需要进行传递(电子邮件),但是直接转换就会导致很多不可显示的字符,会丢失一些信息,因此就转换位Base64编码,这些都是可显示的字符。所以转换后,长度会增加。它是可逆的。
再就是 3DES,DES 这才是加密算法,因此也是可逆的,加解密需要密钥,也就是你说的key
最后是 RSA ,这是公钥密码,也就是加密和解密密钥不同,也是可逆的。