2016-11-08 86 views
3

我试图解密使用pgcrypto加密的数据。我没有使用IV,因为它只是一个测试,但我无法用C#解密数据。解密通过pgcrypto加密的数据(使用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

也许你可以尝试使用C#函数对数据进行加密,并尝试使加密数据与PostGres数据匹配100%。一旦匹配,您应该能够找到两个系统之间的断开连接。 –

+0

谢谢,迈克尔 - 很好的建议。我会试试看。或者甚至确保我只能在C#中进行加密和解密才能开始。 –

回答

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个字节长 - 而不是我所期望的。 这是误解我的一部分,如何PG的字符串到字节转换的作品。我认为“\\ xAACE38F289EC3EA209B48D”会转换成一个11字节的数组(https://www.postgresql.org/docs/9.6/static/datatype-binary.html,第8.4.1节),但不需要双倍的反斜杠。 所以我的字符串转换为'\','x','A'...'D' - 一个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是“d6edd775-47c5-4779-a761-7f8297130073”)

希望这也许有一天帮助别人。

  • Adam。
+0

不错,谢谢 – lhk

+0

很高兴你工作了:) –