JAVA加密方案(AES/RSA/MD5)

1、对称加密和非对称加密

对称加密指的就是加密和解密使用同一个秘钥。对称加密只有一个秘钥,作为私钥。
常见的对称加密算法:DES,AES,3DES等等。
非对称加密指的是加密和解密使用不同的秘钥,一把作为公开的公钥,另一把作为私钥。公钥加密的信息,只有私钥才能解密。私钥加密的信息,只有公钥才能解密。
常见的非对称加密算法:RSA,ECC
对称加密和非对称加密不能说谁好谁不好,主要是要看应用场景,如果可以用对称加密解决的问题,那么就没有必要用非对称进行加密。因为非对称加密的开销一般比较大,例如RSA 1024的安全性,与AES128的安全性是相当的。

2、对称加密算法AES

对称算法以DES和AES为代表性,其底层原理也有相似之处,都有一个S盒子(可不可以叫做黑盒子),然后通过交换和替换等复杂变换,达到加密的效果。对称加密算法有个非常重要的特性,就是加密和解密可以互逆。总之呢,算法还是挺复杂的,不过,作为程序员的我们,可以不去关心这些,我们只要知道,我们可以用他们来做加密。加密的安全性取决于密钥的长度,密钥越长,越安全如密钥长为128的AES,我们称之为AES128,密钥为256的AES,我们称之为AES256。当前计算机的计算能力下,128的AES基本是安全的,256完全可以放心了。
好了,用java代码来实现AES加解密吧,这个才是我们关心的。
加密方法:

public static final String  VIPARA    =  "20179TELIGRR1234";//初始化向量 16位
private static final String DEFAULT_ENCODING = "utf-8";//编码方式
/**
 * AES加密
 * @param content 待加密的内容
 * @param encryptKey 加密密钥
 * @return 加密后的byte[]
 * @throws Exception
 */
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {

    IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes(DEFAULT_ENCODING));
    SecretKeySpec keySpec = new SecretKeySpec(encryptKey.getBytes(DEFAULT_ENCODING),"AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE,keySpec,zeroIv);
    return cipher.doFinal(content.getBytes(DEFAULT_ENCODING));
}

这个加密方法传入参数是文本内容以及密钥,注意密钥长度要为16byte(与上述的初始化向量是一样的)。
解密方法类似:

/**
 * AES解密
 * @param encryptBytes 待解密的byte[]
 * @param decryptKey 解密密钥
 * @return 解密后的String
 * @throws Exception
 */
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {

    IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes(DEFAULT_ENCODING));
    SecretKeySpec keySpec = new SecretKeySpec(decryptKey.getBytes(DEFAULT_ENCODING),"AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE,keySpec,zeroIv);
    byte[] decryptBytes = cipher.doFinal(encryptBytes);
    return new String(decryptBytes);
}

上诉加密和解密方法,还是有挺多与密码学相关的知识的,比如初始化向量,以及加密的CBC模式,不过其实,作为我们应用层的,可以不去关心这些底层的实现,使用就可以完成我们的目标了。不过,使用旧了,自然而且,我们会好奇,它到底怎么实现的?它为什么就是安全的?到时,我们就可以深入去学习了,希望大家这种好奇来的越早越好。
有了上诉的加密和解密方法,我们就可以来进行加解密了,示例如下:

byte[] data1 = aesEncryptToBytes("DW1234567fddddddddddfffffffffff8","aaaaaaaaaaaaaaaa");
String data1Str = bytesToHexString(data1);
System.out.println("密文:"+data1Str);
String  result1 = aesDecryptByBytes(hexStringToBytes(data1Str),"aaaaaaaaaaaaaaaa");
System.out.println("明文:"+result1);

这上面应用到两个函数bytesToHexString与hexStringToBytes,这个其实不是加解密的环节,而是编解码的环节了,它们的作用就是把字节转成16进制数,以及它的逆操作,具体函数如下:

/**
 * 字节数组转十六进制数
 *
 * @param b
 * @return
 */
public static String bytesToHexString(byte[] b) {
   if(b == null || b.length <= 0){
      return null;
   }
   StringBuilder sb = new StringBuilder(b.length * 2);
   for (int i = 0; i < b.length; i++) {
      sb.append(HEXCHAR[(b[i] & 0xf0) >>> 4]);
      sb.append(HEXCHAR[b[i] & 0x0f]);
   }
   return sb.toString();
}

/**
 * 16进制串字符转字节
 *  和 bytesToHexString 互逆
 * @param hexString
 * @return
    */
public static byte[] hexStringToBytes(String hexString){
   if(hexString == null || hexString.length() <=  0){
      return null;
   }
   byte[] data = new byte[hexString.length()/2];
   for(int i=0;i< hexString.length();){
      char high = hexString.charAt(i);
      i++;
      char low = hexString.charAt(i);
      data[i/2] = hexToByte(high,low);
      i++;
   }
   return data;
}

3、非对称加密算法 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方法,进行字节数组与字符串的转换,便于传输。

4、安全哈希函数MD5

实际开发中,经常可以听到我们密码字段是用MD5加密的,其实这种说法是不对的,MD5(安全哈希函数)只是一串数据指纹,只能用来做数据验证。即,只能单向认证,只能从明文单向计算出MD5值,而不能从MD5值计算出明文。
安全哈希函数常用于验证信息完整性以及验证信息等,比如协议的完整性校验、验证密码。
安全哈希函数有MD5/SHA1/SHA2/SHA3,现在推荐使用SHA2/SHA3
Java实现MD5如下

private static final String md5Key = "MD5";
private static final String defaultEncoding = "utf-8";


/**
 * 以字符串为输入输出的Md5
 * @param dataStr
 * @return
    */
public static String md5Encrypt(String dataStr){
   try {
      MessageDigest md5 = MessageDigest.getInstance(md5Key);
      byte [] data = md5.digest(dataStr.getBytes(defaultEncoding));
      return bytesToHexString(data);
   } catch (Exception e) {
      return null;
   }
}

你可能感兴趣的:(JAVA加密方案(AES/RSA/MD5))