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;
   }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容