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

1算凿、對稱加密和非對稱加密

對稱加密指的就是加密和解密使用同一個秘鑰。對稱加密只有一個秘鑰犁功,作為私鑰氓轰。
常見的對稱加密算法:DES,AES浸卦,3DES等等署鸡。
非對稱加密指的是加密和解密使用不同的秘鑰,一把作為公開的公鑰镐躲,另一把作為私鑰储玫。公鑰加密的信息,只有私鑰才能解密萤皂。私鑰加密的信息撒穷,只有公鑰才能解密。
常見的非對稱加密算法:RSA裆熙,ECC
對稱加密和非對稱加密不能說誰好誰不好端礼,主要是要看應(yīng)用場景,如果可以用對稱加密解決的問題入录,那么就沒有必要用非對稱進(jìn)行加密蛤奥。因?yàn)榉菍ΨQ加密的開銷一般比較大,例如RSA 1024的安全性,與AES128的安全性是相當(dāng)?shù)摹?/p>

2僚稿、對稱加密算法AES

對稱算法以DES和AES為代表性凡桥,其底層原理也有相似之處,都有一個S盒子(可不可以叫做黑盒子)蚀同,然后通過交換和替換等復(fù)雜變換缅刽,達(dá)到加密的效果。對稱加密算法有個非常重要的特性蠢络,就是加密和解密可以互逆衰猛。總之呢刹孔,算法還是挺復(fù)雜的啡省,不過,作為程序員的我們,可以不去關(guān)心這些卦睹,我們只要知道畦戒,我們可以用他們來做加密。加密的安全性取決于密鑰的長度结序,密鑰越長兢交,越安全如密鑰長為128的AES,我們稱之為AES128,密鑰為256的AES笼痹,我們稱之為AES256配喳。當(dāng)前計(jì)算機(jī)的計(jì)算能力下,128的AES基本是安全的凳干,256完全可以放心了晴裹。
好了,用java代碼來實(shí)現(xiàn)AES加解密吧救赐,這個才是我們關(guān)心的涧团。
加密方法:

public static final String  VIPARA    =  "20179TELIGRR1234";//初始化向量 16位
private static final String DEFAULT_ENCODING = "utf-8";//編碼方式
/**
 * AES加密
 * @param content 待加密的內(nèi)容
 * @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));
}

這個加密方法傳入?yún)?shù)是文本內(nèi)容以及密鑰,注意密鑰長度要為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);
}

上訴加密和解密方法泌绣,還是有挺多與密碼學(xué)相關(guān)的知識的,比如初始化向量预厌,以及加密的CBC模式阿迈,不過其實(shí),作為我們應(yīng)用層的轧叽,可以不去關(guān)心這些底層的實(shí)現(xiàn)苗沧,使用就可以完成我們的目標(biāo)了。不過炭晒,使用舊了待逞,自然而且,我們會好奇网严,它到底怎么實(shí)現(xiàn)的识樱?它為什么就是安全的?到時震束,我們就可以深入去學(xué)習(xí)了怜庸,希望大家這種好奇來的越早越好。
有了上訴的加密和解密方法驴一,我們就可以來進(jìn)行加解密了休雌,示例如下:

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

這上面應(yīng)用到兩個函數(shù)bytesToHexString與hexStringToBytes灶壶,這個其實(shí)不是加解密的環(huán)節(jié)肝断,而是編解碼的環(huán)節(jié)了,它們的作用就是把字節(jié)轉(zhuǎn)成16進(jìn)制數(shù),以及它的逆操作胸懈,具體函數(shù)如下:

/**
 * 字節(jié)數(shù)組轉(zhuǎn)十六進(jìn)制數(shù)
 *
 * @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進(jìn)制串字符轉(zhuǎn)字節(jié)
 *  和 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

非對稱加密算法都有一個數(shù)學(xué)依據(jù)的,比如RSA的數(shù)學(xué)依據(jù)總結(jié)起來可以說:兩個質(zhì)數(shù)相乘得到一個合數(shù)是很容易的趣钱,而兩個大質(zhì)數(shù)相乘得到的大數(shù)難以被因式分解涌献。
對于非對稱加密,你首先先要一對密鑰首有,一個公鑰燕垃,用來發(fā)布出去的,一個私鑰井联,只能自己擁有的卜壕。基于java的RSA密鑰生成方法如下:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);// 秘鑰長度為1024烙常,可以改成2048等
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();//公鑰
PrivateKey privateKey = keyPair.getPrivate();//私鑰

現(xiàn)在公鑰和私鑰都有了轴捎,首先我們需要把它們保存起來,可以直接保存為文件蚕脏,或者生成字符串等等侦副,下面我把他們保存為文件

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);

現(xiàn)在我們通過文件讀取(或其它途徑)拿到了公鑰和私鑰驼鞭,我們就可以用來使用了秦驯,如果公鑰加密,那么需要私鑰進(jìn)行解密挣棕,反之亦然汇竭。
公鑰加密:

Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] resultbytes = cipher.doFinal(plainBytes);
//plainBytes 要加密的字節(jié)數(shù)組

私鑰解密:

Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] deBytes = cipher.doFinal(ciperBytes);
//ciperBytes要解密的字節(jié)數(shù)組

有了byte[],就可以根據(jù)上面的hexStringToBytes,bytesToHexString方法穴张,進(jìn)行字節(jié)數(shù)組與字符串的轉(zhuǎn)換细燎,便于傳輸。

4皂甘、安全哈希函數(shù)MD5

實(shí)際開發(fā)中玻驻,經(jīng)常可以聽到我們密碼字段是用MD5加密的偿枕,其實(shí)這種說法是不對的璧瞬,MD5(安全哈希函數(shù))只是一串?dāng)?shù)據(jù)指紋,只能用來做數(shù)據(jù)驗(yàn)證渐夸。即嗤锉,只能單向認(rèn)證,只能從明文單向計(jì)算出MD5值墓塌,而不能從MD5值計(jì)算出明文瘟忱。
安全哈希函數(shù)常用于驗(yàn)證信息完整性以及驗(yàn)證信息等奥额,比如協(xié)議的完整性校驗(yàn)、驗(yàn)證密碼访诱。
安全哈希函數(shù)有MD5/SHA1/SHA2/SHA3,現(xiàn)在推薦使用SHA2/SHA3
Java實(shí)現(xiàn)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;
   }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垫挨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子触菜,更是在濱河造成了極大的恐慌九榔,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涡相,死亡現(xiàn)場離奇詭異哲泊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)催蝗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門攻旦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人生逸,你說我怎么就攤上這事牢屋。” “怎么了槽袄?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵烙无,是天一觀的道長。 經(jīng)常有香客問我遍尺,道長截酷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任乾戏,我火速辦了婚禮迂苛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鼓择。我一直安慰自己三幻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布呐能。 她就那樣靜靜地躺著念搬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪摆出。 梳的紋絲不亂的頭發(fā)上朗徊,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機(jī)與錄音偎漫,去河邊找鬼爷恳。 笑死,一個胖子當(dāng)著我的面吹牛象踊,可吹牛的內(nèi)容都是我干的温亲。 我是一名探鬼主播棚壁,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铸豁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起菊碟,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤节芥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后逆害,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體头镊,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年魄幕,在試婚紗的時候發(fā)現(xiàn)自己被綠了相艇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡纯陨,死狀恐怖坛芽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翼抠,我是刑警寧澤咙轩,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站阴颖,受9級特大地震影響活喊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜量愧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一钾菊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偎肃,春花似錦煞烫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至喘落,卻和暖如春茵宪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘦棋。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工稀火, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赌朋。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓凰狞,卻偏偏與公主長得像篇裁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赡若,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容