python Crypto中DSA签名的源码分析(1)——密钥生成

DSA需要的密钥有三种,分别是全局公开钥:p、q、g;私钥x;公钥y,具体要求如下:

    -全局公钥p:满足2^{L-1}<p<2^{L}的大素数,其中512≤L≤1024且L是64的倍数;

    -全局公钥q:p-1的素因子,满足,即q一定是160bit;

    -全局公钥g:,其中h是满足1<h<p-1且使得的任一整数;

    -服务器私钥x:满足0<x<q的随机数或伪随机数;

    -服务器公钥y:

整个代码的结构如下图所示:

(1)首先确定一个随机数生成器,如果未指定,则使用AES加密算法中的随机数生成器(这部分未深入研究,不清楚具体随机数生成算法),代码如下:

    def _get_randfunc(self, randfunc):
        if randfunc is not None:
            return randfunc
        elif self._current_randfunc is None:
            self._current_randfunc = Random.new().read
        return self._current_randfunc

(2)生成全局公钥q,函数generateQ(先生成q,再生成p,因为q是p-1的素因子),先利用上一步得到的随机数生成器生成一个20位的随机数,然后每次取两个hash值的一位作异或,再将异或之后的值加到上一次运算结果的左移八位的值上,最后一次保证是奇数(函数isPrime有两个部分,第一部分是利用10000以内的素数判断素性,第二部分利用Miller-Rabin算法检测素数,此算法主要是利用费马小定理,是一种概率检测,但是目前最好的算法),最后保证q是160bit。大素数生成一般步骤,生成一个大奇数,先用一些素数判定此数的素性,再用Miller-Rabin检测素性。

def generateQ(randfunc):
    S=randfunc(20)
    hash1=SHA.new(S).digest()
    hash2=SHA.new(long_to_bytes(bytes_to_long(S)+1)).digest()
    q = bignum(0)
    for i in range(0,20):
        c=bord(hash1[i])^bord(hash2[i])
        if i==0:
            c=c | 128
        if i==19:
            c= c | 1
        q=q*256+c
    while (not isPrime(q)):
        q=q+2
    if pow(2,159L) < q < pow(2,160L):
        return S, q
    raise RuntimeError('Bad q value generated')

(3)生成全局公钥p,前面的代码一直到p=X-(X%(2*obj.q)-1)这句代码前都是在生成一个大数X,且这个大数一定是等于2的bits-1次方的,然后通过p=X-(X%(2*obj.q)-1)生成p,通过移位等式变为p-1=X-X%(2*obj.q),后面部分保证了是2q的倍数,所以一定p-1一定是q的倍数,满足了q是p-1的素因子,最后在判断p是否满足位数和是否是素数。

 n=divmod(bits-1, 160)[0]
        C, N, V = 0, 2, {}
        b=(obj.q >> 5) & 15
        powb=pow(bignum(2), b)
        powL1=pow(bignum(2), bits-1)
        while C<4096:
            for k in range(0, n+1):
                V[k]=bytes_to_long(SHA.new(S+bstr(N)+bstr(k)).digest())
            W=V[n] % powb
            for k in range(n-1, -1, -1):
                W=(W<<160L)+V[k]
            X=W+powL1
            p=X-(X%(2*obj.q)-1)
            if powL1<=p and isPrime(p):
                break
            C, N = C+1, N+n+1
        if C<4096:
            break

(3)生成全局公钥g,这个没什么好说的,完全按照g的定义来的,代码如下:

power=divmod(p-1, obj.q)[0]
    if progress_func:
        progress_func('h,g\n')
    while (1):
        h=bytes_to_long(randfunc(bits)) % (p-1)
        g=pow(h, power, p)
        if 1<h<p-1 and g>1:
            break
    obj.g=g

(4)私钥x的生成,这个也没什么好说的,直接生成一个随机数,然后再看满足条件么,代码如下:

    while (1):
        x=bytes_to_long(randfunc(20))
        if 0 < x < obj.q:
            break

(5)公钥y的生成,这个也没什么好说的,按照定义来就行,代码如下:

obj.x, obj.y = x, pow(g, x, p)

好了,到此为止Crypto包中DSA签名算法的所有密钥生成源码分析完毕,下篇分析签名和验证签名

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值