github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/encrypt/encrypt.go (about) 1 // Copyright 2019 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package encrypt 15 16 import ( 17 "bytes" 18 "crypto/aes" 19 "crypto/cipher" 20 "crypto/rand" 21 22 "github.com/pingcap/tiflow/dm/pkg/log" 23 "github.com/pingcap/tiflow/dm/pkg/terror" 24 "github.com/pingcap/tiflow/pkg/errors" 25 ) 26 27 var ivSep = []byte("@") // ciphertext format: iv + ivSep + encrypted-plaintext 28 29 // Cipher is the interface for encrypt/decrypt. 30 type Cipher interface { 31 Encrypt(plaintext []byte) ([]byte, error) 32 Decrypt(ciphertext []byte) ([]byte, error) 33 } 34 35 // defaultCipher is the default cipher, it should be initialized using 36 // InitCipher before any call to Encrypt and Decrypt. 37 // we keep it as a global variable to avoid change existing call site. 38 var defaultCipher Cipher = ¬InitializedCipher{} 39 40 // InitCipher initializes the defaultCipher. 41 func InitCipher(key []byte) { 42 if len(key) == 0 { 43 log.L().Warn("empty secret key, password in config file will be in plain text") 44 defaultCipher = ¬InitializedCipher{} 45 return 46 } 47 log.L().Info("password in config file will be encrypted") 48 defaultCipher = &aesCipher{secretKey: key} 49 } 50 51 // IsInitialized returns whether the defaultCipher is initialized or not. 52 func IsInitialized() bool { 53 _, ok := defaultCipher.(*aesCipher) 54 return ok 55 } 56 57 // DM will guess whether the password is encrypted or not. 58 // to compatible with this behavior when InitCipher is not called, 59 // we use a notInitializedCipher to always return error. 60 type notInitializedCipher struct{} 61 62 func (n *notInitializedCipher) Encrypt([]byte) ([]byte, error) { 63 return nil, errors.New("secret key is not initialized") 64 } 65 66 func (n *notInitializedCipher) Decrypt([]byte) ([]byte, error) { 67 return nil, errors.New("secret key is not initialized") 68 } 69 70 type aesCipher struct { 71 secretKey []byte 72 } 73 74 func (c *aesCipher) Encrypt(plaintext []byte) ([]byte, error) { 75 block, err := aes.NewCipher(c.secretKey) 76 if err != nil { 77 return nil, terror.ErrEncryptGenCipher.Delegate(err) 78 } 79 80 iv, err := genIV(block.BlockSize()) 81 if err != nil { 82 return nil, err 83 } 84 85 ciphertext := make([]byte, 0, len(iv)+len(ivSep)+len(plaintext)) 86 ciphertext = append(ciphertext, iv...) 87 ciphertext = append(ciphertext, ivSep...) 88 ciphertext = append(ciphertext, plaintext...) // will be overwrite by XORKeyStream 89 90 stream := cipher.NewCFBEncrypter(block, iv) 91 stream.XORKeyStream(ciphertext[len(iv)+len(ivSep):], plaintext) 92 93 return ciphertext, nil 94 } 95 96 func (c *aesCipher) Decrypt(ciphertext []byte) ([]byte, error) { 97 block, err := aes.NewCipher(c.secretKey) 98 if err != nil { 99 return nil, err 100 } 101 102 if len(ciphertext) < block.BlockSize()+len(ivSep) { 103 return nil, terror.ErrCiphertextLenNotValid.Generate(block.BlockSize()+len(ivSep), len(ciphertext)) 104 } 105 106 if !bytes.Equal(ciphertext[block.BlockSize():block.BlockSize()+len(ivSep)], ivSep) { 107 return nil, terror.ErrCiphertextContextNotValid.Generate() 108 } 109 110 iv := ciphertext[:block.BlockSize()] 111 ciphertext = ciphertext[block.BlockSize()+len(ivSep):] 112 plaintext := make([]byte, len(ciphertext)) 113 114 stream := cipher.NewCFBDecrypter(block, iv) 115 stream.XORKeyStream(plaintext, ciphertext) 116 117 return plaintext, nil 118 } 119 120 func genIV(n int) ([]byte, error) { 121 b := make([]byte, n) 122 _, err := rand.Read(b) 123 return b, terror.ErrEncryptGenIV.Delegate(err) 124 } 125 126 // Encrypt encrypts plaintext to ciphertext. 127 func Encrypt(plaintext []byte) ([]byte, error) { 128 return defaultCipher.Encrypt(plaintext) 129 } 130 131 // Decrypt decrypts ciphertext to plaintext. 132 func Decrypt(ciphertext []byte) ([]byte, error) { 133 return defaultCipher.Decrypt(ciphertext) 134 }