Postgresql的pgcrypto模塊(轉)


轉自:

https://my.oschina.net/ashnah/blog/1550610

 

Postgresql中,pgcrypto是contrib下的一個插件,它提供了一些加密函數,可以實現服務器端的數據加密。我們可以在SQL語句中調用這些函數來完成數據的加密,比如:

insert into p values(encrypt('aaaa','as','bf'),‘b’);,調用加密函數encrypt把'aaaa'加密后寫入了table中。

使用pgcrypto中的加密函數,可以加密比較重要的字段,提高數據的安全性。

pgcrypto中提供了以下幾種函數:

hash函數:用於計算輸入數據的hash值

digest()

 函數原型:

 digest(data text, type text) returns bytea            //hash文本類型的數據  digest(data bytea, type text) returns bytea        //hash  bytea類型的數據

 參數:

data:要hash的數據

type: 加密算法,可取md5, sha1, sha224, sha256, sha384, sha512

例如:

postgres=# select digest('aa','sha1'); digest -------------------------------------------- \xe0c9035898dd52fc65c41454cec9c4d2611bfb37 (1 row) postgres=# select digest('aa'::bytea,'sha1'); digest -------------------------------------------- \xe0c9035898dd52fc65c41454cec9c4d2611bfb37 (1 row)

可以看出,對於同一個數據,使用同樣的算法時,每次hash的結果都一樣。

但是請注意函數參數, 如果要對bytea hash, 那么請在輸入參數時指定參數類型bytea,否則該bytea將被當作text類型的字符串。

例如以下兩次調用分別調用了2個函數. 所以得到的結果也是不一樣的.

postgres=# select digest('\xaa'::bytea,'sha1'); digest -------------------------------------------- \x52538a80094f7b62948fd31e68fd17a315d8dc91 (1 row) postgres=# select digest('\xaa','sha1'); digest -------------------------------------------- \xadbe9dee454ef4167aff588e2a85ae3927454592 (1 row)

 

hmac()

 函數原型: 

hmac(data text, key text, type text) returns bytea     //hash文本類型的數據 hmac(data bytea, key text, type text) returns bytea     //hash  bytea類型的數據

data:要hash的數據

type: 加密算法,可取md5, sha1, sha224, sha256, sha384, sha512

key:  秘鑰

這兩個函數與digest類似, 只是多了一個key參數, 也就是說同一個被加密的值, 可以使用不同的key得到不同的hash值.

這樣的做法是, 不知道key的話, 也無法逆向破解原始值.

使用hmac還有一個好處是, 使用digest如果原始值和hash值同時被別人修改了是無法知道是否被修改的.

但是使用hmac, 如果原始值被修改了, 同時key沒有泄漏的話, 那么hash值是無法被修改的, 因此就能夠知道原始值是否被修改過.

例如:

postgres=# select hmac('aa','key1','sha1'); hmac -------------------------------------------- \x239eb25f1e2dca491a3ed20dea0b93ff95701e57 (1 row) postgres=# select hmac('aa','key2','sha1'); hmac -------------------------------------------- \x0312ab09ab9c4511322ebf41aa5bec78bb0efdf0 (1 row)

如果key的長度大於blocksize(所用算法hash值的位數),則回先對key進行hash,所得的hash值作為key

以上hash函數只要原始值一致, 每次得到的hash值是一樣的, 雖然hmac多了key的參數, 但是只要key和原始數據一樣, 得到的hash值也是一樣的. 這樣的加密很可能被逆向破解掉.

下面的2個函數,提高了逆向破解的難度, 增強了數據的安全性。

crypt()和gen_salt()

crypt()函數 用來計算hash值

 函數原型:

crypt(data text, salt text) returns text

  salt:由gen_salt()生成的一個字符串,包含加密算法、散列次數等信息

 gen_salt()  為crypt()函數生成一個字符串作為算法參數

  函數原型:

gen_salt(type text [, iter_count integer ]) returns text

 type:加密算法,可取 bf、md5、des、xdes

iter_count :散列次數,數字越大加密時間越長, 被破解需要的時間也越長。

iter_count 的取值范圍:

算法 缺省 最小 最大
xdes 725 1 16777215
bf 6 4 31

對於xdes,iter_count 必須是奇數;對於md5、des,iter_count不起作用。

crypt()和gen_salt()結合使用,同一個原始值, 每次得到的hash值是不一樣的。例如:

postgres=# select crypt('123',gen_salt('bf',10)); crypt -------------------------------------------------------------- $2a$10$HoLIt1kGt00tP482DwjRxuZmXzmj.2zOTc3C59Ga9lIsyqMsbUErC (1 row) postgres=# select crypt('123',gen_salt('bf',10)); crypt -------------------------------------------------------------- $2a$10$UIr2lHZUXU2C2V4eQaDrhuIDzhGwuJ8z573foLUGCh0aQxjHSv4ba

原因是gen_salt每次都會給出1個隨機值。gen_salt所得的字符串如下:

postgres=# select gen_salt('bf',10); gen_salt ------------------------------- $2a$10$k8qIUvgDXvJfIRucLOLY1. (1 row)

 $2a$10$k8qIUvgDXvJfIRucLOLY1. 

2a 該字符串代表算法是bf, 10 代表散列次數為10,后面的是一個隨機的字符串

crypt()和gen_salt() 主要用於密碼的存儲和匹配,既然每次的結果不一樣,那么如何匹配呢,如下:

postgres=# select crypt('123',gen_salt('bf',10)); crypt -------------------------------------------------------------- $2a$10$76xcvT9pZpLL8dKn.RY3nOQXjgW1Yqo0nFBlbiIjqmQO61hE8VlZy (1 row) postgres=# select crypt('123','$2a$10$76xcvT9pZpLL8dKn.RY3nOQXjgW1Yqo0nFBlbiIjqmQO61hE8VlZy'); crypt -------------------------------------------------------------- $2a$10$76xcvT9pZpLL8dKn.RY3nOQXjgW1Yqo0nFBlbiIjqmQO61hE8VlZy (1 row)

把hash值作為salt,對原來的明文進行hash計算,得到的hash值是一樣的。當我們需要匹配的時候,只需要比較hash值 與 用hash值作為salt得到的結果是否一樣即可。

Raw Encryption Functions:

此種類型的加密函數提供了加密函數和相對的解密函數,包含如下的函數:

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

參數:

 key : 秘鑰

 type :加密算法 +模式(形式:bf-cbc)

支持的算法和模式有:   blowfish-cbc(bf-cbc)、aes-128-cbc aes-128-ecb; 編譯時,使用with-openssl選項,還可支持 blowfish-cfb、des-cbc、des-ecb、3des-cbc、3des-ecb、cast5-ecb、cast5-cbc。都是對稱加密算法。

 iv:     CBC、CFB模式的初始向量

例如:

postgres=# select decrypt(encrypt('aaaaaaaaaa','key','des-ecb'),'key','des-ecb'); decrypt ------------ aaaaaaaaaa (1 row) postgres=# select decrypt_iv(encrypt_iv('aaaaaaaaaa','key','iv','des-cbc'),'key','iv','des-cbc'); decrypt_iv ------------ aaaaaaaaaa (1 row)

以上提到了對稱加密算法的模式CBC ECB CFB等,關於加密算法的模式請參照https://my.oschina.net/ashnah/blog/870509

PGP加密函數:

PGP加密函數 實現了部分OpenPGP (RFC 4880)標准,提供了對稱秘鑰和公共秘鑰的加密函數,

把對稱秘鑰和公鑰/私鑰相結合,提高數據的安全性。

使用公鑰/私鑰的加密/解密函數

函數原型:

pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea 

參數:

key :公鑰/私鑰

psw:私鑰的密碼

options:一些可選的加密參數,形式如下:

pgp_pub_encrypt(data, psw, 'compress-algo=1, cipher-algo=aes256')

可選的參數:

cipher-algo:使用的加密算法,取值: bf, aes128, aes192, aes256,cast5

compress-algo:使用的壓縮算法,取值 0,1(zib),2(zlib)

compress-level:壓縮級別(0~9)

convert-crlf:在加密時是否將\n轉換為\r\n、在解密時是否將 \r\n轉換為\n (0,1)

disable-mdc:為了與老版本PGP產品兼容

unicode-mode:是否把文本數據從數據庫內部編碼轉換到UTF-8

使用公鑰/私鑰進行加解密的原理如下:

使用公鑰加密:

加密時隨機產生一個sessionkey(會話秘鑰,是一個對稱密鑰),並用這個sessionkey加密數據,形成數據包;之后使用公鑰加密sessionkey形成會話秘鑰包;數據包和會話秘鑰包共同構成加密信息。

使用私鑰解密:

使用私鑰解密會話秘鑰包中的信息,得到sessionkey;使用sessionkey解密數據包中的內容,得到明文。

 

使用對稱密鑰的加密/解密函數

函數原型:

pgp_sym_encrypt(data text, key text [, options text ]) returns bytea pgp_sym_encrypt_bytea(data bytea, key text [, options text ]) returns bytea pgp_sym_decrypt(msg bytea, key text [, options text ]) returns text pgp_sym_decrypt_bytea(msg bytea, key text [, options text ]) returns bytea 

參數:

key:對稱秘鑰,加密解密時相同

options:一些加密的參數,形式和使用 公鑰/私鑰的函數相同,可選的參數 比使用公鑰/私鑰的函數多了以下幾個:

 sess-key:  1:使用隨機生成的會話秘鑰,0:使用s2k秘鑰作為會話秘鑰

 s2k-mode: s2k過程中 是否使用salt、散列次數

 s2k-digest-algo:s2k過程使用的算法

 s2k-cipher-algo:隨機生成的會話秘鑰的加密方法

下面通過加解密過程的原理圖說明以上參數的使用:

使用對稱密鑰進行加解密的原理如下:

s2k key的生成:

把對稱秘鑰 使用s2k-mode、 s2k-digest-algo指定的信息進行hash運算,得到s2k key.

sess-key=0時,使用s2k key作為會話秘鑰

加密:

使用s2k key作為會話秘鑰對明文進行加密,並把生成s2k key的相關信息放入會話秘鑰包

解密:

解密時,首先根據會話秘鑰包中的s2k info 生成s2k key,再使用s2k key解密密文。

 

sess-key=1時,使用隨機生成的sessionkey

加密:

隨機生成sessionkey 對明文進行加密,s2k key對sessionkey進行加密,並把sessionkey密文和生成s2k key的信息一起形成會話秘鑰包

解密:

解密時,首先根據會話秘鑰包中的s2k info 生成s2k key,再使用s2k key解密會話秘鑰包中的sessionkey

最后使用sessionkey解密數據。

 

PGP函數使用舉例:

使用公鑰/私鑰:
由於秘鑰太長,事先把秘鑰放到table keytbl中,pubkey字段表示公鑰,seckey字段表示私鑰
select pgp_pub_decrypt( pgp_pub_encrypt('Secret msg', dearmor(pubkey), 'cipher-algo=aes192'), dearmor(seckey),'123456789') from keytbl where keytbl.id=1; pgp_pub_decrypt ----------------- Secret msg (1 row) 使用對稱秘鑰: select pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'); pgp_sym_encrypt ------------------------------------------------------------------------------------------------------------------------------------------------------ \xc30d04080302bf1d74533d338175d9de66628c441ab1efda51a047b86652e296821a22e59b99f395e5582ae90d724c2f86ed23801525b8f0c58e9fa24e25e9f342eee3156f38f45b2b (1 row) Select pgp_sym_decrypt('\xc30d04080302bf1d74533d3381756ed23801525b8f0c58e9fa24e25e9f342eee3156f38f45b2bd9de66628c441ab1efda51a047b86652e296821a22e59b99f395e5582ae90d724c2f8','key'); pgp_sym_decrypt ----------------- Secret. (1 row) 

 

 

參考資料:

Postgresql官方文檔

postgresql內核code

 

--補充:

涉及到的算法說明:

散列算法:SHA-1,SHA-2和SHA-256之間的區別

隨着SSL證書的普及,以“SHA”開頭的算法的知名度也越多越高,但並不是很多人能夠完全能分清“SHA”所有的算法,本文將會圍繞“SHA”展開分析,深入了解SSL證書是如果通過散列算法來完成簽名。在細說“SHA”之前,首先要了解一個重要的名稱——HASH(哈希)。


什么是HASH(哈希)?  HASH算法將任意長度的二進制值映射為較短的固定長度的二進制值,這個小的二進制值稱為哈希值。例如句子“那只敏捷的棕色狐狸跳過了懶惰的狗,”通過一種稱為CRC32的特定算法運行,將會產生結果“07606bb6”。而這個結果被稱為HASH(哈希)。

 

SHA-1與SHA-2

如上所述,SHA代表安全哈希算法。SHA-1和SHA-2是該算法不同的兩個版本,它們的構造和簽名的長度都有所不一樣,但可以把SHA-2理解為SHA-1的繼承者。

首先,人們一般把哈希值位數長度作為重要的區別,SHA-1是160位的哈希值,而SHA-2是組合值,有不同的位數,其中最受歡迎的是256位。

因為SHA-2有多種不同的位數,導致這個名詞有一些混亂。但是無論是“SHA-2”,“SHA-256”或“SHA-256位”,其實都是指同一種加密算法。但是SHA-224”,“SHA-384”或“SHA-512”,表示SHA-2的二進制長度。還要另一種就是會把算法和二進制長度都寫上,如“SHA-2 384”。

SSL行業選擇SHA作為數字簽名的散列算法,從2011到2015,一直以SHA-1位主導算法。但隨着互聯網技術的提升,SHA-1的缺點越來越突顯。從去年起,SHA-2成為了新的標准,所以現在簽發的SSL證書,必須使用該算法簽名。

也許有人偶爾會看到SHA-2 384位的證書,很少會看到224位,因為224位不允許用於公共信任的證書,512位,不被軟件支持。

 

AES簡介
高級加密標准(AES,Advanced Encryption Standard)為最常見的對稱加密算法(微信小程序加密傳輸就是用這個加密算法的)。

 

bf加密:

BlowFish算法用來加密64Bit長度的字符串。

 

DES加密算法:

DES算法為 密碼體制中的對稱密碼體制,又被稱為美國 數據加密標准,是1972年美國IBM公司研制的對稱密碼體制 加密算法。 明文按64位進行分組, 密鑰長64位,密鑰事實上是56位參與DES運算(第8、16、24、32、40、48、56、64位是校驗位, 使得每個密鑰都有奇數個1)分組后的明文組和56位的密鑰按位替代或交換的方法形成密文組的加密方法。

 

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM