日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

日常開發(fā)中,無論你是使用什么語言,都應該遇到過使用加解密的使用場景,比如接口數(shù)據(jù)需要加密傳給前端保證數(shù)據(jù)傳輸?shù)陌踩籋TTPS使用證書的方式首先進行非對稱加密,將客戶端的私匙傳遞給服務(wù)端,然后雙方后面的通信都使用該私匙進行對稱加密傳輸;使用MD5進行文件一致性校驗,等等很多的場景都使用到了加解密技術(shù)。

很多時候我們對于什么時候要使用什么樣的加解密方式是很懵的。因為可用的加解密方案實在是太多,大家對加解密技術(shù)的類型可能不是很清楚,今天這篇文章就來梳理一下目前主流的加解密技術(shù),本篇文檔只針對算法做科普性說明,不涉及具體算法分析。日常使用的加解密大致可以分為以下四類:

  1. 散列函數(shù)(也稱信息摘要)算法
  2. 對稱加密算法
  3. 非對稱加密算法
  4. 組合加密技術(shù)

1. 散列函數(shù)算法#

聽名字似乎不是一種加密算法,類似于給一個對象計算出hash值。所以這種算法一般用于數(shù)據(jù)特征提取。常用的散列函數(shù)包括:MD5、SHA1、SHA2(包括SHA128、SHA256等)散列函數(shù)的應用很廣,散列函數(shù)有個特點,它是一種單向加密算法,只能加密、無法解密。

1.1 MD5

先來看MD5算法,MD5算法是廣為使用的數(shù)據(jù)特征提取算法,最常見的就是我們在下載一些軟件,網(wǎng)站都會提供MD5值給你進行校驗,你可以通過MD5值是否一致來檢查當前文件是否被別人篡改。MD5算法具有以下特點:

  1. 任意長度的數(shù)據(jù)得到的MD5值長度都是相等的;
  2. 對原數(shù)據(jù)進行任一點修改,得到的MD5值就會有很大的變化;
  3. 散列函數(shù)的不可逆性,即已知原數(shù)據(jù),無法通過特征值反向獲取原數(shù)據(jù)。(需要說明的是2004年的國際密碼討論年會(CRYPTO)尾聲,王小云及其研究同事展示了MD5、SHA-0及其他相關(guān)雜湊函數(shù)的雜湊沖撞。也就是說,她找出了第一個 兩個值不同,但 MD5 值相同的碰撞的例子。這個應該不能稱之為破解)
1.2 MD5用途:
  1. 防篡改。上面說過用于文件完整性校驗。
  2. 用于不想讓別人看到明文的地方。比如用戶密碼入庫,可以將用戶密碼使用MD5加密存儲,下次用戶輸入密碼登錄只用將他的輸入進行MD5加密與數(shù)據(jù)庫的值判斷是否一致即可,這樣就有效防止密碼泄露的風險。
  3. 用于文件秒傳。比如百度云的文件秒傳功能可以用這種方式來實現(xiàn)。在你點擊上傳的時候,前端同學會先計算文件的MD5值然后與服務(wù)端比對是否存在,如果有就會告訴你文件上傳成功,即完成所謂的秒傳。

在JDK中提供了MD5的實現(xiàn):JAVA.security包中有個類MessageDigest,MessageDigest 類為應用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的單向哈希函數(shù),它接收任意大小的數(shù)據(jù),輸出固定長度的哈希值。

MessageDigest 對象使用getInstance函數(shù)初始化,該對象通過使用 update 方法處理數(shù)據(jù)。任何時候都可以調(diào)用 reset 方法重置摘要。一旦所有需要更新的數(shù)據(jù)都已經(jīng)被更新了,應該調(diào)用 digest 方法之一完成哈希計算。

對于給定數(shù)量的更新數(shù)據(jù),digest 方法只能被調(diào)用一次。digest 被調(diào)用后,MessageDigest 對象被重新設(shè)置成其初始狀態(tài)。

下面的例子展示了使用JDK自帶的MessageDigest類使用MD5算法。同時也展示了如果使用了update方法后沒有調(diào)用digest方法,則會累計當前所有的update中的值在下一次調(diào)用digest方法的時候一并輸出:

Copypackage other;

import java.security.MessageDigest;

/**
 * @author: rickiyang
 * @date: 2019/9/13
 * @description:
 */
public class MD5Test {

    static char[] hex = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public static void main(String[] args) {
        try {
            //申明使用MD5算法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update("a".getBytes());//
            System.out.println("md5(a)=" + byte2str(md5.digest()));
            md5.update("a".getBytes());
            md5.update("bc".getBytes());
            System.out.println("md5(abc)=" + byte2str(md5.digest()));
            //你會發(fā)現(xiàn)上面的md5值與下面的一樣
            md5.update("abc".getBytes());
            System.out.println("md5(abc)=" + byte2str(md5.digest()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 將字節(jié)數(shù)組轉(zhuǎn)換成十六進制字符串
     *
     * @param bytes
     * @return
     */
    private static String byte2str(byte[] bytes) {
        int len = bytes.length;
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < len; i++) {
            byte byte0 = bytes[i];
            result.Append(hex[byte0 >>> 4 & 0xf]);
            result.append(hex[byte0 & 0xf]);
        }
        return result.toString();
    }
}

輸出:

Copymd5(a)=0CC175B9C0F1B6A831C399E269772661
md5(abc)=900150983CD24FB0D6963F7D28E17F72
md5(abc)=900150983CD24FB0D6963F7D28E17F72
2.1 SHA系列算法

Secure Hash Algorithm,是一種與MD5同源的數(shù)據(jù)加密算法。SHA算法能計算出一個數(shù)位信息所對應到的,長度固定的字串,又稱信息摘要。而且如果輸入信息有任何的不同,輸出的對應摘要不同的機率非常高。因此SHA算法也是FIPS所認證的五種安全雜湊算法之一。原因有兩點:一是由信息摘要反推原輸入信息,從計算理論上來說是極為困難的;二是,想要找到兩組不同的輸入信息發(fā)生信息摘要碰撞的幾率,從計算理論上來說是非常小的。任何對輸入信息的變動,都有很高的幾率導致的信息摘要大相徑庭。

SHA實際上是一系列算法的統(tǒng)稱,分別包括:SHA-1、SHA-224、SHA-256、SHA-384以及SHA-512。后面4中統(tǒng)稱為SHA-2,事實上SHA-224是SHA-256的縮減版,SHA-384是SHA-512的縮減版。各中SHA算法的數(shù)據(jù)比較如下表,其中的長度單位均為位:

類別
SHA-1SHA-224SHA-256SHA-384SHA-512
消息摘要長度160224256384512消息長度小于264位小于264位小于264位小于2128位小于2128位分組長度51251251210241024計算字長度3232326464計算步驟數(shù)8064648080

SHA-1算法輸入報文的最大長度不超過264位,產(chǎn)生的輸出是一個160位的報文摘要。輸入是按512 位的分組進行處理的。SHA-1是不可逆的、防沖突,并具有良好的雪崩效應。

上面提到的MessageDigest類同時也支持SHA系列算法,使用方式與MD5一樣,注意SHA不同的類型:

CopyMessageDigest md = MessageDigest.getInstance("SHA");
MessageDigest md = MessageDigest.getInstance("SHA-224");
MessageDigest md = MessageDigest.getInstance("SHA-384");

2. 對稱加密算法#

所謂的對稱加密,意味著加密者和解密者需要同時持有一份相同的密匙,加密者用密匙加密,解密者用密匙解密即可。

常用的對稱加密算法包括DES算法、AES算法等。 由于對稱加密需要一個秘鑰,而秘鑰在加密者與解密者之間傳輸又很難保證安全性,所以目前用對稱加密算法的話主要是用在加密者解密者相同,或者加密者解密者相對固定的場景。

對稱算法又可分為兩類:

第一種是一次只對明文中的單個位(有時對字節(jié))運算的算法稱為序列算法或序列密碼;

另一種算法是對明文的一組位進行運算,這些位組稱為分組,相應的算法稱為分組算法或分組密碼。現(xiàn)代計算機密碼算法的典型分組長度為64位――這個長度既考慮到分析破譯密碼的難度,又考慮到使用的方便性。

2.1 BASE64算法

我們很熟悉的BASE64算法就是一個沒有秘密的對稱加密算法。因為他的加密解密算法都是公開的,所以加密數(shù)據(jù)是沒有任何秘密可言,典型的防菜鳥不防程序員的算法。

BASE64算法作用:

  1. 用于簡單的數(shù)據(jù)加密傳輸;
  2. 用于數(shù)據(jù)傳輸過程中的轉(zhuǎn)碼,解決中文問題和特殊符號在網(wǎng)絡(luò)傳輸中的亂碼現(xiàn)象。網(wǎng)絡(luò)傳輸過程中如果雙方使用的編解碼字符集方式不一致,對于中文可能會出現(xiàn)亂碼;與此類似,網(wǎng)絡(luò)上傳輸?shù)淖址⒉蝗强纱蛴〉淖址热缍M制文件、圖片等。Base64的出現(xiàn)就是為了解決此問題,它是基于64個可打印的字符來表示二進制的數(shù)據(jù)的一種方法。

BASE64原理

BASE64的原理比較簡單,每當我們使用BASE64時都會先定義一個類似這樣的數(shù)組:

Copy['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

上面就是BASE64的索引表,字符選用了"A-Z、a-z、0-9、+、/" 64個可打印字符,這是標準的BASE64協(xié)議規(guī)定。在日常使用中我們還會看到“=”或“==”號出現(xiàn)在BASE64的編碼結(jié)果中,“=”在此是作為填充字符出現(xiàn)。

JDK提供了BASE64的實現(xiàn):BASE64Encoder,我們可以直接使用:

Copy//使用base64加密
BASE64Encoder encoder = new BASE64Encoder();  
String encrypt = encoder.encode(str.getBytes());  
//使用base64解密
BASE64Decoder decoder = new BASE64Decoder();  
String decrypt = new String(decoder.decodeBuffer(encryptStr));  
2.2 DES

DES (Data Encryption Standard),在很長時間內(nèi),許多人心目中“密碼生成”與DES一直是個同義詞。

DES是一個分組加密算法,典型的DES以64位為分組對數(shù)據(jù)加密,加密和解密用的是同一個算法。它的密鑰長度是56位(因為每個第8 位都用作奇偶校驗),密鑰可以是任意的56位的數(shù),而且可以任意時候改變。

DES加密過程大致如下:

  1. 首先需要從用戶處獲取一個64位長的密碼口令,然后通過等分、移位、選取和迭代形成一套16個加密密鑰,分別供每一輪運算中使用;
  2. 然后將64位的明文分組M進行操作,M經(jīng)過一個初始置換IP,置換成m0。將m0明文分成左半部分和右半部分m0 = (L0,R0),各32位長。然后進行16輪完全相同的運算(迭代),這些運算被稱為函數(shù)f,在每一輪運算過程中數(shù)據(jù)與相應的密鑰結(jié)合;
  3. 在每一輪迭代中密鑰位移位,然后再從密鑰的56位中選出48位。通過一個擴展置換將數(shù)據(jù)的右半部分擴展成48位,并通過一個異或操作替代成新的48位數(shù)據(jù),再將其壓縮置換成32位。這四步運算構(gòu)成了函數(shù)f。然后,通過另一個異或運算,函數(shù)f的輸出與左半部分結(jié)合,其結(jié)果成為新的右半部分,原來的右半部分成為新的左半部分。將該操作重復16次;
  4. 經(jīng)過16輪迭代后,左,右半部分合在一起經(jīng)過一個末置換(數(shù)據(jù)整理),這樣就完成了加密過程。

對于DES解密的過程大家猛然一想應該是使用跟加密過程相反的算法,事實上解密和加密使用的是一樣的算法,有區(qū)別的地方在于加密和解密在使用密匙的時候次序是相反的。比如加密的時候是K0,K1,K2......K15,那么解密使用密匙的次序就是倒過來的。之所以能用相同的算法去解密,這跟DES特意設(shè)計的加密算法有關(guān),感興趣的同學可以深入分析。

2.3 AES

高級加密標準(AES,Advanced Encryption Standard),與DES一樣,使用AES加密函數(shù)和密匙來對明文進行加密,區(qū)別就是使用的加密函數(shù)不同。

上面說過DES的密鑰長度是56比特,因此算法的理論安全強度是2^56。但以目前計算機硬件的制作水準和升級情況,破解DES可能只是山脈問題,最終NIST(美國國家標準技術(shù)研究所(National Institute of Standards and Technology))選擇了分組長度為128位的Rijndael算法作為AES算法。

AES為分組密碼,分組密碼也就是把明文分成一組一組的,每組長度相等,每次加密一組數(shù)據(jù),直到加密完整個明文。在AES標準規(guī)范中,分組長度只能是128位,也就是說,每個分組為16個字節(jié)(每個字節(jié)8位)。密鑰的長度可以使用128位、192位或256位。密鑰的長度不同,推薦加密輪數(shù)也不同,如下表所示:

AES密鑰長度(32位比特字)分組長度(32位比特字)加密輪數(shù)
AES-1284410AES-1926412AES-2568414

3. 非對稱加密#

非對稱加密算法的特點是,秘鑰一次會生成一對,其中一份秘鑰由自己保存,不能公開出去,稱為“私鑰”,另外一份是可以公開出去的,稱為“公鑰”。

將原文用公鑰進行加密,得到的密文只有用對應私鑰才可以解密得到原文;

將原文用私鑰加密得到的密文,也只有用對應的公鑰才能解密得到原文;

因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。

加解密算法分析

 

與對稱加密算法的對比
  • 優(yōu)點:其安全性更好,對稱加密的通信雙方使用相同的秘鑰,如果一方的秘鑰遭泄露,那么整個通信就會被破解。而非對稱加密使用一對秘鑰,一個用來加密,一個用來解密,而且公鑰是公開的,秘鑰是自己保存的,不需要像對稱加密那樣在通信之前要先同步秘鑰。
  • 缺點:非對稱加密的缺點是加密和解密花費時間長、速度慢,只適合對少量數(shù)據(jù)進行加密。

在非對稱加密中使用的主要算法有:RSA、Elgamal、ESA、背包算法、Rabin、D-H、ECC(橢圓曲線加密算法)等。不同算法的實現(xiàn)機制不同。

非對稱加密工作原理

下面我們就看一下非對稱加密的工作原理。

  • 乙方生成一對密鑰(公鑰和私鑰)并將公鑰向其它方公開。
  • 得到該公鑰的甲方使用該密鑰對機密信息進行加密后再發(fā)送給乙方。
  • 乙方再用自己保存的另一把專用密鑰(私鑰)對加密后的信息進行解密。乙方只能用其專用密鑰(私鑰)解密由對應的公鑰加密后的信息。
  • 在傳輸過程中,即使攻擊者截獲了傳輸?shù)拿芪模⒌玫搅艘业墓€,也無法破解密文,因為只有乙的私鑰才能解密密文。同樣,如果乙要回復加密信息給甲,那么需要甲先公布甲的公鑰給乙用于加密,甲自己保存甲的私鑰用于解密。
非對稱加密鼻祖:RSA

RSA算法基于一個十分簡單的數(shù)論事實:將兩個大質(zhì)數(shù)(素數(shù))相乘十分容易,但是想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。比如:取兩個簡單的質(zhì)數(shù):67,73,得到兩者乘積很簡單4891;但是要想對4891進行因式分解,其工作量成幾何增加。

應用場景:

HTTPS請求的SSL層。

加解密算法分析

 

在JDK中也提供了RSA的實現(xiàn),下面給出示例:

Copy	/**
     * 創(chuàng)建密匙對
     *
     * @return
     */
    private KeyPair genKeyPair() {
        //創(chuàng)建 RSA Key 的生產(chǎn)者。
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");

        //利用用戶密碼作為隨機數(shù)初始化出 1024 比特 Key 的生產(chǎn)者。
        //SecureRandom 是生成安全隨機數(shù)序列,password.getBytes() 是種子,只要種子相同,序列就一樣。
        keyPairGen.initialize(1024, new SecureRandom("password".getBytes()));

        //創(chuàng)建密鑰對
        return keyPairGen.generateKeyPair();
    }


    /**
     * 生成公匙
     *
     * @return
     */
    public PublicKey genPublicKey() {
        try {
            //創(chuàng)建密鑰對
            KeyPair keyPair = genKeyPair();

            //生成公鑰
            PublicKey publicKey = keyPair.getPublic();
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            publicKey = keyFactory.generatePublic(keySpec);
            return publicKey;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 生成私匙
     *
     * @return
     */
    public PrivateKey genPrivateKey() {
        try {
            //創(chuàng)建密鑰對
            KeyPair keyPair = genKeyPair();

            //生成私匙
            PrivateKey privateKey = keyPair.getPrivate();
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(privateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公鑰加密
     *
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey)
            throws Exception {
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey.getBytes());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 對數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > 117) {
                cache = cipher.doFinal(data, offSet, 117);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 117;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /**
     * 私鑰解密
     *
     * @param encryptedData
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData,
                                             String privateKey) throws Exception {
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey.getBytes());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > 118) {
                cache = cipher.doFinal(encryptedData, offSet, 118);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 118;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /**
     * 私鑰加密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
            throws Exception {
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(publicKey.getBytes());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > 117) {
                cache = cipher.doFinal(data, offSet, 117);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 117;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

	/**
     * 公鑰解密
     *
     * @param encryptedData
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData,
                                            String publicKey) throws Exception {
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey.getBytes());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > 118) {
                cache = cipher.doFinal(encryptedData, offSet, 118);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 118;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

4. 組合加密#

上面介紹的3種加密技術(shù),每一種都有自己的特點,比如散列技術(shù)用于特征值提取,對稱加密速度雖快但是有私匙泄露的危險,非對稱加密雖然安全但是速度卻慢。基于這些情況,現(xiàn)在的加密技術(shù)更加趨向于將這些加密的方案組合起來使用,基于此來研發(fā)新的加密算法。

mac(Message Authentication Code,消息認證碼算法)是含有密鑰散列函數(shù)算法,兼容了MD和SHA算法的特性,并在此基礎(chǔ)上加上了密鑰。因此MAC算法也經(jīng)常被稱作HMAC算法。MAC(Message Authentication Code,消息認證碼算法)是含有密鑰散列函數(shù)算法,HMAC加密可以理解為加鹽的散列算法,此處的“鹽”就相當于HMAC算法的秘鑰。

HMAC算法的實現(xiàn)過程需要一個加密用的散列函數(shù)(表示為H)和一個密鑰。

經(jīng)過MAC算法得到的摘要值也可以使用十六進制編碼表示,其摘要值得長度與實現(xiàn)算法的摘要值長度相同。例如 HmacSHA算法得到的摘要長度就是SHA1算法得到的摘要長度,都是160位二進制數(shù),換算成十六進制的編碼為40位。

MAC算法的實現(xiàn):

算法摘要長度備注HmacMD5128JAVA6實現(xiàn)HmacSHA1160JAVA6實現(xiàn)HmacSHA256256JAVA6實現(xiàn)HmacSHA384384JAVA6實現(xiàn)HmacSHA512512JAVA6實現(xiàn)HmacMD2128BouncyCastle實現(xiàn)HmacMD4128BouncyCastle實現(xiàn)HmacSHA224224BouncyCastle實現(xiàn)

過程如下:

  1. 在密鑰key后面添加0來創(chuàng)建一個長為B(64字節(jié))的字符串(str);
  2. 將上一步生成的字符串(str) 與ipad(0x36)做異或運算,形成結(jié)果字符串(istr);
  3. 將數(shù)據(jù)流data附加到第二步的結(jié)果字符串(istr)的末尾;
  4. 做md5運算于第三步生成的數(shù)據(jù)流(istr);
  5. 將第一步生成的字符串(str) 與opad(0x5c)做異或運算,形成結(jié)果字符串(ostr),再將第四步的結(jié)果(istr) 附加到第五步的結(jié)果字符串(ostr)的末尾做md5運算于第6步生成的數(shù)據(jù)流(ostr),最終輸出結(jié)果(out)

注意:如果第一步中,key的長度klen大于64字節(jié),則先進行md5運算,使其長度klen = 16字節(jié)。

JDK中的實現(xiàn):

Copypublic static void jdkHmacMD5() {
    try {
        // 初始化KeyGenerator
        KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
        // 產(chǎn)生密鑰
        SecretKey secretKey = keyGenerator.generateKey();
        // 獲取密鑰
        byte[] key = secretKey.getEncoded();
        //            byte[] key = Hex.decodeHex(new char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e'});
        // 還原密鑰
        SecretKey restoreSecretKey = new SecretKeySpec(key, "HmacMD5");
        // 實例化MAC
        Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());
        // 初始化MAC
        mac.init(restoreSecretKey);
        // 執(zhí)行摘要
        byte[] hmacMD5Bytes = mac.doFinal("data".getBytes());
        System.out.println("jdk hmacMD5:" + new String(hmacMD5Bytes));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

分享到:
標簽:算法 加解密
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定