zoukankan      html  css  js  c++  java
  • 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:在加密时是否将 转换为 、在解密时是否将 转换为 (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位的密钥按位替代或交换的方法形成密文组的加密方法。
     
     
     
  • 相关阅读:
    超链接解决头部fixed问题
    cookie操作
    JS 阻止整个网页的内容被选中
    stopPropagation(), preventDefault() 和 return false
    获得元素的位置。宽、高
    css 清除浮动
    pytest官网文档の第一章:安装和快速开始
    采用Anaconda安装python
    jmeter利用BeanShell PreProcessor编写脚本实现参数化
    java长连接和短连接
  • 原文地址:https://www.cnblogs.com/kuang17/p/12408108.html
Copyright © 2011-2022 走看看