简体   繁体   English

解密由pgcrypto加密的数据(在C#中)

[英]Decrypting data (in C#) encrypted by pgcrypto

I'm trying to decrypt data which was encrypted using pgcrypto. 我正在尝试解密使用pgcrypto加密的数据。 I didn't use an IV as it's only a test, but I can't decrypt the data in C#. 我没有使用IV,因为它只是一个测试,但我不能解密C#中的数据。

Encrypting in PostGres: 在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));

Decrypting in C#: 在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

I copied the resulting encrypted data from one of the rows, and the binary key, but the C# code keeps blowing with a CryptographicException ("Padding is invalid and cannot be removed") exception. 我从其中一行和二进制密钥中复制了生成的加密数据,但是C#代码继续使用CryptographicException(“填充无效且无法删除”)异常。 My understanding is that pgcrypto's encrypt() defaults to cbc \\ pkcs. 我的理解是pgcrypto的encrypt()默认为cbc \\ pkcs。 Obviously, I'm missing something. 显然,我错过了一些东西。

Any help gratefully received. 任何帮助感激不尽。

Adam. 亚当。

Tried Michael's suggestion and was not getting the right results, of course. 当然,试过迈克尔的建议并没有得到正确的结果。 Found the issue. 发现了这个问题。 PG's string to bytea conversion is not for the unwary. PG的字符串转换为字节转换不适合粗心大意。 The vital clue came from 至关重要的线索来自

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;

This showed the binary key in PG was 24 bytes long - not 11 as I expected. 这表明PG中的二进制密钥长度为24个字节 - 而不是我预期的11个字节。 It was down to a misunderstanding on my part of how PG's string to bytea conversion works. 这是由于我对PG的字符串到字节转换的工作方式的误解。 I thought "\\\\xAACE38F289EC3EA209B48D" would translate into an 11 byte array ( https://www.postgresql.org/docs/9.6/static/datatype-binary.html , section 8.4.1) but the doubled backslash is not needed. 我认为“\\\\ xAACE38F289EC3EA209B48D”将转换为11字节数组( https://www.postgresql.org/docs/9.6/static/datatype-binary.html ,第8.4.1节),但不需要加倍反斜杠。 So my string translates into '\\', 'x', 'A' ... 'D' - a 24 byte array. 所以我的字符串转换为'\\','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 };

(Didn't help that I copied the wrong GUID into my C# code to compare against - the real GUID was "d6edd775-47c5-4779-a761-7f8297130073".) (没有帮助我将错误的GUID复制到我的C#代码中进行比较 - 真正的GUID是“d6edd775-47c5-4779-a761-7f8297130073”。)

Hope this maybe helps someone one day. 希望有一天这可能对某人有所帮助。

  • Adam. 亚当。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM