数字签名与数字证书技术简介

原文地址:数字签名与数字证书技术简介
简版介绍地址:数字签名和数字证书详解

数字签名、数字证书等技术,是 现代信息安全的核心技术,可谓使用面十分广泛。其基本理论本身并不复杂,本文希望通过深入浅出的介绍,能够让大家有一些基本了解。

对称加密、非对称加密
让我们通过一个例子开始:我们的主角分别是Alice和Bob。现在假设 Alice 要给 Bob 发送一份文件,文件内容非常机密。 Alice 不希望文件在发送的过程中被人截取而泄密。
这个时候,自然想到的方法就是对文件进行 加密 。当然除了 加密 外,我们还需要让 Bob 能够 解密 。就像 Alice 对文件上了锁,为了让 Bob 能够解开,则 Bob 必须有钥匙来对文件解锁。在信息安全或密码学中,我们将这种钥匙称为 密钥 。密钥一般分为两种, 对称密钥非对称密钥

对称密钥很容易理解,如同 Alice 用一把钥匙将文件上锁,而 Bob 使用相同的钥匙就可以将文件解锁,即加密使用的密钥与解密使用的密钥是相同的。目前的对称密钥算法有 DES 、 3DES 、 AES 等,而密钥则一般是一串固定长度的字符。

如下, Bob 和 Alice 事先已经约定,将使用 DES 算法,并且已经约定好使用的密钥。于是 Alice 使用这份密钥对文件进行了加密,并发送给 Bob 。 Bob 使用相同的密钥对文件解密即可:

对称密钥算法的安全性还是非常有保障的。拿 DES算法 举例 ,到目前为止,除了用 穷举搜索法 对DES算法进行攻击外,还没有发现更有效的办法。而56位长的 密钥 的穷举空间为256,这意味着如果一台计算机的速度是每一秒钟检测一百万个密钥,则它搜索完全部密钥就需要将近2285年的时间 。而 3DES (3次DES操作)、 AES算法 的 安全性则更高。由此可见,使用对称密钥对文件进行了加密,基本上不用太担心文件可能泄密。

目前大部分的开发语言都有对应的数字加密模块,例如JAVA的JCE模块就可以调用简单的实现加解密。以下是一份JAVA代码例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.test.chiper;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class TestChiper {
    private static final BASE64Encoder base64En = new sun.misc.BASE64Encoder();
    private static final BASE64Decoder base64De = new sun.misc.BASE64Decoder();
    private static String AESKey="1234567890123456";
   
    public static String encrypt(String mText) throws Exception {
        SecretKeySpec secrekeysp = new SecretKeySpec(
                AESKey.getBytes(),"AES");
        java.security.Key key = (java.security.Key) secrekeysp;
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key);
        byte[] b = cipher.doFinal(mText.getBytes());
        return base64En.encode(b);
    }
    public static String decrypt(String mText) throws Exception {
        SecretKeySpec secrekeysp = new SecretKeySpec(
                AESKey.getBytes(),"AES");
        java.security.Key key = (java.security.Key) secrekeysp;
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key);
        byte[] b = cipher.doFinal(base64De.decodeBuffer(mText));
        return new String(b);
    }
  }

前文提到的对称密钥算法,已经基本满足了 Alice 对于文件 机密性的要求。然而还是存在两个问题:

1、Alice 与 Bob 彼此之间必须约定将使用的密钥,而这个约定的过程本身就可能存在泄密的风险;

2、如果除了 Alice 以外,还有 Jessica 、 Eva 、 Mary 等 100 位女士也需要向 Bob 发送文件。那么, Bob 可能需要有 100 次约定密钥的过程。

由此可见,无论是安全性还是可用性上,对称密钥都是存在问题的。而两个问题则是必须解决的。

1976 年,美国斯坦福大学的研究生 Diffie 和教授 Hellman 发表一个基于非对称密钥加密的想法,这个想法开创了密码学的变革。他们的想法其实非常简单,将密钥分为 公钥( publicKey ) 和 私钥( privateKey ) 两种。公钥加密的内容,使用私钥可以解开;而私钥加密的内容,公钥可以解开。然而,单独的知道公钥或私钥,却没有办法推出另一份密钥。

继续我们的例子:仍然是Alice 需要与 Bob 发送一份绝密文件。在此之前, Bob 生成了一对密钥:公钥和私钥。 Bob 将公钥发布在了一个公共的密钥库中,而私钥则不对外公开,仅 Bob 本人持有。如下图所示, Alice 从公钥库中取出 Bob 的公钥,对文件进行加密,再发送给 Bob 。而 Bob 通过自己持有的私钥,即可将文件解密:

通过非对称密钥,Bob 只是将公钥公布,并没有和 Alice 约定密钥。仅仅知道公钥是没有办法推出私钥的,因此不用担心私钥泄密的问题。另一反面,如果有 jessica 也想向 Bob 发送文件,仅需要从公钥库中取到 Bob 的公钥即可,也不需要更多的密钥。

非对称密钥算法很有效的解决了安全性和可用性的问题,非对称密钥算法又称作“公开密钥加密算法”,我们常说的 PKI ( Public Key Infrastructure)则是建立在此技术之上的安全基础体系。目前使用最为广泛的非对称密钥为 RSA 算法,该算法是由三位算法发明者的姓氏开头字母命名而来。

由于非对称加密算法的复杂度更高,因此非对称加密的速度远没有对称加密算法快,甚至可能比对称加密慢上 1000 倍。

信息摘要、数字签名
基于上文的非对称密钥算法,我们可以继续我们的场景:

假设有一天, Alice 收到了一份署名为 Bob 的文件。 Alice 希望能够确认这份文件一定是来自 Bob ;另外 Alice 希望能够确信,这份文件在传输过程中并没有被它人篡改。那么基于非对称密钥算法我们应该怎么做?

确认文件一定来自于 Bob ,其实就是 Bob 无法否认自己发送过这份文件。信息安全中称作 不可抵赖性 ;另一方面,确信文件并没有中途被篡改,则称作 不可篡改性

在非对称密钥算法中提到,公钥加密的内容使用私钥可以解密。同样的,基于私钥加密的内容使用公钥也可以解密,两者一一对应。因此我们可以很容易想到。如果 Bob 利用自己手里的私钥对文件进行加密后,传输给 Alice 。 Alice 再通过公钥库中 Bob 的公钥进行解密,则可以证明文件一定是由 Bob 发出(由于只有 Bob 持有私钥)。另外,因为传输的是密文,如果能够使用公钥解密,同时也证明了文件并没有中途被篡改。这样的做法其实已经同时满足了不可抵赖性和不可篡改性。

然而,由于传输的文件可能很大,为了证明文件的不可抵赖性和不可篡改性,需要对整个文件进行加密,由于非对称算法效率较低,这样做的代价太大。因此常规的做法是用到 信息摘要 和 数字签名 的方式。
所谓信息摘要,其实就是某种 HASH 算法。将信息明文转化为固定长度的字符,它具有如下特点:

① 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的 ;

② 用相同的 摘要算法对相同的消息求两次摘要,其结果必然相同;

③ 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也 几乎不可能相同;

④ 消息摘要函数是单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息 ;

⑤ 好的摘要算法,没有人能从中找到 “ 碰撞 ” ,虽然 “ 碰撞 ” 是肯定存在的。即对于给定的一个摘要,不可能找到一条信息使其摘要正好是给定的。或者说,无法找到两条消息,是它们的摘要相同。

一般的,我们将信息的摘要也称作信息的 指纹 。如同指纹的含义,相同的信息一定会得相同的指纹,而仅通过指纹又无法还原出原始信息。目前主要的摘要算法有 MD5 SHA1

当有了信息摘要技术以后,基于 Bob 向 Alice 发送文件的场景,我们可以进行如下的操作:

第一步:

① Bob 将原始的信息进行一次信息摘要算法,得到原始信息的摘要值;

② Bob 使用自己的私钥,对该摘要值进行加密。得到信息摘要的密文;

③ Bob 将原始文件和摘要值的密文一起发送给 Alice 。

④ 一般的,我们将原始文件和摘要密文称作 Bob 对原始文件的签名结果。

第二步:

① 当Alice 接收到 Bob 传输的信息(原始文件,信息摘要密文)后,使用 Bob 的公钥将摘要密文解密,得到信息摘要明文;

② 使用信息摘要算法,取原文的摘要信息,获取原始文件摘要信息;

③ Alice 比较解密后的摘要信息和取得的摘要信息。如果相同,则可以证明文件一定由 Bob 发送,并且中途并没有经过任何篡改。一般将这个过程称作 验签。

所谓数字签名,就是对原始文件的“指纹”进行了私钥加密。这样,即可保证文件的特征(摘要值)一定经过了私钥的加密。同时由于信息摘要的长度普遍不长( MD5 为 128 位, SHA1 主要为 256 位),也并没有带来太大的开销。

如同对称密钥算法,在大部分开发语言中,基于非对称算法的数字签名,数字加密算法。也都进行了一定的封装。如下链接就比较详细的描述了基于 JCE 如何实现数字签名、加密、验证等:
java RSA加密解密实现

数字证书
Bob 生成了一对公私钥。 Bob 将公钥发布在公开的密钥库中。而 Alice 在向 Bob 发送加密文件或者验证 Bob 签名的文件时,均要从公钥库取到 Bob 的公钥。我们已经知道,一般来说公钥就是一段固定长度的字符串,并没有特定的含义。

为了让 Alice 能够方便的辨别公钥,我们可以考虑对给公钥附加一些信息,例如该公钥使用的算法,该公钥的所有者( 主题 ),该公钥的有效期等一系列属性。这样的数据结构我们称作 PKCS10 数据包

公钥的 主题 我们采用唯一标示符 ( 或称 DN-distinguished name) ,以尽量唯一的标示公钥所有者。以下是基于 抽象语法表示法所定义的 PKCS10 数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CertificationRequestInfo ::= SEQUENCE {  
        version          INTEGER { v1(0) } (v1,...),
        subject          Name,  
        subjectPKInfo  SubjectPublicKeyInfo{{ PKInfoAlgorithms }},  
        attributes       [0] Attributes{{ CRIAttributes }}  
        }  
    SubjectPublicKeyInfo { ALGORITHM : IOSet} ::= SEQUENCE {  
        algorithm     AlgorithmIdentifier {{IOSet}},
        subjectPublicKey  BIT STRING  
        }  

    PKInfoAlgorithms ALGORITHM ::= {  
        ...  -- add any locally defined algorithms here -- }  
   
    Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}  
   
    CRIAttributes  ATTRIBUTE  ::= {  
        ... -- add any locally defined attributes here -- }  

    Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {  
        type    ATTRIBUTE.&id({IOSet}),  
        values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
    }

我们已经有了 PKCS10 数据包,除了公钥信息外,还有公钥的持有者,公钥的版本号等信息。然而这样的数据结构其实并没有任何权威性。例如有一天一个叫做 Richard 的人想冒充 Bob ,也生成一对公私钥,并且使用了相同的公钥主题封装为 P10 数据结构。 Alice 其实并没有办法分辨哪个是真实 Bob 的公钥。

为了解决这个问题,就需要一个权威的第三方机构,对 P10 结构的数据进行认证。就如同对 P10 文件盖上一个权威的章,防止仿照。这样的权威机构,我们称作 CA (Certificate Authority) 数字证书认证中心 。而 CA 如何为 P10 数据盖章呢?非常简单,就是我们前文已经提到的数字签名技术:

① 如上图所示,CA 机构其实也持有一张私钥。一般来说, CA 会对这份私钥进行特别的保护,严禁泄漏和盗用。

② Bob 将自己的公钥附加上一系列信息后,形成了 P10 数据包(请求包),并发送给 CA 。

③ CA 机构通过其他一些手段,例如查看 Bob 的身份信息等方式,认可了 Bob 的身份。于是使用自己的私钥对 P10 请求进行签名。(也可能会先对数据进行一些简单修改,如修改有效期或主题等)

④ 这样的签名结果,我们就称作数字证书。

数字证书同样遵循一个格式标准,我们称作X509标准,我们一般提到的 X509 证书就是如此。以下是 X509 的格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
[Certificate ::= SEQUENCE {
    tbsCertificate TBSCertificate,
    signatureAlgorithm AlgorithmIdentifier,
    signature BIT STRING
}

TBSCertificate ::= SEQUENCE {
    version [0] EXPLICIT Version DEFAULT v1,
    serialNumber CertificateSerialNumber,
    signature AlgorithmIdentifier,
    issuer Name,
    validity Validity,
    subject Name,
    subjectPublicKeyInfo SubjectPublicKeyInfo,
    issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
    -- If present, version must be v2or v3
    subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
    -- If present, version must be v2or v3
    extensions [3] EXPLICIT Extensions OPTIONAL
    -- If present, version must be v3
    }
Version ::= INTEGER {
    v1(0), v2(1), v3(2)
}

CertificateSerialNumber ::= INTEGER
    Validity ::= SEQUENCE {
    notBefore CertificateValidityDate,
    notAfter CertificateValidityDate
}

CertificateValidityDate ::= CHOICE {
    utcTime UTCTime,
    generalTime GeneralizedTime
}

UniqueIdentifier ::= BIT STRING
    SubjectPublicKeyInfo ::= SEQUENCE {
    algorithm AlgorithmIdentifier,
    subjectPublicKey BIT STRING
}

Extensions ::= SEQUENCE OF Extension
Extension ::= SEQUENCE {
    extnID OBJECT IDENTIFIER,
    critical BOOLEAN DEFAULT FALSE,
    extnValue OCTET STRING
}

基于数字证书,我们可以再来看看 Bob 如何给 Alice 发送一份不可否认、不可篡改的文件

第一步: Bob 除了对文件进行签名操作外,同时附加了自己的数字证书。一同发给 Alice 。

第二步: Alice 首先使用 CA 的公钥,对证书进行验证。如果验证成功,提取证书中的公钥,对 Bob 发来的文件进行验签。如果验证成功,则证明文件的不可否认和不可篡改。

可以看到,基于数字证书后, Alice 不在需要一个公钥库维护 Bob (或其他人)的公钥证书,只要持有 CA 的公钥即可。 数字证书在电子商务,电子认证等方面使用非常广泛,就如同计算机世界的身份证,可以证明企业、个人、网站等实体的身份。同时基于数字证书,加密算法的技术也可以支持一些安全交互协议(如 SSL )。下一篇文章,将为大家介绍 SSL 协议的原理。

ˆ Back To Top