Skip to content

Commit

Permalink
expression,util/encrypt: add support for AES OFB mode (#8605)
Browse files Browse the repository at this point in the history
  • Loading branch information
snithish authored and XuHuaiyu committed Jan 11, 2019
1 parent b552bf8 commit 786a9d5
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 1 deletion.
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-ofb": {"ofb", 16, true},
"aes-192-ofb": {"ofb", 24, true},
"aes-256-ofb": {"ofb", 32, true},
"aes-128-cfb": {"cfb", 16, true},
"aes-192-cfb": {"cfb", 24, true},
"aes-256-cfb": {"cfb", 32, true},
Expand Down Expand Up @@ -212,6 +215,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 "ofb":
plainText, err = encrypt.AESDecryptWithOFB([]byte(cryptStr), key, []byte(iv))
case "cfb":
plainText, err = encrypt.AESDecryptWithCFB([]byte(cryptStr), key, []byte(iv))
default:
Expand Down Expand Up @@ -337,6 +342,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 "ofb":
cipherText, err = encrypt.AESEncryptWithOFB([]byte(str), key, []byte(iv))
case "cfb":
cipherText, err = encrypt.AESEncryptWithCFB([]byte(str), key, []byte(iv))
default:
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 ofb
{"aes-128-ofb", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "0515A36BBF3DE0"},
{"aes-128-ofb", "pingcap", []interface{}{"123456789012345678901234", "1234567890123456"}, "C2A93A93818546"},
{"aes-192-ofb", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "FE09DCCF14D458"},
{"aes-256-ofb", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "2E70FCAC0C0834"},
{"aes-256-ofb", "pingcap", []interface{}{"12345678901234561234567890123456", "1234567890123456"}, "83E2B30A71F011"},
{"aes-256-ofb", "pingcap", []interface{}{"1234567890123456", "12345678901234561234567890123456"}, "2E70FCAC0C0834"},
// test for cfb
{"aes-128-cfb", "pingcap", []interface{}{"1234567890123456", "1234567890123456"}, "0515A36BBF3DE0"},
{"aes-128-cfb", "pingcap", []interface{}{"123456789012345678901234", "1234567890123456"}, "C2A93A93818546"},
Expand Down
30 changes: 30 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,21 @@ func (s *testIntegrationSuite) TestEncryptionBuiltin(c *C) {
result.Check(testkit.Rows("341672829F84CB6B0BE690FEC4C4DAE9 341672829F84CB6B0BE690FEC4C4DAE9 D43734E147A12BB96C6897C4BBABA283 16F2C972411948DCEF3659B726D2CCB04AD1379A1A367FA64242058A50211B67 41E71D0C58967C1F50EEC074523946D1 1117D292E2D39C3EAA3B435371BE56FC 8ACB7ECC0883B672D7BD1CFAA9FA5FAF5B731ADE978244CD581F114D591C2E7E D2B13C30937E3251AEDA73859BA32E4B 2CF4A6051FF248A67598A17AA2C17267"))
result = tk.MustQuery("select HEX(AES_ENCRYPT('123', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT(123, 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('你好', 'foobar', '1234567890123456')), AES_ENCRYPT(NULL, 'foobar', '1234567890123456')")
result.Check(testkit.Rows(`80D5646F07B4654B05A02D9085759770 80D5646F07B4654B05A02D9085759770 B3C14BA15030D2D7E99376DBE011E752 0CD2936EE4FEC7A8CDF6208438B2BC05 <nil>`))
tk.MustExec("SET block_encryption_mode='aes-128-ofb';")
result = tk.MustQuery("select HEX(AES_ENCRYPT(a, 'key', '1234567890123456')), HEX(AES_ENCRYPT(b, 'key', '1234567890123456')), HEX(AES_ENCRYPT(c, 'key', '1234567890123456')), HEX(AES_ENCRYPT(d, 'key', '1234567890123456')), HEX(AES_ENCRYPT(e, 'key', '1234567890123456')), HEX(AES_ENCRYPT(f, 'key', '1234567890123456')), HEX(AES_ENCRYPT(g, 'key', '1234567890123456')), HEX(AES_ENCRYPT(h, 'key', '1234567890123456')), HEX(AES_ENCRYPT(i, 'key', '1234567890123456')) from t")
result.Check(testkit.Rows("40 40 40C35C 40DD5EBDFCAA397102386E27DDF97A39ECCEC5 43DF55BAE0A0386D 78 47DC5D8AD19A085C32094E16EFC34A08D6FEF459 46D5 06840BE8"))
result = tk.MustQuery("select HEX(AES_ENCRYPT('123', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT(123, 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('你好', 'foobar', '1234567890123456')), AES_ENCRYPT(NULL, 'foobar', '1234567890123456')")
result.Check(testkit.Rows(`48E38A 48E38A 9D6C199101C3 <nil>`))
tk.MustExec("SET block_encryption_mode='aes-192-ofb';")
result = tk.MustQuery("select HEX(AES_ENCRYPT(a, 'key', '1234567890123456')), HEX(AES_ENCRYPT(b, 'key', '1234567890123456')), HEX(AES_ENCRYPT(c, 'key', '1234567890123456')), HEX(AES_ENCRYPT(d, 'key', '1234567890123456')), HEX(AES_ENCRYPT(e, 'key', '1234567890123456')), HEX(AES_ENCRYPT(f, 'key', '1234567890123456')), HEX(AES_ENCRYPT(g, 'key', '1234567890123456')), HEX(AES_ENCRYPT(h, 'key', '1234567890123456')), HEX(AES_ENCRYPT(i, 'key', '1234567890123456')) from t")
result.Check(testkit.Rows("4B 4B 4B573F 4B493D42572E6477233A429BF3E0AD39DB816D 484B36454B24656B 73 4C483E757A1E555A130B62AAC1DA9D08E1B15C47 4D41 0D106817"))
result = tk.MustQuery("select HEX(AES_ENCRYPT('123', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT(123, 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('你好', 'foobar', '1234567890123456')), AES_ENCRYPT(NULL, 'foobar', '1234567890123456')")
result.Check(testkit.Rows(`3A76B0 3A76B0 EFF92304268E <nil>`))
tk.MustExec("SET block_encryption_mode='aes-256-ofb';")
result = tk.MustQuery("select HEX(AES_ENCRYPT(a, 'key', '1234567890123456')), HEX(AES_ENCRYPT(b, 'key', '1234567890123456')), HEX(AES_ENCRYPT(c, 'key', '1234567890123456')), HEX(AES_ENCRYPT(d, 'key', '1234567890123456')), HEX(AES_ENCRYPT(e, 'key', '1234567890123456')), HEX(AES_ENCRYPT(f, 'key', '1234567890123456')), HEX(AES_ENCRYPT(g, 'key', '1234567890123456')), HEX(AES_ENCRYPT(h, 'key', '1234567890123456')), HEX(AES_ENCRYPT(i, 'key', '1234567890123456')) from t")
result.Check(testkit.Rows("16 16 16D103 16CF01CBC95D33E2ED721CBD930262415A69AD 15CD0ACCD55732FE 2E 11CE02FCE46D02CFDD433C8CA138527060599C35 10C7 5096549E"))
result = tk.MustQuery("select HEX(AES_ENCRYPT('123', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT(123, 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('', 'foobar', '1234567890123456')), HEX(AES_ENCRYPT('你好', 'foobar', '1234567890123456')), AES_ENCRYPT(NULL, 'foobar', '1234567890123456')")
result.Check(testkit.Rows(`E842C5 E842C5 3DCD5646767D <nil>`))

// for AES_DECRYPT
tk.MustExec("SET block_encryption_mode='aes-128-ecb';")
Expand All @@ -1018,6 +1033,21 @@ func (s *testIntegrationSuite) TestEncryptionBuiltin(c *C) {
result.Check(testkit.Rows("foo"))
result = tk.MustQuery("select AES_DECRYPT(UNHEX('80D5646F07B4654B05A02D9085759770'), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX('B3C14BA15030D2D7E99376DBE011E752'), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX('0CD2936EE4FEC7A8CDF6208438B2BC05'), 'foobar', '1234567890123456'), AES_DECRYPT(NULL, 'foobar', '1234567890123456'), AES_DECRYPT('SOME_THING_STRANGE', 'foobar', '1234567890123456')")
result.Check(testkit.Rows(`123 你好 <nil> <nil>`))
tk.MustExec("SET block_encryption_mode='aes-128-ofb';")
result = tk.MustQuery("select AES_DECRYPT(AES_ENCRYPT('foo', 'bar', '1234567890123456'), 'bar', '1234567890123456')")
result.Check(testkit.Rows("foo"))
result = tk.MustQuery("select AES_DECRYPT(UNHEX('48E38A'), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX(''), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX('9D6C199101C3'), 'foobar', '1234567890123456'), AES_DECRYPT(NULL, 'foobar', '1234567890123456'), HEX(AES_DECRYPT('SOME_THING_STRANGE', 'foobar', '1234567890123456'))")
result.Check(testkit.Rows(`123 你好 <nil> 2A9EF431FB2ACB022D7F2E7C71EEC48C7D2B`))
tk.MustExec("SET block_encryption_mode='aes-192-ofb';")
result = tk.MustQuery("select AES_DECRYPT(AES_ENCRYPT('foo', 'bar', '1234567890123456'), 'bar', '1234567890123456')")
result.Check(testkit.Rows("foo"))
result = tk.MustQuery("select AES_DECRYPT(UNHEX('3A76B0'), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX(''), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX('EFF92304268E'), 'foobar', '1234567890123456'), AES_DECRYPT(NULL, 'foobar', '1234567890123456'), HEX(AES_DECRYPT('SOME_THING_STRANGE', 'foobar', '1234567890123456'))")
result.Check(testkit.Rows(`123 你好 <nil> 580BCEA4DC67CF33FF2C7C570D36ECC89437`))
tk.MustExec("SET block_encryption_mode='aes-256-ofb';")
result = tk.MustQuery("select AES_DECRYPT(AES_ENCRYPT('foo', 'bar', '1234567890123456'), 'bar', '1234567890123456')")
result.Check(testkit.Rows("foo"))
result = tk.MustQuery("select AES_DECRYPT(UNHEX('E842C5'), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX(''), 'foobar', '1234567890123456'), AES_DECRYPT(UNHEX('3DCD5646767D'), 'foobar', '1234567890123456'), AES_DECRYPT(NULL, 'foobar', '1234567890123456'), HEX(AES_DECRYPT('SOME_THING_STRANGE', 'foobar', '1234567890123456'))")
result.Check(testkit.Rows(`123 你好 <nil> 8A3FBBE68C9465834584430E3AEEBB04B1F5`))

// for COMPRESS
tk.MustExec("DROP TABLE IF EXISTS t1;")
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)
}

// AESEncryptWithOFB encrypts data using AES with OFB mode.
func AESEncryptWithOFB(plainStr []byte, key []byte, iv []byte) ([]byte, error) {
cb, err := aes.NewCipher(key)
if err != nil {
return nil, errors.Trace(err)
}
mode := cipher.NewOFB(cb, iv)
crypted := make([]byte, len(plainStr))
mode.XORKeyStream(crypted, plainStr)
return crypted, nil
}

// AESDecryptWithOFB decrypts data using AES with OFB mode.
func AESDecryptWithOFB(cipherStr []byte, key []byte, iv []byte) ([]byte, error) {
cb, err := aes.NewCipher(key)
if err != nil {
return nil, errors.Trace(err)
}
mode := cipher.NewOFB(cb, iv)
plainStr := make([]byte, len(cipherStr))
mode.XORKeyStream(plainStr, cipherStr)
return plainStr, nil
}

// AESEncryptWithCFB decrypts data using AES with CFB mode.
func AESEncryptWithCFB(cryptStr, key []byte, iv []byte) ([]byte, error) {
cb, err := aes.NewCipher(key)
Expand Down
71 changes: 70 additions & 1 deletion util/encrypt/aes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,75 @@ func (s *testEncryptSuite) TestAESEncryptWithCBC(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 := AESEncryptWithOFB(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) TestAESDecryptWithOFB(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 := AESDecryptWithOFB(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) TestAESDecryptWithCBC(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
Expand Down Expand Up @@ -342,7 +411,7 @@ func (s *testEncryptSuite) TestAESDecryptWithCBC(c *C) {
}
}

func (s *testEncryptSuite) TestAESEncryptWithOFB(c *C) {
func (s *testEncryptSuite) TestAESEncryptWithCFB(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
str string
Expand Down

0 comments on commit 786a9d5

Please sign in to comment.