Redshift Python加密/解密UDF错误-字符串包含无效或不受支持的UTF8代码点

时间:2018-08-02 21:33:13

标签: python amazon-redshift user-defined-functions

我想在Redshift中创建以下加密和解密UDF。

库:

create library pyaes
language plpythonu
from 's3://aws_python/library/pyaes/pyaes.zip'
credentials 'aws-role'
region as 'aws-region';

加密:

CREATE OR REPLACE FUNCTION test.aes_encrypt(input varchar(max))
RETURNS varchar(max) AS
'    if input is None:
        return None
    import pyaes
    key = ''abcdefghijklopoo''
    aes = pyaes.AESModeOfOperationCTR(key)
    encrypted_msg = aes.encrypt(input)
    return encrypted_msg
'
LANGUAGE plpythonu STABLE;

还尝试了以下选项:

encrypted_msg = aes.encrypt(input.encode("utf8")) 
 key = key.encode('utf-8')

解密:

CREATE OR REPLACE FUNCTION test.aes_decrypt(encrypted_msg varchar(max))
RETURNS varchar(max) AS 
'
    if encrypted_msg is None or len(str(encrypted_msg)) == 0:
       return None
    import pyaes
    key = ''abcdefghijklopoo''
    aes = pyaes.AESModeOfOperationCTR (key)
    decrypted_msg = aes.decrypt(encrypted_msg).decode("utf8")
    return decrypted_msg
'
LANGUAGE plpythonu STABLE;

选择aes_encrypt('Testing'); 选择aes_decrypt('');

但是它抛出以下错误:

错误:无效的操作:字符串包含无效或不受支持的UTF8代码点。错误的UTF8十六进制序列:d5 fc(错误4);

请告知。预先感谢。

1 个答案:

答案 0 :(得分:2)

我在一个可以查看输出的笔记本上进行了此操作。基本上,在发生AES函数时会发生错误,您看不到它的输出,并且它将错误类型传递回Redshift,因为aes作为字节返回。

请注意:这是为了对数据列进行加密混淆,而不是服务器端加密。如果安全性至关重要,请对整个数据库进行加密。如果您打算用它来保护您的客户数据,请不要,请加密盐并哈希所有内容等。这是您的免责声明。

这需要转换为redshift可以处理的东西,例如十六进制,所以使用 'binascii.hexlify(cipher_txt)'以可打印的方式取回值。

CREATE OR REPLACE FUNCTION aes_encrypt(input VARCHAR(20000)) 
RETURNS VARCHAR STABLE AS $$
  import pyaes 
  import binascii
  if input is None:
    return None  
  key = 'abcdefghijklnosp'
  aes=pyaes.AESModeOfOperationCTR(key)
  cipher_txt=aes.encrypt(input)
  cipher_txt2=binascii.hexlify(cipher_txt)

  return str(cipher_txt2.decode('utf-8'))

$$ LANGUAGE plpythonu ;

请注意,返回时的解码是多余的,并且密文分为几行进行说明。我相信您可以将它们放回一行。喜欢
    cipher_txt = binascii.hexlify(aes.encrypt(input))

要取消加密:

CREATE OR REPLACE FUNCTION aes_decrypt(encrypted_msg varchar(max))
RETURNS VARCHAR STABLE AS $$
  import pyaes
  import binascii
  if encrypted_msg is None or len(str(encrypted_msg)) == 0:
       return None
  key = 'abcdefghijklnosp'
  aes = pyaes.AESModeOfOperationCTR(key)
  encrypted_msg2=binascii.unhexlify(encrypted_msg)
  decrypted_msg2 = aes.decrypt(encrypted_msg2)
  return str(decrypted_msg2.decode('utf-8'))
$$ LANGUAGE plpythonu ;

另外-旁注-除非由于其他原因(联合或类似的原因)而无需指定返回varchar的长度-因为将所有内容都设为max会浪费空间。