RSA非对称加密、签名

RSA非对称加密、验签

模拟场景

  • A与B对接
  • A司拥有一对RSA密钥 APublicKey、APrivateKey
  • B司拥有一对RSA密钥 BPublicKey、BPrivateKey
  • 数据有三大模块
    1. 透明参数
    2. 业务参数(需要加密处理)
    3. 签名
  • A 与 B互相知晓对方的公钥
  • 密钥对通过OpenSSL生成

    数字签名与验证签名的重要性

    我们的数据传输是基于HTTP协议的,A与B在通信的过程中,可能遭遇数据劫持,C在截取到A发给B的数据之后,如果修改部分数据,再次发给B就造成了灾难。所以我们需要一个条件来确定过数据是最原始的数据。这就是签名存在的目的。

广义上的签名是对数据做一个摘要,可以通过数据得到签名,但是不能通过签名逆向得到数据。

A与B数据通信加密解密逻辑

假设A向B发送数据:

透明参数是不包含业务参数的参数字段,例如时间戳,字符集等要素。我们不需要对其进行加密处理。

业务参数:A使用B的公钥(BPublicKey)进行加密,那么只有拥有B公司私钥的才能解密出其中的数据(也就是B公司自己)
具体的代码实现(golang):

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
func UsualParamsEncrypt(data interface{}, publicKey string) (encryptParams string, err error) {
dataByte, err := json.Marshal(data)
if err != nil {
return "", err
}
pStr, err := crypt.EncryptPKCS1v15(dataByte, []byte(publicKey))
if err != nil {
return "", err
}
return pStr, nil
}
//rsa公钥加密
func EncryptPKCS1v15(origData, publicKey []byte) (string, error) {
block, _ := pem.Decode(publicKey)
if block == nil {
return "", errors.New("publicKey error")
}
var err error
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return "", err
}
pub := pubInterface.(*rsa.PublicKey)
encrypted := make([]byte, 0, len(origData))
for i := 0; i < len(origData); i += 117 {
if i+117 < len(origData) {
partial, _ := rsa.EncryptPKCS1v15(rand.Reader, pub, origData[i:i+117])
encrypted = append(encrypted, partial...)
} else {
partial, _ := rsa.EncryptPKCS1v15(rand.Reader, pub, origData[i:])
encrypted = append(encrypted, partial...)
}
}
return base64.StdEncoding.EncodeToString(encrypted), nil
}

在完成参数之后需要对业务数据进行签名,A使用自己的私钥(APrivateKey),那么所有拥有A公钥的公司就能知道数据是否是完整的、未被篡改的,具体的代码实现(golang):

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
func UsualSign(param http.Values, APrivateKey string) (signedStr string, err error) {
signedStr, err = crypt.SignPKCS1v15([]byte(param.Encode()), []byte(wrPrivateKey), crypto.SHA1)
if err != nil {
return "", err
}
return
}
func SignPKCS1v15(origData, privateKey []byte, hash crypto.Hash) (string, error) {
h := hash.New()
h.Write(origData)
digest := h.Sum(nil)
block, _ := pem.Decode(privateKey)
if block == nil {
return "", errors.New("privateKey key error")
}
var pri *rsa.PrivateKey
var err error
if hash == crypto.MD5 {
pubInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
pri = pubInterface.(*rsa.PrivateKey)
} else {
pri, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
}
data, err := rsa.SignPKCS1v15(nil, pri, hash, digest)
if err != nil {
fmt.Errorf("rsaSign SignPKCS1v15 error")
return "", err
}
return base64.StdEncoding.EncodeToString(data), nil
}

随后我们把角色从A转换到B

在签名确认之前用B自己的私钥(BPrivateKey)解密参数代码实现:

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
func UsualParamsDecrypt(paramsStr string, wrPrivateKey string) (encryptParams string, err error) {
decodeData, err := base64.StdEncoding.DecodeString(paramsStr)
if err != nil {
return "", errors.New("Base64 DecodeString error")
}
pStr, err := RSADecrypt(decodeData, []byte(wrPrivateKey))
if err != nil {
return "", err
}
return pStr, nil
}
//DecryptRSA decrypt given []byte with RSA algorithm
func RSADecrypt(data, privateKey []byte) (string, error) {
block, _ := pem.Decode(privateKey)
if block == nil {
return "", errors.New("privateKey error")
}
privInterface, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
decrypted := make([]byte, 0, len(data))
partial, _ := rsa.DecryptPKCS1v15(rand.Reader, privInterface, data)
decrypted = append(decrypted, partial...)
return string(decrypted), nil
}

之后我们需要验证签名,来确保数据是未被篡改过的,使用A的公钥(APublicKey)代码实现:

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
func UsualVerifySign(paramWithoutSign http.Values, signStr string, publicKey string) error {
decodeData, err := base64.StdEncoding.DecodeString(signStr)
if err != nil {
return errors.New("Base64 DecodeString error")
}
err = crypt.VerifyPKCS1v15([]byte(paramWithoutSign.Encode()), decodeData, []byte(publicKey), crypto.SHA1)
if err != nil {
return errors.New("VerifySign error")
}
return nil
}
// rsa 验签
func VerifyPKCS1v15(origData, signedData, publicKey []byte, hash crypto.Hash) error {
h := hash.New()
h.Write(origData)
digest := h.Sum(nil)
block, _ := pem.Decode(publicKey)
if block == nil {
return errors.New("public key error")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return err
}
pub := pubInterface.(*rsa.PublicKey)
return rsa.VerifyPKCS1v15(pub, hash, digest, signedData)
}

还有一点就是我们需要把解密后的数据通过BASE64再次加密在传输,一是为了加密强度,而是为了保证加密解密的安全性。