我正在尝试解密使用pgcrypto加密的数据。我没有使用IV,因为它只是一个测试,但我无法解密C#中的数据。
在PostGres中加密:
enc_key := '\\xAACE38F289EC3EA209B48D';
-- Time insertions
ts_start := clock_timestamp();
FOR i IN 1..num_loops LOOP
-- The text to insert and its key
plaintext := 'Number: ' || i;
plaintext_pk := gen_random_uuid();
plaintext_pk_as_text := plaintext_pk::text;
-- The ref entries
user_pk := gen_random_uuid();
user_ref_pk := encrypt(plaintext_pk_as_text::bytea, enc_key, 'aes');
-- Add the enries
INSERT INTO "Text" VALUES(plaintext_pk, plaintext);
INSERT INTO "User" VALUES(user_ref_pk, user_pk);
END LOOP;
ts_end := clock_timestamp();
elapsed_raw := cast(extract(epoch from (ts_end - ts_start)) as numeric(18,3));
在C#中解密:
// The decryption key
byte[] enc_key = new byte[] { 0xAA, 0xCE, 0x38, 0xF2, 0x89, 0xEC, 0x3E, 0xA2, 0x09, 0xB4, 0x8D,
0x00, 0x00, 0x00, 0x00, 0x00 };
public static string AESDecryptByteArray(byte [] encoded_data, byte [] key)
{
string result = "";
byte [] result_ba = new byte[64];
using (Aes myAes = Aes.Create())
{
if (myAes == null)
{
throw new Exception("Failed to create AES object.");
}
myAes.Key = key;
myAes.Mode = CipherMode.CBC;
myAes.Padding = PaddingMode.PKCS7;
MemoryStream streamMem = new MemoryStream(encoded_data);
byte[] IV = new byte[16];
// streamMem.Read(IV, 0, 16);
for (int i = 0; i < 16; ++i )
{
IV[i] = 0;
}
myAes.IV = IV;
int iNumBytes = 0;
var decryptor = myAes.CreateDecryptor();
using (CryptoStream streamCrypt = new CryptoStream(streamMem, decryptor, CryptoStreamMode.Read))
{
iNumBytes = streamCrypt.Read(result_ba, 0, 48);
}
result = System.Text.Encoding.ASCII.GetString(result_ba);
}
return result;
} // AESDecryptByteArray
我从其中一行和二进制密钥复制了生成的加密数据,但C#代码仍然存在CryptographicException(“填充无效且无法删除”)异常。我的理解是pgcrypto的encrypt()默认为cbc \ pkcs。显然,我错过了一些东西。
感激不尽的任何帮助。
亚当。
答案 0 :(得分:3)
尝试迈克尔的建议,当然没有得到正确的结果。发现了这个问题。 PG的字符串到bytea的转换不适合粗心的人。重要线索来自
DO $$
declare enc_data bytea;
enc_key bytea;
dec_bytea bytea;
dec_text text;
begin
enc_data := '\305\347fyau\030 \223\014E\307\346\267|\365R\3236l\322f\344\312z\220\271\207C\003\255\210+\316\330&\205l>\342\203\350\214$W\253\370D';
enc_key := '\\xAACE38F289EC3EA209B48D';
dec_bytea := decrypt(enc_data, enc_key, 'aes');
dec_text := dec_bytea::text;
raise info 'Decoded text -> %', dec_text;
DROP TABLE IF EXISTS tmpTable;
CREATE TEMPORARY TABLE tmpTable AS
select dec_text as "Decoded text",
char_length(dec_text) as "Decoded length",
length(enc_data) as "Encoded length",
enc_key as "Enc Key",
length(enc_key) as "Enc Key Len",
encode(enc_key, 'hex') as "Hex key",
encode(enc_key, 'escape') as "Esc key";
END $$;
select * from tmpTable;
这表明PG中的二进制密钥长度为24个字节 - 而不是我预期的11个字节。 这是由于我对PG的字符串到字节转换的工作方式的误解。 我想&#34; \\ xAACE38F289EC3EA209B48D&#34;将转换为11字节数组(https://www.postgresql.org/docs/9.6/static/datatype-binary.html,第8.4.1节),但不需要加倍反斜杠。 所以我的字符串会翻译成&#39; \&#39;,&#39; x&#39;,&#39; A&#39; ......&#39; D&#39; - 一个24字节的数组。
//
// In C# this is the key needed
//
byte[] enc_key_aaaahhhh =
new byte[] { 0x5c, 0x78, 0x41, 0x41, 0x43, 0x45, 0x33, 0x38,
0x46, 0x32, 0x38, 0x39, 0x45, 0x43, 0x33, 0x45,
0x41, 0x32, 0x30, 0x39, 0x42, 0x34, 0x38, 0x44 };
//
// This is wrong.
// For this key you'd need to enter '\xAACE38F289EC3EA209B48D' in PG - only one backslash
//
byte[] enc_key = new byte[] { 0xAA, 0xCE, 0x38, 0xF2, 0x89, 0xEC, 0x3E, 0xA2, 0x09, 0xB4, 0x8D,
0x00, 0x00, 0x00, 0x00, 0x00 };
(没有帮助我将错误的GUID复制到我的C#代码中进行比较 - 真正的GUID是&#34; d6edd775-47c5-4779-a761-7f8297130073&#34 ;.
希望有一天这可能对某人有所帮助。