证书以及加密

证书

一些基础知识

1. 证书

证书(数字证书)是由受信任的第三方(称为证书颁发机构,CA)签发的电子文档,用于验证某个公钥的持有者身份。证书包含了公钥信息、持有者的身份信息,以及由CA的私钥签名,以确保其真实性。证书常用于建立安全的HTTPS连接。

常见CA证书颁发机构:

  1. DigiCert
  2. GlobalSign
  3. GoDaddy
  4. Let's Encrypt(提供免费证书)
  5. Comodo (现为 Sectigo)
  6. Symantec (现为 DigiCert 的一部分)
  7. Entrust Datacard
  8. Trustwave

常见证书类型及使用场景:

  1. 域名验证证书(DV)
    • 用途:简单的网站加密。
    • 适用情况:个人博客或小型企业网站,要求快速验证。
  2. 企业验证证书(OV)
    • 用途:企业身份验证,提供更高的可信度。
    • 适用情况:中小型企业网站,电商平台。
  3. 扩展验证证书(EV)
    • 用途:提供最高级别的身份验证,通常会在浏览器中显示公司名称。
    • 适用情况:金融机构、大型企业网站、重要的商业网站。
  4. 自签名证书
    • 用途:仅用于开发或内部环境,无法由公认的CA信任。
    • 适用情况:开发测试,内部网络。

2. 加密算法

加密算法是一种将数据转化为特殊格式的技术,使得未授权用户无法读取数据。加密算法可以分为两大类:

  • 对称加密算法:使用相同的密钥进行加密和解密,效率较高。常见的对称加密算法有AES、DES等。
  • 非对称加密算法:使用一对密钥(公钥和私钥),公钥加密的数据只能用私钥解密,反之亦然。常见的非对称加密算法有RSA、ECC等。

3. 加密套件

加密套件是一系列加密算法的组合,通常用于网络协议(如SSL/TLS)中,以确保数据传输的安全。一个加密套件通常包括:

  • 用于加密数据的对称加密算法(例如AES)
  • 用于身份验证的哈希算法(例如SHA)
  • 用于密钥交换的算法(例如RSA或Diffie-Hellman)

通过选择不同的加密套件,可以实现不同级别的数据安全性和性能。

一个 tls 证书签署的正确步骤

签署一个 正规厂家的TLS 证书的步骤主要涉及生成一个证书请求 (CSR)、提交请求以及最终获得和安装证书。以下是详细的步骤:

步骤 1:生成私钥

在生成 TLS 证书之前,您首先需要创建一个私钥。这个私钥将用于加密和解密信息。

openssl genrsa -out private.key 2048
证书以及加密

步骤 2:生成证书签署请求 (CSR)

使用刚刚创建的私钥生成一个 CSR。CSR 包含有关您的组织和域名的信息,并且将用于请求证书。

openssl req -new -key private.key -out request.csr

在这个过程中,您需要提供:

证书以及加密
  • 国家或地区 (C)
  • 省/州 (ST)
  • 城市 (L)
  • 企业/单位名称 (O)
  • 部门/组织单位(OU)
  • 通用名称 (CN),CN 通常指的是您希望为其申请 SSL 证书的域名,如果您申请的是通配符证书(Wildcard SSL Certificate),则 CN 应该填写为 *.example.com,这样可以保护该域下的所有子域。
  • 电子邮件地址 (不一定需要)
证书以及加密

查看生成的 CSR

证书以及加密

步骤 3:提交 CSR

将生成的 CSR 提交给一个受信任的证书颁发机构 (CA)。可以选择许多不同的 CA,例如 Let's Encrypt、DigiCert、Comodo 等。

步骤 4:验证身份

CA 收到 CSR 后会进行身份验证。这可能包括:

  • 通过电子邮件确认
  • 验证您是否拥有域名
  • 实体检查(对于一些高级的证书)

步骤 5:接收 SSL/TLS 证书

一旦 CA 验证通过,它会向您发送公钥证书(通常是 .crt.pem 文件)。有时,您还会收到中间证书和根证书,这些都需要安装(这里我们就使用自签证书颁发的证书文件,来模拟CA下发的证书,这个步骤如果是 CA 前发的,则不需要自签)。

openssl x509 -req -days 365 -in request.csr -signkey private.key -out certificate.crt

这条命令会使用上一步中生成的 CSR 和私钥自签署一个有效期为 365 天的证书,输出为 certificate.crt

证书以及加密

步骤 6:安装和配置证书

将证书及其对应的私钥配置到您的服务器(如 Apache、Nginx 等)。不同的服务器有不同的配置方式。

Nginx 示例:

server {
    listen 443 ssl;
    server_name your_domain.com; # 这里是 tls.ljh.cool
    ssl_certificate /etc/nginx/ssl/certificate.crt;
    ssl_certificate_key /etc/nginx/ssl/private.key;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

Apache 示例(同上):

同样地,将证书和私钥复制到适当的目录,然后在 Apache 配置文件中添加以下内容:

<VirtualHost *:443>
    ServerName your_domain.com

    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/certificate.crt
    SSLCertificateKeyFile /etc/apache2/ssl/private.key

    # 其他配置...
</VirtualHost>

步骤 7:测试和验证

安装完成后,确保重启服务器,并使用 SSL 网站检查工具(例如 SSL Labs)来测试和验证您的证书配置是否正确。

通过以上步骤,您就可以完成 TLS 证书的签署过程。

证书以及加密
证书以及加密

如何申请免费证书

申请 Let's Encrypt 免费证书的步骤如下:

1. 确保你的环境支持
你需要一个域名,且该域名的 DNS 记录已经指向你的服务器。
确保你的防火墙允许 80(HTTP)和 443(HTTPS)端口的流量
你需要有对服务器的管理权限。

2. 安装 Certbot
Let's Encrypt 使用 Certbot 工具来简化证书的申请和安装过程。你可以按照以下步骤安装 Certbot:

Linux(以 Debian/Ubuntu 为例)
# sudo apt update
# sudo apt install certbot
# sudo apt install python3-certbot-nginx  # 如果使用 Nginx
# sudo apt install python3-certbot-apache  # 如果使用 Apache

3. 申请证书
根据你使用的 Web 服务器,执行以下命令:

Nginx
# sudo certbot --nginx

Apache
# sudo certbot --apache
在执行命令后,Certbot 会提示你输入电子邮件地址、同意服务条款、选择域名等信息。

4. 自动续期
Let's Encrypt 的证书有效期为 90 天,因此你需要设置自动续期。
Certbot 默认会在安装时添加一个 cron 作业来自动续期。但你可以手动测试续期是否有效:
# sudo certbot renew --dry-run

5. 完成
完成以上步骤后,你将获得免费的 SSL 证书,且网站可以通过 HTTPS 协议安全访问。

Let's Encrypt 使用 SSL/TLS 证书涉及到的四种证书文件

  1. cert.pem
    • 这是你的服务器证书,它由一个证书颁发机构(CA)签署。它代表你的域名,可以用于验证你的服务器的身份。
  2. chain.pem
    • 这个文件包含了证书链中的中间证书。中间证书连接了你的服务器证书和根证书,帮助客户端信任你的证书。这个文件是用来确保浏览器或其他客户端可以验证你的证书是否可信。
  3. fullchain.pem
    • 这个文件包含了服务器证书和链中的所有中间证书。通常,使用这个文件更为方便,因为客户端在接收到这个文件后可以在一次请求中取得所需的所有证书,从而简化了证书的验证过程。
  4. privkey.pem
    • 这是你的私钥,用于SSL/TLS加密过程的解密。私钥应该严格保密,任何人都不应访问。

Nginx 配置中使用的证书

在 Nginx 的配置中,通常只需要以下两个文件:

  • fullchain.pem:因为它包含了服务器证书和整个链条的中间证书,能确保浏览器可以正确地认证和连接到你的服务器。
  • privkey.pem:因为它是用于加密和解密 SSL/TLS 连接的密钥。

为什么只用这两个

使用 fullchain.pem 而不是同时使用 cert.pemchain.pem 是为了简化配置以及减少出错的可能性。同样,只使用 privkey.pem 是因为这是进行加密和解密所必需的两个核心部分。

因此,Nginx 的 SSL/TLS 配置通常只需要 fullchain.pemprivkey.pem,这足以确保安全的 HTTPS 连接。

证书内容信息详解

我们可以详细查看并拆解下,对于申请的域名证书,可以用命令查看全部信息

例子 :查询百度的 tls 证书情况

openssl s_client -connect www.baidu.com:443 -showcerts
1. 连接信息
CONNECTED(00000003): 表示成功建立连接。
CONNECTED(00000003)

2. 证书链
证书0
s=Subject (证书主体):
C (Country): CN 代表中国(China)。
ST =state 省/州: 北京,表示证书主体的地址位于中国北京
L (Locality): 北京,进一步确认证书主体位于北京市。
O (Organization): "Beijing Baidu Netcom Science Technology Co., Ltd" 表示证书是颁发给百度公司。
CN (Common Name): baidu.com,指定这个证书主要用于保护域名为 baidu.com 的网站流量。

i=Issuer (颁发机构):
C (Country): BE 代表比利时(Belgium)。
O (Organization): GlobalSign nv-sa 表示这个证书的颁发机构是 GlobalSign 公司。
CN (Common Name): GlobalSign RSA OV SSL CA 2018 指的是该机构的某一特殊的证书颁发中心,其类型为组织验证(OV)SSL证书,通常会提供较高的信任度。
公钥类型: RSA,位数为2048
签名算法: RSA-SHA256
有效期:
NotBefore: 2024年7月8日
NotAfter: 2025年8月9日
---
Certificate chain
 0 s:C = CN, ST = beijing, L = beijing, O = "Beijing Baidu Netcom Science Technology Co., Ltd", CN = baidu.com
   i:C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Jul  8 01:41:02 2024 GMT; NotAfter: Aug  9 01:41:01 2025 GMT
-----BEGIN CERTIFICATE-----
MIIJ7DCCCNSgAwIBAgIMTkADpl62gfh/S9jrMA0GCSqGSIb3DQEBCwUAMFAxCzAJ
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSYwJAYDVQQDEx1H
bG9iYWxTaWduIFJTQSBPViBTU0wgQ0EgMjAxODAeFw0yNDA3MDgwMTQxMDJaFw0y
......
-----END CERTIFICATE-----

证书1
Subject:
C: BE
O: GlobalSign nv-sa
CN: GlobalSign RSA OV SSL CA 2018
Issuer:
OU: GlobalSign Root CA - R3
O: GlobalSign
CN: GlobalSign
公钥类型: RSA,位数为2048
签名算法: RSA-SHA256
有效期:
NotBefore: 2018年11月21日
NotAfter: 2028年11月21日 
1 s:C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018
   i:OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Nov 21 00:00:00 2018 GMT; NotAfter: Nov 21 00:00:00 2028 GMT
-----BEGIN CERTIFICATE-----
MIIETjCCAzagAwIBAgINAe5fIh38YjvUMzqFVzANBgkqhkiG9w0BAQsFADBMMSAw
HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs
U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODExMjEwMDAwMDBaFw0yODEx
......
-----END CERTIFICATE-----

证书2
Subject:
OU: GlobalSign Root CA - R3
O: GlobalSign
CN: GlobalSign
Issuer:
C: BE
O: GlobalSign nv-sa
OU: Root CA
CN: GlobalSign Root CA
公钥类型: RSA,位数为2048
签名算法: RSA-SHA256
有效期:
NotBefore: 2018年9月19日
NotAfter: 2028年1月28日
 2 s:OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign
   i:C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Sep 19 00:00:00 2018 GMT; NotAfter: Jan 28 12:00:00 2028 GMT
-----BEGIN CERTIFICATE-----
MIIETjCCAzagAwIBAgINAe5fFp3/lzUrZGXWajANBgkqhkiG9w0BAQsFADBXMQsw
CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UECxMH
Um9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE4MDkxOTAw
......
-----END CERTIFICATE-----

---
Server certificate
subject=C = CN, ST = beijing, L = beijing, O = "Beijing Baidu Netcom Science Technology Co., Ltd", CN = baidu.com
issuer=C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018

3. 客户端证书
No client certificate CA names sent: 表示未发送客户端证书CA名称,说明未进行客户端身份验证。
4. SSL握手结果
Peer signing digest: SHA256 (表明使用的摘要算法)
Peer signature type: RSA-PSS (使用RSA-PSS签名方案)
Server Temp Key: ECDH, prime256v1, 256 bits (表示在会话中使用的临时密钥协议)
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: ECDH, prime256v1, 256 bits

5. SSL会话和加密信息
SSL handshake has read 5414 bytes and written 441 bytes: 握手过程中读取和写入的字节数,表明交互过程的流量。
Verification: OK: 证书验证成功。
---
SSL handshake has read 5414 bytes and written 441 bytes
Verification: OK

6. 使用的协议和加密套件
New, TLSv1.2: 表示使用的TLS版本为1.2。
Cipher is ECDHE-RSA-AES128-GCM-SHA256 - 使用的加密套件是 ECDHE-RSA-AES128-GCM-SHA256。具体来说:
  * ECDHE:使用椭圆曲线 Diffie-Hellman 进行密钥交换。
  * RSA:用于身份验证。
  * AES128-GCM:对称加密算法(AES)使用 128 位密钥,以 Galois/Counter Mode (GCM) 进行操作,提供数据加密和完整性。
  * SHA256:用于消息的哈希和完整性检查。

Server public key is 2048 bit - 服务器的公钥长度为 2048 位。
Secure Renegotiation IS supported - 支持安全的重新协商。
Compression: NONE - 没有使用数据压缩。
Expansion: NONE - 没有使用数据扩展。
No ALPN negotiated - 没有协商应用层协议协商(ALPN)。


SSL-Session:
Protocol : TLSv1.2 - 会话使用的协议是 TLS 1.2。
Cipher : ECDHE-RSA-AES128-GCM-SHA256 - 会话使用的加密套件。
Session-ID - 会话 ID 字符串,用于标识会话。
Session-ID-ctx - 会话 ID 上下文,未使用。
Master-Key - 主密钥,用于会话加密。
PSK identity: None - 使用预共享密钥的标识,未使用。
PSK identity hint: None - 预共享密钥的身份提示,未使用。
SRP username: None - 使用安全随机密码(SRP)的用户名,未使用。
TLS session ticket: - TLS 会话票证,用于恢复会话。后面是以十六进制格式显示的票证内容。
Start Time: 1725011603 - 会话开始的时间(通常是 Unix 时间戳)。
Timeout : 7200 (sec) - 会话超时时间为 7200 秒(2 小时)。
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: 9DEAF036859176B3A982849FF4D9C2005BD0CE7C17CFAD3E416879027D7F0FF5
    Session-ID-ctx:
    Master-Key: 6115B5D4ACDC1715FAF8A54B33A7A38B0ECF4DF877627BCBFD0F5CA51F9CD975E66A3282C73824C15EF6E6E4F08FF933
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket:
    0000 - 5d de 2d bc 5a 6c e5 37-27 64 b5 1b 52 e5 c2 32   ].-.Zl.7'd..R..2
    0010 - ad b8 e8 6f 9c 2c c0 53-cf 8c 79 e2 ad b9 4f 93   ...o.,.S..y...O.
    0020 - 57 69 d2 03 d9 5c 01 50-bf 24 7f 49 68 4a 4e 80   Wi...\.P.$.IhJN.
    0030 - 1b ea 40 0f 09 7d 04 79-19 fb 9f c5 c6 22 e4 89   ..@..}.y....."..
    0040 - 4b 1e c9 d8 8d 05 d0 d7-ea 2c b0 59 27 28 97 02   K........,.Y'(..
    0050 - 5c d5 c1 59 b7 48 2a 00-c4 e4 d3 e0 7d 28 85 82   \..Y.H*.....}(..
    0060 - 6e 3d 88 5f 0b 34 35 14-22 38 3d b8 50 0d 4b 1b   n=._.45."8=.P.K.
    0070 - d2 a8 b9 5d 81 60 90 8b-f8 14 3d db dd 2c 62 80   ...].`....=..,b.
    0080 - 8a 9c 20 b5 c3 a9 d4 16-da 36 8e 45 cb e5 ee 4c   .. ......6.E...L
    0090 - 76 66 0a de 87 12 8d 14-2e c7 3c cd c1 e5 dd 54   vf........<....T

    Start Time: 1725011603
    Timeout   : 7200 (sec)
8. 验证返回码
Verify return code: 0 (ok): 表示所有证书通过了验证,连接安全有效。
    Verify return code: 0 (ok)
    Extended master secret: no
---

总结:该连接成功建立,所有证书均有效,并使用现代安全的加密协议和算法,符合最佳实践,没有明显的安全隐患。

下面我们将刚才申请的自签证书输出下:

openssl s_client -connect tls.ljh.cool:443 -showcerts
表示成功建立了TLS连接。
CONNECTED(00000005) 

输出中的 depth= 表示证书链的深度,也就是从服务器证书到根证书的路径长度。
Depth 2 和 Depth 1:
第2级的证书(根证书)是一个自签名证书(即它是自己签发的),因此验证失败,返回代码为19。

depth=2 C = CN, O = Alibaba Inc., OU = Alilang Cert Signing Authority, CN = Alilang Root CA 2048 - G2, emailAddress = alilang@alibaba-inc.com
verify error:num=19:self-signed certificate in certificate chain
verify return:1
depth=2 C = CN, O = Alibaba Inc., OU = Alilang Cert Signing Authority, CN = Alilang Root CA 2048 - G2, emailAddress = alilang@alibaba-inc.com
verify return:1
Depth 1: 第1级的证书验证成功。虽然它的颁发者(issuer)和被颁发者(subject)是同一个人,但可以成功验证。
depth=1 emailAddress = alilang@alibaba-inc.com, CN = Alilang OA TLS Server Root 2048 - G2, OU = alibaba-inc.com, O = Alibaba Inc., L = HangZhang, ST = ZheJiang, C = CN
verify return:1
Depth 0:第0级的证书即服务器证书,验证通过。
depth=0 emailAddress = alilang@alibaba-inc.com, CN = tls.ljh.cool, OU = alibaba-inc.com, O = Alibaba Inc., L = HangZhou, ST = ZheJiang, C = CN
verify return:1

3. 证书链
这里展示了完整的证书链,包括每个证书的主题(subject)和颁发者(issuer)。
证书0 是服务器证书。
证书1 是其颁发的中间证书。
证书2 是根证书。
---
Certificate chain
 0 s:emailAddress = alilang@alibaba-inc.com, CN = tls.ljh.cool, OU = alibaba-inc.com, O = Alibaba Inc., L = HangZhou, ST = ZheJiang, C = CN
   i:emailAddress = alilang@alibaba-inc.com, CN = Alilang OA TLS Server Root 2048 - G2, OU = alibaba-inc.com, O = Alibaba Inc., L = HangZhang, ST = ZheJiang, C = CN
公钥算法:
指定了公钥算法及密钥长度,第一证书使用的是ECDSA(椭圆曲线数字签名算法),256位密钥。
   a:PKEY: id-ecPublicKey, 256 (bit); sigalg: RSA-SHA512
有效期:
证书的有效期,确保在使用时未过期。
   v:NotBefore: Sep  1 02:43:09 2024 GMT; NotAfter: Sep 16 02:43:09 2024 GMT
-----BEGIN CERTIFICATE-----
MIID8zCCAtugAwIBAgIIBOfZTeyLiAAwDQYJKoZIhvcNAQENBQAwgbwxJjAkBgkq
hkiG9w0BCQEWF2FsaWxhbmdAYWxpYmFiYS1pbmMuY29tMS0wKwYDVQQDDCRBbGls
......
viLRgyJBcIPZFjP5klyp4+Y9yVSAxfuz/TmTsmtT7fWnyfZzu/0RZVL64kYpQIP3
np9rDImbxw==
-----END CERTIFICATE-----
 1 s:emailAddress = alilang@alibaba-inc.com, CN = Alilang OA TLS Server Root 2048 - G2, OU = alibaba-inc.com, O = Alibaba Inc., L = HangZhang, ST = ZheJiang, C = CN
   i:C = CN, O = Alibaba Inc., OU = Alilang Cert Signing Authority, CN = Alilang Root CA 2048 - G2, emailAddress = alilang@alibaba-inc.com
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Oct 30 14:38:21 2022 GMT; NotAfter: Oct 29 02:38:21 2032 GMT
-----BEGIN CERTIFICATE-----
MIIEQTCCAymgAwIBAgIIAYar1T7IRAAwDQYJKoZIhvcNAQELBQAwgZkxCzAJBgNV
......
AZLaKJPB0KXb5AtBB4FLnGRjMRFCjMiOgoUQHKpsn/5HEZUirg==
-----END CERTIFICATE-----
 2 s:C = CN, O = Alibaba Inc., OU = Alilang Cert Signing Authority, CN = Alilang Root CA 2048 - G2, emailAddress = alilang@alibaba-inc.com
   i:C = CN, O = Alibaba Inc., OU = Alilang Cert Signing Authority, CN = Alilang Root CA 2048 - G2, emailAddress = alilang@alibaba-inc.com
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Oct 10 09:53:39 2019 GMT; NotAfter: Oct  5 09:53:39 2039 GMT
-----BEGIN CERTIFICATE-----
MIIDsDCCApgCCQDUblPK/A1XPjANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UEBhMC
......
bF7/jQEC6YQQW7pv56J7nPOks2fsvYirvjINJRk+ljUO9xUU
-----END CERTIFICATE-----
---
Server certificate
subject=emailAddress = alilang@alibaba-inc.com, CN = tls.ljh.cool, OU = alibaba-inc.com, O = Alibaba Inc., L = HangZhou, ST = ZheJiang, C = CN
issuer=emailAddress = alilang@alibaba-inc.com, CN = Alilang OA TLS Server Root 2048 - G2, OU = alibaba-inc.com, O = Alibaba Inc., L = HangZhang, ST = ZheJiang, C = CN
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits

TLS握手过程:
握手过程中读取和写入的字节数,这在调试时会很有用。
---
SSL handshake has read 3437 bytes and written 394 bytes
Verification error: self-signed certificate in certificate chain

TLS版本与加密套件
建立的连接使用TLS 1.3协议与AES_256_GCM_SHA384加密套件,表示使用256位密钥的GCM模式。
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 19 (self-signed certificate in certificate chain)
---

会话票据:
会话ID及相关参数用于会话恢复,表明该连接的会话参数,包括超时等。
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: EF64E2B2C317DA893DB3D951FF70A1E5E5CEE8C9935083CE13AF58B09FDDBE37
    Session-ID-ctx:
    Resumption PSK: 66589C665DBC75ACB8A5743484B297B409A371817CD3156D42573667359AA9DC80D24C1C8FF370C5A22F7FD8DACE7616
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 604800 (seconds)
    TLS session ticket:
    0000 - 10 f4 51 73 c7 12 86 ab-04 b0 a2 9d 7a 13 1c e8   ..Qs........z...
    0010 - ee b9 8a a1 ce 76 2b a7-16 e8 fc 26 9d 64 ba 5c   .....v+....&.d.\
    0020 - 7b ba d5 61 85 c9 a1 92-2f 92 f8 db bb c0 86 64   {..a..../......d
    0030 - 99 cc c1 7c a6 42 5a 96-de b0 e3 bc 77 5e 29 ad   ...|.BZ.....w^).
    0040 - 14 38 49 36 ee 70 d9 37-09 98 af 71 78 eb de c3   .8I6.p.7...qx...
    0050 - 33 a5 40 d8 37 66 09 a8-06 64 bb 6f 9a ee 46 80   3.@.7f...d.o..F.
    0060 - b0 f8 c1 fb 25 3d 55 a4-40 8a eb 92 80 96 91 7b   ....%=U.@......{
    0070 - 46 c5 84 65 4d 65 d6 d3-43 f2 79 50 7b b1 1e fa   F..eMe..C.yP{...
    0080 - de                                                .

    Start Time: 1725245231
    Timeout   : 7200 (sec)
错误信息:
验证返回代码为19,指出在证书链中发现了自签名证书。这通常意味着链中的某一部分没有经过值得信任的CA签署。
Verify return code: 19 (self-signed certificate in certificate chain)
    Verify return code: 19 (self-signed certificate in certificate chain)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK

总结:这段输出展示了一个TLS连接建立过程中的证书链和相关参数。在该连接中,证书的验证并未完全成功,有自签名证书存在。因此,虽然连接可能会建立,但可能会存在安全性方面的风险。在实际部署中,应确保使用的证书由可信的CA签署。

加密

在服务器和网络安全中,常见的加密方式主要包括对称加密、非对称加密和哈希函数等。以下是这些加密方法的简要说明及其原理:

加密类型

1. 对称加密

  • 原理: 使用相同的密钥进行加密和解密。加密算法将明文变成密文,使用密钥来进行反向操作。
  • 常见算法:
    • AES (Advanced Encryption Standard):广泛使用的加密标准,具有较高的安全性和效率。
    • DES (Data Encryption Standard):旧标准,已被认为不再安全;通常更少使用。
    • 3DES (Triple DES):在DES的基础上进行增强,但效率较低,仍被逐步替代。
  • 特点:
    • 安全性依赖于密钥的保密性。
    • 加密和解密速度较快,适合处理大量数据。
    • 密钥分发是一个挑战,因为发送方和接收方都需要安全地共享密钥。

2. 非对称加密

  • 原理: 使用一对密钥,即公钥和私钥。公钥用于加密,私钥用于解密。只有拥有私钥的人才能解密由其公钥加密的数据。
  • 常见算法:
    • RSA (Rivest-Shamir-Adleman):常用的非对称加密算法,用于加密小数据块和数字签名。
    • DSA (Digital Signature Algorithm):用于数字签名的标准算法。
    • ECC (Elliptic Curve Cryptography):基于椭圆曲线的加密算法,能在较小的密钥长度下提供较高的安全性。
  • 特点:
    • 解决了密钥分发问题。公钥可以公开,而私钥必须保密。
    • 加密和解密速度相对较慢,通常用于小量数据的加密,如密钥交换和数字签名。
    • 非对称加密还经常用于身份验证。

3. 哈希函数

  • 原理: 将输入数据(明文)进行处理,输出固定长度的哈希值。该过程是单向的,无法从哈希值还原出原数据。哈希函数接受任意大小的数据并生成固定大小的输出(如SHA-256生成256位的哈希值),而加密算法的输入和输出通常都是可变的。
  • 目的:哈希函数的主要目的是生成一个定长的独特摘要(哈希值),用于验证数据的完整性,不同于加密的目的是保护数据的机密性,使其只能被授权方读取。生成的哈希值可以存储在安全的位置,例如数据库或文件中。确保存储的哈希值不会被篡改。在后续的任何时间,您可能会想验证原始数据是否被修改。获取要验证的数据,并再次使用 SHA-256 计算哈希值,将新生成的哈希值与之前储存的哈希值进行比较,如果两个哈希值相同,则说明数据未被篡改,完整性得以保持。如果两个哈希值不同,则数据可能被修改或损坏。
  • 常见算法:
    • SHA (Secure Hash Algorithm):如SHA-256、SHA-1(已不推荐使用)等,用于生成数据的哈希值,确保数据完整性。
    • MD5 (Message Digest Algorithm 5):虽然曾经广泛使用,但因安全性问题而不再推荐。
  • 特点:
    • 适用于数据完整性验证和存储密码(结合加盐技术)。
    • 同一输入总是产生相同的哈希值,不同输入应产生不同的哈希值。
    • 对抗碰撞攻击,即极难找到两个不同的输入其哈希值相同。

4. 混合加密

很多实际应用中,都会结合使用对称加密和非对称加密,例如在SSL/TLS协议中,非对称加密用于安全地交换对称密钥,而后续的数据传输则使用对称加密进行加密,达到安全性与效率的平衡。

TLS(传输层安全协议)是一种广泛使用的安全协议,旨在为计算机网络提供通信安全。它的工作过程包含几个重要步骤,尤其是在加密方面。

混合加密TLS握手过程详解(以上述通过 https 连接百度网站为例)

1 客户端发送Client Hello请求
客户端(浏览器)发起一个 HTTPS 请求,首先会通过 DNS 查询获取服务器的 IP 地址,随后向服务器的 IP 地址发送一个Client Hello连接请求。此请求通常会包括以下内容:

  • 使用的协议版本(TLS 版本)
  • 支持的加密套件(Cipher Suites),如 ECDHE-RSA-AES128-GCM-SHA256
  • 客户端随机数(Client Random),后面用于生成会话密钥

2 服务器响应Server Hello
百度服务器响应 Server Hello 消息,选择一个加密套件并发送:

  • 服务器选择的TLS版本:TLSv1.2
  • 加密算法:ECDHE-RSA-AES128-GCM-SHA256
  • 随机数(Server Random)

3 证书交换

  • 服务器发送其 SSL 证书链。
    • 第一份证书是百度的服务器证书,签发机构是 GlobalSign。
    • 证书中的:
      • 公钥算法:rsaEncryption (2048 位)
      • 签名算法:SHA256 (签名值使用 RSA-SHA256)

证书信息分析

  • 证书链中的第二个证书是 GlobalSign 的中间证书,同样使用 RSA-SHA256 签名。
  • 第三个证书是 GlobalSign 的根证书。

4. 证书验证

  • 客户端验证服务器的 SSL 证书链,以检查证书的有效性、签名和是否被信任。
  • 在这里,使用的验证算法是 RSA,结合 SHA256 执行签名验证。

5 密钥交换
在确认了服务器的身份后,客户端进行密钥交换:

  • 客户端生成一个预主密钥随机数(Pre-Master Secret),并使用从服务器的证书中获取的公钥对其进行加密,然后发送给服务器。
  • 服务器接收到加密的预主密钥后,使用其私钥解密,得到预主密钥。
  • 客户端和服务器使用预主密钥以及之前生成的 Client Random 和 Server Random,通过一个预定义的算法(如 PRF,伪随机函数)生成会话密钥(Session Keys,也称为主密钥)。这些会话密钥用于后续的对称加密。

6. 加密的会话

  • 之后的通信都将使用对称加密算法。
  • 在此例中使用的对称加密算法是 AES-128-GCM,提供加密和认证(加密后附加数据认证)。

7. 总结

上述和百度 tls 连接过程中使用的加密算法总结有:

  • 非对称加密: RSA(用于交换密钥和证书验证)【RSA 的主要作用是确保在建立安全的 HTTPS 连接过程中,客户端和服务器能够安全地交换会话密钥,并提供身份验证和数据完整性。通过这种方式,HTTPS 确保了安全的通信渠道,使得数据在传输过程中的机密性和安全性得以保持。】
  • 对称加密: AES-128-GCM(用于会话中的加密数据)
  • 哈希算法: SHA256(用于证书签名【认证机构(CA)使用 SHA256 对证书内容进行哈希,然后用自己的私钥对这个哈希值进行签名,以确保用户在访问网站时可以验证】和数据完整性校验【在 SSL/TLS 握手以及数据传输过程中,SHA256 也用于生成消息摘要,以确保数据在传输中没有被篡改】)
  • 密钥交换算法: ECDHE(基于椭圆曲线的 Diffie-Hellman 交换,提供完美向前保密)【用于安全地交换会话密钥:ECDHE 允许客户端和服务器在不直接传输密钥的情况下生成一个共享的私密会话密钥,确保对称加密通信的安全性。由于 ECDHE 每次握手生成的会话密钥都是随机的,即使长期的私钥被泄露,过去的会话内容仍然是安全的,这就是完美向前保密(PFS)所提供的安全性。】

tls 更多密钥和握手细节见:https://www.ljh.cool/39516.html(Wireshark抓包分析TCP三次握手部分)

以上过程涉及到的加密数学算法

1. RSA算法

RSA 是一种基于大数因子的公钥密码体制,主要用于加密和数字签名。虽然它本身不是专门的密钥交换协议,但可以用来交换会话密钥。

过程:

  1. 生成密钥对:
    • 选择两个大质数 pp 和 qq
    • 计算 n=p×qn=p×q,这是模数。
    • 计算 ϕ(n)=(p−1)(q−1)ϕ(n)=(p−1)(q−1),这是欧拉函数。
    • 选择一个小于 ϕ(n)ϕ(n) 且与 ϕ(n)ϕ(n) 互质的整数 ee(通常选择 65537)。
    • 计算私钥 dd,使得 d×emod  ϕ(n)=1d×emodϕ(n)=1。
    • 公钥为 (e,n)(e,n),私钥为 (d,n)(d,n)。
  2. 密钥交换:
    • 发送方选择一个对称加密密钥 KK
    • 使用接收方的公钥 (e,n)(e,n) 对 KK 进行加密,得到密文 C=Kemod  nC=Kemodn
    • 将密文 CC 发送给接收方。
    • 接收方使用自己的私钥 dd 解密得到 K=Cdmod  nK=Cdmodn

2. ECDHE(Elliptic Curve Diffie-Hellman Ephemeral)一种基于椭圆曲线的公钥加密算法,提供更高的安全性和性能,常用于现代 TLS 版本中的密钥交换。

证书以及加密

3. 对称加密AES加密过程

  1. 密钥扩展:将原始128位密钥扩展为一系列轮密钥,AES-128通常进行10轮加密。
  2. 初始轮
    • 添加轮密钥:将明文和第一个轮密钥进行异或(XOR)操作。
  3. 主轮(进行9轮):
    • 字节替换(SubBytes):使用S-盒替换每个字节。
    • 行移位(ShiftRows):对行进行循环左移。
    • 混合列(MixColumns):将每列进行线性变换,提高扩散性。
    • 添加轮密钥(AddRoundKey):与当前轮的轮密钥进行XOR操作。
  4. 最终轮(进行1轮,不进行混合列):
    • 执行字节替换、行移位,最后进行添加轮密钥。

GCM模式:

  • 计数器模式:GCM使用增量计数器(IV)来生成伪随机的密钥流。
  • 认证标签生成:生成的加密文本和附加数据一同使用GHASH算法生成认证标签,确保数据未被篡改。

4. 哈希验证方式SHA-256算法过程

说明:

TLS 使用哈希函数进行完整性校验和身份验证。

  1. 数据填充:将输入数据填充到448位的倍数,填充位为1,后面填充0,并把总长度表示为64位,最后附加一个64位的长度信息。
  2. 分块处理:将填充后的数据分为512位的块。
  3. 初始化哈希值:使用特定常数初始化8个32位的哈希值。
  4. 循环摘要
    • 对每一个512位的块执行64轮操作,使用SHA-256的压缩函数(包括位运算、模2运算等)。
    • 在每一轮中,使用当前哈希值和当前块的数据来更新哈希值。
  5. 输出:最终输出256位的哈希值。

非对称加密 SSH 加密过程

SSH连接过程中的加密过程

1. 密钥对的生成
用户在本地生成一对密钥:一个公钥和一个私钥。
公钥可以自由分发,而私钥必须保密。
2. 将公钥放置在服务器上
用户将公钥上传到服务器,并放在特定的文件(通常是 ~/.ssh/authorized_keys)中。
3. 连接过程
当用户尝试通过SSH连接到服务器时,以下步骤发生:
  a. 客户端发起连接
    SSH客户端向服务器发送一个连接请求。
  b. 服务器生成挑战
    服务器接收到连接请求后,会生成一个随机的“挑战”字符串,并用用户的公钥加密该字符串。
  c. 发送挑战
    服务器将这个加密过的挑战字符串发送给客户端。
  d. 客户端解密挑战
    客户端使用其私钥解密这个挑战字符串。如果解密成功,客户端就知道自己是合法的用户,因为只有持有对应私钥的人才能成功解密。
4. 响应挑战
客户端在获取到挑战后,会生成一个基于该挑战的响应并将其发送回服务器。
5. 服务器验证
服务器收到响应后,使用同样的公钥对响应进行验证,以确保响应是由合法的客户端生成的。
6. 完成连接
如果验证成功,SSH连接建立,后续的数据传输会使用对称加密来保障安全性。

在SSH中:
* 私钥用于身份验证,而不是直接用于数据加密。
* 公钥用于验证客户端凭证,而不是直接用于解密传输的数据。
* 通过这种方式,即使黑客窃取了通过网络传输的数据,只要他们没有私钥,也无法解密通过SSH建立的连接的信息。

加密练习

使用 Python 进行对称加密和解密

使用 Python 的 cryptography.hazmat 库进行对称加密和解密的过程。以下是一个完整的示例,展示了如何使用对称加密(AES)加密和解密数据。

首先,确保你已经安装了 cryptography 库。如果尚未安装,可以通过以下命令安装:

pip install cryptography

这里使用AES 对称加密和解密的示例

以下是用于对称加密和解密数据的示例代码。我们将使用 AES 算法,并利用 Fernet 进行处理。

from cryptography.fernet import Fernet

# 生成密钥
def generate_key():
    key = Fernet.generate_key()  # 生成密钥
    with open('secret.key', 'wb') as key_file:
        key_file.write(key)  # 将密钥写入文件
    return key

# 加载密钥
def load_key():
    return open('secret.key', 'rb').read()  # 从文件加载密钥

# 加密数据
def encrypt_data(data):
    key = load_key()  # 加载密钥
    f = Fernet(key)  # 创建 Fernet 对象
    encrypted_data = f.encrypt(data.encode())  # 加密数据
    return encrypted_data

# 解密数据
def decrypt_data(encrypted_data):
    key = load_key()  # 加载密钥
    f = Fernet(key)  # 创建 Fernet 对象
    decrypted_data = f.decrypt(encrypted_data).decode()  # 解密数据
    return decrypted_data

if __name__ == "__main__":
    # 生成密钥,确保只需调用一次
    # generate_key()

    # 假设我们有一些数据需要加密
    data_to_encrypt = "这是一段需要加密的文本。"

    # 加密数据
    encrypted = encrypt_data(data_to_encrypt)
    print("加密后的数据:", encrypted)

    # 解密数据
    decrypted = decrypt_data(encrypted)
    print("解密后的数据:", decrypted)

代码解析

  1. 生成密钥 (generate_key): 该函数生成一个新的 Fernet 密钥并将其保存到文件中。只需运行一次来创建密钥。
  2. 加载密钥 (load_key): 从文件中读取保存的密钥。
  3. 加密数据 (encrypt_data): 使用加载的密钥创建 Fernet 对象并加密输入数据。
  4. 解密数据 (decrypt_data): 使用同样的方式创建 Fernet 对象并解密已加密的数据。
  5. 主程序: 在 __main__ 部分,我们可以调用这些函数并展示加密和解密的过程。

生成密钥只调用一次,结果如下:

证书以及加密

分析代码加密原理

这段代码使用了对称加密算法中的一个实例,具体来说是 Fernet,它由 cryptography 库提供。接下来我将解析加密的原理,以及为什么每次加密得到不同的密文。

代码中涉及的加密原理

  1. 对称加密:Fernet 是一种对称加密算法,这意味着加密和解密使用的是同一个密钥。你生成密钥后,必须保密以确保数据安全。
  2. 生成随机 IV(Initialization Vector):Fernet 在加密数据时,会生成一个随机的初始化向量(IV),这会导致即便是相同的明文内容,每次加密后得到的密文都会不同。IV 的存在是为了增强加密的安全性,使得相同的明文在加密后即使在相同的密钥下也不会产生相同的密文。
  3. 加密过程
    • 当调用 encrypt 方法时,Fernet 会生成一个随机的 IV,结合密钥和明文进行加密,得到密文。
    • 加密算法会将 IV 和密文结合在一起,并且通常会以特定的格式存储,例如一个大字符串。
  4. 解密过程
    • 在解密时,Fernet 从密文中提取出 IV 和真正的密文部分,使用相同的密钥和提取出来的 IV 来还原出原始的明文。
    • 由于使用了相同的密钥和 IV,解密过程可以恢复出原始数据。

为什么会产生不同的密文

由于每次加密时都会生成一个新的随机 IV,因此即使相同的明文数据在多次加密时,也会得出不同的密文。这个设计使得加密更安全,因为攻击者无法仅通过观察密文来获取原始信息,即使知道加密使用的算法和密钥,也不能保证可预测。

综上所述,Fernet 的设计使得对称加密既高效又安全,确保了每次加密的数据都是唯一的,尽管明文内容相同。这个特性在许多应用场景中非常重要,比如加密敏感信息以保护用户隐私。

Fernet库中涉及到的数学过程

加密过程:

证书以及加密

解密过程:

证书以及加密

以上就是Fernet库中字符串加密和解密的基本数学过程。通过这种方式,确保了数据不仅被加密保护,而且在传输过程中保持了完整性。

使用 Java 进行对称加密和解密

环境 Ubuntu22 jdk11.0.24

sudo apt update
sudo apt install openjdk-11-jdk

EncryptionClient.java

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class EncryptionClient {
    // 使用AES算法加密字符串
    public static String encrypt(String data, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    // 生成一个AES密钥
    public static SecretKey generateKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(128); // 使用128位AES密钥
        return keyGen.generateKey();
    }

    public static void main(String[] args) {
        try {
            // 生成密钥
            SecretKey secretKey = generateKey();
            String secretKeyString = Base64.getEncoder().encodeToString(secretKey.getEncoded());

            // 待加密的明文
            String dataToEncrypt = "Hello, secure world!";
            // 加密
            String encryptedData = encrypt(dataToEncrypt, secretKey);
            System.out.println("Encrypted Data: " + encryptedData);
            System.out.println("Secret Key (Base64): " + secretKeyString);
            
            // 此处可以将密钥和加密数据发送到服务端

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

DecryptionServer.java

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class DecryptionServer {
    // 解密字符串
    public static String decrypt(String encryptedData, SecretKeySpec secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(decryptedBytes);
    }
    
    public static void main(String[] args) {
        try {
            // 这个秘钥应该由客户端发送过来
            String secretKeyString = "YOUR_SECRET_KEY_BASE64"; // 需要替换为实际的Base64编码秘钥
            SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(secretKeyString), "AES");
            
            // 需要解密的数据
            String encryptedData = "YOUR_ENCRYPTED_DATA"; // 需要替换为实际的加密数据
            
            // 解密
            String decryptedData = decrypt(encryptedData, secretKeySpec);
            System.out.println("Decrypted Data: " + decryptedData);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用说明

  1. 客户端代码:
    • 生成一个AES密钥,并使用该密钥加密要传输的数据。
    • 输出加密数据和Base64格式的秘钥。
  2. 服务端代码:
    • 从客户端接收Base64编码的秘钥和加密数据。
    • 使用秘钥解密加密数据,并输出明文。

执行过程:

加密:

javac EncryptionClient.java

java EncryptionClient

证书以及加密

解密:

修改DecryptionServer.java

证书以及加密

javac DecryptionServer.java

java DecryptionServer

证书以及加密

使用 Python 进行非对称加密的示例

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes

# 生成一对 RSA 密钥对
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

public_key = private_key.public_key()

# 将公钥和私钥序列化为 PEM 格式
pem_private_key = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.TraditionalOpenSSL,
    encryption_algorithm=serialization.NoEncryption()  # 这里不加密私钥

)

pem_public_key = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

print("私钥:")
print(pem_private_key.decode())

print("\n公钥:")
print(pem_public_key.decode())

# 原始消息
message = "这是一个需要加密的消息。".encode('utf-8')

# 使用公钥加密消息
ciphertext = public_key.encrypt(
    message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

print("\n加密后的消息:")
print(ciphertext)

# 使用私钥解密消息
decrypted_message = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

print("\n解密后的消息:")
print(decrypted_message.decode())

代码解释:

  1. 生成密钥对:使用 RSA 算法生成一对私钥和公钥。
  2. 序列化密钥:将私钥和公钥序列化为 PEM 格式,以便于查看和存储。
  3. 加密消息:使用公钥对消息进行加密。
  4. 解密消息:使用私钥对加密后的消息进行解密。

执行:

证书以及加密

记录公钥和私钥内容注入到下面文件中,下面验证这个过程:

私钥:private_key.pem
公钥:public_key.pem

加密字符串

假设你要加密的字符串是 "Hello, World!"。可以将其保存在一个文件中,比如 plaintext.txt

echo "Hello, World!" > plaintext.txt

使用公钥加密字符串:

openssl rsautl -encrypt -inkey public_key.pem -pubin -in plaintext.txt -out ciphertext.bin

解密字符串

使用私钥解密使得得出的密文:

openssl rsautl -decrypt -inkey private_key.pem -in ciphertext.bin -out decrypted.txt

查看解密结果

cat decrypted.txt
证书以及加密

发布者:LJH,转发请注明出处:https://www.ljh.cool/41325.html

(0)
上一篇 2024年6月28日 上午8:46
下一篇 2022年9月26日 上午2:37

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注