Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression: ECB/CBC modes with 128/192/256-bit key length for AES #7425

Merged
merged 23 commits into from
Sep 23, 2018

Conversation

mccxj
Copy link
Contributor

@mccxj mccxj commented Aug 17, 2018

What problem does this PR solve?

Fix #7300. Support the init_vector argument for builtin function AES_ENCRYPT/AES_DECRYPT

What is changed and how it works?

  • add system variable 'block_encryption_mode' support

Check List

Tests

  • Unit test
  • Integration test

Code changes

  • Has exported function/method change

if isNull || err != nil {
return "", true, errors.Trace(err)
}
if len(iv) < aes.BlockSize {
Copy link
Contributor

@lysu lysu Aug 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about give another const IVSize to help understand~? although our IVSize = BlockSize = 16

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. add const IVSize = aes.BlockSize.

case "ecb":
plainText, err = encrypt.AESDecryptWithECB([]byte(cryptStr), key)
case "cbc":
plainText, err = encrypt.AESDecryptWithCBC([]byte(cryptStr), key, []byte(iv))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems some duplicate logic in AESDecryptWithECB and AESDecryptWithCBC, AESEncryptWithECB and AESEncryptWithCBC~

what about use AESDecrypt, AESEncrypt, then inversion of control, pass a cipher.BlockMode argument?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add "type blockModeBuild func(block cipher.Block) cipher.BlockMode" to create BlockMode argument.

"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/auth"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/encrypt"
"strings"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move strings to line 28(it's TiDB rule, standard package need in first import group ^ ^)

@lysu lysu added contribution This PR is from a community contributor. component/expression status/all tests passed labels Aug 17, 2018
@mccxj
Copy link
Contributor Author

mccxj commented Aug 20, 2018

@lysu PTAL.

Copy link
Contributor

@lysu lysu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM @zz-jason @coocood PTAL

@lysu lysu added the status/LGT1 Indicates that a PR has LGTM 1. label Aug 21, 2018
@lysu
Copy link
Contributor

lysu commented Aug 21, 2018

/run-all-tests

aes128ecbBlobkSize = 16
)
// IVSize indicates the initialization vector supplied to aes_decrypt
const IVSize = aes.BlockSize
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to export this variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to ivSize

// IVSize indicates the initialization vector supplied to aes_decrypt
const IVSize = aes.BlockSize

type aesModeAttr struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to add some comment about this struct.

}

var aesModes = map[string]*aesModeAttr{
//TODO support more modes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we create a github issue for this TODO and explain what modes need to be supported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. see #7490

}
if mode.ivRequired {
if len(b.args) != 3 {
return "", true, ErrIncorrectParameterCount.GenByArgs("aes_decrypt")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check should be done in aesDecryptFunctionClass.getFunction()

return "", true, errors.Trace(err)
}
if len(iv) < IVSize {
return "", true, errIncorrectArgs.Gen("The initialization vector supplied to aes_decrypt is too short. Must be at least 16 bytes long")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this error message the same with MySQL?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes..I had checked, messages is same to mysql.

but in strict, errorcode returned by this PR has some different to mysql, expect this point, new code using errors.Errorf maybe should add a new ErrXXX.GenByArgs

@mccxj mccxj mentioned this pull request Aug 26, 2018
18 tasks
return "", true, errors.Trace(err)
}
if len(iv) < aes.BlockSize {
return "", true, errIncorrectArgs.Gen("The initialization vector supplied to aes_decrypt is too short. Must be at least 16 bytes long")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/16/aes.BlockSize/?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

return &builtinAesDecryptIVSig{bf, mode}, nil
} else if len(args) == 3 {
// For modes that do not require init_vector, it is ignored and a warning is generated if it is specified.
ctx.GetSessionVars().StmtCtx.AppendWarning(errWarnOptionIgnored.GenByArgs("IV"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this warning should be appended in the function execution phase for every input row:

MySQL(localhost:3306) > select aes_encrypt(a, b, c) from t;
+----------------------+
| aes_encrypt(a, b, c) |
+----------------------+
| 0SF&Qٜ               |
| 0SF&Qٜ               |
| 0SF&Qٜ               |
| 0SF&Qٜ               |
+----------------------+
4 rows in set, 4 warnings (0.00 sec)

MySQL(localhost:3306) > show warnings;
+---------+------+---------------------+
| Level   | Code | Message             |
+---------+------+---------------------+
| Warning | 1618 | <IV> option ignored |
| Warning | 1618 | <IV> option ignored |
| Warning | 1618 | <IV> option ignored |
| Warning | 1618 | <IV> option ignored |
+---------+------+---------------------+
4 rows in set (0.00 sec)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to execution phase, and new testcase is added.

@mccxj
Copy link
Contributor Author

mccxj commented Sep 9, 2018

@zz-jason PTAL.


"crypto/aes"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please put the standard packages together and add an empty line between the third-part packages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

// See https://security.stackexchange.com/questions/4863/mysql-aes-encrypt-key-length.
func DeriveKeyMySQL(key []byte, blockSize int) []byte {
rKey := make([]byte, blockSize)
rIdx := 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why prefix Idx and Key with r?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not changed it. It seems that code position change affects 'git diff'.see line#163.

}

// aesDecrypt decrypts data using AES.
func aesDecrypt(cryptStr, key []byte, build blockModeBuild) ([]byte, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to pass cipher.BlockMode instead of blockModeBuild

Copy link
Contributor Author

@mccxj mccxj Sep 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zz-jason AESEncryptWithCBC/AESDecryptWithCBC is similar with AESEncryptWithECB/AESDecryptWithECB with different cipher.BlockMode, CBC needs iv but ECB does not, so blockModeBuild is the hook method to build cipher.BlockMode.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, if we can remove this hook, pass the required cipher.BlockMode directly, the code would be easier to read and maintain.

@zz-jason
Copy link
Member

@XuHuaiyu PTAL

@jackysp
Copy link
Member

jackysp commented Sep 12, 2018

@mccxj , I've added a word "Fix" before the issue link in the description of this PR, then the issue could be closed automatically when this PR is merged.

@zz-jason
Copy link
Member

@mccxj CI failed.

@zz-jason
Copy link
Member

/run-all-tests

aes128ecbBlobkSize = 16
)
// ivSize indicates the initialization vector supplied to aes_decrypt
const ivSize = aes.BlockSize
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a const variable BlockSize in aes package.

@mccxj
Copy link
Contributor Author

mccxj commented Sep 23, 2018

@zz-jason @lamxTyler @jackysp PTAL

Copy link
Member

@zz-jason zz-jason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zz-jason zz-jason added status/LGT2 Indicates that a PR has LGTM 2. and removed status/LGT1 Indicates that a PR has LGTM 1. labels Sep 23, 2018
@zz-jason
Copy link
Member

/run-all-tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component/expression contribution This PR is from a community contributor. status/LGT2 Indicates that a PR has LGTM 2.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants