rsa OAEP 加密、解密
OAEP
全称为Optimal Asymmetric Encryption Padding
.是一种非对称加密填充场景.
生成RSA证书
use the openssl command to set up the RSA key files.
create 2,048-bit keys.
1
2
|
openssl genrsa -out private_key.pem 2048
openssl rsa -in private_key.pem -pubout -out public_key.pem
|
set the access modes for the key files. The private key should be readable only by the server
1
2
|
chmod 400 private_key.pem
chmod 444 public_key.pem
|
用go生成RSA证书
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
package main
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io"
"io/ioutil"
)
func generateRSAKey2File(bits int, publicKeyName, privateKeyName string) (err error) {
publicKeyWriter := bytes.NewBuffer([]byte{})
privateKeyWriter := bytes.NewBuffer([]byte{})
err = generateRSAKey(bits, publicKeyWriter, privateKeyWriter)
if err != nil {
return
}
fmt.Println(string(publicKeyWriter.Bytes()))
fmt.Println(string(privateKeyWriter.Bytes()))
err = ioutil.WriteFile(publicKeyName, publicKeyWriter.Bytes(), 0444)
if err != nil {
return
}
err = ioutil.WriteFile(privateKeyName, privateKeyWriter.Bytes(), 0400)
if err != nil {
return
}
return
}
func generateRSAKey(bits int, publicKeyWriter, privateKeyWriter io.Writer) error {
// generate private key
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return err
}
x509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey)
privateBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509PrivateKey,
}
err = pem.Encode(privateKeyWriter, privateBlock)
if err != nil {
return err
}
// generate public key
publicKey := &privateKey.PublicKey
x509PublicKey, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return err
}
publicBlock := &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: x509PublicKey,
}
err = pem.Encode(publicKeyWriter, publicBlock)
if err != nil {
return err
}
return nil
}
func main() {
publicKeyName := "public.pem"
privateKeyName := "private.pem"
bits := 4096
err := generateRSAKey2File(bits, publicKeyName, privateKeyName)
if err != nil {
panic(err)
}
}
|
执行输出到文件
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
> go run main.go
-----BEGIN RSA PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw5b5cKSASrqA4ILeJsWP
Z672st+jHEbG6uiNZfQ1kV1y7BJz+m9NDYIeLUGguz9tDmSGkq+maftv2oZEbNTI
EKxIvoD1UZVtWLZqtoJ1+EvOmO4bJ3EZJ7a+807LamLTftuylTd4SUml4Czcrl6h
/3gQSq5mNZFUay96p5hyDr3yhwPAxqbnyCf3j/PXFthoSqIoYICkgHrB2xc+NsX7
7z6oV8VBtIVKigJI+2PI9tLdHsOs3/8ZdoNgPYDGu71SPk/3s1UJ8YlC8u3HcB+T
kyiJRK659COLwVqkXqW8rnQoe2RlWPu1maSJC+BtZXUrL/rmko37R8EdgyKH85YK
jefjLavDMEON+4HdDu6AALQhre++lOwDimaPTjSOLQUR24wFixgPTZQFE3cudUtk
VJJ+53MVZsevVG9jTHKrrECMKplb/7FgwPI5GwkF5HXu5Y7VQHuXR+QkHXqw0sPS
5t79CWVHA2ZXLJMJ5gSaqgLYKTpun8185DMe7hxyFOxjqpiY7ttm50ylHs0kiMAd
WpWQwV2Nm3b2VyvaGkyGCEH0vmdb3+3CJ3W2GWXWUUFLkWG+qrADWLRNx22GCjqT
0CR2K7IvEZnwRWJd0zKnTFsdlLSoMapSVOs5rrkpOfRYmuQHrfqZ8UXqFZmRZYWx
DVQl3YJ0pBh96Ti6yrQXcNMCAwEAAQ==
-----END RSA PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
|
用生成的证书加密、解密
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
49
50
51
52
53
54
55
56
57
58
59
60
61
|
func main() {
publicKeyName := "public.pem"
privateKeyName := "private.pem"
publicKey, err := ioutil.ReadFile(publicKeyName)
if err != nil {
panic(err)
}
privateKey, err := ioutil.ReadFile(privateKeyName)
if err != nil {
panic(err)
}
password := []byte("123456")
cipherdata, err := encryptOAEP(publicKey, password)
if err != nil {
panic(err)
}
ciphertext := base64.StdEncoding.EncodeToString(cipherdata)
fmt.Println(ciphertext)
cipherdata, _ = base64.StdEncoding.DecodeString(ciphertext)
password, err = decryptOAEP(privateKey, cipherdata)
if err != nil {
panic(err)
}
fmt.Println(string(password))
}
func encryptOAEP(publicKey, password []byte) ([]byte, error) {
block, _ := pem.Decode(publicKey)
if block == nil {
err := fmt.Errorf("failed to parse certificate PEM")
return nil, err
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
rsaPublicKey := pub.(*rsa.PublicKey)
h := sha256.New() // sha1.New() or md5.New()
return rsa.EncryptOAEP(h, rand.Reader, rsaPublicKey, password, nil)
}
func decryptOAEP(privateKey, cipherdata []byte) ([]byte, error) {
block, _ := pem.Decode(privateKey)
if block == nil {
err := fmt.Errorf("failed to parse certificate PEM")
return nil, err
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) // ASN.1 PKCS#1 DER encoded form.
if err != nil {
return nil, err
}
h := sha256.New()
return rsa.DecryptOAEP(h, rand.Reader, priv, cipherdata, nil)
}
|
执行输出密文和原文
1
2
3
|
> go run main.go
YBFO/X38/MwQF4+wpjZZOujFxExMnM1a8sZ7F8+5Qt+A2QDL5CNWEV7KTRxYoNwymlOvl+MYnDPAzsofHuynszOASidBZNkJ74M0TgNdnIgOcAl8NPgXTRupP3kkAZe5vlc11ndT/+yWGnzgslNc9jh46sMhNkvpJhOIJjpD+jPZh83/P+ayOG2CqRJDovMf7++aNDeoME/yLdOG8sXWEBFRU4cGiqXdd7ZG1i4RuSPyMVliACCEA/p9+Ck0JauTh4EzNL1ioOj7Z6htllaqCbt8Z8a5Puo8JnOisD54nyTGh9m/KgJOERv2JWGCySUnjjK0uJaCYYxgEuUUtAniV7/hYfCOnaeh2BMserfN3+He7WgKJkbwWAH0h8RHC6chwbLDT2QNTKByfi1PABJYaugb263YqVJR5A9kkQoVDfnBD7lpZxdQDSlg8Cl2+hFDzq8x0L9BpbDuP1QOtw/5In8zHLvynlVBkSOJf1VSiVxlaU+T55Xw1XwAwBs0X4UfDVfbXtmxg6lulDsPmBe5Psjr26IIyCZPKkL3Fe+MUA5gyi2eXZn9w/Er1n3DkVq/SVKq2zrXiDijLgcqnsnQURh9FNKjoxPLAOABBswHOwwZgbWOxmqtFd4RM9rpFtpdvpi5VzdwYHCBxoZG43Ej6CZcJ4jwT09OdO7OcDbZODQ=
123456
|
mysql Auth Method Switch 密码加密传输处理逻辑
从 MySQL 5.6 开始支持 sha256_password 认证插件。它使用加盐密码(salted password)进行多轮 SHA256 哈希,确保哈希值转换更安全。并且需要在安全连接(ssl)或密码使用 RSA 秘钥对加密传输
–default-authentication-plugin=sha256_password
–default-authentication-plugin=caching_sha2_password
以下为mysql在rsa加密传输时客户端和服务端处理逻辑
mysql 客户端authMoreRequest
处理
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
|
// 1、接收 public key
publicKeyData, err := c.ReadPacket()
if err != nil {
return errors.Wrap(err, "ReadPacket failed")
}
// 2、用 public key 和 authData 对密码加密
func encryptPassword(password string, authData []byte, pub *rsa.PublicKey) ([]byte, error) {
plain := make([]byte, len(password)+1)
copy(plain, password)
for i := range plain {
j := i % len(authData)
plain[i] ^= authData[j]
}
sha1 := sha1.New()
return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil)
}
block, _ := pem.Decode(publicKeyData[1:])
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
rsaPublicKey := pub.(*rsa.PublicKey)
enc, err := encryptPassword(password, authData, rsaPublicKey)
// 2、密码后发送密文
data = make([]byte, 4+len(enc))
copy(data[4:], enc)
writeAuthSwitchPacket(data)
|
mysql 服务端authMoreRequest
处理
发送public key协议包,接收密文,然后解密出密码原文并验证
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
|
// 1. send the public key
func writeAuthMoreDataPubkey() error {
length := 1 + len(pubKey)
data := make([]byte, length)
data[0] = 0x01 // iAuthMoreData
data = copy(data[1:], pubKey...)
return WritePacket(data)
}
// 2. read the encrypted password
authData, err := c.readAuthSwitchRequestResponse()
// 3. decrypt the encrypted password
dbytes, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, (privateKey).(*rsa.PrivateKey), authData, nil)
if err != nil {
return err
}
plain := make([]byte, len(password)+1)
copy(plain, password)
for i := range plain {
j := i % len(salt)
plain[i] ^= salt[j]
}
if bytes.Equal(plain, dbytes) {
return nil
}
|
参考