PKI知识点整理

1 基础

1.1 对称算法

  • 描述:对称加密是指加密过程和解密过程使用相同的密码。主要分:分组加密序列加密
  • 原理:XOR运算,将二进制数据进行XOR运算,两次同样的操作得到原文,所以大致过程就是加密->A xor B = C,解密->C xor B = A(B就是密钥)。
  • 优点:加密速度快,适合于对大量数据加密。
  • 缺点:发送方和接受方需要使用相同的密钥,一旦密钥泄露,在互联网上传输的加密数据将会被中间人破解。而且由于加密数据量大

分类:

  • DES(Data Encryption Standard),
    • 分组算法
    • 分组长度64bit(8字节),明文分为左右两侧轮回与密钥XOR运算,每轮使用不同的密钥
    • 密钥空间2^56
  • 三重DES(triple-DES),将DES重复3次
    • 分组长度64bit(8字节)
  • AES(Advances Encryption Standard),高级加密标准
    • 分组长度为128bit(16字节)
    • 密钥长度只有128、192、256bit
  • RC2,RC4,RC5
    • RC2和RC5是分组算法,RC4是序列算法
    • RC5分组可变、密钥长度可变
  • SSF33,SM1,SM4
    • 分组算法
    • 分组长度128bit(16字节)

1.2 摘要算法

摘要算法使用密码学hash函数,用于验证数据完整性(没有修改、插入、删除、或重放)。找到两个不同数据具有相同hash值的难度高。
输入数据的长度首先被填充为某固定长度分组的整数倍,填充的内容包括原始数据的位长度信息。安全性要求如下两种情况在计算上不可行(即没有攻击方法比穷举攻击更有效):

  • 对预先指定的hash值找到对应的数据块(单向性)
  • 找到两个不同的数据块对应相同的hash值(抗碰撞性)

Hash算法一般是指Hash表的摘要算法,将不同的键值分散到不同的数组位置,允许少量的冲突碰撞。安全Hash算法(SHA)是使用最广泛的Hash函数

  • MD2、MD4、MD5
    • 摘要长度128bit(16字节)
  • SHA1、SHA2、SHA3
    • Secure Hash Algorithm
    • SHA-1摘要长度160bit(20字节)
    • SHA-2摘要长度256bit(32byte)
    • SHA-3摘要长度384bit(48byte)
  • SM3
    • 中国国家商用密码算法
    • 摘要长度256bit(32byte)

摘要函数——MD2/MD4/MD5数字签名

附1:消息认证码(MAC)

又称密码校验和,利用密钥K和可变长度的数据M生成固定长度的短数据块MAC,并将数据块附加在数据M之后:
$$
MAC = C(K, M)
$$
若对于数据的保密性要求不高(例如广播),可直接将消息MMAC一起发给接受者,接收者收到后使用相同的密钥K和MAC函数C对消息M计算得出MAC2,再对比两者是否相等。(这里设定通信双方共享相同的密钥K
若对于数据的保密性要求严格,可选择将消息MMAC加密再发送:
$$
ENC = E(K_2, M||C(K_1,M))
$$
接收者收到数据后首先解密。

附2:基于Hash函数的MAC:HMAC

HMAC将Hash函数视为黑盒,将现有Hash函数作为一个模块,预先封装,在需要时直接使用。

HMAC结构
  • H:嵌入的Hash函数
  • IV:Hash函数输入的初始化数组
  • M:HMAC的消息输入(包括由嵌入Hash函数定义的填充位)
  • $Y_i$:M的第i个分组
  • L:M中的分组个数
  • b:每一分组所含位数(bits)
  • n:嵌入的Hash函数所产生的Hash码长

1.3 分组模式

  • ECB (Electronic Code book,电子密码本方式)明文分组与密文分组一一对应
    • 优点:最简单的一种模式,可并行运算,误差不会传递
    • 缺点:若有相同明文分组,将被加密成相同密文分组,即明文的结构容易被泄露
    • CA产品的私钥保护使用ECB算法
  • CBC (Cipher-block chaining,密码分组链接)明文分组首先与一个密文分组XOR运算,然后再加密,这样做的目的就是改变明文分组的结构,由于第一个明文分组前没有密文分组,需增添IV初始化向量,与第一个明文分组XOR运算
    • 若密文分组损坏,但是长度没有改变,即仅改变几位的数据,解密后最多只影响两个明文分组(密文分组本身对应的明文分组,密文分组为后一个分组提供XOR伙伴的后一个明文分组)
    • 若密文缺失bit,则缺失bit之后的密文全部无法解密
  • CFB (Cipher Feedback ,密码反馈模式)明文分组与密钥XOR运算,CFB实现了一个被我成为伪伪随机数发生器的密码算法,它将前一个密文分组加密生成一个bit序列,称为密钥流(key stream),由于第一个明文分组前没有密文分组,需添加IV初始化向量,执行加密生成第一个密钥流。
  • OFB (Output Feedback ,输出反馈模式)OFB与CFB相同的地方在于都是将明文分组与密钥XOR运算,区别就在于密钥的生成。OFB的密钥算法的输入来自于上一个密钥算法的输出。第一个密钥算法的输入使用一个IV向量

OFB与CFB都采用将分组加密转换成流加密的方式

1.4 填充模式

  • PKCS#5Padding
PKCS5Padding

如图,用自己的话来描述就是缺多少bit,就在每个bit里填多少。该方式是8分组结构,只适合DES/3DES。

  • PKCS7Padding
    分组长度可以是小于255的任意长度
  • ZeroPadding
    使用0X0补齐:... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 00 |
  • ANSI X.923
    该模式在最后一个字节填缺少的bit数,其它补0X0(我觉得这个模式更符合一般人的想法):... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 04 |
  • ISO 10126
    该模式个人觉得稍好一些,最后一个填充位填写缺少的bit数,其它位填充随机数:... | DD DD DD DD DD DD DD DD | DD DD DD DD 81 A6 23 04 |
  • ISO/IEC 7816-4
    填充实例如下:... | DD DD DD DD DD DD DD DD | DD DD DD DD 80 00 00 00 |(未解)

1.5 密钥运算

密钥运算包含两种操作(私钥操作、公钥操作),签名验签正是基于这两种操作:
$$
C=P^d mod n
$$

$$
P=C^d mod n
$$

1.5.1 签名验签

使用签名的前提是使用公钥加密的密文只有私钥才能解开,使用私钥加密的密文只有公钥才能解开,确保了身份认证抗抵赖性。
过程:

  • 对原文摘要
  • A使用自己的私钥AS对摘要私钥加密运算,得到签名
  • B使用A的公钥AP对签名公钥解密运算,得到摘要值2,这一步证明签名来自A,若C伪造A的身份使用自己的私钥CP,则B的公钥解密失败。
  • B再使用和A相同的hash算法对原文摘要,得到摘要值3,这一步可用来验证原文是否遭到篡改,
  • B验证摘要值2和3是否相等

至于填充模式,定义在PKCS#1:00||BT||PS||00||D

  • 00保证大数是非负整数
  • BT分为00,01,02。00,01是私钥操作,02是公钥操作
    • 00:填充数据全为0X00,摘要必须以非0开头,如果摘要以0开头,将与填充数据无法区分
    • 01:填充数据全为0XFF
    • 02:填充数据必须为随机数

1.5.2 RSA公钥加密

使用RSA公钥运算,过程如下:

  • 对原文数据填充、封装->$P$
  • 对P大数运算:$C=P^e mod n$

用途:用于非对称传输信息,比如Bob有一个信息想传给Alice,需使用Alice的公钥加密信息,传给Alice,Alice得到加密信息后使用自己的私钥即可解开读取信息。他人即使截获加密信息也无法解开,利用了大数分解难题。

1.5.3 RSA私钥解密

使用RSA私钥运算,过程如下:

  • 对密文数据大数运算:$P=C^d mod n$
  • 对P进行去填充

以上可以看出,私钥解密和签名的运算过程一致!

1.6 PKCS#1

定义RSA公私钥数据表达形式,及加密,解密,签名,验签,填充过程,定义了数字签名如何计算,包括签名数据和签名本身的格式。

RSA公钥结构:

RSAPublicKey :: = SEQUENCE{
   modulus              INTEGER,   ------ n(RSA合数模)
   publicExponent    INTEGER    ------ e (RSA公开幂,3~n-1范围内的正整数)
}

RSA公钥的ASN.1结构,可以表述为:名为RSAPublicKey的这个结构呢,就可以用来表述一个RSA公钥了。它有两个INTEGER型变量:modulus和publicExponent。

RSA私钥结构:

RSAPrivateKey :: = SEQUENCE{
    version                 Version,(版本号,如果使用多素数,版本号为1)
    modulus               INTEGER,   ------ n(RSA合数模)
    publicExponent     INTEGER,   ------ e(RSA的公开幂)
    privateExponent    INTEGER,   ------ d(RSA的私有幂)
    prime1                 INTEGER,   ------ p(n的素数因子p)
    prime2                 INTEGER,   ------ q(n的素数因子q)
    exponent1            INTEGER,   ------ d mod (p -1)
    exponent2            INTEGER,   ------ d mod (q -1)
    coefficient            INTEGER,   ------- (inverse of q) mod p
    otherPrimeInfos    OtherPrimeInfos   ------ OPTIONAL(当version为0时,不存在;当 version为1时,必须有)
}

加密和签名方案的对象标识

以下是对PKCS#1 OID的类型表示的定义

PKCS1Algorithms ALGORITHM-IDENTIFIER ::= {
 { OID rsaEncryption PARAMETERS NULL } |
 { OID md2WithRSAEncryption PARAMETERS NULL } |
 { OID md5WithRSAEncryption PARAMETERS NULL } |
 { OID sha1WithRSAEncryption PARAMETERS NULL } |
 { OID sha256WithRSAEncryption PARAMETERS NULL } |
 { OID sha384WithRSAEncryption PARAMETERS NULL } |
 { OID sha512WithRSAEncryption PARAMETERS NULL } |
{ OID id-RSAES-OAEP PARAMETERS RSAES-OAEP-params } |
 PKCS1PSourceAlgorithms |
{ OID id-RSASSA-PSS PARAMETERS RSASSA-PSS-params } ,
 ... -- Allows for future expansion --
} 

RSAES-OAEP加密

RSAES-OAEP-params ::= SEQUENCE {
 hashAlgorithm [0] HashAlgorithm DEFAULT sha1,(标识了散列函数)
 maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, (标识掩膜生成函数)
 pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty(标识标签L的源)
} 

hashAlgorithm支持的散列函数:

OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= {
 { OID id-sha1 PARAMETERS NULL }|
{ OID id-sha256 PARAMETERS NULL }|
{ OID id-sha384 PARAMETERS NULL }|
{ OID id-sha512 PARAMETERS NULL },
 ... -- Allows for future expansion --
} 

1.7 PKCS#5

基于口令的加密规范Password-Based Cryptography Specification

目的:保护私钥文件的安全性

通过将原始口令+salt派生出新口令进行加密

PKSC5Padding(用于制定算法DES)对称加密填充方式,填充块固定为8个字节,填充值为待填充的长度,与PKCS7Padding类似。

1.8 PKCS#7

加密消息的语法标准Cryptographic Message Syntax Version 1.5
结构:

typedef struct pkcs7_st
{
  /* 其他项 */

  ASN1_OBJECT *type;

  union
  {
    char *ptr;
   /* NID_pkcs7_data */
   ASN1_OCTET_STRING *data;

   /* NID_pkcs7_signed */
   PKCS7_SIGNED *sign;

   /* NID_pkcs7_enveloped */
   PKCS7_ENVELOPE *enveloped;

   /* NID_pkcs7_signedAndEnveloped */
   PKCS7_SIGN_ENVELOPE *signed_and_enveloped;

   /* NID_pkcs7_digest */
   PKCS7_DIGEST *digest;

   /* NID_pkcs7_encrypted */
   PKCS7_ENCRYPT *encrypted;

   /* Anything else */
   ASN1_TYPE *other;
 } d;
} PKCS7;

pkcs7 各种类型数据结构的 DER 编解码通过宏在 crypto/pkcs7/pk7_asn1.c 中实现

  • 可以包含6种类型的数据:
    • id-data: 任意数据,由应用解析,可以是明文数据。
    • id-signedData: 签名数据
    • id-envelopedData: 加密数据
    • id-signedAndEnvelopedData: 签名又加密数据,数字信封
    • id-digestedData: 摘要数据,原文及摘要结果
    • id-encryptedData: 只有加密数据,密钥在带外传送、管理

数字信封流程:(A:发送方;B:接收方;SK:私钥;PK:公钥)

  • A对明文进行hash运算,得到摘要

  • A用自己的私钥A:SK对摘要进行RSA私钥加密运算,得到A的数字签名

  • A随即产生一个用于特定加密算法的加密密钥(DES密钥),并使用该密钥对明文进行对称加密,形成密文

  • A使用B的公钥B:PK对随机产生的加密密钥进行RSA公钥加密运算,并将结果与密文一同传送给B

  • B用自己的私钥B:SK对对称加密的结果进行RSA私钥解密运算,得到A随机产生的对称加密密钥

  • B用加密密钥对密文解密,得到明文

  • B用A的公钥A:PK对A的数字签名进行RSA公钥解密运算,得到A的信息摘要

  • B用相同的hash算法对明文进行hash运算,得到新的信息摘要,并与收到的信息摘要比较,若一致,则说明明文未被修改,来自A。

常用的用途有:

  • 证书链
  • 数字信封
  • 带原文的签名数据

PKCS#7结构分析之签名

PKCS#7结构分析之数字信封

附:数字信封

envelop

构造数字信封要能够达到以下功能:

  • 保密(对称加密,RSA公钥加密)
  • 验证完整性(MAC值)
  • 验证身份(签名)

因此该结构应该包含:

  • 明文加密后的密文cryptodata
  • Hash函数生成的MAC值
  • RSA私钥加密的签名值signdata
  • (也应该包含证书,由CA担保身份)

1.8 PKCS#8

私钥封装格式Private_Key Information Syntax Specification Version 1.2

定义了私钥信息语法和加密私钥语法。
私钥类型任意,对称算法可设置

1.9 PKCS#10

证书请求格式(主题,公钥,私钥签名)

RA注册流程:注册信息->审核通过->生成密钥->生成PKCS10请求->将信息和P10请求的公钥合并成CMP请求->发送到CA

1.10 PKCS#11

介质接口格式:

  • 硬件驱动
  • 定义文件操作
  • 权限管理

对应于Windows的CSP,国密接口的SKF

1.11 PKCS#12

带私钥的个人证书格式,包含私钥、证书、证书链、CRL...

1.12 X.509

X.509证书与509黑名单规范

X.509数字证书主体如下:

  • 签名前的证书申请(签名对象的信息)
  • 数字签名的算法(CA对证书签名使用的算法)
  • 数字签名(用于验证证书的有效性,使用者使用CA的公钥使用同种算法对证书签名,查看和该数字签名是否相同)

一个真实的X509数字证书包含:

  • 证书版本(V3)
  • 证书序列号
  • 签名算法(sha1RSA)
  • 签名哈希算法(sha1)
  • 签名
  • 颁发者信息
    • CN
    • OU
    • O组织
    • L地点
    • S州
    • C
  • 使用者信息
  • 有效期
  • 公钥
  • 密钥用法
    • Key Encipherment, Data Encipherment
    • Digital Signature, Non-Repudiation
  • CRL分发点
  • 指纹算法
  • 指纹

结构

struct x509_st
{
    X509_CINF *cert_info;
    X509_ALGOR *sig_alg;
    ASN1_BIT_STRING *signature;
    int valid;
    int references; 
    char *name;
    CRYPTO_EX_DATA ex_data;
    long ex_pathlen;
    long ex_pcpathlen;
    unsigned long ex_flags;
    unsigned long ex_kusage;
    unsigned long ex_xkusage;
    unsigned long ex_nscert;
    ASN1_OCTET_STRING *skid;
    struct AUTHORITY_KEYID_st *akid;
    X509_POLICY_CACHE *policy_cache;
#ifndef OPENSSL_NO_SHA
    unsigned char sha1_hash[SHA_DIGEST_LENGTH];
#endif
    X509_CERT_AUX *aux; 
};

以上结构表示一个完整的数字证书,主要项如下:

  • cert_info:证书主体信息;
  • sig_alg:签名算法;
  • signature:签名值,存放CA对该证书采用sig_alg算法签名的结果(验证证书持有者身份时,使用该CA公钥对该证书采用sig_alg签名算法签名得到signature1,将两个签名值比较,若相等,则表明是通过CA确认的证书持有者);
  • valid:是否是合法证书,1 为合法,0 为未知;
  • references:引用次数,被引用一次则加一;
  • name:证书持有者信息该内容在调用 d2i_X509的过程中,通过回调函数 x509_cb(crypto/asn1/x_x509.c)调用 X509_NAME_oneline 来设置;

编程接口

DER 编解码接口由宏在 crypto/asn1/x_x509.c 中实现,包括各自的new、free、i2d 和 d2i 函数:

  • d2i_X509:解码 DER 编码的数字证书
  • PEM_read_bio_X509:从PEM格式的数字证书中得到X509数据结构

1.13 ASN.1

Abstract Syntax Notation One,抽象语法标识,是与平台、语言无关的数据结构定义语法

编码格式

BER、CER、DER、XER,可以编码成XML格式,不仅仅是常用的二进制流。
二进制流的TLV方式表达数据结构,如下:

Identifier octets Type Length octets Length Contents octets Value End-of-contents octets
  Personnel
  Record     Length   Contents
  60         8185
                      Name     Length  Contents
                      61       10
                                       VisibleString  Length  Contents
                                       1A             04      "John"
                                       VisibleString  Length  Contents
                                       1A             01      "P"
                                       VisibleString  Length  Contents
                                       1A             05      "Smith"

                       DateofBirth     Length  Contents
                       A0              0A
                                               Date    Length  Contents
                                               43      08      "19590717"
  • BER: Basic Encoding Rules
    • 基本编码格式。
    • 对相同的数据,可以有多种编码方式,比如长字节型、短字节型、不定长型等。
  • DER: Distinguished Encoding Rules
    • 是BER的一个子集,为更严格的一个变种版本。
    • 和BER相比,DER的编码格式只有固定一种。比如BER的Boolean变量编码值是可以1~255的任意值,而DER只能是1。
    • DER使用在有数据签名的场合,以保证数据原文编码后可以保持一致。
    • X.509证书都是DER编码。
  • CER: Canonical Encoding Rules
    • CER和DER一样,都是BER的限定编码规则的子集。
    • CER和DER不同在于它是不定长编码,可以用于大数据块的封装。
    • PKCS#7数字信封可以用DER编码,也可以用CER编码。
  • Privacy Enhanced Mail: 安全增强邮件,通过加密算法、证书加密邮件。
    • 更常用的概念是一种文件格式,该文件格式使用一个头、尾标识文件的内容,以方便解析。如下:
    • 被加密的私钥:
-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----

  • PEM格式的证书:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
  • PEM格式的PKCS#10证书请求:
-----BEGIN CERTIFICATE REQUEST-----
...
-----END CERTIFICATE REQUEST-----
  • CER、DER、CRT、PEM的关系

  • PFX

    • Personal Information Exchange
    • PKCS#12是PFX的后续版本,一般情况二者为等同概念。
    • PFX或PKCS#12,是包括私钥的个人证书,通过口令保护私钥。
    • 后缀名为.pfx或.p12
    • 使用openssl、keytool、Portecle(KeyStore工具)都可以很方便生成PFX证书。
    • references:

1.14 CRL

证书撤销列表(Certificate Revocation List,简称 CRL),是一种包含撤销的证书列表的签名数据结构。基本的 CRL 信息有:被撤销证书序列号、撤销时间、撤销原因、签名者以及 CRL 签名等信息。

被撤销证书的信息:X509_REVOKED

typedef struct X509_revoked_st
{
    ASN1_INTEGER *serialNumber;
    ASN1_TIME *revocationDate;
    STACK_OF(X509_EXTENSION) *extensions;
    int sequence;
} X509_REVOKED; 
  • serialNumber:被撤销证书的序列号;
  • revocationDate:撤销时间;
  • extensions:扩展项,可选;
  • sequence:顺序号,用于排序,表示当前被撤销证书信息在 crl 中的顺序。

crl信息主体:

typedef struct X509_crl_info_st
{
    ASN1_INTEGER *version;
    X509_ALGOR *sig_alg;
    X509_NAME *issuer;
    ASN1_TIME *lastUpdate;
    ASN1_TIME *nextUpdate;
    STACK_OF(X509_REVOKED) *revoked; 
    STACK_OF(X509_EXTENSION) *extensions;
    ASN1_ENCODING enc;
} X509_CRL_INFO;
  • version:crl 版本;
  • sig_alg:crl 签名法;
  • issuer:签发者信息;
  • lastUpdate:上次更新时间;
  • nextUpdate:下次更新时间;
  • revoked:被撤销证书信息;
  • extensions:扩展项,可选。

完整crl数据结构:

struct X509_crl_st
{
    X509_CRL_INFO *crl;
    X509_ALGOR *sig_alg;
    ASN1_BIT_STRING *signature;
    int references;
} ; 
  • crl:crl 信息主体;

  • sig_alg:签名算法,与 X509_CRL_INFO 中的一致;

  • signature:签名值;

  • references:引用

附3 LDAP

轻量目录访问协议(Lightweight Directory Access Protocol),运行于TCP/IP之上。

目录的信息按照树型结构组织,数据结构:

条目entry->区别名DN->属性Attribute->类型Type
                                |
                                ->值Values

附4 OCSP

在线证书状态协议(Online Certificate Status Protocol)

数据格式:

  • 协议版本
  • 服务请求
  • 目标证书标识
  • 可能被OCSP响应器处理的可选扩展

OCSP响应端检测:

  • 信息正确格式化
  • 响应器被配置提供请求服务而且
  • 请求包含了响应器需要的信息,返回一个确定的回复,OCSP响应端回复的加密消息中包含证书的状态可以是’good’,’revoked’或者’unknown’
  • 如果任何一个先决条件没有满足,那么OCSP响应器将产生一个错误信息,错误码可能包含以下内容:
    • 未正确格式化的请求(malformedRequest)
    • 内部错误(internalError)
    • 请稍后再试(trylater)
    • 需要签名(sigRequired)
    • 未授权(unauthorized)

1.15 数字证书

发证流程:

  • 申请者将合法的身份信息(参考X509章节)以PKCS#10格式通过SCEP(简单证书颁发协议,工作在HTTP之上)发送给CA,
  • CA验证申请者的合法性,满足条件就会产生一个合法的证书,内容包括身份信息、公钥、CA信息、CA签名、有效时间、序列号、CRL表的下载地址或查询地址
  • CA使用申请者公钥将X.509v3加密得到密文格式证书,使用SCEP协议颁发给申请者
  • 申请者使用自己的私钥解密得到X.509v3证书并保存

双证书:

双证书即双密钥(签名密钥对,加密密钥对)

  • 签名密钥对用于数据完整性检测,保证放伪造与防抵赖,若遗失,不影响以前数据的验证。因此不需要第三方管理。
  • 加密密钥对用于数据的加密保护,若遗失,将导致之前加密的数据无法解密。因此加密密钥对应有可信第三方(CA)产生备份。

(附:我曾今将整理的文件使用一款加密软件加密,选择加密密码的时候由于自己记不住长密码,又不想将长密码以任何形式记录下来,于是决定使用自认为固定的文件作为密钥,然后当再次使用文件解密的时候,被告知不是该文件。才想起,这个当时在我看来是固定的文件,由于版本需要被我修改了!整理的三个月的文件就这样脱胎换骨成了0110...)

验证过程

  1. 拆封证书
  • 目的:获取证书中的公钥
  1. 验证证书链
  • 目的:验证签发用户实体证书的CA是否是权威可信的CA
  • 操作:使用每级CA的公钥验证每级数字签名
  1. 验证序列号
  • 目的:检查实体证书中的签名实体序列号是否与签发者证书的序列号相一致
  • 操作:用户实体证书中的Authority Key Identifier扩展项Cert Serial Number,即签发证书的序列号与CA证书中的Certificate Serial Number 证书序列号是否一致
  1. 证书废止列表查询(黑名单查询,CRL)
  • 目的:检查用户证书是否作废

2 OpenSSL

2.1 命令行

构建数字证书

主要操作包括产生私钥(key),构造证书请求(req),签发用户证书,自签发根证书。

  • 1.产生私钥(带密码保护):openssl genrsa -out mysite.key -des3 -passout pass:123456 1024
  • 2.构造证书请求
    • 交互式输入:openssl req -key mysite.key -passin pass:123456 -new -out mysite.req
    • 非交互式输入,先编辑配置文件mysite.conf,然后生成请求:openssl req -key mysite.key -passin pass:123456 -new -config mysite.conf -out mysite.req
  • 3.签发用户证书:openssl x509 -req -in mysite.req -CA testca.pem -CAkey testca.key -out mysite.pem -passin pass:abcdef -CAcreateserial-days指定证书有效期
  • 当然,签发用户证书的前提是已经自签发根证书,先执行1,2步生成根证书申请,然后自签发:openssl x509 -req -in testCA.req -signkey testca.key -out testca.pem -passin pass:abcdef

2.2 编程

对称算法和摘要算法全局初始化:OpenSSL_add_all_algorithms();

释放句柄:EVP_MD_CTX_cleanup(&ctx);

2.2.1 加解密

int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, unsigned char *key, unsigned char *iv, int enc)
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, unsigned char *in, int inl);
int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);

2.2.2 摘要

int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type);
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s);

2.2.3 签名验签(RSA/ECDSA)

EVP_SignInit ( &md_sign_ctx, md )
EVP_SignUpdate(&md_sign_ctx, data, data_cb)
EVP_SignFinal (&md_sign_ctx, sign, psign_cb, pPriKey )

EVP_VerifyInit( &md_verify_ctx, md )
EVP_VerifyUpdate(&md_verify_ctx, data, data_cb)
EVP_VerifyFinal(&md_verify_ctx, sign, sign_cb, pPubKey)

2.2.4 公钥加密与私钥解密(RSA算法)

int EVP_PKEY_encrypt    (   EVP_PKEY_CTX *  ctx, unsigned char *    out, size_t *   outlen, const unsigned char *   in, size_t  inlen ) 

2.2.5 PKCS7签名验签(RSA/ECDSA)

p7 = PKCS7_sign(x, pPriKey, NULL, in, PKCS7_BINARY)
PKCS7_verify(p7, NULL, NULL, in, NULL, PKCS7_BINARY|PKCS7_NOVERIFY)

2.2.6 PKCS7数字信封加密解密(RSA)

p7 = PKCS7_encrypt(certs, in, EVP_des_cbc(), PKCS7_BINARY)
PKCS7_decrypt(p7, pPriKey, x, out, PKCS7_BINARY)

2.2.7解密公司的加密邮件(SMIME)

公司加密邮件为标准SMIME格式,导出后得到.eml文件
使用PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont)将bio读取到的SMIME格式保存在PKCS7格式内,然后通过PKCS7_dncrypt接口解密

2.2.8错误处理

错误处理应该尽可能多的包含各种信息,包括:

  • 错误码;
  • 出错文件以及行号;
  • 错误原因;
  • 出错函数;
  • 出错库;
  • 出错模块与类别信息;
  • 错误堆栈信息等。

ERR_get_error获取第一个错误号

ERR_error_string根据错误码获取具体的错误信息,包括出错的库、出错的函数以及出错原因

ERR_print_errors_fp将错误打印到FILE中

3 SSL与TLS协议

推荐阅读更多精彩内容