JAVA加密方案(AES/RSA/MD5)
- 对称加密和非对称加密
对称加密指的就是加密和解密使用同一个秘钥。对称加密只有一个秘钥,作为私钥。
常见的对称加密算法:DES,AES,3DES等等。
非对称加密指的是加密和解密使用不同的秘钥,一把作为公开的公钥,另一把作为私钥。公钥加密的信息,只有私钥才能解密。私钥加密的信息,只有公钥才能解密。
常见的非对称加密算法:RSA,ECC
对称加密和非对称加密不能说谁好谁不好,主要是要看应用场景,如果可以用对称加密解决的问题,那么就没有必要用非对称进行加密。因为非对称加密的开销一般比较大,例如RSA 1024的安全性,与AES128的安全性是相当的。
- 对称加密算法AES
对称算法以DES和AES为代表性,其底层原理也有相似之处,都有一个S盒子(可不可以叫做黑盒子),然后通过交换和替换等复杂变换,达到加密的效果。对称加密算法有个非常重要的特性,就是加密和解密可以互逆。总之呢,算法还是挺复杂的,不过,作为程序员的我们,可以不去关心这些,我们只要知道,我们可以用他们来做加密。加密的安全性取决于密钥的长度,密钥越长,越安全如密钥长为128的AES,我们称之为AES128,密钥为256的AES,我们称之为AES256。当前计算机的计算能力下,128的AES基本是安全的,256完全可以放心了。
好了,用java代码来实现AES加解密吧,这个才是我们关心的。
加密方法:
public static final String VIPARA = "20179TELIGRR1234";//初始化向量 16位
|
这个加密方法传入参数是文本内容以及密钥,注意密钥长度要为16byte(与上述的初始化向量是一样的)。
解密方法类似:
/** |
上诉加密和解密方法,还是有挺多与密码学相关的知识的,比如初始化向量,以及加密的CBC模式,不过其实,作为我们应用层的,可以不去关心这些底层的实现,使用就可以完成我们的目标了。不过,使用旧了,自然而且,我们会好奇,它到底怎么实现的?它为什么就是安全的?到时,我们就可以深入去学习了,希望大家这种好奇来的越早越好。
有了上诉的加密和解密方法,我们就可以来进行加解密了,示例如下:
byte[] data1 = aesEncryptToBytes("DW1234567fddddddddddfffffffffff8","aaaaaaaaaaaaaaaa"); |
这上面应用到两个函数bytesToHexString与hexStringToBytes,这个其实不是加解密的环节,而是编解码的环节了,它们的作用就是把字节转成16进制数,以及它的逆操作,具体函数如下:
/**
|
- 非对称加密算法 RSA
非对称加密算法都有一个数学依据的,比如RSA的数学依据总结起来可以说:两个质数相乘得到一个合数是很容易的,而两个大质数相乘得到的大数难以被因式分解。
对于非对称加密,你首先先要一对密钥,一个公钥,用来发布出去的,一个私钥,只能自己拥有的。基于java的RSA密钥生成方法如下:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(1024);// 秘钥长度为1024,可以改成2048等 KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic();//公钥 PrivateKey privateKey = keyPair.getPrivate();//私钥 |
现在公钥和私钥都有了,首先我们需要把它们保存起来,可以直接保存为文件,或者生成字符串等等,下面我把他们保存为文件
byte[] publicKeyByte = publicKey.getEncoded(); byte[] privateKeyByte = privateKey.getEncoded(); BufferedOutputStream pukout = new BufferedOutputStream( new FileOutputStream("src/com/lh/test/publicKey.key")); BufferedOutputStream prkout = new BufferedOutputStream( new FileOutputStream("src/com/lh/test/privateKey.key")); pukout.write(publicKeyByte); prkout.write(privateKeyByte); pukout.flush(); prkout.flush(); |
保存的文件读出如下:
BufferedInputStream pukIn = new BufferedInputStream( new FileInputStream("src/com/lh/test/publicKey.key")); BufferedInputStream prkIn = new BufferedInputStream( new FileInputStream("src/com/lh/test/privateKey.key")); byte[] puKeyByte = new byte[1024]; byte[] prKeyByte = new byte[1024]; pukIn.read(puKeyByte, 0, 1024); prkIn.read(prKeyByte, 0, 1024); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec( puKeyByte);// 公钥 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec( prKeyByte);// 私钥 PrivateKey privateKey = keyFactory .generatePrivate(pkcs8EncodedKeySpec); |
现在我们通过文件读取(或其它途径)拿到了公钥和私钥,我们就可以用来使用了,如果公钥加密,那么需要私钥进行解密,反之亦然。
公钥加密:
Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] resultbytes = cipher.doFinal(plainBytes); //plainBytes 要加密的字节数组 |
私钥解密:
Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] deBytes = cipher.doFinal(ciperBytes); //ciperBytes要解密的字节数组
|
有了byte[],就可以根据上面的hexStringToBytes,bytesToHexString方法,进行字节数组与字符串的转换,便于传输。
- 安全哈希函数MD5
实际开发中,经常可以听到我们密码字段是用MD5加密的,其实这种说法是不对的,MD5(安全哈希函数)只是一串数据指纹,只能用来做数据验证。即,只能单向认证,只能从明文单向计算出MD5值,而不能从MD5值计算出明文。
安全哈希函数常用于验证信息完整性以及验证信息等,比如协议的完整性校验、验证密码。
安全哈希函数有MD5/SHA1/SHA2/SHA3,现在推荐使用SHA2/SHA3
Java实现MD5如下
private static final String md5Key = "MD5";
/**
|