轉自:
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加密算法: