3.1 DH算法簡介

非對稱加密算法 - DH算法

DH算法是非對稱加密算法的鼻祖轮纫,為非對稱加密算法奠定了基礎(chǔ)捎稚,主要用途是進(jìn)行密鑰交換棉饶。

DH算法歷史

1976年非對稱加密算法思想被提出表箭,但是當(dāng)時(shí)并沒有給出具體算法和方案赁咙,因?yàn)楫?dāng)時(shí)沒有研究出單向函數(shù)(也就是信息摘要算法還沒出現(xiàn)),但是IEEE的期刊(作者:W.Diffie和M.Hellman)中給出了通信時(shí)雙方如何通過信息交換協(xié)商密鑰的算法燃逻,也就是DH算法序目,通過該算法雙方可以協(xié)商對稱加密的密鑰。

DH算法的目的僅在于<b>雙方在安全的環(huán)境下協(xié)商一個(gè)加解密的密鑰</b>伯襟,因此僅僅用于密鑰分配猿涨,不能用于加解密消息。

應(yīng)用場景

僅用于密鑰交換場景姆怪,不適用于數(shù)據(jù)傳輸?shù)募咏饷芘炎鏏B兩個(gè)系統(tǒng)需要交換密鑰澡绩,則過程如下:

  • A系統(tǒng)構(gòu)建密鑰:構(gòu)建一對公私密鑰Private Key1和Public Key1;
  • A系統(tǒng)向B系統(tǒng)公布自己的公鑰(Public Key1)俺附;
  • B系統(tǒng)使用A公布的公鑰(Public Key1)建立一對密鑰:Private Key2和Public Key2肥卡;
  • B系統(tǒng)向A系統(tǒng)公布自己的公鑰Public Key2;
  • A系統(tǒng)使用自己的私鑰Private Key1和B系統(tǒng)的公鑰Public Key2構(gòu)建本地密鑰事镣;
  • B系統(tǒng)使用自己的私鑰Private Key2和A系統(tǒng)的公鑰Public Key1構(gòu)建本地密鑰步鉴;

關(guān)鍵點(diǎn):B系統(tǒng)使用A系統(tǒng)的公鑰建立加密用的Key;

本地密鑰用來加解密數(shù)據(jù)璃哟;

雖然AB系統(tǒng)使用了不同的密鑰建立自己的本地密鑰氛琢,但是AB系統(tǒng)獲得本地密鑰是一致的。

流程描述

sequenceDiagram
A->> A: 構(gòu)建密鑰對:private key1 和 public key1
A->> B: 公布自己的公鑰: public key1
B->> B: 使用public key1構(gòu)建自己的密鑰對 private key2 和 public key2随闪;
B-->> A: 返回自己的public key2阳似;
A->> A: 使用private key1 和 public key2 構(gòu)建本地密鑰;
B->> B : 使用private key2 和 public key1構(gòu)建本地密鑰铐伴;

Java中算法實(shí)現(xiàn)

Java提供DH算法的實(shí)現(xiàn)撮奏,不用使用第三方開源包,DH算法的產(chǎn)生的密鑰長度在512到1024之間当宴,必須是64的倍數(shù)畜吊,默認(rèn)是1024。

A系統(tǒng)建立自己的密鑰對

此過程不需要參數(shù)

/***
     * A系統(tǒng)產(chǎn)生密鑰,這個(gè)過程不需要參數(shù),由DH算法計(jì)算得出<br/>
     * 內(nèi)部使用一些安全的隨機(jī)函數(shù)隨機(jī)計(jì)算出一個(gè)公私鑰<br>
     * 計(jì)算后的公私鑰要存儲下來,存儲二進(jìn)制數(shù)據(jù)
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Key> initASysKey() throws Exception {
        // 使用DH算法生成公司密鑰
        KeyPairGenerator keyPairGr = KeyPairGenerator.getInstance(KEY_ALGORITH);
        keyPairGr.initialize(KEY_SIZE);
        KeyPair keyPair = keyPairGr.generateKeyPair();

        // 可以使用DB算法專業(yè)密鑰前行轉(zhuǎn)換獲取的PublicKey和PrivateKey
        // DHPublicKey dhPK = (DHPublicKey) publicKey;
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        // 存儲,傳輸密鑰
        Map<String, Key> keyMap = new HashMap<String, Key>(2);
        keyMap.put(MAP_KEY_PUBLIC, publicKey);
        keyMap.put(MAP_KEY_PRIVATGE, privateKey);
        return keyMap;
    }

B建立自己的密鑰對

需要A系統(tǒng)發(fā)送自己的公鑰給B后即供,B才能建立自己的密鑰對:

/**
     * B構(gòu)建自己的公私鑰,要使用A的公鑰構(gòu)建<br>
     * DH算法接受公鑰,并構(gòu)建自己的密鑰對<br>
     * 這個(gè)過程中用到了一些密鑰格式轉(zhuǎn)換對象,不是重點(diǎn)<br>
     * B也要保持自己的密鑰對,二進(jìn)制形式
     * 
     * @param pubKey
     * @return
     * @throws Exception
     */
    public static Map<String, Key> initBSysKey(byte[] pubKey) throws Exception {

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITH);
        // 密鑰格式轉(zhuǎn)換對象
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
        // 轉(zhuǎn)換PublicKey格式
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        // 構(gòu)建DH算法參數(shù)
        DHParameterSpec dhParamSpec = ((DHPublicKey) publicKey).getParams();
        // 使用DH算法創(chuàng)建密鑰對
        KeyPairGenerator keyPairGr = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
        keyPairGr.initialize(dhParamSpec);
        KeyPair keyPair = keyPairGr.generateKeyPair();
        // 創(chuàng)建的公私鑰
        DHPublicKey publicKey1 = (DHPublicKey) keyPair.getPublic();
        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
        // 存儲傳輸密鑰
        Map<String, Key> keyMap = new HashMap<String, Key>(2);
        keyMap.put(MAP_KEY_PUBLIC, publicKey1);
        keyMap.put(MAP_KEY_PRIVATGE, privateKey);
        return keyMap;
    }

AB分別建立自己的本地密鑰

A定拟、B系統(tǒng)都需要對方已經(jīng)發(fā)送了公鑰給自己,使用自己的私鑰和對方的公鑰建立密鑰對逗嫡。

/**
     * 使用對方的公鑰和自己的私鑰構(gòu)建對稱加密的SecretKey<br>
     * 
     * @param publicKey
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws Exception {
        // 建立密鑰工廠
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITH);
        // 密鑰編碼轉(zhuǎn)換對象
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
        // 轉(zhuǎn)換公鑰格式
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
        // 密鑰編碼轉(zhuǎn)換對象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
        // 轉(zhuǎn)換私鑰格式
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 利用公鑰和私鑰創(chuàng)建本地密鑰
        KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
        keyAgree.init(priKey);
        keyAgree.doPhase(pubKey, true);
        // 創(chuàng)建了一個(gè)本地密鑰
        SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITH);
        return secretKey.getEncoded();
    }

AB系統(tǒng)加解密數(shù)據(jù)

使用構(gòu)建的本地密鑰對進(jìn)行數(shù)據(jù)加解密:

/**
     * 使用本地密鑰加密數(shù)據(jù)
     * 
     * @param key
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] key, byte[] data) throws Exception {
        // 構(gòu)建本地密鑰
        SecretKey secretKey = new SecretKeySpec(key, SECRET_ALGORITH);
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 使用本地密鑰解密數(shù)據(jù)
     * 
     * @param key
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] key, byte[] data) throws Exception {
        // 構(gòu)建本地密鑰
        SecretKey secretKey = new SecretKeySpec(key, SECRET_ALGORITH);
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

完整的代碼流程

NOTE:下面的代碼最后加解密步驟無法完成青自,之前提過,對稱加密技術(shù)驱证,JAVA的AES僅支持128位長度的密鑰延窜,DH最少產(chǎn)生512的密鑰,所以一般Java系統(tǒng)無法支持抹锄,需要下載授權(quán)文件逆瑞。

public class DHTest {
    // 密鑰交換算法
    public static final String KEY_ALGORITH = "DH";
    // 對稱加密算法
    public static final String SECRET_ALGORITH = "AES";
    // DH算法的密鑰長度
    private static final int KEY_SIZE = 512;
    // Map的一些參數(shù)
    private static final String MAP_KEY_PUBLIC = "DHPublicKey";
    private static final String MAP_KEY_PRIVATGE = "DHPrivateKey";

    public static void main(String[] args) throws Exception {
        // A系統(tǒng)構(gòu)建自己的公私鑰
        Map<String, Key> aKeyMap = initASysKey();
        byte[] aPubKey = aKeyMap.get(MAP_KEY_PUBLIC).getEncoded();
        byte[] aPriKey = aKeyMap.get(MAP_KEY_PRIVATGE).getEncoded();
        logKeyMap("A", aPubKey, aPriKey);

        // A將自己的公鑰發(fā)給B,B構(gòu)建自己的公私鑰
        // 一般都是發(fā)送二進(jìn)制或者base64等數(shù)據(jù)
        Map<String, Key> bKeyMap = initBSysKey(aPubKey);
        byte[] bPubKey = bKeyMap.get(MAP_KEY_PUBLIC).getEncoded();
        byte[] bPriKey = bKeyMap.get(MAP_KEY_PRIVATGE).getEncoded();
        logKeyMap("B", bPubKey, bPriKey);

        // A B系統(tǒng)產(chǎn)生自己的本地對稱加密算法密鑰
        byte[] aSecretKey = getSecretKey(bPubKey, aPriKey);
        byte[] bSecretKey = getSecretKey(aPubKey, bPriKey);

        // 轉(zhuǎn)換為字符串比較下
        String aSecKeyStr = toBase64(aSecretKey);
        String bSecKeyStr = toBase64(bSecretKey);
        log("A SecretKey : %s", aSecKeyStr);
        log("B SecretKey : %s", bSecKeyStr);
        log("A B SecretKey equeals : %s", aSecKeyStr.equals(bSecKeyStr));

        log("%s", aSecretKey.length);

        // A加密數(shù)據(jù),B解密數(shù)據(jù),能正常加解密
        String input = "A要發(fā)送給B的數(shù)據(jù)";
        byte[] data = encrypt(aSecretKey, input.getBytes());
        byte[] rs = decrypt(bSecretKey, data);
        log("A Send : %s , B Recive : %s ", toBase64(data), new String(rs));
    }

    /***
     * A系統(tǒng)產(chǎn)生密鑰,這個(gè)過程不需要參數(shù),由DH算法計(jì)算得出<br/>
     * 內(nèi)部使用一些安全的隨機(jī)函數(shù)隨機(jī)計(jì)算出一個(gè)公私鑰<br>
     * 計(jì)算后的公私鑰要存儲下來,存儲二進(jìn)制數(shù)據(jù)
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Key> initASysKey() throws Exception {
        // 使用DH算法生成公司密鑰
        KeyPairGenerator keyPairGr = KeyPairGenerator.getInstance(KEY_ALGORITH);
        keyPairGr.initialize(KEY_SIZE);
        KeyPair keyPair = keyPairGr.generateKeyPair();

        // 可以使用DB算法專業(yè)密鑰前行轉(zhuǎn)換獲取的PublicKey和PrivateKey
        // DHPublicKey dhPK = (DHPublicKey) publicKey;
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        // 存儲,傳輸密鑰
        Map<String, Key> keyMap = new HashMap<String, Key>(2);
        keyMap.put(MAP_KEY_PUBLIC, publicKey);
        keyMap.put(MAP_KEY_PRIVATGE, privateKey);
        return keyMap;
    }

    /**
     * B構(gòu)建自己的公私鑰,要使用A的公鑰構(gòu)建<br>
     * DH算法接受公鑰,并構(gòu)建自己的密鑰對<br>
     * 這個(gè)過程中用到了一些密鑰格式轉(zhuǎn)換對象,不是重點(diǎn)<br>
     * B也要保持自己的密鑰對,二進(jìn)制形式
     * 
     * @param pubKey
     * @return
     * @throws Exception
     */
    public static Map<String, Key> initBSysKey(byte[] pubKey) throws Exception {

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITH);
        // 密鑰格式轉(zhuǎn)換對象
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
        // 轉(zhuǎn)換PublicKey格式
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        // 構(gòu)建DH算法參數(shù)
        DHParameterSpec dhParamSpec = ((DHPublicKey) publicKey).getParams();
        // 使用DH算法創(chuàng)建密鑰對
        KeyPairGenerator keyPairGr = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
        keyPairGr.initialize(dhParamSpec);
        KeyPair keyPair = keyPairGr.generateKeyPair();
        // 創(chuàng)建的公私鑰
        DHPublicKey publicKey1 = (DHPublicKey) keyPair.getPublic();
        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
        // 存儲傳輸密鑰
        Map<String, Key> keyMap = new HashMap<String, Key>(2);
        keyMap.put(MAP_KEY_PUBLIC, publicKey1);
        keyMap.put(MAP_KEY_PRIVATGE, privateKey);
        return keyMap;
    }

    /**
     * 使用對方的公鑰和自己的私鑰構(gòu)建對稱加密的SecretKey<br>
     * 
     * @param publicKey
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws Exception {
        // 建立密鑰工廠
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITH);
        // 密鑰編碼轉(zhuǎn)換對象
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
        // 轉(zhuǎn)換公鑰格式
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
        // 密鑰編碼轉(zhuǎn)換對象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
        // 轉(zhuǎn)換私鑰格式
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 利用公鑰和私鑰創(chuàng)建本地密鑰
        KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
        keyAgree.init(priKey);
        keyAgree.doPhase(pubKey, true);
        // 創(chuàng)建了一個(gè)本地密鑰
        SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITH);
        return secretKey.getEncoded();
    }

    /**
     * 使用本地密鑰加密數(shù)據(jù)
     * 
     * @param key
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] key, byte[] data) throws Exception {
        // 構(gòu)建本地密鑰
        SecretKey secretKey = new SecretKeySpec(key, SECRET_ALGORITH);
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 使用本地密鑰解密數(shù)據(jù)
     * 
     * @param key
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] key, byte[] data) throws Exception {
        // 構(gòu)建本地密鑰
        SecretKey secretKey = new SecretKeySpec(key, SECRET_ALGORITH);
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    public static void log(String tmp, Object... params) {
        System.out.println(String.format(tmp, params));
    }

    public static void logKeyMap(String sysName, byte[] pubKey, byte[] priKey) {
        log("%s Public Key : %s", sysName, toBase64(pubKey));
        log("%s Private Key : %s", sysName, toBase64(priKey));
    }

    private static String toBase64(byte[] data) {
        return new String(Base64.getEncoder().encode(data));
    }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市伙单,隨后出現(xiàn)的幾起案子获高,更是在濱河造成了極大的恐慌,老刑警劉巖吻育,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件念秧,死亡現(xiàn)場離奇詭異,居然都是意外死亡布疼,警方通過查閱死者的電腦和手機(jī)摊趾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門币狠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人砾层,你說我怎么就攤上這事漩绵。” “怎么了肛炮?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵止吐,是天一觀的道長。 經(jīng)常有香客問我铸董,道長祟印,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任粟害,我火速辦了婚禮,結(jié)果婚禮上颤芬,老公的妹妹穿的比我還像新娘悲幅。我一直安慰自己,他們只是感情好站蝠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布汰具。 她就那樣靜靜地躺著,像睡著了一般菱魔。 火紅的嫁衣襯著肌膚如雪留荔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天澜倦,我揣著相機(jī)與錄音聚蝶,去河邊找鬼。 笑死藻治,一個(gè)胖子當(dāng)著我的面吹牛碘勉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桩卵,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼验靡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了雏节?” 一聲冷哼從身側(cè)響起胜嗓,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钩乍,沒想到半個(gè)月后辞州,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡件蚕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年孙技,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了产禾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牵啦,死狀恐怖亚情,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哈雏,我是刑警寧澤楞件,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站裳瘪,受9級特大地震影響土浸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜彭羹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一黄伊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧派殷,春花似錦还最、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至经伙,卻和暖如春扶叉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背帕膜。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工枣氧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泳叠。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓作瞄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親危纫。 傳聞我的和親對象是個(gè)殘疾皇子宗挥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

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

  • 文中首先解釋了加密解密的一些基礎(chǔ)知識和概念,然后通過一個(gè)加密通信過程的例子說明了加密算法的作用种蝶,以及數(shù)字證書的出現(xiàn)...
    納蘭三少閱讀 1,901評論 1 6
  • 專題一契耿,主要介紹HTTPS建立安全鏈接的原理,包括非對稱加密螃征、對稱加密搪桂、CA認(rèn)證等知識,還包括對一些業(yè)界常用算法的...
    有何不可12317閱讀 296評論 0 0
  • 文中首先解釋了加密解密的一些基礎(chǔ)知識和概念,然后通過一個(gè)加密通信過程的例子說明了加密算法的作用踢械,以及數(shù)字證書的出現(xiàn)...
    sunny沖哥閱讀 1,364評論 0 3
  • 簡介 在早期酗电,互聯(lián)網(wǎng)通信是直接以明文進(jìn)行傳輸,幾乎沒任何安全性可言内列,在你發(fā)送數(shù)據(jù)到接收者手上撵术,經(jīng)過n個(gè)網(wǎng)絡(luò)設(shè)備,在...
    li_zw閱讀 4,207評論 0 4
  • 7:45我們從榆中一中出發(fā)前往學(xué)農(nóng)地點(diǎn)话瞧。經(jīng)歷了一路的顛簸嫩与,11點(diǎn)我們終于平安到達(dá)。在當(dāng)?shù)剞r(nóng)戶的帶領(lǐng)下交排,我...
    習(xí)習(xí)晨風(fēng)閱讀 210評論 0 0