加密算法基础(1) -- 非对称加密算法之RSA

RSA产生背景

在一些经典和现代的加密算法中,一个主要的问题是密钥,它们都只有一个密钥,这个密钥既用来加密,也用来解密。问题在于,每一个有权访问明文的人都必须具有该密钥。密钥的发布成为了一个弱点。因为如果一个粗心的用户泄露了密钥,那么就等于泄露了所有的密文。此问题在新的一种加密模式中得到了解决,那就是公钥加密算法。该算法由Diffie、Hellmann于1976年提出。其有两个不同的密钥,一个用来加密,一个用来解密。加密密钥可以是公开的,每个人都可以使用它来加密,只有解密密钥是保密的。也成为非对称加密算法。

公钥加解密过程

假如Alice和Bob通信,他们希望使用公钥加密算法是因为它有多个密钥。因为这样他们每个人都将拥有一个保密密钥和一个公钥。Bob将公钥给Alice,与Alice共享该密钥。而第三者Eva也可以得到这个公钥。这既不会泄露Bob的内容,也不会泄露Alice的内容。公钥(PK)系统的优点在于,一旦共享了密钥,Alice便可以发送消息给Bob,该消息使用Bob的公钥进行加密。只有Bob才能解密该消息,因为只有Bob才有相对应的私钥。
一个PK系统的要求如下:

  • 应该很容易生成公钥和私钥;
  • 应该很容易加密和解密;
  • 从公钥很难得出私钥;
  • 利用密钥和公钥很难得出明文。
    公钥概念的真正贡献在于,它减少了网络用户必须管理的密钥数。在公钥系统中,每个用户既创建了自己的密钥,也创建了公钥,用户之间无需因此进行通信。

RSA加密算法的数学原理

RSA是基于指数加密的。指数加密就是使用乘法来生成密钥。其过程是首先将明文字符转换成数字,即将明文字符的ASCII二进制表示转换为相等的整数。计算出明文整数值的e次幂,在对n取模,即可计算出密文:

e和n就是加密的密钥,当然如果要让其对加密有效,此过程必须是可逆的。指数加密可以用另一个密钥d来解密,如下:
在这里插入图片描述
d的值可以通过下面式子求出:
在这里插入图片描述
其中,φ(n)为欧拉函数。其定义为整数j的数目,其中j小于等于n,且GCD(j, n) = 1。即整数个数小于n,且与n没有公因子。如果n是两个素数p和q的乘积,则φ(n) = (p - 1)(q - 1)。求解φ(n)的数学方法是欧拉定理,如果GCD(j, n) = 1,那么:
在这里插入图片描述
RSA即采用这个模型,把他应用到公钥加密算法中,用特殊的方法来确定e、d、n的值。n通过选取两个大素数p和q,且n = pq来确定。由于n属于公钥的一部分,因此需要将其公开。但p、q必须保密,随后在min(p, q)和(p - 1)(q - 1)之间选取另一个数d,该数与(p - 1)(q - 1)互质(即两者之间没有公因子),用如下式计算出e:
在这里插入图片描述
将e作为公钥的一部分公开,但是d需要保密。即:(n, e)为公钥,(n, d)为私钥。
RSA的加密过程就像是一个指数加密。将明文分成若干的消息块,这样每个块就可以用一个大数表示。消息块M的密文C可以通过以下公式算出:
在这里插入图片描述
由于e和n是公钥,也就是说任何人都可以通过上式生成密文。RSA解密过程是通过私钥d,通过如下等式求解出M:
在这里插入图片描述
由于d是私用的,所以只有d的拥有者才能解开密文。此过程是安全的,因为如果想找出d,就必须知道p和q。找出p,q的唯一方法是对n分解因子。如果n很大,那么分解起来就很困难。
举个例子:Bob和Alice想使用RSA加密算法,他们现在先拿简单的例子进行测试,从而可以了解加密是如何工作的。Bob选取了两个素数11和23,两个素数的乘积n为:n = 11 x 23 = 253。接下来选取私钥d,d与(p - 1)(q -1)互质(也就是10 x 22 = 220),这样的数有很多,但是Bob选取了19。另一个公钥e可以使用下式子计算出:19e mod 220 = 1。算出e = 139。
此时Bob告诉Alice,e和n的值为(139,253)。Alice决定检测一下该加密算法,给Bob发送消息:“Hi”。在ASCII码中,该消息用16位二进制表示为0100100001011001,将其转换为十进制为72 105,然后Alice使用Bob的公钥来转换这两个数:
72^(139) mod 253 = 2
105^(139) mod 253 = 101
Bob解析到该消息为(2, 101),然后用私钥还原成原来的文字:
2^(19) mod 253 = 72
101^(19) mod 253 = 105
将这两个数转换成二进制,并在ASCII码表中查到对应的字符,可以知道发送给Bob的真正消息为“Hi”。
但在实际的应用中不可能需要这么小的数字,因为如果Eve知道了Bob的公钥(139,253),那么他就可以尝试分解253以便得出p和q的值。最简单的办法是用16去除253(因为16是大于253的平方根的最小整数)。用不了多长时间,Eva就会发现11除253得23。知道了p和q的值,也就知道了(p - 1)(q - 1) = 220,由于知道了e的值为139,就会很容易算出私钥d = 19。至此密文即可被破解。所以实际中可能需要选取很大的素数p和q,从而使得n几乎不可分解因子或者分解相当困难。要求选择的时候要多于100个数字的数。

RSA算法的Python实现

下面是RSA的一个Python代码的实现:

#RSA Key Generator

import random, sys, os, rabinMiller, cryptomath

def main():
    #Create a public/private keypair with 1024 bit bytes
    print('Making key files...')
    makeKeyFiles('al_sweigart', 1024)
    print('key files made.')

def GenerateKey(KeySize):
    #Create a public/private keypair that are KeySize bits in size.
    #This function may take a while to run.

    #Step 1:Generate two prime numbers, p and q. Calculate n = p * q.
    print('Generate p prime...')
    p = rabinMiller.GenerateLargePrime(KeySize)
    print('Generate q prime...')
    q = rabinMiller.GenerateLargePrime(KeySize)
    n = p * q

    #Step 2:Create a number e that is relatively prime to (p-1)*(q-1)
    print('Generate e that is relatively prime to (p - 1)*(q - 1)...')
    while True:
        #Keep trying random numbers for e until one is valid.
        e = random.randrange(2 ** (KeySize - 1), 2 ** (KeySize))
        if cryptomath.gcd(e, (p - 1)*(q - 1)) == 1:
            break

    #Step 3:Calculate d, the mod inverse of e.
    print('Calculate d, the mod inverse of e.')
    d = cryptomath.findModInverse(e, (p - 1)*(q - 1))

    publicKey = (n , e)
    privateKey = (n, d)

    print('PublicKey :', publicKey)
    print('PrivateKey :', privateKey)

    return (publicKey, privateKey)

def makeKeyFiles(name, KeySize):
    #Create two files 'x_pubkey.txt' and 'x_prikey.txt'
    if os.path.exists('%s_pubkey.txt' %(name)) or os.path.exists('%s_prikey.txt' %(name))
    sys.exit('WARNING:The file %s_pubkey.txt or %s_prikey.txt already exists! Use a differentname or rerun this program.' %(name, name))

    publicKey, privateKey = GenerateKey(KeySize)

    print()
    print('the public key is %s and a %s digit number.' %(len(str(publicKey[0])), len(str(publicKey[1]))))
    print('write public key to file %s_pubkey.txt...' %(name))
    fo = open('%s_pubkey.txt' %(name), 'w')
    fo.write('%s, %s, %s' %(KeySize, publicKey[0], publicKey[1]))
    fo.close

    print()
    print('the private key is %s and a %s digit number.' %(len(str(privateKey[0])), len(str(privateKey[1]))))
    print('write private key to file %s_prikey.txt...' %(name))
    fo = open('%s_prikey.txt' %(name), 'w')
    fo.write('%s, %s, %s' %(KeySize, privateKey[0], privateKey[1]))
    fo.close

#if makeRSAkey.py is run (instead of imported as a module)
#the main() function.
if __name__ = '__main__':
    main()

写在结尾

最近有时间会更新密码学系列的一些算法和代码实现,希望大家能够批评指正,代码也是参考了一些相关的书籍。大家一起学习,共同进步。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值