資料庫PGP加密演算法、mode、PAD的選擇-PG與Oracle,MySQL的差異(安全性)

德哥發表於2017-11-27

標籤

PostgreSQL , Greenplum , crypt , pgcrypt , mode , padding , 演算法 , aes , bf , cbc , ecb , openssl , enc , linux


背景

PostgreSQL, Greenplum的資料加密外掛pgcrypto,用於加密資料。

其中用於PGP對稱加密的函式例子:

Introduction of PGP encryption, usage of raw encryption functions is discouraged.

encrypt(data bytea, key bytea, type text) returns bytea  
decrypt(data bytea, key bytea, type text) returns bytea  
  
encrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea  
decrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea  

Encrypt/decrypt data using the cipher method specified by type.

The syntax of the type string is:

algorithm [ - mode ] [ /pad: padding ]  

where algorithm is one of:

bf — Blowfish  
  
aes — AES (Rijndael-128)  

and mode is one of:

cbc — next block depends on previous (default)  
  
ecb — each block is encrypted separately (for testing only)  

and padding is one of:

pkcs — data may be any length (default)  
  
none — data must be multiple of cipher block size  

So, for example, these are equivalent:

encrypt(data, `fooz`, `bf`)  
encrypt(data, `fooz`, `bf-cbc/pad:pkcs`)  

In encrypt_iv and decrypt_iv, the iv parameter is the initial value for the CBC mode;

it is ignored for ECB.

It is clipped or padded with zeroes if not exactly block size.

It defaults to all zeroes in the functions without this parameter.

注意,在實際使用時,通常不需要寫mode和pad方法。這樣就帶來了一定的差異。

例如Oracle, MySQL預設的mode是ecb,並不安全。

PostgreSQL預設的mode是cbc,更加安全。

AES

aes是基於資料塊的加密方式,也就是說,每次處理的資料時一塊(16位元組),當資料不是16位元組的倍數時填充,這就是所謂的分組密碼(區別於基於位元位的流密碼),16位元組是分組長度

分組加密的幾種模式:

ECB:是一種基礎的加密方式,密文被分割成分組長度相等的塊(不足補齊),然後單獨一個個加密,一個個輸出組成密文。

CBC:是一種迴圈模式,前一個分組的密文和當前分組的明文異或或操作後再加密,這樣做的目的是增強破解難度。這是PostgreSQL pgcrypto的預設MODE。

CFB/OFB:實際上是一種反饋模式,目的也是增強破解的難度。

FCB和CBC的加密結果是不一樣的,兩者的模式不同,而且CBC會在第一個密碼塊運算時加入一個初始化向量。

mode不一樣導致加密結果不一樣的例子

選擇不一樣的mode,對同一串字元加密,得到的加密結果是不一樣的

1、mode=cbc

postgres=# SELECT  UPPER(ENCODE(ENCRYPT(DECODE(`6999217001930000722099991`,`escape`),`DATAENCRYPTIONYH`::bytea,`aes`::text),`hex`))::text ;  
                              upper                                 
------------------------------------------------------------------  
 BE298AD86D3ADA917C5831A1EA7C856761B0FA22F618928BA56FC4D1C972E402  
(1 row)  
  
postgres=# SELECT  UPPER(ENCODE(ENCRYPT(DECODE(`6999217001930000722099991`,`escape`),`DATAENCRYPTIONYH`::bytea,`aes-cbc`::text),`hex`))::text ;  
                              upper                                 
------------------------------------------------------------------  
 BE298AD86D3ADA917C5831A1EA7C856761B0FA22F618928BA56FC4D1C972E402  
(1 row)  

2、mode=ecb

postgres=# SELECT  UPPER(ENCODE(ENCRYPT(DECODE(`6999217001930000722099991`,`escape`),`DATAENCRYPTIONYH`::bytea,`aes-ecb`::text),`hex`))::text ;  
                              upper                                 
------------------------------------------------------------------  
 BE298AD86D3ADA917C5831A1EA7C8567EB01669E109F443A90D7EEABA3343E3A  
(1 row)  

解密時,如果使用ecb加密的串,用cbc來解密,顯然得到的結果是不對的,反之亦然

postgres=# select encode(decrypt(ENCRYPT(DECODE(`6999217001930000722099991`,`escape`),`DATAENCRYPTIONYH`::bytea,`aes-ecb`::text), `DATAENCRYPTIONYH`::bytea, `aes-ecb`), `escape`);  
          encode             
---------------------------  
 6999217001930000722099991  
(1 row)  
  
postgres=# select encode(decrypt(ENCRYPT(DECODE(`6999217001930000722099991`,`escape`),`DATAENCRYPTIONYH`::bytea,`aes-cbc`::text), `DATAENCRYPTIONYH`::bytea, `aes-cbc`), `escape`);  
          encode             
---------------------------  
 6999217001930000722099991  
(1 row)  
  
postgres=# select encode(decrypt(ENCRYPT(DECODE(`6999217001930000722099991`,`escape`),`DATAENCRYPTIONYH`::bytea,`aes-ecb`::text), `DATAENCRYPTIONYH`::bytea, `aes-cbc`), `escape`);  
                             encode                               
----------------------------------------------------------------  
 6999217001930000211x1B270350Tx03343250M_6246355{202`  
(1 row)  

小結

如果你發現同樣用到了AES演算法加密,但是得到的加密串不一樣,那麼請注意兩者用的mode, padding是否一致,如果不一致,結果肯定是不一樣的。

解密與加密的演算法、MODE、PADDING都需要一樣,才能保證正常的解密。

如果你的ORACLE或MYSQL用了ecb mode,那麼在PostgreSQL, Greenplum中解密時,請務必使用同樣的mode來解密。

參考

https://www.postgresql.org/docs/10/static/pgcrypto.html

《PostgreSQL 和 Greenplum pgcrypto 加解密bytea處理差異》

《固若金湯 – PostgreSQL pgcrypto加密外掛》

《PostgreSQL 如何實現網路壓縮傳輸或加密傳輸(openssl)》

man openssl

man enc

        aes-[128|192|256]-cbc  128/192/256 bit AES in CBC mode  
        aes-[128|192|256]      Alias for aes-[128|192|256]-cbc  
        aes-[128|192|256]-cfb  128/192/256 bit AES in 128 bit CFB mode  
        aes-[128|192|256]-cfb1 128/192/256 bit AES in 1 bit CFB mode  
        aes-[128|192|256]-cfb8 128/192/256 bit AES in 8 bit CFB mode  
        aes-[128|192|256]-ecb  128/192/256 bit AES in ECB mode  
        aes-[128|192|256]-ofb  128/192/256 bit AES in OFB mode  


相關文章