終極武器——數(shù)字證書

數(shù)字證書也稱電子證書矾芙,由數(shù)字證書頒發(fā)認(rèn)證機(jī)構(gòu)(CA)簽發(fā)才具備可認(rèn)證性。數(shù)字證書采用了公鑰基礎(chǔ)設(shè)施(PKI)潮瓶,使用了相應(yīng)的加密算法確保網(wǎng)絡(luò)應(yīng)用安全性:

  • 非對(duì)稱加密算法用于對(duì)數(shù)據(jù)進(jìn)行加密/解密操作伟恶,確保數(shù)據(jù)的機(jī)密性。
  • 數(shù)字簽名算法用于數(shù)據(jù)進(jìn)行簽名/驗(yàn)證操作歹苦,確保數(shù)據(jù)的完整性和抗否性。
  • 消息摘要算法用于對(duì)數(shù)字證書本身做摘要處理督怜,確保數(shù)字證書完整性殴瘦。

數(shù)字證書常用算法

1、非對(duì)稱加密算法:RSA号杠、DSA(無(wú)法完成加密/解密實(shí)現(xiàn)蚪腋,這樣的數(shù)字證書不包括數(shù)據(jù)加密/解密功能)
2、簽名算法:SHA1withRSAsha1RSA
3姨蟋、消息摘要算法:SHA1

數(shù)字證書文件編碼格式

1屉凯、CER(規(guī)范編碼格式),是BER(基本編碼格式)的一個(gè)變種眼溶,使用變長(zhǎng)模式悠砚。
2、DER(卓越編碼格式)堂飞,也是BER的一個(gè)變種灌旧,并使用定長(zhǎng)模式。

公鑰基礎(chǔ)設(shè)施(PKI)

所有證書都符合PKI制定的X.509標(biāo)準(zhǔn)绰筛,如:PKCS(公鑰加密標(biāo)準(zhǔn))
PKCS常用標(biāo)準(zhǔn)如下:

公鑰加密標(biāo)準(zhǔn) 描述信息 文件名后綴
PKCS#7 密碼消息語(yǔ)法標(biāo)準(zhǔn) .p7b枢泰、.p7c、.spc
PKCS#10 證書請(qǐng)求語(yǔ)法標(biāo)準(zhǔn) .p10铝噩、.csr
PKCS#12 個(gè)人信息交換語(yǔ)法標(biāo)準(zhǔn) .p12衡蚂、.pfx

以上標(biāo)準(zhǔn)主要用于證書的申請(qǐng)和更新等操作。例如:PKCS#10文件用于證書簽發(fā)申請(qǐng),PKCS#12文件可作為JAVA中的密鑰庫(kù)或信任庫(kù)直接而使用讳窟。

數(shù)字證書模型

1、數(shù)字證書頒發(fā)流程


數(shù)字證書頒發(fā)流程

2敞恋、數(shù)字證書服務(wù)請(qǐng)求與響應(yīng)

數(shù)字證書服務(wù)請(qǐng)求與響應(yīng)

數(shù)字證書管理

KeyTool證書管理

KeyTool是JAVA中的數(shù)字證書管理工具丽啡,用于數(shù)字證書的申請(qǐng)、導(dǎo)入硬猫、導(dǎo)出和撤銷等操作补箍。KeyTool與本地密鑰庫(kù)相關(guān)聯(lián),將私鑰存于密鑰庫(kù)啸蜜,公鑰則以數(shù)字證書輸出坑雅。

1、構(gòu)建自簽名證書

下面演示先生成一個(gè)自簽名證書衬横,然后導(dǎo)出數(shù)字證書裹粤,最后打印數(shù)字證書。使用keytool工具導(dǎo)出的證書蜂林,是一個(gè)自簽名的X.509第三版類型根證書遥诉,并以Base64編碼保存。但是噪叙,沒(méi)有經(jīng)過(guò)CA機(jī)構(gòu)認(rèn)證矮锈,幾乎不具備任何法律效力。

詳細(xì)參數(shù)說(shuō)明:

生成本地?cái)?shù)字證書

D:\MyData\majx2>keytool -genkeypair -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -validity 36000 -alias www.crazyxing.com -keystore crazyxing.keystore -dname "CN=www.crazyxing.com,OU=crazyxing,O=crazyxing,L=GZ,ST=GD,C=CN"
輸入密鑰庫(kù)口令:
再次輸入新口令:
輸入 <www.crazyxing.com> 的密鑰口令
        (如果和密鑰庫(kù)口令相同, 按回車):

Warning:
JKS 密鑰庫(kù)使用專用格式睁蕾。建議使用 "keytool -importkeystore -srckeystore crazyxing.keystore -destkeystore crazyxing.keystore -deststoretype pkcs12" 遷移到行業(yè)標(biāo)準(zhǔn)格式 PKCS12苞笨。
命令參數(shù) 命令說(shuō)明
-genkeypair 表示生成密鑰
-keyalg 指定密鑰算法,這里制定RSA
-keysize 指定密鑰長(zhǎng)度子眶,默認(rèn)1024瀑凝,這里制定2048
-sigalg 指定數(shù)字簽名算法,這里指定SHA1withRSA算法
-validity 指定證書有效期壹店,這里指定為36000天
-alias 指定別名猜丹,這里www.crazyxing.com
-keystore 指定密鑰庫(kù)存儲(chǔ)位置,這里是crazyxing.keystore
-storepass 指定密碼
-dname 值得你個(gè)用戶信息

導(dǎo)出數(shù)字證書

D:\MyData\majx2>keytool -exportcert -alias www.crazyxing.com -keystore crazyxing.keystore -file crazyxing.cer -rfc
輸入密鑰庫(kù)口令:
存儲(chǔ)在文件 <crazyxing.cer> 中的證書

Warning:
JKS 密鑰庫(kù)使用專用格式硅卢。建議使用 "keytool -importkeystore -srckeystore crazyxing.keystore -destkeystore crazyxing.keystore -deststoretype pkcs12" 遷移到行業(yè)標(biāo)準(zhǔn)格式 PKCS12射窒。

D:\MyData\majx2>keytool -printcert -file crazyxing.cer
所有者: CN=www.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
發(fā)布者: CN=www.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
序列號(hào): 1b2162b5
有效期為 Sat Mar 09 22:11:16 CST 2019 至 Fri Oct 01 22:11:16 CST 2117
證書指紋:
         MD5:  A4:50:BA:56:C5:84:9A:2F:EE:73:5E:53:D2:AD:F8:4A
         SHA1: 17:FF:93:47:A6:C0:26:58:86:60:6E:8C:0A:BE:03:FE:07:53:A2:D7
         SHA256: E5:09:24:87:25:F1:C2:CE:4F:F7:D8:D6:CA:07:B8:88:01:70:A4:F1:D9:31:51:B0:C5:D2:F1:9D:F1:D8:FD:22
簽名算法名稱: SHA1withRSA
主體公共密鑰算法: 2048 位 RSA 密鑰
版本: 3

擴(kuò)展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 40 DA 0E 81 94 6C 51 41   57 4A 56 CD 21 D6 8D 5E  @....lQAWJV.!..^
0010: 38 48 96 20                                        8H.
]
]
命令參數(shù) 命令說(shuō)明
-exportcert 表示證書導(dǎo)出操作
-alias 指定別名,這里為www.crazyxing.com
-keystore 指定密鑰庫(kù)文件将塑,這里crazyxing.keystore
-file 指定導(dǎo)出文件路徑脉顿,這里為crazyxing.cer
-rfc 指定為Base64編碼格式輸出
-storepass 指定密碼

遷移到行業(yè)標(biāo)準(zhǔn)格式 PKCS12

D:\MyData\majx2>keytool -importkeystore -srckeystore crazyxing.keystore -destkeystore crazyxing.keystore -deststoretype pkcs12
輸入源密鑰庫(kù)口令:
已成功導(dǎo)入別名 www.crazyxing.com 的條目。
已完成導(dǎo)入命令: 1 個(gè)條目成功導(dǎo)入, 0 個(gè)條目失敗或取消

Warning:
已將 "crazyxing.keystore" 遷移到 Non JKS/JCEKS点寥。將 JKS 密鑰庫(kù)作為 "crazyxing.keystore.old" 進(jìn)行了備份艾疟。

D:\MyData\majx2>keytool -exportcert -alias www.crazyxing.com -keystore crazyxing.keystore -file crazyxing.p12 -rfc
輸入密鑰庫(kù)口令:
存儲(chǔ)在文件 <crazyxing.p12> 中的證書

D:\MyData\majx2>keytool -printcert -file crazyxing.p12
所有者: CN=www.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
發(fā)布者: CN=www.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
序列號(hào): 1b2162b5
有效期為 Sat Mar 09 22:11:16 CST 2019 至 Fri Oct 01 22:11:16 CST 2117
證書指紋:
         MD5:  A4:50:BA:56:C5:84:9A:2F:EE:73:5E:53:D2:AD:F8:4A
         SHA1: 17:FF:93:47:A6:C0:26:58:86:60:6E:8C:0A:BE:03:FE:07:53:A2:D7
         SHA256: E5:09:24:87:25:F1:C2:CE:4F:F7:D8:D6:CA:07:B8:88:01:70:A4:F1:D9:31:51:B0:C5:D2:F1:9D:F1:D8:FD:22
簽名算法名稱: SHA1withRSA
主體公共密鑰算法: 2048 位 RSA 密鑰
版本: 3

擴(kuò)展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 40 DA 0E 81 94 6C 51 41   57 4A 56 CD 21 D6 8D 5E  @....lQAWJV.!..^
0010: 38 48 96 20                                        8H.
]
]

2、構(gòu)建CA簽發(fā)證書

獲取CA機(jī)構(gòu)認(rèn)證的數(shù)字證書,需要將數(shù)字證書簽發(fā)申請(qǐng)(CSR)導(dǎo)出蔽莱,經(jīng)由CA機(jī)構(gòu)認(rèn)證并頒發(fā)弟疆,同時(shí)將認(rèn)證后的證書導(dǎo)入本地鑰匙庫(kù)和信任庫(kù)。

導(dǎo)出數(shù)字證書簽發(fā)申請(qǐng)

D:\MyData\majx2>keytool -certreq -alias www.crazyxing.com -keystore crazyxing.keystore -file crazyxing.pfx -v
輸入密鑰庫(kù)口令:
存儲(chǔ)在文件 <crazyxing.pfx> 中的認(rèn)證請(qǐng)求
將此提交給您的 CA
命令參數(shù) 命令說(shuō)明
-certreq 表示數(shù)字證書申請(qǐng)操作
-alias 指定別名盗冷,這里為www.crazyxing.com
-keystore 指定密鑰庫(kù)文件怠苔,這里crazyxing.keystore
-flie 指定導(dǎo)出文件路徑,這里crazyxing.pfx(文件后綴仪糖,參考PKCS常用標(biāo)準(zhǔn))
-v 詳細(xì)信息
-storepass 指定密碼

導(dǎo)入數(shù)字證書

D:\MyData\majx2>keytool -delete -alias www.crazyxing.com -keystore crazyxing.keystore
輸入密鑰庫(kù)口令:

D:\MyData\majx2>keytool -importcert -trustcacerts -alias www.crazyxing.com -file crazyxing.p12 -keystore crazyxing.keystore
輸入密鑰庫(kù)口令:
所有者: CN=www.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
發(fā)布者: CN=www.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
序列號(hào): 1b2162b5
有效期為 Sat Mar 09 22:11:16 CST 2019 至 Fri Oct 01 22:11:16 CST 2117
證書指紋:
         MD5:  A4:50:BA:56:C5:84:9A:2F:EE:73:5E:53:D2:AD:F8:4A
         SHA1: 17:FF:93:47:A6:C0:26:58:86:60:6E:8C:0A:BE:03:FE:07:53:A2:D7
         SHA256: E5:09:24:87:25:F1:C2:CE:4F:F7:D8:D6:CA:07:B8:88:01:70:A4:F1:D9:31:51:B0:C5:D2:F1:9D:F1:D8:FD:22
簽名算法名稱: SHA1withRSA
主體公共密鑰算法: 2048 位 RSA 密鑰
版本: 3

擴(kuò)展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 40 DA 0E 81 94 6C 51 41   57 4A 56 CD 21 D6 8D 5E  @....lQAWJV.!..^
0010: 38 48 96 20                                        8H.
]
]

是否信任此證書? [否]:  是
證書已添加到密鑰庫(kù)中

D:\MyData\majx2>keytool -list -alias www.crazyxing.com -keystore crazyxing.keystore
輸入密鑰庫(kù)口令:
www.crazyxing.com, 2019-3-9, trustedCertEntry,
證書指紋 (SHA1): 17:FF:93:47:A6:C0:26:58:86:60:6E:8C:0A:BE:03:FE:07:53:A2:D7
命令參數(shù) 命令說(shuō)明
-importcert 表示導(dǎo)入數(shù)字證書
-trustcacerts 表示將數(shù)字證書導(dǎo)入信任庫(kù)
-alias 指定別名 www.crazyxing.com
-file 指定導(dǎo)入證書的文件路徑柑司,這里為crazyxing.p12
-keystore 指定密鑰庫(kù)文件,這里為crazyxing.keystore
-storepass 指定密碼

3锅劝、證書的使用

先實(shí)現(xiàn)一個(gè)認(rèn)證工具:

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.crypto.Cipher;

public abstract class CertificateCoder {

    /**
     * 類型證書X509
     */
    public static final String CERT_TYPE = "X.509";

    /**
     * 由KeyStore獲得私鑰
     * 
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return PrivateKey 私鑰
     * @throws Exception
     */
    private static PrivateKey getPrivateKeyByKeyStore(String keyStorePath,
            String alias, String password) throws Exception {

        // 獲得密鑰庫(kù)
        KeyStore ks = getKeyStore(keyStorePath, password);

        // 獲得私鑰
        return (PrivateKey) ks.getKey(alias, password.toCharArray());

    }

    /**
     * 由Certificate獲得公鑰
     * 
     * @param certificatePath
     *            證書路徑
     * @return PublicKey 公鑰
     * @throws Exception
     */
    private static PublicKey getPublicKeyByCertificate(String certificatePath)
            throws Exception {

        // 獲得證書
        Certificate certificate = getCertificate(certificatePath);

        // 獲得公鑰
        return certificate.getPublicKey();

    }

    /**
     * 獲得Certificate
     * 
     * @param certificatePath
     *            證書路徑
     * @return Certificate 證書
     * @throws Exception
     */
    private static Certificate getCertificate(String certificatePath)
            throws Exception {

        // 實(shí)例化證書工廠
        CertificateFactory certificateFactory = CertificateFactory
                .getInstance(CERT_TYPE);

        // 取得證書文件流
        FileInputStream in = new FileInputStream(certificatePath);

        // 生成證書
        Certificate certificate = certificateFactory.generateCertificate(in);

        // 關(guān)閉證書文件流
        in.close();

        return certificate;
    }

    /**
     * 獲得Certificate
     * 
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return Certificate 證書
     * @throws Exception
     */
    private static Certificate getCertificate(String keyStorePath,
            String alias, String password) throws Exception {

        // 獲得密鑰庫(kù)
        KeyStore ks = getKeyStore(keyStorePath, password);

        // 獲得證書
        return ks.getCertificate(alias);
    }

    /**
     * 獲得KeyStore
     * 
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param password
     *            密碼
     * @return KeyStore 密鑰庫(kù)
     * @throws Exception
     */
    private static KeyStore getKeyStore(String keyStorePath, String password)
            throws Exception {

        // 實(shí)例化密鑰庫(kù)
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

        // 獲得密鑰庫(kù)文件流
        FileInputStream is = new FileInputStream(keyStorePath);

        // 加載密鑰庫(kù)
        ks.load(is, password.toCharArray());

        // 關(guān)閉密鑰庫(kù)文件流
        is.close();

        return ks;
    }

    /**
     * 私鑰加密
     * 
     * @param data
     *            待加密數(shù)據(jù)
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return byte[] 加密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {

        // 取得私鑰
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
                password);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**
     * 私鑰解密
     * 
     * @param data
     *            待解密數(shù)據(jù)
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return byte[] 解密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {

        // 取得私鑰
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
                password);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**
     * 公鑰加密
     * 
     * @param data
     *            待加密數(shù)據(jù)
     * @param certificatePath
     *            證書路徑
     * @return byte[] 加密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {

        // 取得公鑰
        PublicKey publicKey = getPublicKeyByCertificate(certificatePath);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**
     * 公鑰解密
     * 
     * @param data
     *            待解密數(shù)據(jù)
     * @param certificatePath
     *            證書路徑
     * @return byte[] 解密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {

        // 取得公鑰
        PublicKey publicKey = getPublicKeyByCertificate(certificatePath);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**
     * 簽名
     * 
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return byte[] 簽名
     * @throws Exception
     */
    public static byte[] sign(byte[] sign, String keyStorePath, String alias,
            String password) throws Exception {

        // 獲得證書
        X509Certificate x509Certificate = (X509Certificate) getCertificate(
                keyStorePath, alias, password);

        // 構(gòu)建簽名攒驰,由證書指定簽名算法
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());

        // 獲取私鑰
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
                password);

        // 初始化簽名,由私鑰構(gòu)建
        signature.initSign(privateKey);

        signature.update(sign);

        return signature.sign();
    }

    /**
     * 驗(yàn)證簽名
     * 
     * @param data
     *            數(shù)據(jù)
     * @param sign
     *            簽名
     * @param certificatePath
     *            證書路徑
     * @return boolean 驗(yàn)證通過(guò)為真
     * @throws Exception
     */
    public static boolean verify(byte[] data, byte[] sign,
            String certificatePath) throws Exception {

        // 獲得證書
        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);

        // 由證書構(gòu)建簽名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());

        // 由證書初始化簽名故爵,實(shí)際上是使用了證書中的公鑰
        signature.initVerify(x509Certificate);

        signature.update(data);

        return signature.verify(sign);

    }

}

下面是相應(yīng)的單元測(cè)試:

import org.apache.commons.codec.binary.Hex;
import org.junit.Test;
import static org.junit.Assert.*;

public class CertificateCoderTest {

    private String password = "123456";
    
    private String alias = "www.crazyxing.com";
    
    private String certificatePath = "D:/MyData/majx2/crazyxing.cer";
    
    private String keyStorePath = "D:/MyData/majx2/crazyxing.keystore.old";

    /**
     * 公鑰加密——私鑰解密
     * 
     * @throws Exception
     */
    @Test
    public void test1() throws Exception {

        System.err.println("公鑰加密——私鑰解密");
        String inputStr = "Ceritifcate";
        byte[] data = inputStr.getBytes();

        // 公鑰加密
        byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
                certificatePath);

        // 私鑰解密
        byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
                keyStorePath, alias, password);
        String outputStr = new String(decrypt);

        System.err.println("加密前:\n" + inputStr);

        System.err.println("解密后:\n" + outputStr);

        // 驗(yàn)證數(shù)據(jù)一致
        assertArrayEquals(data, decrypt);

    }

    /**
     * 私鑰加密——公鑰解密
     * 
     * @throws Exception
     */
    @Test
    public void test2() throws Exception {

        System.err.println("私鑰加密——公鑰解密");

        String inputStr = "sign";
        byte[] data = inputStr.getBytes();

        // 私鑰加密
        byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
                keyStorePath, alias, password);

        // 公鑰加密
        byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
                certificatePath);

        String outputStr = new String(decodedData);

        System.err.println("加密前:\n" + inputStr);
        System.err.println("解密后:\n" + outputStr);

        // 校驗(yàn)
        assertEquals(inputStr, outputStr);
    }

    /**
     * 簽名驗(yàn)證
     * 
     * @throws Exception
     */
    @Test
    public void testSign() throws Exception {

        String inputStr = "簽名";
        byte[] data = inputStr.getBytes();
        System.err.println("私鑰簽名——公鑰驗(yàn)證");

        // 產(chǎn)生簽名
        byte[] sign = CertificateCoder
                .sign(data, keyStorePath, alias, password);
        System.err.println("簽名:\n" + Hex.encodeHexString(sign));

        // 驗(yàn)證簽名
        boolean status = CertificateCoder.verify(data, sign, certificatePath);
        System.err.println("狀態(tài):\n" + status);
        
        // 校驗(yàn)
        assertTrue(status);

    }

}

OpenSSL證書管理

下面示例生成雙向認(rèn)證所需的全部證書玻粪。

安裝OpenSSL工具

1、首先下載OpenSSL
http://slproweb.com/download/Win64OpenSSL-1_1_1b.exe

2诬垂、給OpenSSL設(shè)置環(huán)境變量


設(shè)置環(huán)境變量
設(shè)置Path

3奶段、修改ca證書路徑
編輯%OpenSSL_HOME%\bin\openssl.cfg配置文件,設(shè)置ca路徑


修改配置文件

4剥纷、構(gòu)建CA目錄結(jié)構(gòu)

D:\MyData\majx2>mkdir demoCA

D:\MyData\majx2>cd demoCA
# 構(gòu)建已發(fā)行證書存放目錄
D:\MyData\majx2\demoCA>mkdir certs
# 構(gòu)建新證書存放目錄
D:\MyData\majx2\demoCA>mkdir newcerts
# 構(gòu)建私鑰存放目錄
D:\MyData\majx2\demoCA>mkdir private
# 構(gòu)建證書吊銷列表存放目錄
D:\MyData\majx2\demoCA>mkdir cr1
# 構(gòu)建索引文件
D:\MyData\majx2\demoCA>echo 0>index.txt
# 構(gòu)建序列號(hào)文件
D:\MyData\majx2\demoCA>echo 01>serial

構(gòu)建根證書

1痹籍、構(gòu)建隨機(jī)數(shù)

D:\MyData\majx2\demoCA>openssl rand -out private/.rand 1000
命令參數(shù) 命令說(shuō)明
-rand 隨機(jī)數(shù)命令
-out 輸出文件路徑,這里將隨機(jī)數(shù)文件輸出到private目錄下

2晦鞋、構(gòu)建根證書
openssl通常使用PEM(隱私增強(qiáng)郵件)編碼格式保存私鑰

D:\MyData\majx2\demoCA>openssl genrsa -aes256 -out private/ca.key.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
...............................................+++++
...................+++++
e is 65537 (0x010001)
Enter pass phrase for private/ca.key.pem:
Verifying - Enter pass phrase for private/ca.key.pem:
命令參數(shù) 命令說(shuō)明
genrsa 產(chǎn)生RSA密鑰命令
-aes256 使用AES算法(256位密鑰)對(duì)產(chǎn)生的私鑰加密蹲缠。可選算法包括DES/DESede/IDEA/AES
-out 輸出路徑悠垛,這里是private/ca.key.pem

3线定、生成根證書簽發(fā)申請(qǐng)

D:\MyData\majx2\demoCA>openssl req -new -key private/ca.key.pem -out private/ca.csr -subj "/C=CN/ST=GD/L=GZ/O=crazyxing/OU=crazyxing/CN=*.crazyxing.com"
Enter pass phrase for private/ca.key.pem:
命令參數(shù) 命令說(shuō)明
req 生成證書簽發(fā)申請(qǐng)命令
-new 表示新請(qǐng)求
-key 密鑰,這里pirvate/ca.key.pem文件
-out 輸出路徑确买,這里private/ca.csr文件
-subj 指定用戶信息斤讥,這里使用泛域名"*.crazyxing.com"作為用戶名

4、簽發(fā)根證書
得到根證書申請(qǐng)文件后湾趾,可以發(fā)送給CA機(jī)構(gòu)簽發(fā)芭商,也可以自行簽發(fā)根證書

D:\MyData\majx2\demoCA>openssl x509 -req -days 10000 -sha1 -extensions v3_ca -signkey private/ca.key.pem -in private/ca.csr -out certs/ca.cer
Signature ok
subject=C = CN, ST = GD, L = GZ, O = crazyxing, OU = crazyxing, CN = *.crazyxing.com
Getting Private key
Enter pass phrase for private/ca.key.pem:
命令參數(shù) 命令說(shuō)明
x509 簽發(fā)X.509格式證書命令
-req 表示證書輸入請(qǐng)求
-days 表示有效天數(shù),這里10000天
-sha1 表示證書摘要算法搀缠,這里為SHA1算法
-extensions 表示按OpenSSL配置文件v3_ca項(xiàng)添加擴(kuò)展
-signkey 表示自簽名密鑰铛楣,這里private/ca.key.pem
-in 表示輸入文件,這里private/ca.csr
-out 表示輸出文件艺普,這里certs/ca.cer

5簸州、根證書轉(zhuǎn)換
OpenSSL產(chǎn)生的數(shù)字證書不能在Java語(yǔ)言中直接使用鉴竭,需要將其轉(zhuǎn)化成PKCS#12編碼格式

D:\MyData\majx2\demoCA>openssl pkcs12 -export -cacerts -inkey private/ca.key.pem -in certs/ca.cer -out certs/ca.p12
Enter pass phrase for private/ca.key.pem:
Enter Export Password:
Verifying - Enter Export Password:

D:\MyData\majx2\demoCA>keytool -list -keystore certs/ca.p12 -storetype pkcs12 -v -storepass 123456
密鑰庫(kù)類型: PKCS12
密鑰庫(kù)提供方: SunJSSE

您的密鑰庫(kù)包含 1 個(gè)條目

別名: 1
創(chuàng)建日期: 2019-3-10
條目類型: PrivateKeyEntry
證書鏈長(zhǎng)度: 1
證書[1]:
所有者: CN=*.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
發(fā)布者: CN=*.crazyxing.com, OU=crazyxing, O=crazyxing, L=GZ, ST=GD, C=CN
序列號(hào): 6fad9a9cb9fb61a60c976403ee5fe42228c956fa
有效期為 Sun Mar 10 09:29:11 CST 2019 至 Thu Jul 26 09:29:11 CST 2046
證書指紋:
         MD5:  4D:FA:6B:F3:A9:91:16:37:34:C1:7E:E3:66:1B:3C:A3
         SHA1: F8:52:09:30:17:02:07:CF:82:45:4C:92:66:7A:85:73:C6:BE:40:4D
         SHA256: 03:5B:03:ED:C8:15:9F:B5:76:3F:F6:F9:43:EB:7D:4A:ED:B5:6F:88:73:0D:C2:7C:3C:CB:08:6A:04:05:56:F4
簽名算法名稱: SHA1withRSA
主體公共密鑰算法: 2048 位 RSA 密鑰
版本: 1


*******************************************
*******************************************
命令參數(shù) 命令說(shuō)明
pkcs12 PKCS#12編碼格式證書命令
-export 表示導(dǎo)出證書
-cacerts 表示僅導(dǎo)出CA證書
-inkey 表示輸入密鑰,這里為private/ca.key.pem
-in 表示輸入文件岸浑,這里為certs/ca.cer
-out 表示輸出文件搏存,這里為certs/ca.p12

構(gòu)建服務(wù)器證書

1、構(gòu)建服務(wù)器私鑰

D:\MyData\majx2\demoCA>openssl genrsa -aes256 -out private/server.key.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.......................................+++++
.................................................................................................................................................+++++
e is 65537 (0x010001)
Enter pass phrase for private/server.key.pem:
Verifying - Enter pass phrase for private/server.key.pem:
命令參數(shù) 命令說(shuō)明
genrsa 產(chǎn)生RSA密鑰命令
-aes256 使用AES算法(256位密鑰)對(duì)產(chǎn)生的私鑰加密矢洲〖拦。可選算法包括DES/DESede/IDEA/AES
-out 輸出路徑,這里是private/server.key.pem

2兵钮、生成服務(wù)器證書簽發(fā)申請(qǐng)

D:\MyData\majx2\demoCA>openssl req -new -key private/server.key.pem -out private/server.csr -subj "/C=CN/ST=GD/L=GZ/O=crazyxing/OU=crazyxing/CN=www.crazyxing.com"
Enter pass phrase for private/server.key.pem:
命令參數(shù) 命令說(shuō)明
req 生成證書簽發(fā)申請(qǐng)命令
-new 表示新請(qǐng)求
-key 密鑰,這里pirvate/server.key.pem文件
-out 輸出路徑舌界,這里private/server.csr文件
-subj 指定用戶信息掘譬,這里使用泛域名"www.crazyxing.com"作為用戶名

3、簽發(fā)服務(wù)器證書

D:\MyData\majx2\demoCA>openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA certs/ca.cer -CAkey private/ca.key.pem -CAserial ca.sr1 -CAcreateserial -in private/server.csr -out certs/server.cer
Signature ok
subject=C = CN, ST = GD, L = GZ, O = crazyxing, OU = crazyxing, CN = www.crazyxing.com
Getting CA Private Key
Enter pass phrase for private/ca.key.pem:
命令參數(shù) 命令說(shuō)明
x509 簽發(fā)X.509格式證書命令
-req 表示證書輸入請(qǐng)求
-days 表示有效天數(shù)呻拌,這里10000天
-sha1 表示證書摘要算法葱轩,這里為SHA1算法
-extensions 表示按OpenSSL配置文件v3_ca項(xiàng)添加擴(kuò)展
-CA 表示CA證書,這里certs/ca.cer
-CAkey 表示CA證書密鑰藐握,這里private/ca.key.pem
-CAserial 表示CA證書序列號(hào)文件靴拱,這里ca.sr1
-CAcreateserial 表示創(chuàng)建CA證書序列號(hào)
-in 表示輸入文件,這里private/ca.csr
-out 表示輸出文件猾普,這里certs/ca.cer

4袜炕、服務(wù)器證書轉(zhuǎn)換

D:\MyData\majx2\demoCA>openssl pkcs12 -export -clcerts -inkey private/server.key.pem -in certs/server.cer -out certs/server.p12
Enter pass phrase for private/server.key.pem:
Enter Export Password:
Verifying - Enter Export Password:
命令參數(shù) 命令說(shuō)明
pkcs12 PKCS#12編碼格式證書命令
-export 表示導(dǎo)出證書
-clcerts 表示僅導(dǎo)出客戶證書
-inkey 表示輸入密鑰,這里為private/server.key.pem
-in 表示輸入文件初家,這里為certs/server.cer
-out 表示輸出文件偎窘,這里為certs/server.p12

構(gòu)建客戶端證書

1、產(chǎn)生客戶密鑰

D:\MyData\majx2\demoCA>openssl genrsa -aes256 -out private/client.key.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
................................................................................................+++++
.................+++++
e is 65537 (0x010001)
Enter pass phrase for private/client.key.pem:
Verifying - Enter pass phrase for private/client.key.pem:
命令參數(shù) 命令說(shuō)明
genrsa 產(chǎn)生RSA密鑰命令
-aes256 使用AES算法(256位密鑰)對(duì)產(chǎn)生的私鑰加密溜在∧爸可選算法包括DES/DESede/IDEA/AES
-out 輸出路徑,這里是private/server.key.pem

2掖肋、生成客戶證書簽發(fā)申請(qǐng)

D:\MyData\majx2\demoCA>openssl req -new -key private/client.key.pem -out private/client.csr -subj "/C=CN/ST=GD/L=GZ/O=crazyxing/OU=crazyxing/CN=crazyxing"
Enter pass phrase for private/client.key.pem:
命令參數(shù) 命令說(shuō)明
req 生成證書簽發(fā)申請(qǐng)命令
-new 表示新請(qǐng)求
-key 密鑰仆葡,這里pirvate/client.key.pem文件
-out 輸出路徑,這里private/client.csr文件
-subj 指定用戶信息志笼,這里使用"crazyxing"作為用戶名

3沿盅、簽發(fā)客戶證書

D:\MyData\majx2\demoCA>openssl ca -days 3650 -in private/client.csr -out certs/client.cer -cert certs/ca.cer -keyfile private/ca.key.pem
Using configuration from C:\Program Files\Common Files\SSL/openssl.cnf
Enter pass phrase for private/ca.key.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Mar 10 02:44:01 2019 GMT
            Not After : Mar  7 02:44:01 2029 GMT
        Subject:
            countryName               = CN
            stateOrProvinceName       = GD
            organizationName          = crazyxing
            organizationalUnitName    = crazyxing
            commonName                = crazyxing
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                AB:6F:ED:7E:D7:15:C2:6B:8C:F4:C7:5E:20:5A:15:A0:5C:DF:ED:8E
            X509v3 Authority Key Identifier:
                DirName:/C=CN/ST=GD/L=GZ/O=crazyxing/OU=crazyxing/CN=*.crazyxing.com
                serial:6F:AD:9A:9C:B9:FB:61:A6:0C:97:64:03:EE:5F:E4:22:28:C9:56:FA

Certificate is to be certified until Mar  7 02:44:01 2029 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
命令參數(shù) 命令說(shuō)明
ca 簽發(fā)證書命令
-days 表示有效天數(shù),這里3650天
-in 表示輸入文件纫溃,這里private/client.csr
-out 表示輸出文件嗡呼,這里certs/client.cer
-cert 表示證書文件,這里為certs/ca.cer
-keyfile 表示根證書密鑰文件皇耗,這里為private/ca.key.pem

4南窗、客戶證書轉(zhuǎn)換

D:\MyData\majx2\demoCA>openssl pkcs12 -export -inkey private/client.key.pem -in certs/client.cer -out certs/client.p12
Enter pass phrase for private/client.key.pem:
Enter Export Password:
Verifying - Enter Export Password:
命令參數(shù) 命令說(shuō)明
pkcs12 PKCS#12編碼格式證書命令
-export 表示導(dǎo)出證書
-clcerts 表示僅導(dǎo)出客戶證書
-inkey 表示輸入密鑰,這里為private/client.key.pem
-in 表示輸入文件,這里為certs/client.cer
-out 表示輸出文件万伤,這里為certs/client.p12

證書使用

先給出一個(gè)證書工具類

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.crypto.Cipher;

public abstract class CertificateCoder {

    /**
     * 證書類型X509
     */
    public static final String CERT_TYPE = "X.509";

    /**
     * 密鑰庫(kù)類型PCKS12
     */
    private static final String STORE_TYPE = "PKCS12";

    /**
     * 由KeyStore獲得私鑰
     * 
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return PrivateKey 私鑰
     * @throws Exception
     */
    public static PrivateKey getPrivateKeyByKeyStore(String keyStorePath,
            String alias, String password) throws Exception {

        // 獲得密鑰庫(kù)
        KeyStore ks = getKeyStore(keyStorePath, password);

        // 獲得私鑰
        return (PrivateKey) ks.getKey(alias, password.toCharArray());

    }

    /**
     * 由Certificate獲得公鑰
     * 
     * @param certificatePath
     *            證書路徑
     * @return PublicKey 公鑰
     * @throws Exception
     */
    public static PublicKey getPublicKeyByCertificate(String certificatePath)
            throws Exception {

        // 獲得證書
        Certificate certificate = getCertificate(certificatePath);

        // 獲得公鑰
        return certificate.getPublicKey();

    }

    /**
     * 獲得Certificate
     * 
     * @param certificatePath
     *            證書路徑
     * @return Certificate 證書
     * @throws Exception
     */
    private static X509Certificate getCertificate(String certificatePath)
            throws Exception {

        // 實(shí)例化證書工廠
        CertificateFactory certificateFactory = CertificateFactory
                .getInstance(CERT_TYPE);

        // 取得證書文件流
        FileInputStream in = new FileInputStream(certificatePath);

        // 生成證書
        Certificate certificate = certificateFactory.generateCertificate(in);

        // 關(guān)閉證書文件流
        in.close();

        return (X509Certificate) certificate;
    }

    /**
     * 獲得KeyStore
     * 
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param password
     *            密碼
     * @return KeyStore 密鑰庫(kù)
     * @throws Exception
     */
    private static KeyStore getKeyStore(String keyStorePath, String password)
            throws Exception {

        // 實(shí)例化密鑰庫(kù)
        KeyStore ks = KeyStore.getInstance(STORE_TYPE);

        // 獲得密鑰庫(kù)文件流
        FileInputStream in = new FileInputStream(keyStorePath);
        // 加載密鑰庫(kù)
        ks.load(in, password.toCharArray());

        // 關(guān)閉密鑰庫(kù)文件流
        in.close();

        return ks;
    }

    /**
     * 私鑰加密
     * 
     * @param data
     *            待加密數(shù)據(jù)
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return byte[] 加密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {

        // 取得私鑰
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
                password);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**
     * 私鑰解密
     * 
     * @param data
     *            待解密數(shù)據(jù)
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return byte[] 解密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
            String alias, String password) throws Exception {

        // 取得私鑰
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
                password);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**
     * 公鑰加密
     * 
     * @param data
     *            待加密數(shù)據(jù)
     * @param certificatePath
     *            證書路徑
     * @return byte[] 加密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {

        // 取得公鑰
        PublicKey publicKey = getPublicKeyByCertificate(certificatePath);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**
     * 公鑰解密
     * 
     * @param data
     *            待解密數(shù)據(jù)
     * @param certificatePath
     *            證書路徑
     * @return byte[] 解密數(shù)據(jù)
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
            throws Exception {

        // 取得公鑰
        PublicKey publicKey = getPublicKeyByCertificate(certificatePath);

        // 對(duì)數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**
     * 簽名
     * 
     * @param keyStorePath
     *            密鑰庫(kù)路徑
     * @param alias
     *            別名
     * @param password
     *            密碼
     * @return byte[] 簽名
     * @throws Exception
     */
    public static byte[] sign(byte[] sign, String keyStorePath, String alias,
            String password, String certificatePath) throws Exception {

        // 獲得證書
        X509Certificate x509Certificate = getCertificate(certificatePath);

        // 構(gòu)建簽名窒悔,由證書指定簽名算法
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());

        // 獲取私鑰
        PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
                password);

        // 初始化簽名,由私鑰構(gòu)建
        signature.initSign(privateKey);

        signature.update(sign);

        return signature.sign();
    }

    /**
     * 驗(yàn)證簽名
     * 
     * @param data
     *            數(shù)據(jù)
     * @param sign
     *            簽名
     * @param certificatePath
     *            證書路徑
     * @return boolean 驗(yàn)證通過(guò)為真
     * @throws Exception
     */
    public static boolean verify(byte[] data, byte[] sign,
            String certificatePath) throws Exception {

        // 獲得證書
        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);

        // 由證書構(gòu)建簽名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());

        // 由證書初始化簽名敌买,實(shí)際上是使用了證書中的公鑰
        signature.initVerify(x509Certificate);

        signature.update(data);

        return signature.verify(sign);

    }

}

下面是相應(yīng)的單元測(cè)試

import org.apache.commons.codec.binary.Hex;
import org.junit.Test;
import static org.junit.Assert.*;

public class CertificateCoderTest {

    private String password = "123456";

    private String alias = "1";

    private String certificatePath = "D:/MyData/majx2/demoCA/certs/ca.cer";

    private String keyStorePath = "D:/MyData/majx2/demoCA/certs/ca.p12";

    /**
     * 公鑰加密——私鑰解密
     * 
     * @throws Exception
     */
    @Test
    public void test1() {

        try {
            System.err.println("公鑰加密——私鑰解密");
            String inputStr = "Ceritifcate";
            byte[] data = inputStr.getBytes();

            // 公鑰加密
            byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
                    certificatePath);

            // 私鑰解密
            byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
                    keyStorePath, alias, password);

            String outputStr = new String(decrypt);

            System.err.println("加密前:\n" + inputStr);

            System.err.println("解密后:\n" + outputStr);

            // 驗(yàn)證數(shù)據(jù)一致
            assertArrayEquals(data, decrypt);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            fail(e.getMessage());
        }

    }

    /**
     * 私鑰加密——公鑰解密
     * 
     * @throws Exception
     */
    @Test
    public void test2() {

        System.err.println("私鑰加密——公鑰解密");

        String inputStr = "sign";
        byte[] data = inputStr.getBytes();

        try {
            // 私鑰加密
            byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
                    keyStorePath, alias, password);

            // 公鑰加密
            byte[] decodedData = CertificateCoder.decryptByPublicKey(
                    encodedData, certificatePath);

            String outputStr = new String(decodedData);

            System.err.println("加密前:\n" + inputStr);
            System.err.println("解密后:\n" + outputStr);

            // 校驗(yàn)
            assertEquals(inputStr, outputStr);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            fail(e.getMessage());
        }
    }

    /**
     * 簽名驗(yàn)證
     * 
     * @throws Exception
     */
    @Test
    public void testSign() {

        try {
            String inputStr = "簽名";
            byte[] data = inputStr.getBytes();
            System.err.println("私鑰簽名——公鑰驗(yàn)證");

            // 產(chǎn)生簽名
            byte[] sign = CertificateCoder.sign(data, keyStorePath, alias,
                    password,certificatePath);
            System.err.println("簽名:\n" + Hex.encodeHexString(sign));

            // 驗(yàn)證簽名
            boolean status = CertificateCoder.verify(data, sign,
                    certificatePath);
            System.err.println("狀態(tài):\n" + status);

            // 校驗(yàn)
            assertTrue(status);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            fail(e.getMessage());
        }

    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末简珠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子虹钮,更是在濱河造成了極大的恐慌聋庵,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芙粱,死亡現(xiàn)場(chǎng)離奇詭異祭玉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)春畔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門脱货,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人律姨,你說(shuō)我怎么就攤上這事振峻。” “怎么了择份?”我有些...
    開(kāi)封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵扣孟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我荣赶,道長(zhǎng)哈打,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任讯壶,我火速辦了婚禮料仗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伏蚊。我一直安慰自己立轧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布躏吊。 她就那樣靜靜地躺著氛改,像睡著了一般。 火紅的嫁衣襯著肌膚如雪比伏。 梳的紋絲不亂的頭發(fā)上胜卤,一...
    開(kāi)封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音赁项,去河邊找鬼葛躏。 笑死澈段,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舰攒。 我是一名探鬼主播败富,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼摩窃!你這毒婦竟也來(lái)了兽叮?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤猾愿,失蹤者是張志新(化名)和其女友劉穎鹦聪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蒂秘,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泽本,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了材彪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡琴儿,死狀恐怖段化,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情造成,我是刑警寧澤显熏,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站晒屎,受9級(jí)特大地震影響喘蟆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鼓鲁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一蕴轨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骇吭,春花似錦橙弱、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至龙致,卻和暖如春蛀缝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背目代。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工屈梁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嗤练,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓俘闯,卻偏偏與公主長(zhǎng)得像潭苞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子真朗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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

  • 1 基礎(chǔ) 1.1 對(duì)稱算法 描述:對(duì)稱加密是指加密過(guò)程和解密過(guò)程使用相同的密碼此疹。主要分:分組加密、序列加密遮婶。 原理...
    御淺永夜閱讀 2,393評(píng)論 1 4
  • 數(shù)字證書就是網(wǎng)絡(luò)通訊中標(biāo)志通訊各方身份信息的一系列數(shù)據(jù)蝗碎,其作用類似于現(xiàn)實(shí)生活中的身份證。它是由一個(gè)權(quán)威機(jī)構(gòu)發(fā)行的旗扑,...
    拉肚閱讀 21,139評(píng)論 1 17
  • 所有的概念都基于一個(gè)非常重要的基礎(chǔ): rsa 非對(duì)稱加密算法 : 在加解密上致燥,兩個(gè)秘鑰是對(duì)等的 任何一個(gè)可以加密登疗,...
    嘿嘿嘿_y閱讀 2,278評(píng)論 1 3
  • 文中首先解釋了加密解密的一些基礎(chǔ)知識(shí)和概念,然后通過(guò)一個(gè)加密通信過(guò)程的例子說(shuō)明了加密算法的作用嫌蚤,以及數(shù)字證書的出現(xiàn)...
    納蘭三少閱讀 1,917評(píng)論 1 6
  • 先給大家普及下陳丹青和《退步集》: 陳丹青辐益,畫家、文藝評(píng)論家脱吱、作家智政。1953年生于上海,1978年考入中央美術(shù)學(xué)院...
    林瀟Ena閱讀 948評(píng)論 0 4