数据在存储和传输的过程中,可能会面临被窃听、篡改等风险。同时,还可能有人伪装成为客户端进行破坏性的操作,因此为了保证数据的机密性、完整性、不可否认性、认证功能,我们通常对数据的存储和传输进行加密。这里我学习了生产中常用的三种加密算法,MD5、3DES、RSA。
MD5,全名Message Digest Algorithm 5,是一种摘要算法,通过内置的hash算法将信息摘要成为定长的十六进制字串。
具体算法:
1.数据填充:在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。
2.增加长度信息:果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
3.hash算法:四个链接变量,四个循环运算
4个常数:
A = 0x67452301,
B = 0x0EFCDAB89,
C = 0x98BADCFE,
D = 0x10325476;
将上面四个链接变量复制到另外四个变量中:A到a,B到b,C到c,D到d。 主循环有四轮,每轮循环都很相似。第一轮进行16次操作。每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量(文本中的一个子分组和一个常数)。
再将所得结果向右环移一个不定的数,并加上a、b、c或d中之一。最后用该结果取代a、b、c或d中之一。 以一下是每次操作中用到的四个非线性函数(每轮一个)。
F(X,Y,Z)=(X∧Y)∨(( X)∧Z)
G(X,Y,Z)=(X∧Z)∨(Y∧( Z))
H(X,Y,Z)=X?Y?Z
I(X,Y,Z)=Y?(X∨( Z))
其中,?是异或,∧是与,∨是或, 是反符号。
如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。F是一个逐位运算的函数。即,如果X,那么Y,否则Z。函数H是逐位奇偶操作符。所有这些完成之后,将A,B,C,D分别加上a,b,c,d。然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联。最后得到的A,B,C,D就是输出结果,A是低位,D为高位,DCBA组成128位输出结果(32位16进制)。
技巧: 接口提供和接口使用双方同样可以约定秘钥(key),尽管MD5没有使用特定key加密的方法,
但是如果双方都在加密前的明文末尾加上这个key,然后再去加密,也可以起到秘钥的作用。
DES是Data Encryption Standard(数据加密标准),DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。它的密钥长度是56位(因为每个第8 位都用作奇偶校验),密钥可以是任意的56位的数,所以保密性依赖于密钥。
DES加密的算法框架如下:
首先要生成一套加密密钥,从用户处取得一个64位长的密码口令,然后通过等分、移位、选取和迭代形成一套16个加密密钥,分别供每一轮运算中使用。DES对64位(bit)的明文分组M进行操作,M经过一个初始置换IP,置换成m0。将m0明文分成左半部分和右半部分m0 = (L0,R0),各32位长。然后进行16轮完全相同的运算(迭代),这些运算被称为函数f,在每一轮运算过程中数据与相应的密钥结合。
在每一轮中,密钥位移位,然后再从密钥的56位中选出48位。通过扩展置换将数据的右半部分扩展成48位,并通过一个异或操作替代成新的48位数据,再将其压缩置换成32位。这四步运算构成了函数f。然后,通过另一个异或运算,函数f的输出与左半部分结合,其结果成为新的右半部分,原来的右半部分成为新的左半部分。将该操作重复16次。
经过16轮迭代后,左,右半部分合在一起经过一个末置换(数据整理),这样就完成了加密过程。
加密流程如图所示:
与DES不同,RSA算法中,每个通信主体都有两个钥匙,一个公钥一个私钥。就是有2把钥匙:使用publicKey可以对数据进行加密,使用私钥才能对数据进行解密。
算法原理参见:
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
http://blog.csdn.net/sunmenggmail/article/details/11994013
import java.io.UnsupportedEncodingException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Encoder;
public class TestEncrypt {
public static BASE64Encoder encoder = new BASE64Encoder();
public static void main(String[] args) throws Exception {
String string = "hahahahahahahaaldsfangnaKCFAK";
System.out.println("加密前长度"+string.length());
String paramKey = "addf";
testMD5(string);
testDes(string, paramKey);
testRSA(string);
}
public static void testMD5(String string) {
byte[] bytes = string.getBytes();
String sign = MD5EncoderMethod(string);
System.out.println("MD5十六进制摘要:"+sign+"---->>> length ::"+ sign.length());
System.out.println();
}
public static String MD5EncoderMethod(String string) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] bytes = string.getBytes();
byte[] md5Bytes = md5.digest(bytes);
System.out.println("md5.digest后:"+encoder.encode(md5Bytes)+"---->>md5.digest byteArray.length:"+md5Bytes.length);
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));
}
return hexValue.toString();
}
public static void testDes(String string, String paramKey) throws Exception {
try {
Cipher cipher = Cipher.getInstance("DESede");
SecretKey sKey = new SecretKeySpec(build3DesKey(paramKey), "DESede");
cipher.init(Cipher.ENCRYPT_MODE, sKey);
byte[] bytes = cipher.doFinal(string.getBytes());
System.out.println("DES加密后:"+encoder.encode(bytes)+" ——————》DES加密后长度:"+bytes.length);
cipher.init(Cipher.DECRYPT_MODE, sKey);
System.out.println("DES解密后: "+new String(cipher.doFinal(bytes)));
System.out.println();
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
}
public static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {
final byte[] key = new byte[24]; // 声明一个24位的字节数组,默认里面都是0
final byte[] temp = keyStr.getBytes("UTF-8"); // 将字符串转成字节数组
/*
* 执行数组拷贝 System.arraycopy(源数组,从源数组哪里开始拷贝,目标数组,拷贝多少位)
*/
if (key.length > temp.length) {
// 如果temp不够24位,则拷贝temp数组整个长度的内容到key数组中
System.arraycopy(temp, 0, key, 0, temp.length);
} else {
// 如果temp大于24位,则拷贝temp数组24个长度的内容到key数组中
System.arraycopy(temp, 0, key, 0, key.length);
}
return key;
}
public static void testRSA(String string) {
try {
Cipher cipher = Cipher.getInstance("RSA");
HashMap keMap = getKeys();
RSAPublicKey pubKey = (RSAPublicKey) keMap.get("public");
System.out.println(pubKey.toString());
RSAPrivateKey priKey = (RSAPrivateKey) keMap.get("private");
System.out.println(priKey.toString());
cipher.init(cipher.ENCRYPT_MODE, pubKey);
byte[] bytes = cipher.doFinal(string.getBytes());
System.out.println("RSA公钥加密后的字符串::"+encoder.encode(bytes)+" --->>加密后长度"+bytes.length);
cipher.init(Cipher.DECRYPT_MODE, priKey);
bytes = cipher.doFinal(bytes);
System.out.println("RSA私钥解密后的字符串::"+new String(bytes,"UTF-8")+" --->>解密后长度"+bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 生成公钥和私钥
*/
public static HashMap getKeys() throws NoSuchAlgorithmException {
HashMap map = new HashMap();
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;
}
}