非对称密钥加密算法

非对称密钥加密算法有两个密钥:公钥(Public Key)和私钥(Private Key)。如果用公钥加密,只能用私钥解密还原,加密和解密使用的是不同密钥,因此叫非对称密钥加密算法。

最常用的非对称密钥加密算法是RSA,除此之外还有ECC(椭圆曲线算法)等。

RSA算法历史

1976年,美国计算机学家Whitfield Diffie和Martin Hellman发明了Diffie-Hellman密钥交换算法。

基于Diffie-Hellman密钥交换算法的原理,1977年,美国麻省理工的三名科学家Ron Rivest、Adi Shamir和Leonard Adleman共同提出了RSA算法。

RSA算法应用

RSA需要进行大整数运算,因此性能较低,一般不直接用于加密大量数据的场景。除此之外,RSA广泛运用于密钥交换、签名等领域。

密钥交换

RSA的一个应用领域就是密钥交换。我们知道,为了加密通信就需要交换密钥,然而明文传输密钥不安全,加密传输又需要已有一个密钥,因此这种情况下就陷入了死循环。

后来出现了Diffie-Hellman密钥交换算法巧妙的解决了这一问题。在其基础上发展出来的RSA也能够用于密钥交换,流程如下:

  1. 客户端C对服务器S发起请求,C首先能够得到S证书中包含的公钥
  2. C生成随机值Key,并用公钥加密为Enc(Key)发给S
  3. S收到Enc(Key)并用私钥解密,得到C发送的随机值Key
  4. 双方对Key进行KDF等操作,得到对称加密密钥
  5. 此时可以用密钥进行对称加密通信

数字签名

数字签名的作用和现实中“签名”类似,就是认证签署人的身份,其左右为两个方面,确认发送人的身份,以及防抵赖。流程如下:

  1. 为了实现数字签名,客户端C需要将公钥上传到服务器S
  2. C对数据Data的消息摘要进行私钥加密,得到Enc(Hash(Data))上传到服务器S
  3. S使用C的公钥能够解密数据,并验证消息摘要值,如验证成功则此签名有效,确认该数据为C提交
  4. 攻击者无法得知C的私钥,无法伪造C的签名

RSA密钥管理

一些软件、服务程序的配置中经常需要配置RSA密钥,RSA密钥在存储格式方面有很多标准,这里简单介绍一下。

X.509公钥证书标准

X.509是ITU-T(国际电信联盟电信标准分局)和国际标准化组织(ISO)制定的公钥证书标准,标准包括证书公钥格式、身份信息和签名信息。我们日常使用的TLS/SSL使用的就是X.509证书。

PKCS公钥密码学标准

PKCS(Public Key Cryptography Standards)即公钥密码标准,是由美国RSA数据安全公司制定的一组公钥密码学标准,其中包括证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议。

PKCS#1标准定义了RSA 密码学规范,内容包括RSA密钥文件的格式和编码方式,以及加解密、签名、填充的基础算法。PKCS#8是后出的私钥格式标准,它除了RSA还支持其他算法私钥,PKCS#8支持基于PBE的密钥加密存储,因此我们能够对其设定密码口令。PKCS#12则定义了一种存档文件格式,用于实现存储加密对象在一个单独的文件中,可以用作密钥库。

对于RSA私钥,比较常用的就是PKCS#1和PKCS#8格式,后者因为可以设置PBE密码加密,因此安全性更高。

生成RSA密钥对

PEM和DER是两种比较常见的证书、密钥文件编码格式,两者的区别是PEM为BASE64编码的文本密钥文件,DER为二进制密钥文件,其内部数据格式相同的前提下可以直接用BASE64编解码转换。DER格式比较方便程序读取,而PEM格式是为了邮件等方式传输而出现的。PEM文本中会有标签头尾,例如:

-----BEGIN PUBLIC KEY-----
(此处为具体BASE64编码)
-----END PUBLIC KEY-----

一些常见的标签:

CERTIFICATE:X.509证书。

PUBLIC KEY:X.509主体公钥。

RSA PUBLIC KEY:PKCS#1 RSA公钥。

RSA PRIVATE KEY:PKCS#1 RSA私钥。

PRIVATE KEY:PKCS#8私钥。

ENCRYPTED PRIVATE KEY:加密的PKCS#8私钥。

注意:PEM和DER是编码格式文件,不是指里面具体内容,里面可以是密钥,可以是证书,或是可能的其他内容。

我们可以用openssl命令行工具生成密钥对的PEM文件,生成PEM格式密钥对:

openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -out public.pem -pubout

openssl默认会生成PEM格式的RSA密钥文件,公钥内部数据为X.509的公钥格式,私钥为PKCS#1格式。我们也可以将密钥对转为DER格式:

 openssl rsa -in private.pem -out private.der -outform der
openssl rsa -in public.pem -out private.der -pubin -outform der

上述命令将密钥文件格式转为了DER格式,但内部数据依然保持原样,这里我们也可以将私钥转换为常用的PKCS#8格式:

openssl pkcs8 -topk8 -inform der -in private.der -outform der -nocrypt -out private_pkcs8.der

代码读取RSA密钥对文件

JDK默认公钥支持X.509格式,私钥支持PKCS#8格式。下面代码读取了之前用openssl生成的密钥文件。

byte[] data = "Hello, world!".getBytes();

// 读取公钥
byte[] pubKeyBytes = FileUtils.readFileToByteArray(new File("E:/public.der"));
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKeyBytes);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec);

// 读取私钥
byte[] priKeyBytes = FileUtils.readFileToByteArray(new File("E:/private_pkcs8.der"));
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(priKeyBytes);
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);

// 加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encData = cipher.doFinal(data);

// 解密
cipher.init(Cipher.DECRYPT_MODE, privateKey);
data = cipher.doFinal(encData);
作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap