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
}

参考