-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
Changes from 4 commits
e50e207
3ce847d
f3ba799
2f0de8d
3bf2a60
1c10b19
e9e5fa4
4d5d8a9
817f05a
d206725
58e1efd
4279572
dda3ec7
b4e0ee9
f1e233b
492f94c
d732b47
6cd647f
ec0e07b
7d06fbf
3b8a159
b423fb8
90b51e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,13 +26,16 @@ import ( | |
"hash" | ||
"io" | ||
|
||
"crypto/aes" | ||
"github.com/juju/errors" | ||
"github.com/pingcap/tidb/mysql" | ||
"github.com/pingcap/tidb/sessionctx" | ||
"github.com/pingcap/tidb/sessionctx/variable" | ||
"github.com/pingcap/tidb/types" | ||
"github.com/pingcap/tidb/util/auth" | ||
"github.com/pingcap/tidb/util/chunk" | ||
"github.com/pingcap/tidb/util/encrypt" | ||
"strings" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please move |
||
) | ||
|
||
var ( | ||
|
@@ -68,10 +71,21 @@ var ( | |
_ builtinFunc = &builtinUncompressedLengthSig{} | ||
) | ||
|
||
// TODO: support other mode | ||
const ( | ||
aes128ecbBlobkSize = 16 | ||
) | ||
type aesModeAttr struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better to add some comment about this struct. |
||
modeName string | ||
keySize int | ||
ivRequired bool | ||
} | ||
|
||
var aesModes = map[string]*aesModeAttr{ | ||
//TODO support more modes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. see #7490 |
||
"aes-128-ecb": {"ecb", 16, false}, | ||
"aes-192-ecb": {"ecb", 24, false}, | ||
"aes-256-ecb": {"ecb", 32, false}, | ||
"aes-128-cbc": {"cbc", 16, true}, | ||
"aes-192-cbc": {"cbc", 24, true}, | ||
"aes-256-cbc": {"cbc", 32, true}, | ||
} | ||
|
||
type aesDecryptFunctionClass struct { | ||
baseFunctionClass | ||
|
@@ -81,7 +95,11 @@ func (c *aesDecryptFunctionClass) getFunction(ctx sessionctx.Context, args []Exp | |
if err := c.verifyArgs(args); err != nil { | ||
return nil, errors.Trace(c.verifyArgs(args)) | ||
} | ||
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString, types.ETString) | ||
argTps := make([]types.EvalType, 0, len(args)) | ||
for range args { | ||
argTps = append(argTps, types.ETString) | ||
} | ||
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, argTps...) | ||
bf.tp.Flen = args[0].GetType().Flen // At most. | ||
types.SetBinChsClnFlag(bf.tp) | ||
sig := &builtinAesDecryptSig{bf} | ||
|
@@ -112,9 +130,42 @@ func (b *builtinAesDecryptSig) evalString(row chunk.Row) (string, bool, error) { | |
return "", true, errors.Trace(err) | ||
} | ||
|
||
// TODO: Support other modes. | ||
key := encrypt.DeriveKeyMySQL([]byte(keyStr), aes128ecbBlobkSize) | ||
plainText, err := encrypt.AESDecryptWithECB([]byte(cryptStr), key) | ||
var iv string | ||
modeName, _ := b.ctx.GetSessionVars().GetSystemVar(variable.BlockEncryptionMode) | ||
mode, exists := aesModes[strings.ToLower(modeName)] | ||
if !exists { | ||
return "", true, errors.Errorf("unsupported block encryption mode - %v", modeName) | ||
} | ||
if mode.ivRequired { | ||
if len(b.args) != 3 { | ||
return "", true, ErrIncorrectParameterCount.GenByArgs("aes_decrypt") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check should be done in |
||
} | ||
iv, isNull, err = b.args[2].EvalString(b.ctx, row) | ||
if isNull || err != nil { | ||
return "", true, errors.Trace(err) | ||
} | ||
if len(iv) < aes.BlockSize { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about give another const There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. add const IVSize = aes.BlockSize. |
||
return "", true, errIncorrectArgs.Gen("The initialization vector supplied to aes_decrypt is too short. Must be at least 16 bytes long") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this error message the same with MySQL? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
} | ||
// init_vector must be 16 bytes or longer (bytes in excess of 16 are ignored) | ||
iv = iv[0:aes.BlockSize] | ||
} else { | ||
if len(b.args) == 3 { | ||
// For modes that do not require init_vector, it is ignored and a warning is generated if it is specified. | ||
b.ctx.GetSessionVars().StmtCtx.AppendWarning(errWarnOptionIgnored.GenByArgs("IV")) | ||
} | ||
} | ||
|
||
key := encrypt.DeriveKeyMySQL([]byte(keyStr), mode.keySize) | ||
var plainText []byte | ||
switch mode.modeName { | ||
case "ecb": | ||
plainText, err = encrypt.AESDecryptWithECB([]byte(cryptStr), key) | ||
case "cbc": | ||
plainText, err = encrypt.AESDecryptWithCBC([]byte(cryptStr), key, []byte(iv)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems some duplicate logic in what about use There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
default: | ||
return "", true, errors.Errorf("unsupported block encryption mode - %v", mode.modeName) | ||
} | ||
if err != nil { | ||
return "", true, nil | ||
} | ||
|
@@ -129,8 +180,12 @@ func (c *aesEncryptFunctionClass) getFunction(ctx sessionctx.Context, args []Exp | |
if err := c.verifyArgs(args); err != nil { | ||
return nil, errors.Trace(c.verifyArgs(args)) | ||
} | ||
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString, types.ETString) | ||
bf.tp.Flen = aes128ecbBlobkSize * (args[0].GetType().Flen/aes128ecbBlobkSize + 1) // At most. | ||
argTps := make([]types.EvalType, 0, len(args)) | ||
for range args { | ||
argTps = append(argTps, types.ETString) | ||
} | ||
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, argTps...) | ||
bf.tp.Flen = aes.BlockSize * (args[0].GetType().Flen/aes.BlockSize + 1) // At most. | ||
types.SetBinChsClnFlag(bf.tp) | ||
sig := &builtinAesEncryptSig{bf} | ||
return sig, nil | ||
|
@@ -160,9 +215,42 @@ func (b *builtinAesEncryptSig) evalString(row chunk.Row) (string, bool, error) { | |
return "", true, errors.Trace(err) | ||
} | ||
|
||
// TODO: Support other modes. | ||
key := encrypt.DeriveKeyMySQL([]byte(keyStr), aes128ecbBlobkSize) | ||
cipherText, err := encrypt.AESEncryptWithECB([]byte(str), key) | ||
var iv string | ||
modeName, _ := b.ctx.GetSessionVars().GetSystemVar(variable.BlockEncryptionMode) | ||
mode, exists := aesModes[strings.ToLower(modeName)] | ||
if !exists { | ||
return "", true, errors.Errorf("unsupported block encryption mode - %v", modeName) | ||
} | ||
if mode.ivRequired { | ||
if len(b.args) != 3 { | ||
return "", true, ErrIncorrectParameterCount.GenByArgs("aes_encrypt") | ||
} | ||
iv, isNull, err = b.args[2].EvalString(b.ctx, row) | ||
if isNull || err != nil { | ||
return "", true, errors.Trace(err) | ||
} | ||
if len(iv) < aes.BlockSize { | ||
return "", true, errIncorrectArgs.Gen("The initialization vector supplied to aes_encrypt is too short. Must be at least 16 bytes long") | ||
} | ||
// init_vector must be 16 bytes or longer (bytes in excess of 16 are ignored) | ||
iv = iv[0:aes.BlockSize] | ||
} else { | ||
if len(b.args) == 3 { | ||
// For modes that do not require init_vector, it is ignored and a warning is generated if it is specified. | ||
b.ctx.GetSessionVars().StmtCtx.AppendWarning(errWarnOptionIgnored.GenByArgs("IV")) | ||
} | ||
} | ||
|
||
key := encrypt.DeriveKeyMySQL([]byte(keyStr), mode.keySize) | ||
var cipherText []byte | ||
switch mode.modeName { | ||
case "ecb": | ||
cipherText, err = encrypt.AESEncryptWithECB([]byte(str), key) | ||
case "cbc": | ||
cipherText, err = encrypt.AESEncryptWithCBC([]byte(str), key, []byte(iv)) | ||
default: | ||
return "", true, errors.Errorf("unsupported block encryption mode - %v", mode.modeName) | ||
} | ||
if err != nil { | ||
return "", true, nil | ||
} | ||
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.