Skip to content

Commit

Permalink
expression,util/encrypt:add support for AES CFB mode (#8760)
Browse files Browse the repository at this point in the history
  • Loading branch information
kjzz authored and lysu committed Dec 21, 2018
1 parent 94df8d1 commit b818fb2
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 0 deletions.
7 changes: 7 additions & 0 deletions expression/builtin_encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ var aesModes = map[string]*aesModeAttr{
"aes-128-cbc": {"cbc", 16, true},
"aes-192-cbc": {"cbc", 24, true},
"aes-256-cbc": {"cbc", 32, true},
"aes-128-cfb": {"cfb", 16, true},
"aes-192-cfb": {"cfb", 24, true},
"aes-256-cfb": {"cfb", 32, true},
}

type aesDecryptFunctionClass struct {
Expand Down Expand Up @@ -209,6 +212,8 @@ func (b *builtinAesDecryptIVSig) evalString(row chunk.Row) (string, bool, error)
switch b.modeName {
case "cbc":
plainText, err = encrypt.AESDecryptWithCBC([]byte(cryptStr), key, []byte(iv))
case "cfb":
plainText, err = encrypt.AESDecryptWithCFB([]byte(cryptStr), key, []byte(iv))
default:
return "", true, errors.Errorf("unsupported block encryption mode - %v", b.modeName)
}
Expand Down Expand Up @@ -332,6 +337,8 @@ func (b *builtinAesEncryptIVSig) evalString(row chunk.Row) (string, bool, error)
switch b.modeName {
case "cbc":
cipherText, err = encrypt.AESEncryptWithCBC([]byte(str), key, []byte(iv))
case "cfb":
cipherText, err = encrypt.AESEncryptWithCFB([]byte(str), key, []byte(iv))
default:
return "", true, errors.Errorf("unsupported block encryption mode - %v", b.modeName)
}
Expand Down
7 changes: 7 additions & 0 deletions expression/builtin_encryption_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ var aesTests = []struct {
{"aes-256-cbc", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "5D0E22C1E77523AEF5C3E10B65653C8F"},
{"aes-256-cbc", "pingcap", []interface{}{"12345678901234561234567890123456", "1234567890123456"}, "A26BA27CA4BE9D361D545AA84A17002D"},
{"aes-256-cbc", "pingcap", []interface{}{"1234567890123456", "12345678901234561234567890123456"}, "5D0E22C1E77523AEF5C3E10B65653C8F"},
// test for cfb
{"aes-128-cfb", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "0515A36BBF3DE0"},
{"aes-128-cfb", "pingcap", []interface{}{"123456789012345678901234", "1234567890123456"}, "C2A93A93818546"},
{"aes-192-cfb", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "FE09DCCF14D458"},
{"aes-256-cfb", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "2E70FCAC0C0834"},
{"aes-256-cfb", "pingcap", []interface{}{"12345678901234561234567890123456", "1234567890123456"}, "83E2B30A71F011"},
{"aes-256-cfb", "pingcap", []interface{}{"1234567890123456", "12345678901234561234567890123456"}, "2E70FCAC0C0834"},
}

func (s *testEvaluatorSuite) TestAESEncrypt(c *C) {
Expand Down
24 changes: 24 additions & 0 deletions util/encrypt/aes.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,30 @@ func AESDecryptWithCBC(cryptStr, key []byte, iv []byte) ([]byte, error) {
return aesDecrypt(cryptStr, mode)
}

// AESEncryptWithCFB decrypts data using AES with CFB mode.
func AESEncryptWithCFB(cryptStr, key []byte, iv []byte) ([]byte, error) {
cb, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
cfb := cipher.NewCFBEncrypter(cb, iv)
crypted := make([]byte, len(cryptStr))
cfb.XORKeyStream(crypted, cryptStr)
return crypted, nil
}

// AESDecryptWithCFB decrypts data using AES with CFB mode.
func AESDecryptWithCFB(cryptStr, key []byte, iv []byte) ([]byte, error) {
cb, err := aes.NewCipher(key)
if err != nil {
return nil, errors.Trace(err)
}
cfb := cipher.NewCFBDecrypter(cb, []byte(iv))
dst := make([]byte, len(cryptStr))
cfb.XORKeyStream(dst, cryptStr)
return dst, nil
}

// aesDecrypt decrypts data using AES.
func aesDecrypt(cryptStr []byte, mode cipher.BlockMode) ([]byte, error) {
blockSize := mode.BlockSize()
Expand Down
69 changes: 69 additions & 0 deletions util/encrypt/aes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,75 @@ func (s *testEncryptSuite) TestAESDecryptWithCBC(c *C) {
}
}

func (s *testEncryptSuite) TestAESEncryptWithOFB(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
str string
key string
iv string
expect string
isError bool
}{
// 128 bits key
{"pingcap", "1234567890123456", "1234567890123456", "0515A36BBF3DE0", false},
{"pingcap123", "1234567890123456", "1234567890123456", "0515A36BBF3DE0DBE9DD", false},
// 192 bits key
{"pingcap", "123456789012345678901234", "1234567890123456", "45A57592449893", false}, // 192 bit
// negtive cases: invalid key length
{"pingcap", "12345678901234567", "1234567890123456", "", true},
{"pingcap", "123456789012345", "1234567890123456", "", true},
}

for _, t := range tests {
str := []byte(t.str)
key := []byte(t.key)
iv := []byte(t.iv)

crypted, err := AESEncryptWithCFB(str, key, iv)
if t.isError {
c.Assert(err, NotNil, Commentf("%v", t))
continue
}
c.Assert(err, IsNil, Commentf("%v", t))
result := toHex(crypted)
c.Assert(result, Equals, t.expect, Commentf("%v", t))
}
}

func (s *testEncryptSuite) TestAESDecryptWithCFB(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
str string
key string
iv string
expect string
isError bool
}{
// 128 bits key
{"0515A36BBF3DE0", "1234567890123456", "1234567890123456", "pingcap", false},
{"0515A36BBF3DE0DBE9DD", "1234567890123456", "1234567890123456", "pingcap123", false},
// 192 bits key
{"45A57592449893", "123456789012345678901234", "1234567890123456", "pingcap", false}, // 192 bit
// negtive cases: invalid key length
{"pingcap", "12345678901234567", "1234567890123456", "", true},
{"pingcap", "123456789012345", "1234567890123456", "", true},
}

for _, t := range tests {
str, _ := hex.DecodeString(t.str)
key := []byte(t.key)
iv := []byte(t.iv)

plainText, err := AESDecryptWithCFB(str, key, iv)
if t.isError {
c.Assert(err, NotNil, Commentf("%v", t))
continue
}
c.Assert(err, IsNil, Commentf("%v", t))
c.Assert(string(plainText), Equals, t.expect, Commentf("%v", t))
}
}

func (s *testEncryptSuite) TestDeriveKeyMySQL(c *C) {
defer testleak.AfterTest(c)()

Expand Down

0 comments on commit b818fb2

Please sign in to comment.