38_安全密码学基础

安全密码学

在了解安全密码学之前,我们需要补充一些额外知识。

ASCII

是基于拉丁字母的一套电脑编码系统,就好像这些字符,对应的就是十进制的65
97,简单来说就是计算机没有办法识别字符,他只理解01二进制,所以用一个字符表,规定了什么字符用什么01表示。

   @Test
    public void ascii() {
       char c1 = 'A';
       char c2 = 'a';

        System.out.println((byte)c1);
        System.out.println((byte)c2);

        //65 
        //97
    }



  @Test
    public void ascii() {
        char c1 = 'A';
        char c2 = 'a';
		
        // 字符 = 整型 无强转可替换
        int n1 = c1;
        int n2 = c2;
        System.out.println("---将字符转为十进制的ASCII码--");
        System.out.println(n1);
        System.out.println(n2);


        System.out.println("---将字符转为二进制的ASCII码--");
        String binary1 = Integer.toBinaryString(n1);
        String binary2 = Integer.toBinaryString(n2);
        System.out.println(binary1);
        System.out.println(binary2);

        /**
         *
         * ---将字符转为十进制的ASCII码--
         * 65
         * 97
         * ---将字符转为二进制的ASCII码--
         * 1000001
         * 1100001
         *
         */

    }

PBE

PBE(Password Based
Encryption,基于口令加密)算法是一种基于口令的加密算法,其特点在于口令是由用户自己掌握的,采用随机数杂凑多重加密等方法保证数据的安全性,
PBE算法没有密钥的概念,密钥在其它对称加密算法中是经过算法计算得出来的,PBE算法则是使用口令替代了密钥。

PKCS&X.509

ASN.1

在计算机界,有各种密码学标准,它们表示了如何在计算机中计算、存储、传输(等)各种算法,这些标准由 IEFT、ITU-T、ISO 等标准组织机构编写。

ASN.1(Abstract Syntax Notation One) 是 ISO 和 ITU-T
的联合标准,是描述数据的表示、编码、传输、解码的灵活的记法。它提供了一套正式、无歧义和精确的规则以描述独立于特定计算机硬件的对象结构。

ASN.1 本身只定义了表示信息的抽象句法,但是没有限定其编码的方法**。各种 ASN.1 编码规则提供了由 ASN.1
描述其抽象句法的数据的值的传送语法(具体表达)。标准的 ASN.1 编码规则有基本编码规则(BER,Basic Encoding
Rules)、规范编码规则(CER,Canonical Encoding Rules)、可分辨编码规则(DER,Distinguished Encoding
Rules)、压缩编码规则(PER,Packed Encoding Rules)和 XML 编码规则(XER,XML Encoding Rules)。

该机构从上层规定了规范,有点像IP协议ISO组织一个意思。

  • X.509

X.509 是密码学里公钥证书的格式标准。X.509 证书已应用包括 TLS/SSL
在内的众多网络协议里和一些非在线应用场景里,比如电子签名服务。X.509 证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等、
签名信息(可以是证书签发机构 CA 的签名,也可以是自签名)

  • PKCS 系列

公钥加密标准(Public Key Cryptography Standards, PKCS),此一标准的设计与发布皆由 RSA 资讯安全公司(英语:RSA
Security)所制定。

标准版本名称简介
PKCS #12.2RSA 加密规范(RSA Cryptography Standard)提供了基于 RSA
算法的公钥加密实现的建议,包括加密原语、加密方案、带附录的签名方案,以及用于表示密钥和识别方案的 ASN.1 语法。参见 RFC 8017。
PKCS #2-弃用原本是用以规范 RSA 加密摘要的转换方式,现已被纳入 PKCS #1 之中。
PKCS #31.4Diffie-Hellman 协议标准(Diffie-Hellman key agreement Standard)规范以
Diffie-Hellman 协议为基础的密钥协议标准。其功能可以让两方通过过协议,拟定一把会议密钥(Session key)。
PKCS #4-弃用原本用以规范转换 RSA 密钥的流程。已被纳入 PKCS #1 之中。
PKCS #52.1基于密码的加密规范(Password-based Encryption Standard)参见 RFC 8018。
PKCS #61.5证书扩展语法标准(Extended-Certificate Syntax Standard)将原本 X.509
的证书格式标准加以扩充。
PKCS #71.5密码讯息语法标准(Cryptographic Message Syntax Standard)参见 RFC
2315。规范了以公开密钥基础设施(PKI)所产生之签章/密文的格式。其目的一样是为了拓展数位证书的应用。其中,包含了 S/MIME 与
CMS(英语:Cryptographic Message Syntax)。
PKCS #81.2私钥信息语法规范(Private-Key Information Syntax Standard)
存储私钥信息的标准语法。参见 RFC 5208。
PKCS #92.0选择属性格式(Selected Attribute Types)定义 PKCS #6、7、8、10 的选择属性格式。
PKCS #101.7证书申请标准(Certification Request Standard)参见 RFC
2986。规范了向证书中心申请证书的 CSR(certificate signing request)的格式。
PKCS #112.20密码装置标准介面(Cryptographic Token Interface (Cryptoki))
定义了密码装置的应用程式介面(API)之规格。
PKCS #121.0个人讯息交换标准(Personal Information Exchange Syntax Standard)
定义了包含私钥与公钥证书(public key certificate)的文件格式。私钥采密码(password)保护。常见的 PFX 就履行了 PKCS
#12。
PKCS #13椭圆曲线密码学标准(Elliptic curve cryptography Standard)
制定中。规范以椭圆曲线密码学为基础所发展之密码技术应用。椭圆曲线密码学是新的密码学技术,其强度与效率皆比现行以指数运算为基础之密码学演算法来的优秀。然而,该演算法的应用尚不普及。
PKCS #14伪随机数生成器(英语:Pseudorandom number generator)标准制定中。规范伪随机数生成器的使用与设计。
PKCS #151.1密码装置讯息格式标准(Cryptographic Token Information Format Standard)
定义了密码设备内部数据的组织结构。

Base64

Base64只是更利于数据显示,并不具备加密效果。

  • 能表示的全部字符

因为Base64编码会把字节按照6bit 为一组进行划分,而6位所表示的二进制数的范围就是 000000 ~ 111111

能表示的字符如下所示:

![image-20221225144720292](https://img-
blog.csdnimg.cn/img_convert/7604a097203e52c1c84e0d8931e33295.png)

  • 编码过程

他会把客户端的字符按照 3个字节 为一组进行编码。如果客户端字符不够不够三个字节,他内部会用0进行补位。补齐到3个字节一组。

对于一组来说,他会按照6bit 进行二次分组。分成4组。

这4组,每一组就能表示一个字符

请注意,如果是补位得到的组,也就是000000 表示的不是ASCII码里面的A字符,而是 = 。

![image-20221225145713752](https://img-
blog.csdnimg.cn/img_convert/91b7abe32ff8d56d1b88b6c45bbd373f.png)

Java内置了Base64类,封装了编码解码的算法,帮我们做上面这些事情。

package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Base64Test {

    @Test
    @DisplayName("将字符串转为Base64编码的字符串")
    public void strToBase64(){
        String source = "123456789";
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(source.getBytes(StandardCharsets.UTF_8));
        System.out.println(base64); // MTIzNDU2Nzg5
    }

    @Test
    @DisplayName("将Base64编码的字符串转为字符串")
    public void base64ToStr(){
        String base64 = "MTIzNDU2Nzg5";
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(base64);
        String source = new String(decode);
        System.out.println(source); //123456789
    }
}

签名

签名的优点:

A向B发送签名的消息P,可以有如下好处:

  • 1、B可以验证消息P确实来源A
  • 2、A以后不能否定发送过P
  • 3、B不能编造或者改变消息P

如商城A发送消息P给支付宝网关B

从支付宝网关的角度看:

从互联网环境中,拿到了A的消息,通过验签(解密出来的数据和发送数据是否一致)来确定数据传输过程中没有被他人利用篡改。

从而执行了转账业务操作。

从商城A的角度看:

发送的数据签名是用了自己的私钥签名的,还用了支付宝的公钥加密了。很安全。支付宝不能改变这个消息。

![image-20221225150455911](https://img-
blog.csdnimg.cn/img_convert/ffddcd483d102d0c78aeae761f8a561a.png)

摘要

摘要算法:SHA和MD5:就是通过一种算法,依据数据内容生成一种固定长度的摘要,这串摘要值与原数据存在对应关系。

实际应用过程中,因为需要加密的数据可能会很大,进行加密费时费力,所以一般都会把原数据先进行摘要,然后对这个摘要值进行加密,将原数据的明文和加密后的摘要值一起传给你.这样你解开加密后的摘要值,再和你得到的数据进行的摘要值对应一下就可以知道数据有没有被修改了(下文说的签名)。

摘要算法有很多,来看看JDK支持的摘要算法,摘要算法又分两种实现

一种是 MessageDigest 消息摘要

另一种是 Mac Mac实现

MessageDigest

我先来看看MessageDigest 实现的。

MD2
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class CipherTest {

    @Test
    @DisplayName("MD2 ")
    public void encAndDen() throws NoSuchAlgorithmException {
        String  algorithm = "MD2";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String result = Base64.getEncoder().encodeToString(digest);
        System.out.println(result);     // 1FQSULWGKW/M5d6kRjrhfw==

    }

}



package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class CipherTest {

    @Test
    @DisplayName("MD5 加密")
    public void jdkMd5AndEncodeTOBase64() throws NoSuchAlgorithmException {
        String  algorithm = "MD5";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String result = Base64.getEncoder().encodeToString(digest);
        System.out.println(result);     // 4QrcOUm6Wau+VuBX8g+IPg==

    }
}

MD5 可以将任意长度的原文 生成一个 128位(16字节的哈希值)。

在某些业务场景,我们除了会把该16字节的哈希值 转为 Base64 字符串 之外,也可以处理成 16进制字符串。

package com.wnx.naizi;

import cn.hutool.core.util.HexUtil;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class CipherTest {


    @Test
    @DisplayName("MD5 加密")
    public void jdkMd5AndEncodeTOHexStr() throws NoSuchAlgorithmException {
        String  algorithm = "MD5";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));
        String s = HexUtil.encodeHexStr(digest);
        System.out.println(s);     //

    }
}
SHA-1
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class CipherTest {



    @Test
    @DisplayName("SHA-1 摘要")
    public void encAndDen() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-1";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));
        System.out.println(digest.length); // 20
        String result = Base64.getEncoder().encodeToString(digest);
        System.out.println(result);     // fEqNCco3Yq9h5ZUglD3CZJT4lBs=

    }

}



package com.wnx.naizi;

import cn.hutool.core.util.HexUtil;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class CipherTest {


    @Test
    @DisplayName("SHA-1 摘要")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-1";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));
        String str = HexUtil.encodeHexStr(digest);  // 7c4a8d09ca3762af61e59520943dc26494f8941b
        System.out.println(str);


    }
}

SHA-1可以将任意长度的原文 生成 20个字节(20 * 8 bit = 160 bit)位的哈希值。

我们也会把这样的Hash值转为Base64编码字符串之外,有时业务上也会转为 十六进制字符串。

SHA-224
package com.wnx.naizi;

import cn.hutool.core.util.HexUtil;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class CipherTest {


    @Test
    @DisplayName("SHA-224 摘要")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-224";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));
        String str = HexUtil.encodeHexStr(digest);  // f8cdb04495ded47615258f9dc6a3f4707fd2405434fefc3cbf4ef4e6
        System.out.println(str);

    }
}
SHA-256
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class CipherTest {

    @Test
    @DisplayName("SHA-256 摘要")
    public void encAndDen() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-256";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String result = Base64.getEncoder().encodeToString(digest);
        System.out.println(result);     // jZae727K08KaOmKSgOaGzww/XVqGr/PKEgIMkjrcbJI=

    }

}
SHA-384
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class CipherTest {

    @Test
    @DisplayName("SHA-384 加密")
    public void encAndDen() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-384";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String result = Base64.getEncoder().encodeToString(digest);
        System.out.println(result);     // CpievEp3tWpuK7exnZldGFzkQJDBPimEt+zG1EbUth6pmRt2pMLwSxtNJEhBRJRU

    }
}
SHA-512
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class CipherTest {

    @Test
    @DisplayName("SHA-512 加密")
    public void encAndDen() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-512";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String result = Base64.getEncoder().encodeToString(digest);
        System.out.println(result);     // ujJTh2rta8ItSm/1PYQGxq2GQZXtFEq1yHYhtsIztUi66uaVbfNG7IwX9eoQ817jy8UUeX7X3dMUVGTioLq0Ew==

    }

}
SHA-512/224
    @Test
    @DisplayName("SHA-512/224 加密")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-512/224";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));
        String str = HexUtil.encodeHexStr(digest);  // 007ca663c61310fbee4c1680a5bbe70071825079b23f092713383296
        System.out.println(str);


    }
SHA-512/256
    @Test
    @DisplayName("SHA-512/256 加密")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA-512/256";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));
        String str = HexUtil.encodeHexStr(digest);  // 184b5379d5b5a7ab42d3de1d0ca1fedc1f0ffb14a7673ebd026a6369745deb72
        System.out.println(str);


    }
SHA3-224
    @Test
    @DisplayName("SHA3-224 加密")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA3-224";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String str = new BigInteger(1, digest).toString(16);    // 6be790258b73da9441099c4cb6aeec1f0c883152dd74e7581b70a648
        System.out.println(str);


    }
SHA3-256
    @Test
    @DisplayName("SHA3-256 加密")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA3-256";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String str = new BigInteger(1, digest).toString(16);    // d7190eb194ff9494625514b6d178c87f99c5973e28c398969d2233f2960a573e
        System.out.println(str);


    }
SHA3-384
    @Test
    @DisplayName("SHA3-384 加密")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA3-384";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String str = new BigInteger(1, digest).toString(16);    // 1fb0da774034ba308fbe02f3e90dc004191df7aec3758b6be8451d09f1ff7ec18765f96e71faff637925c6be1d65f1cd
        System.out.println(str);


    }
SHA3-512
    @Test
    @DisplayName("SHA3-512 加密")
    public void encAndDenToHexString() throws NoSuchAlgorithmException {
        String  algorithm = "SHA3-512";
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        String source = "123456";
        byte[] digest = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));

        String str = new BigInteger(1, digest).toString(16);    //64d09d9930c8ecf79e513167a588cb75439b762ce8f9b22ea59765f32aa74ca19d2f1e97dc922a3d4954594a05062917fb24d1f8e72f2ed02a58ed7534f94d27
        System.out.println(str);


    }

Mac

MessageDigest 比较。这个Mac对象需要一个SecretKey 进行初始化,才能用。

HmacMD5
    @Test
    @DisplayName("HmacMD5 加密")
    public void jdkMd5AndEncodeTOBase64() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacMD5";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 2fa5a2a2d2e9d68a2cfb9821e2415464

    }
HmacSHA1
public class CipherTest {



    @Test
    @DisplayName("HmacSHA1 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA1";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 560462b95eff73ca176032de405c0c08297de10f

    }
 }
HmacSHA256
    @Test
    @DisplayName("HmacSHA256 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA256";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 8ad6f4abeb59ba6009724395c90049105b427050c10808618ebb9be4f9a33aa

    }
HmacSHA224
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA224 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA224";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 4cd1c941009fae2ac26587cc2cdaabe5c3a0f798f01fb618288aedf0

    }

}
HmacSHA384
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA384 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA384";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // a107a03e92e770c79d4d0e76160d853d63f253d4cc28654d39f03c0b8f900ea110b791dd9f67567ac3ed85f4692748d6

    }


}
HmacSHA512
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA512 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA512";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 4e646209bd3a2aab053efdaeb58300ebb1bb80c6c5c66640218bd0136b6faa051ef5e8834531d51f4f413bc1e439d72bd52b40292674d3381aeccbc030d912e2

    }



}
HmacSHA512/224
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA512/224 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA512/224";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // ee9f2b8c40fdded9f753b4816db7c308252726f14618c7b77573218a

    }

}
HmacSHA512/256
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA512/256 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA512/256";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 421dd7a2b5df6a6deac04da3f087a0a842ea77da07db58a65097a22fa616dfb5

    }

}
HmacSHA3-224
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA3-224 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA3-224";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 82889d40ef2964e42efb2bbb7ef9e23e9353a1e9002d8059049819b4

    }



}
HmacSHA3-256
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA3-256 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA3-256";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 42646c3ebc0eb96d605cc6a0d181c25ac558ca3710bf4fd4971698367648fd84

    }

}
HmacSHA3-224
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA3-224 加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA3-224";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 82889d40ef2964e42efb2bbb7ef9e23e9353a1e9002d8059049819b4

    }



}
HmacSHA3-384
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA3-384加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA3-384";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // 742b2721109585685add7d0c0abf5b655c78d749d8a1e3b59527e8faa4e0c9d2b4ce53a71aec3ae58f6e9f93780b283c

    }

}
HmacSHA3-512
package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CipherTest {

    @Test
    @DisplayName("HmacSHA3-512加密")
    public void encAndDec() throws NoSuchAlgorithmException, InvalidKeyException {
        String useKey = "123456789";
        String algorithm = "HmacSHA3-512";
        SecretKey secretKey = new SecretKeySpec(useKey.getBytes(), algorithm);

        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);

        String source = "123456";
        mac.update(source.getBytes());
        byte[] result = mac.doFinal();

        String hexStr = new BigInteger(1, result).toString(16);
        System.out.println(hexStr);
        // b10de64a2b9cb26893448e676a65e14aeffbb98014b94361ed37430c983ee52ca99f20a8a9fc66834e56e59a7cf822bb50dfab4ae7abe2a4dfc7764ae65fbc1f

    }
}

签名

日常什么时候需要签名?确定这个东西和你有关,是你批准的,是你同意的。XXXX合同??签名技术也被运用到互联网领域,确定这个数据包是你的。这XXX合同不是伪造的,对你,对他都是一种保护。在Java中对签名这件事用Signature对象表示。我们只需要写入签名算法就能把他创建出来。

Signature signature = Signature.getInstance("MD5WithRSA");

initSign

签名实例,实际上就是用某个hash算法把IP数据报的数据部分(POST报文请求体)得到一个Hash值了。然后用私钥加密。这就完成了签名工作了。在Java你需要对签名进行初始化,等价于人家给你笔的过程。

以下演示了根据私钥初始化签名。

      private String privateKeyStr = "MIIG/AIBADANBgkqhkiG9w0BAQEFAASCBuYwggbiAgEAA...";
      private String publicKeyStr = "MIIBojANBgkqhkiG9w0BAQEFAAOCA...";

    @Test
    @DisplayName("根据私钥初始化签名对象")
    public void initSignByPriateKey() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
      
      String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5WithRSA");
        signature.initSign(privateKey);
      

    }


   @Test
    @DisplayName("根据 私钥和秘密随机对象 初始化签名对象")
    public void getSignatureByPrivateKeyAndSecureRandom() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5WithRSA");
        SecureRandom secureRandom = new SecureRandom();

        signature.initSign(privateKey,secureRandom);
        byte[] sign = signature.sign();


    }

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-
home.csdnimg.cn/images/20230724024159.png?origin_url=38_%E5%AE%89%E5%85%A8%E5%AF%86%E7%A0%81%E5%AD%A6%E5%9F%BA%E7%A1%80.assets%2Fimage-20221218224723742.png&pos_id=img-
BJq5rvY4-1702569326760)

sign

拿到笔了,签个名吧老哥。

    private String privateKeyStr = "MIIG/AIBADANBgkqhkiG9w0BAQEFA...";


    private String publicKeyStr = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBig...";

    
    @Test
    @DisplayName("签名对象进行签名")
    public void getSignatureByPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5WithRSA");

        

        signature.initSign(privateKey);
        
         // 需要签名的数据 = POST请求体数据
        byte[] needSignatureData = "王乃醒".getBytes(StandardCharsets.UTF_8);
        signature.update(needSignatureData);
        
        byte[] sign = signature.sign();

        String signResult = Base64.getEncoder().encodeToString(sign);
        System.out.println(signResult);
        // 需要签名的数据
        byte[] needSignatureData = "王乃醒".getBytes(StandardCharsets.UTF_8);
        signature.update(needSignatureData);
        
 //Scbno/HT9YmNPbzC0S3Sk1Q+6UivEecjoAZ9loFbmmsJvOfwiXEF48naPNfX1dRNt4FRAagv4EDpc0jUSAZmKn0yYkG44leXBRNMp72pMnIrl138odSRDlG4OZCFxnot3OGWJiBVVK+dRi5Sqe3js+/5Y35sxoCOe0d4HNvyFkiR4PWT1CTA62Q7UDNfBv/lgA2UNtzGpEREZvDU86utVj3H9nOvy4oo/X5k9NhdDr3EVODw2/tajoQNWWKNITMAfpz8Gd/uQe/us34sXZk7tkIFDCkqpcTpOlibN+yoIQ8yEcw3cnDlWHSNVxMBWzUQd0l9qMGHhqQZv3mayajxQ6zpKT5B3k8/+DBCTsH3bmkqYTllt60X+mToMRv0ZFQr8JEw/ZZDVV/yyCd+eg2EIGnqNY5p9M+UVYuFteF/vVwrJ4SbCWEsgQ2MWJ2qD8fsh4C+xZydP1SPzG4ilO7+ltHaBGP07xR+rp5my5D3iNxV+7yP8Oa1RD7uzFpYR7v5


    }

initVerify

好了,开始在互联网传输了。人家即使把信息拦截了,因为没有你的公钥,完全看不懂这是什么。。。最终经过路由转发到你手上了。你有公钥,解密他.

    private String privateKeyStr = "MIIG/AIBADANBgkqhkiG9w0BAQEFA...";


    private String publicKeyStr = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBig...";


    @Test
    @DisplayName("签名验证公钥")
    public void initVerify() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(publicKey);

    }

verify

怎么验签?无非把解密数据用发送方的hash算法做一次他做过的事情,由相同原文经过同一hash算法后最终得到的hash值均一致(hash算法特点),所以我们看这个签名和这个hash如果一致,我就认为这个签名没有被篡改。

Java封装好了,你只需要告诉我 相同原文是啥?该事例POST请求数据 = 王乃醒

    private String privateKeyStr = "MIIG/AIBADANBgkqhkiG9w0BAQEFA...";
    private String publicKeyStr = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBig...";


    @Test
    @DisplayName("用公钥验证签名")
    public void getPublicKeyByRSA() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(publicKey);
        String signResult = "Scbno/HT9YmNPbzC0S3Sk1Q+6UivEecjoAZ9loFbmmsJvOfwiXEF48naPNfX1dRNt4FRAagv4EDpc0jUSAZmKn0yYkG44leXBRNMp72pMnIrl138odSRDlG4OZCFxnot3OGWJiBVVK+dRi5Sqe3js+/5Y35sxoCOe0d4HNvyFkiR4PWT1CTA62Q7UDNfBv/lgA2UNtzGpEREZvDU86utVj3H9nOvy4oo/X5k9NhdDr3EVODw2/tajoQNWWKNITMAfpz8Gd/uQe/us34sXZk7tkIFDCkqpcTpOlibN+yoIQ8yEcw3cnDlWHSNVxMBWzUQd0l9qMGHhqQZv3mayajxQ6zpKT5B3k8/+DBCTsH3bmkqYTllt60X+mToMRv0ZFQr8JEw/ZZDVV/yyCd+eg2EIGnqNY5p9M+UVYuFteF/vVwrJ4SbCWEsgQ2MWJ2qD8fsh4C+xZydP1SPzG4ilO7+ltHaBGP07xR+rp5my5D3iNxV+7yP8Oa1RD7uzFpYR7v5";

        byte[] data = Base64.getDecoder().decode(signResult);
        //对王乃醒请求报文 做一次hash。
        byte[] needSignatureData = "王乃醒".getBytes(StandardCharsets.UTF_8);
        signature.update(needSignatureData);

        boolean verify = signature.verify(data);
        System.out.println(verify);  // true


    }

有了上面的API铺垫,我们来看看Java原生支持的签名算法,并执行一遍完整的流程。

MD5WithRSA

package com.wnx.naizi;

import cn.hutool.core.io.FileUtil;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @ClassName: SecretKeyFactoryTest
 * @Package: com.wnx.naizi
 * @Description: 密钥工厂 API测试
 * @Author: wangnaixing
 * @Create: 2022/12/18 - 16:40
 * @Version:v1.0
 */
public class SignatureTest {


    private String privateKeyStr = "MIIG/AIBADANBgkqhkiG9w0BAQEFAASCB..";

    private String publicKeyStr = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY..";


    @Test
    @DisplayName("签名")
    public void signByMD5WithRSA() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5WithRSA");

        

        signature.initSign(privateKey);
        byte[] needSignatureData = "王乃醒".getBytes(StandardCharsets.UTF_8);
        signature.update(needSignatureData);
        byte[] sign = signature.sign();

        String signResult = Base64.getEncoder().encodeToString(sign);
        System.out.println(signResult);
        //Scbno/HT9YmNPbzC0S3Sk1Q+6UivEecjoAZ9loFbmmsJvOfwiXEF48naPNfX1dRNt4FRAagv4EDpc0jUSAZmKn0yYkG44leXBRNMp72pMnIrl138odSRDlG4OZCFxnot3OGWJiBVVK+dRi5Sqe3js+/5Y35sxoCOe0d4HNvyFkiR4PWT1CTA62Q7UDNfBv/lgA2UNtzGpEREZvDU86utVj3H9nOvy4oo/X5k9NhdDr3EVODw2/tajoQNWWKNITMAfpz8Gd/uQe/us34sXZk7tkIFDCkqpcTpOlibN+yoIQ8yEcw3cnDlWHSNVxMBWzUQd0l9qMGHhqQZv3mayajxQ6zpKT5B3k8/+DBCTsH3bmkqYTllt60X+mToMRv0ZFQr8JEw/ZZDVV/yyCd+eg2EIGnqNY5p9M+UVYuFteF/vVwrJ4SbCWEsgQ2MWJ2qD8fsh4C+xZydP1SPzG4ilO7+ltHaBGP07xR+rp5my5D3iNxV+7yP8Oa1RD7uzFpYR7v5

    }


    @Test
    @DisplayName("得到签名和传输数据 开始验签~~")
    public void verifyByMD5WithRSA() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(publicKey);
        String signResult = "Scbno/HT9YmNPbzC0S3Sk1Q+6UivEecjoAZ9loFbmmsJvOfwiXEF48naPNfX1dRNt4FRAagv4EDpc0jUSAZmKn0yYkG44leXBRNMp72pMnIrl138odSRDlG4OZCFxnot3OGWJiBVVK+dRi5Sqe3js+/5Y35sxoCOe0d4HNvyFkiR4PWT1CTA62Q7UDNfBv/lgA2UNtzGpEREZvDU86utVj3H9nOvy4oo/X5k9NhdDr3EVODw2/tajoQNWWKNITMAfpz8Gd/uQe/us34sXZk7tkIFDCkqpcTpOlibN+yoIQ8yEcw3cnDlWHSNVxMBWzUQd0l9qMGHhqQZv3mayajxQ6zpKT5B3k8/+DBCTsH3bmkqYTllt60X+mToMRv0ZFQr8JEw/ZZDVV/yyCd+eg2EIGnqNY5p9M+UVYuFteF/vVwrJ4SbCWEsgQ2MWJ2qD8fsh4C+xZydP1SPzG4ilO7+ltHaBGP07xR+rp5my5D3iNxV+7yP8Oa1RD7uzFpYR7v5";

        byte[] data = Base64.getDecoder().decode(signResult);
        byte[] needSignatureData = "王乃醒".getBytes(StandardCharsets.UTF_8);
        signature.update(needSignatureData);

        boolean verify = signature.verify(data);
        System.out.println(verify);  // true

    }
}

SHA256WithRSA

package com.wnx.naizi;

import cn.hutool.core.io.FileUtil;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @ClassName: SignatureTest
 * @Package: com.wnx.naizi
 * @Description:
 * @Author: wangnaixing
 * @Create: 2022/12/25 - 17:39
 * @Version:v1.0
 */
public class SignatureTest {

    private String privateKeyStr = "MIIG/AIBADANBgkqhkiG9w0BAQEFAASC...";

    private String publicKeyStr = "MIIBojANBgkqhkiG9w0BAQEFA...";




    @Test
    @DisplayName("签他")
    public void signSHA256WithRSA() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Signature signature = Signature.getInstance("SHA256WithRSA");



        signature.initSign(privateKey);
        String plainText = "王乃醒";
        byte[] needSignatureData = plainText.getBytes(StandardCharsets.UTF_8);
        signature.update(needSignatureData);
        byte[] sign = signature.sign();

        String signResult = Base64.getEncoder().encodeToString(sign);
        System.out.println(signResult);
        //     tlp4x/DKD2pwWCJ8vaGQ1f3KPFvL2uV4/WNgQGjyP6qEGtFCjLispMd78SOePb2xBweMpX6ddnSGTwHaTinPfIAE79MK0ebCzm9jnRy+2o1VOb6bmX1TL8BocNRifEAclLOUdw8DTRx6vWpf5Es+vDyTyR+RbNa8Q9qgX56Ot7Q1+85ze+15idvcWRy4YnUdYhh06zJm4avYqln8+vy93fFp83dKGptdi7ei5sJq08QUgw1btz+t/4T39rsWSvk4FNUpuCDKXNIuPjSzTVKk7i1GJUwO5tM/INwmsJal0Ill8p7awOfZKReh+UHbpXxr/VyFi53G0/eNa4f9Q96ws7mviKUsZN445ITjCBx2gRhfPAz8k9s96OTTlqru9XEvZduk+mXyGI9zEeoJe4lIF2hiyX4I3ExAgRxbIOCUukaOdVyc1ylNYeJwt6TPbstjP1XjogqPKsTVz/Y6y2f3gIArYNF1t8ZOT6r6W5cqjvkEVpeYeHw3S1kC0EbDLL8/

    }


    @Test
    @DisplayName("验货")
    public void verifySHA256WithRSA() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        String algorithm = "RSA";
        byte[] encodedKey = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedKey);

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        Signature signature = Signature.getInstance("SHA256WithRSA");
        signature.initVerify(publicKey);
        String signResult = "tlp4x/DKD2pwWCJ8vaGQ1f3KPFvL2uV4/WNgQGjyP6qEGtFCjLispMd78SOePb2xBweMpX6ddnSGTwHaTinPfIAE79MK0ebCzm9jnRy+2o1VOb6bmX1TL8BocNRifEAclLOUdw8DTRx6vWpf5Es+vDyTyR+RbNa8Q9qgX56Ot7Q1+85ze+15idvcWRy4YnUdYhh06zJm4avYqln8+vy93fFp83dKGptdi7ei5sJq08QUgw1btz+t/4T39rsWSvk4FNUpuCDKXNIuPjSzTVKk7i1GJUwO5tM/INwmsJal0Ill8p7awOfZKReh+UHbpXxr/VyFi53G0/eNa4f9Q96ws7mviKUsZN445ITjCBx2gRhfPAz8k9s96OTTlqru9XEvZduk+mXyGI9zEeoJe4lIF2hiyX4I3ExAgRxbIOCUukaOdVyc1ylNYeJwt6TPbstjP1XjogqPKsTVz/Y6y2f3gIArYNF1t8ZOT6r6W5cqjvkEVpeYeHw3S1kC0EbDLL8/";

        byte[] data = Base64.getDecoder().decode(signResult);
        String plainText = "王乃醒";
        byte[] needSignatureData = plainText.getBytes(StandardCharsets.UTF_8);
        signature.update(needSignatureData);

        boolean verify = signature.verify(data);
        System.out.println(verify);  // true


    }

}

证书

证书文件存在多种格式保存在计算机中。

1. .p12 .pfx 二进制格式,同时包含证书和私钥,一般有密码保护。
2. .pem 文本格式,保存证书或者私钥
3. .crt 二进制格式或者文本格式,只保存证书
4. .jks 二进制格式,同时包含证书和私钥,一般有密码保护;jks是java的专属格式,它里面可以存储多张证书。
5. .der .cer 二进制格式,只保存证书,不保存密钥

秘钥库类型:

  • 1、JKS
  • 2、PKCS12 行业标准

现在让我们制作一个证书吧,JDK提供了KeyTool 工具,借助他,我们就能生成证书啦。

# 使用JDK的KeyTool工具 生成秘钥
# 给秘钥起一个别名 指定为 keystore01 
# 给秘钥库的类型 指定为 JKS,
# 给秘钥使用的算法 指定为 RSA 
# 给秘钥的长度 指定为 2048 bit 
# 给指定秘钥生成路径, 指定为 D盘 名称为 keystore01.p12文件中
# 给秘钥库访问的密码 指定为 wangnaixing
# 给秘钥有效期 指定为 3650

keytool -genkey -alias keystore01 -storetype JKS -keyalg RSA -keysize 2048 -keystore D:/keystore01.p12 -storepass wangnaixing -validity 3650

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-
home.csdnimg.cn/images/20230724024159.png?origin_url=38_%E5%AE%89%E5%85%A8%E5%AF%86%E7%A0%81%E5%AD%A6%E5%9F%BA%E7%A1%80.assets%2Fimage-20221225205255922.png&pos_id=img-
rNkjchgZ-1702569326760)

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-
home.csdnimg.cn/images/20230724024159.png?origin_url=38_%E5%AE%89%E5%85%A8%E5%AF%86%E7%A0%81%E5%AD%A6%E5%9F%BA%E7%A1%80.assets%2Fimage-20221225205401400.png&pos_id=img-
Hm3GiE9j-1702569326761)

嗯嗯,我们再生成一个新的,行业标准的 PKCS12

# 使用JDK的KeyTool工具 生成秘钥
# 给秘钥起一个别名 指定为 keystore02 
# 给秘钥库的类型 指定为 PKCS12,
# 给秘钥使用的算法 指定为 RSA 
# 给秘钥的长度 指定为 2048 bit 
# 给指定秘钥生成路径, 指定为 D盘 名称为 keystore02.p12文件中
# 给秘钥库访问的密码 指定为 wangnaixing
# 给秘钥有效期 指定为 3650

keytool -genkey -alias keystore02 -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore D:/keystore02.p12 -storepass wangnaixing -validity 3650

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-
home.csdnimg.cn/images/20230724024159.png?origin_url=38_%E5%AE%89%E5%85%A8%E5%AF%86%E7%A0%81%E5%AD%A6%E5%9F%BA%E7%A1%80.assets%2Fimage-20221225210056083.png&pos_id=img-
GWzch0Ti-1702569326761)

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-
home.csdnimg.cn/images/20230724024159.png?origin_url=38_%E5%AE%89%E5%85%A8%E5%AF%86%E7%A0%81%E5%AD%A6%E5%9F%BA%E7%A1%80.assets%2Fimage-20221225210418897.png&pos_id=img-
ISmogXcM-1702569326761)

KeyStore

我们想把 keystore01.p12 keystore02.p12 加载到Java中。该怎么做呢?Java提供了keyStore类来给我们做。

根据秘钥类型拿到KeyStore对象,load一下就好。这是不是很像Properties配置文件加载进Java中一样。

    @Test
    @DisplayName("获取密钥库对象 PKCS12")
    public void getInstanceUseTypeIsPKCS12() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore01.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);
        char[] password = "wangnaixing".toCharArray();
        keyStore.load(fileInputStream,password);

    }

    @Test
    @DisplayName("获取密钥库对象 JKS")
    public void getInstanceUseJKS() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "JKS";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();
        keyStore.load(fileInputStream,password);
    }

你可以加载多个同样类型的证书到KeyStore
存储中。假设此刻你加载了两个同样类型的证书到KeyStore了,我怎么取到我想要的那一个呢?通过别名alias 每一个证书都有一个别名的。

    @Test
    @DisplayName("返回与给定别名关联的证书")
    public void getCertificate() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);

        String alias = "keystore02";
        Certificate certificate = keyStore.getCertificate(alias);
        System.out.println(certificate);

    }

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-
home.csdnimg.cn/images/20230724024159.png?origin_url=38_%E5%AE%89%E5%85%A8%E5%AF%86%E7%A0%81%E5%AD%A6%E5%9F%BA%E7%A1%80.assets%2Fimage-20221225212546165.png&pos_id=img-o2vOomGe-1702569326761)

你记不清楚别名叫什么的情况下,你可以通过aliases() 拿到所有证书的别名数组。

    @Test
    @DisplayName(" 获取所有证书名")
    public void aliases() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);

        Enumeration<String> aliases = keyStore.aliases();
        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            System.out.println(alias);   // keystore02
        }


    }

在生成证书的时候,你输入秘钥库访问的密码,这个密码底层采用的是对称加密。同样你通过KeyStore 对象拿到。

    @Test
    @DisplayName(" 返回与给定别名关联的密钥,并使用给定密码恢复该密钥。")
    public void getKey() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException, UnrecoverableKeyException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);
        String  alias = "keystore02";
        // key = wangnaixing
        Key key = keyStore.getKey(alias, password);
        System.out.println(key);


    }

Certificate

证书的格式,是遵从ITUT X509国际协议标准。在X.509标准中,数字证书的一般格式包含的作用域如下。

  • 1、版本号
  • 2、序列号
  • 3、签名算法
  • 4、发行者
  • 5、有效期
  • 6、主体名
  • 7、公钥
  • 8、发行者ID
  • 9、主体ID
  • 10、扩展域
  • 11、CA(认证机构)对证书的签名

我们得到的Java对象 Certificate 确实封装了这些信息。

    @Test
    @DisplayName("获取证书版本号")
    public void getVersion() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException, UnrecoverableKeyException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);
        String  alias = "keystore02";
        Certificate certificate = keyStore.getCertificate(alias);
        X509Certificate x509Certificate = (X509Certificate) certificate;
        
        int version = x509Certificate.getVersion();
        System.out.println(version);    // 3


    }



    @Test
    @DisplayName("获取证书版本号 序列号是由证书颁发机构CA分配给每个证书的整数 此整数唯一")
    public void getSerialNumber() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException, UnrecoverableKeyException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);
        String  alias = "keystore02";
        Certificate certificate = keyStore.getCertificate(alias);
        X509Certificate x509Certificate = (X509Certificate) certificate;

        BigInteger serialNumber = x509Certificate.getSerialNumber();
        System.out.println(serialNumber);  // 1928866772





    @Test
    @DisplayName("获取证书签名算法 签署整数所用到的算法以及参数")
    public void getSigAlgName() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException, UnrecoverableKeyException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);
        String  alias = "keystore02";
        Certificate certificate = keyStore.getCertificate(alias);
        X509Certificate x509Certificate = (X509Certificate) certificate;

        String sigAlgName = x509Certificate.getSigAlgName();
        System.out.println(sigAlgName); // SHA256withRSA

    }





    @Test
    @DisplayName("获取证书发行者")
    public void getIssuerX500Principal() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException, UnrecoverableKeyException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);
        String  alias = "keystore02";
        Certificate certificate = keyStore.getCertificate(alias);
        X509Certificate x509Certificate = (X509Certificate) certificate;

        X500Principal issuer = x509Certificate.getIssuerX500Principal();
        System.out.println(issuer.getName());    // CN=test,OU=test,O=test,L=test,ST=test,C=test
        
    }



    @Test
    @DisplayName("获取证书有效期 不早于 不晚于")
    public void getNotBeforeAndGetNotAfter() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException, UnrecoverableKeyException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);
        String  alias = "keystore02";
        Certificate certificate = keyStore.getCertificate(alias);
        X509Certificate x509Certificate = (X509Certificate) certificate;

        Date notBefore = x509Certificate.getNotBefore();
        Date notAfter = x509Certificate.getNotAfter();

        System.out.println(DateUtil.format(notBefore, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:dd")));
        System.out.println(DateUtil.format(notAfter, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:dd")));
        /**
         * 2022-12-25 21:00:25
         * 2032-12-22 21:00:22
         */
    }




    @Test
    @DisplayName("获取证书主体名 指的证书持有者的名称和有关信息")
    public void getSubjectX500Principal() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException, UnrecoverableKeyException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);
        String  alias = "keystore02";
        Certificate certificate = keyStore.getCertificate(alias);
        X509Certificate x509Certificate = (X509Certificate) certificate;

        X500Principal subject= x509Certificate.getSubjectX500Principal();
        System.out.println(subject); // CN=test, OU=test, O=test, L=test, ST=test, C=test
    }




package com.wnx.naizi;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;

public class CipherTest {



    @Test
    @DisplayName("生成证书对象扩展值")
    public void getExtensionValue() throws CertificateException, IOException {

        String type = "X.509";
        CertificateFactory certificateFactory = CertificateFactory.getInstance(type);


        String certPath = "D:/Microsoft2010.cer";
        FileInputStream fileInputStream = new FileInputStream(certPath);
        Certificate certificate = certificateFactory.generateCertificate(fileInputStream);

        X509Certificate x509Certificate = (X509Certificate) certificate;
        // 策略映射
        byte[] SubjectKeyIdentifier = x509Certificate.getExtensionValue("2.5.29.14");
        // 关键字用法
        byte[] KeyUsage = x509Certificate.getExtensionValue("2.5.29.15");
        // PrivateKey用法
        byte[] PrivateKeyUsage = x509Certificate.getExtensionValue("2.5.29.16");
        //主体可选名
        byte[] SubjectAlternativeName = x509Certificate.getExtensionValue("2.5.29.17");
        // 发行者可选名
        byte[] IssuerAlternativeName = x509Certificate.getExtensionValue("2.5.29.18");
        // 基本约束
        byte[] BasicConstraints = x509Certificate.getExtensionValue("2.5.29.19");
        // 名称约束
        byte[] NameConstraints = x509Certificate.getExtensionValue("2.5.29.30");
        // 策略映射
        byte[] PolicyMappings = x509Certificate.getExtensionValue("2.5.29.33");
        //   授权密钥识别符
        byte[] AuthorityKeyIdentifier = x509Certificate.getExtensionValue("2.5.29.35");
        //    策略约束
        byte[] PolicyConstraints = x509Certificate.getExtensionValue("2.5.29.36");


    }


}



    @Test
    @DisplayName("生成证书认证机构的签名")
    public void getSignature() throws CertificateException, IOException {

        String type = "X.509";
        CertificateFactory certificateFactory = CertificateFactory.getInstance(type);


        String certPath = "D:/Microsoft2010.cer";
        FileInputStream fileInputStream = new FileInputStream(certPath);
        Certificate certificate = certificateFactory.generateCertificate(fileInputStream);

        X509Certificate x509Certificate = (X509Certificate) certificate;
        byte[] signature = x509Certificate.getSignature();
        System.out.println(Arrays.toString(signature));


    }
getPublicKey

除了这些获取信息的API之外,证书的公钥。仔细观察浏览器,只要是https请求,在浏览器某个存储位置,就保存有这个证书,同服务器建立TCP连接之后,他们之间通信都是一种加密通信,也是我们说HTTPS只是TLS+HTTP的原因了。

    @Test
    @DisplayName("从证书获取访问服务器资源公钥")
    public void getPublicKey() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);

        String alias = "keystore02";

        Certificate certificate = keyStore.getCertificate(alias);


        PublicKey publicKey = certificate.getPublicKey();
        System.out.println(publicKey);


    }
verify

证书还携带了CA的签名。验证有没有这个签名存在。

    @Test
    @DisplayName("验证此证书是否使用与指定公钥对应的私钥进行了签名")
    public void verify() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);

        String alias = "keystore02";

        Certificate certificate = keyStore.getCertificate(alias);

        PublicKey publicKey = certificate.getPublicKey();

        certificate.verify(publicKey);
getEncoded
    @Test
    @DisplayName("返回此证书的编码形式  encoded as ASN.1 DER")
    public void getEncoded() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
        FileInputStream fileInputStream = new FileInputStream("D:/keystore02.p12");
        String type = "PKCS12";
        KeyStore keyStore = KeyStore.getInstance(type);

        char[] password = "wangnaixing".toCharArray();

        keyStore.load(fileInputStream,password);

        String alias = "keystore02";

        Certificate certificate = keyStore.getCertificate(alias);
		
		// 转为Base64输出
        String content = new String(Base64.getEncoder().encode(certificate.getEncoded()));
        System.out.println(content);
     
        
    }



MIIDUzCCAjugAwIBAgIEcvgr1DANBgkqhkiG9w0BAQsFADBaMQ0wCwYDVQQGEwR0ZXN0MQ0wCwYDVQQIEwR0ZXN0MQ0wCwYDVQQHEwR0ZXN0MQ0wCwYDVQQKEwR0ZXN0MQ0wCwYDVQQLEwR0ZXN0MQ0wCwYDVQQDEwR0ZXN0MB4XDTIyMTIyNTEzMDAzOFoXDTMyMTIyMjEzMDAzOFowWjENMAsGA1UEBhMEdGVzdDENMAsGA1UECBMEdGVzdDENMAsGA1UEBxMEdGVzdDENMAsGA1UEChMEdGVzdDENMAsGA1UECxMEdGVzdDENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJSFLV1dAbefTifo6MV7ZfJKbEsqqO9CP14EBvQ8rSFeHrrFAntz3GNhwjXZZSWVhJJYqyR3wCPZ3F8Oxpen9DlNZH4mRvRcXIisXUZtp/TBUntS0K0428iq09A9hgsxnEX/Bp/YyYeG4YSYQ+xroyiQSdzU8XlIrZT9RUuBmDFtawNeSa0n/2OWGbt/3Df5I9veHDLjBLXW2M6pVmI+zTgRuApGinimIQs6qehwqIrYJXxy4Z+Qf5RPdQoPho/6Mmt6NrKTJWWogwuE2qZk+vWg5oz/eoGt20aZUV7D+izIlrQvmiWdMiZOujhjFWXjtEPq1FUTS49b2nIY4OfN40sCAwEAAaMhMB8wHQYDVR0OBBYEFLJmywmQay8x+356elK3biTmAC6sMA0GCSqGSIb3DQEBCwUAA4IBAQBsXNBCVCgzAWSI3HUm8sxoc237Ml1BzbR/6OoGngaLmDTIoFnflRNUriKcLbytZTGY/V3GkMslLuKPmXGLsqV9swqpdJaBo1YW+jTKrGqItyHgpfP0xRwwTqKC+ZRVGQfwzXB4taOqL/5AUI6eM+Mcm5hR7/7Kj/0ghQ6NkRIEmIyBDcTwNFx46RosBnNa2/e2ShkTGIE8RVNoiYGGpzaJIvE+veuMTkC8gV4ITA6j5KbQsGMtjwUDM+0FDADj+4UqkDSyGmdo0i9iEkWKpmc4wOXq0XaTRBTlokqbajl7fWRbeQuRGlPIBOgmz+2k19n8iMZZJp6OZvrImBswqNbM

CertificateFactory

如果使用KeyTool生成的证书,可以用KeyStore
加载到Java程序内存,然后从这个内存中拿到证书对象,但是生成证书的方式不止KeyTool
这一种方式吧。比如openssl呢?为了满足各种情况下证书文件都能被创建出来,Java提供了CertificateFactory 工厂类来生产。

我们打开本地的证书管理器certmgr

# 1、通过win + r 输入certmgr.msc 进入到证书管理页面
certmgr.msc 

# 2、点击菜单栏的操作选项,并选定查找证书下拉项。

# 3、输入操作内容 比如2010

# 4、 选中某项证书,直接导出就可以。

# 5、给导出的文件指定一个文件名,比如我这边就叫做 Microsoft2010

# 6、最后就可以拿到这个证书了!

![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/9d8687a8c8af4d6880ef02f053f943c8.png#pic_center)
![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/9150c5fa55994e43b6ac0ecd93e3a7d2.png#pic_center)

![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/56e0fa421e12462ba9fd391f54875af0.png#pic_center)

    @Test
    @DisplayName("返回实现指定证书类型的证书工厂对象")
    public void getInstance() throws CertificateException, FileNotFoundException {

        String type = "X.509";
        CertificateFactory certificateFactory = CertificateFactory.getInstance(type);
        System.out.println(certificateFactory);   // java.security.cert.CertificateFactory@358ee631

        String certPath = "D:/Microsoft2010.cer";
        FileInputStream fileInputStream = new FileInputStream(certPath);
        Certificate certificate = certificateFactory.generateCertificate(fileInputStream);

        X509Certificate x509Certificate = (X509Certificate) certificate;


    }

最后

从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。

因为入门学习阶段知识点比较杂,所以我讲得比较笼统,大家如果有不懂的地方可以找我咨询,我保证知无不言言无不尽,需要相关资料也可以找我要,我的网盘里一大堆资料都在吃灰呢。

干货主要有:

①1000+CTF历届题库(主流和经典的应该都有了)

②CTF技术文档(最全中文版)

③项目源码(四五十个有趣且经典的练手项目及源码)

④ CTF大赛、web安全、渗透测试方面的视频(适合小白学习)

⑤ 网络安全学习路线图(告别不入流的学习)

⑥ CTF/渗透测试工具镜像文件大全

⑦ 2023密码学/隐身术/PWN技术手册大全

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

扫码领取

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值