31、公钥加密:原理、实现与安全性分析

公钥加密:原理、实现与安全性分析

公钥生成程序

公钥加密在安全通信中扮演着重要角色,而生成公钥和私钥是其基础步骤。以下是生成公钥和私钥的具体步骤:
1. 生成两个大素数 :创建两个随机、不同且非常大的素数 p q ,并将它们相乘得到 n
2. 选择随机数 e :生成一个随机数 e ,使其与 (p - 1) × (q - 1) 互质。
3. 计算模逆元 d :计算 e 的模逆元 d

以下是生成公钥和私钥的 Python 代码:

# Public Key Generator
# https://www.nostarch.com/crackingcodes/ (BSD Licensed)

import random, sys, os, primeNum, cryptomath

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

def generateKey(keySize):
    # Creates public/private keys keySize bits in size.
    p = 0
    q = 0
    # Step 1: Create two prime numbers, p and q. Calculate n = p * q:
    print('Generating p prime...')
    while p == q:
        p = primeNum.generateLargePrime(keySize)
        q = primeNum.generateLargePrime(keySize)
    n = p * q

    # Step 2: Create a number e that is relatively prime to (p-1)*(q-1):
    print('Generating 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('Calculating d that is mod inverse of e...')
    d = cryptomath.findModInverse(e, (p - 1) * (q - 1))

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

    print('Public key:', publicKey)
    print('Private key:', privateKey)

    return (publicKey, privateKey)

def makeKeyFiles(name, keySize):
    # Creates two files 'x_pubkey.txt' and 'x_privkey.txt' (where x
    # is the value in name) with the n,e and d,e integers written in
    # them, delimited by a comma.

    # Our safety check will prevent us from overwriting our old key files:
    if os.path.exists('%s_pubkey.txt' % (name)) or os.path.exists('%s_privkey.txt' % (name)):
        sys.exit('WARNING: The file %s_pubkey.txt or %s_privkey.txt already exists! Use a different name or delete these files and rerun this program.' % (name, name))

    publicKey, privateKey = generateKey(keySize)

    print()
    print('The public key is a %s and a %s digit number.' % (len(str(publicKey[0])), len(str(publicKey[1]))))
    print('Writing 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 a %s and a %s digit number.' % (len(str(publicKey[0])), len(str(publicKey[1]))))
    print('Writing private key to file %s_privkey.txt...' % (name))
    fo = open('%s_privkey.txt' % (name), 'w')
    fo.write('%s,%s,%s' % (keySize, privateKey[0], privateKey[1]))
    fo.close()

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

运行该程序时,输出示例如下:

Making key files...
Generating p prime...
Generating q prime...
Generating e that is relatively prime to (p-1)*(q-1)...
Calculating d that is mod inverse of e...
Public key: (210902406316700502401968491406579417405090396754616926135810621216116191338086567840745987535546889792807238627051072044382732467143589327485839374968506241167776147241821152026946322876869404394483922202407821672864242478920813182699000847352671174429654856386676845425140495196080522468242549897523048895590808649185211634877784953627068508544697095291564005052221220422180374449406588101033148646830531744960702788478777031572995978999471326531132766377616771007701834003666830661266575941720784582347990344057272406812521100232929833871861585954209372109725826359561748245019920074018549204468791300114315056117093, 1746023076917516102173184545923683355383240391086912905495420037367858093524760662226576438823575217665473780584902300654473289630868551366950991745119582226113980989513066766009588891895645995814564600702703936932776834043548115756816059906591453170741270845572335375041024799371425300216777273298110097435989)
Private key: (210902406316700502401968491406579417405090396754616926135810621216116191338086567840745987535546889792807238627051072044382732467143589327485839374968506241167776147241821152026946322876869404394483922202407821672864242478920813182699000847352671174429654856386676845425140495196080522468242549897523048895590808649185211634877784953627068508544697095291564005052221220422180374449406588101033148646830531744960702788478777031572995978999471326531132766377616771007701834003666830661266575941720784582347990344057272406812521100232929833871861585954209372109725826359561748245019920074018549204468791300114315056117093, 4767673579813771041216688491698376504317312028941690434129597155228687099187466609993337100807594854900855122476069594266696246596816899540499393450839901428305371067676083594890231288863993840268618707505236077306236416266427614496565255854533116668173598098138449334931305875025941768372702963348445191139635826000818122373486213256488077192893119257248107794256818846036400286732731352928311701786142068171658028122915283195622006250825572616804708456070635960183391931797437503163601143217769616471700002543036826990539739057474642785416933878499897014777481407371328053001838085314443545845219087249544663398589)
The public key is a 617 and a 309 digit number.
Writing public key to file al_sweigart_pubkey.txt...
The private key is a 617 and a 309 digit number.
Writing private key to file al_sweigart_privkey.txt...
混合密码系统

公钥加密虽然在安全通信中具有重要作用,但计算成本较高,尤其是对于需要每秒处理数千个加密连接的服务器。为了解决这个问题,人们通常采用混合密码系统。在混合密码系统中,公钥加密用于加密和分发对称密钥,而对称密钥则用于后续的快速加密和解密操作。具体流程如下:
1. 生成对称密钥 :发送方生成一个对称密钥。
2. 使用公钥加密对称密钥 :发送方使用接收方的公钥对对称密钥进行加密。
3. 发送加密后的对称密钥 :发送方将加密后的对称密钥发送给接收方。
4. 使用对称密钥进行通信 :接收方使用自己的私钥解密对称密钥,然后双方使用该对称密钥进行后续的通信。

公钥密码的工作原理

公钥密码与之前的密码系统不同,它将多个字符转换为一个称为块的整数,然后对每个块进行加密。这样做的原因是,如果对单个字符进行加密,相同的明文将始终加密为相同的密文,从而使公钥密码退化为简单的替换密码。

创建块

在密码学中,块是一个大整数,代表固定数量的文本字符。在 publicKeyCipher.py 程序中,消息字符串被转换为块,每个块代表 169 个文本字符。最大块大小取决于符号集大小和密钥大小,需要满足 2^key size > 符号集大小^块大小 的条件。例如,使用 1024 位密钥和 66 个字符的符号集时,最大块大小为 169 个字符。

将字符串转换为块

可以使用符号集字符串的索引将文本字符转换为整数,然后通过将字符的符号集索引乘以符号集大小的递增幂来创建块。例如,将字符串 ‘Howdy’ 转换为块的过程如下:

SYMBOLS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !?.'
blockInteger = 0
blockInteger += SYMBOLS.index('H') * (len(SYMBOLS) ** 0)
blockInteger += SYMBOLS.index('o') * (len(SYMBOLS) ** 1)
blockInteger += SYMBOLS.index('w') * (len(SYMBOLS) ** 2)
blockInteger += SYMBOLS.index('d') * (len(SYMBOLS) ** 3)
blockInteger += SYMBOLS.index('y') * (len(SYMBOLS) ** 4)
print(blockInteger)  # 输出: 957285919

如果消息长度超过 169 个字符,可以使用多个块进行加密,并使用逗号分隔这些块。以下是一个消息分割成块的示例:
| 消息 | 块整数 |
| — | — |
| 1st block (169 字符)
Alan Mathison Turing was a British cryptanalyst and computer scientist. He was highly influential in the development of computer science and provided a formalisation of | 30138103381200276581206111663322701590471547608326152595431391575797140707837485089852659286061395648657712401264848061468979996871106525448961558640277994456848107158423162065952633246425985956987627719631460939256595688769305982915401292341459466451137309352608735432166613773623460986403811099485392482698 |
| 2nd block (169 字符)
the concepts of algorithm and computation with the Turing machine. Turing is widely considered to be the father of computer science and artificial intelligence. During W | 11068907809221474552159350801956343731326801027081927136514840854754026777527919580758722720267087026340702811097095557610085841376819190225258032442691476944762174257333902148064107269871669093655004577014280290424452471175143504911739898604483879159731507893719486011257479801658756445279245156715863348631 |
| 3rd block (82 字符)
orld War II he worked for the Government Code and Cypher School at Bletchley Park. | 158367975496160191442895244721758369787583763597486412804750943905655902273209591807729054194485980905328691576422832688749509527709935741799076979034 |

公钥密码加密和解密的数学原理

公钥密码的加密和解密基于以下两个方程:
- 加密方程 C = M^e mod n
- 解密方程 M = C^d mod n

其中, M 是消息块整数, C 是密文块整数, e n 组成公钥, d n 组成私钥。加密时,将每个块整数 M 提升到 e 次幂,然后对 n 取模,得到加密块 C 。解密时,将加密块 C 提升到 d 次幂,然后对 n 取模,得到原始消息块 M

例如,加密字符串 ‘Howdy’ 并发送给 Alice 的过程如下:

# 消息转换为块
message_block = 957285919
# Alice 的公钥
n = 1162845649586043152586764918142848831759
e = 13805220545651593223
# 加密
encrypted_block = pow(message_block, e, n)
print(encrypted_block)  # 输出: 43924807641574602969334176505118775186
# Alice 的私钥
d = 72424475949690145396970707764378340583
# 解密
decrypted_block = pow(encrypted_block, d, n)
print(decrypted_block)  # 输出: 957285919
将块转换为字符串

将块转换为字符串的过程是将块整数转换为每个文本字符的小整数。以字符串 ‘Howdy’ 为例,块整数为 957285919,符号集大小为 66,消息长度为 5 个字符。具体步骤如下:

blockInteger = 957285919
SYMBOLS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !?.'
# 确定最后一个字符的符号集索引
last_char_index = blockInteger // (66 ** 4)
print(SYMBOLS[last_char_index])  # 输出: 'y'
# 计算下一个块整数
blockInteger = blockInteger % (66 ** 4)
# 确定倒数第二个字符的符号集索引
second_last_char_index = blockInteger // (66 ** 3)
print(SYMBOLS[second_last_char_index])  # 输出: 'd'
# 继续处理其他字符
# ...
无法破解公钥密码的原因

公钥密码在正确实现时,对常见的密码攻击具有很强的抵抗力,原因如下:
1. 暴力攻击无效 :可能的密钥数量太多,无法通过暴力枚举来破解。
2. 字典攻击无效 :密钥基于数字,而不是单词,因此字典攻击无法生效。
3. 单词模式攻击无效 :相同的明文单词在不同的块中可能被加密为不同的密文,因此单词模式攻击无法破解。
4. 频率分析无效 :单个加密块代表多个字符,无法进行单个字符的频率分析。

即使密码分析师截获了密文并知道公钥 (e, n) 和密文 C ,但由于不知道私钥 d ,在数学上无法求解原始消息 M 。虽然可以通过分解 n 来计算 d ,但 n 是一个非常大的数,分解它在计算上是不可行的。例如,使用 Python 的 math.sqrt() 函数无法处理约 600 位长的 n ,即使可以处理,计算时间也会非常长。这正是公钥密码的强大之处:在数学上,没有捷径可以找到一个大数字的因子。

综上所述,公钥加密在安全通信中具有重要作用,但也存在计算成本高的问题。混合密码系统结合了公钥加密和对称加密的优点,可以在保证安全性的同时提高通信效率。同时,公钥密码对常见的密码攻击具有很强的抵抗力,为信息安全提供了可靠的保障。

公钥加密:原理、实现与安全性分析

公钥加密程序实现细节分析

在前面我们已经了解了公钥生成程序和公钥密码的基本原理,接下来我们进一步深入分析公钥加密程序的一些实现细节。

生成公钥和私钥的流程

下面是生成公钥和私钥的流程图:

graph TD;
    A[开始] --> B[生成两个大素数p和q];
    B --> C[计算n = p * q];
    C --> D[生成与(p - 1) * (q - 1)互质的e];
    D --> E[计算e的模逆元d];
    E --> F[生成公钥(n, e)和私钥(n, d)];
    F --> G[保存公钥和私钥到文件];
    G --> H[结束];

这个流程清晰地展示了生成公钥和私钥的主要步骤。在代码中, generateKey 函数实现了这个流程,具体代码如下:

def generateKey(keySize):
    p = 0
    q = 0
    # Step 1: Create two prime numbers, p and q. Calculate n = p * q:
    print('Generating p prime...')
    while p == q:
        p = primeNum.generateLargePrime(keySize)
        q = primeNum.generateLargePrime(keySize)
    n = p * q

    # Step 2: Create a number e that is relatively prime to (p-1)*(q-1):
    print('Generating e that is relatively prime to (p-1)*(q-1)...')
    while True:
        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('Calculating d that is mod inverse of e...')
    d = cryptomath.findModInverse(e, (p - 1) * (q - 1))

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

    print('Public key:', publicKey)
    print('Private key:', privateKey)

    return (publicKey, privateKey)

在这个函数中,首先通过 primeNum.generateLargePrime 函数生成两个不同的大素数 p q ,然后计算 n = p * q 。接着,使用 random.randrange 函数生成随机数 e ,并通过 cryptomath.gcd 函数检查 e 是否与 (p - 1) * (q - 1) 互质。最后,使用 cryptomath.findModInverse 函数计算 e 的模逆元 d ,并生成公钥和私钥。

消息加密和解密的流程

消息加密和解密的流程如下:

graph TD;
    A[开始] --> B[将消息转换为块];
    B --> C[使用公钥(e, n)加密块];
    C --> D[得到加密消息];
    D --> E[接收方使用私钥(d, n)解密加密消息];
    E --> F[将解密后的块转换为消息];
    F --> G[结束];

在代码中,加密和解密主要使用 pow 函数实现。例如,加密时使用 C = M^e mod n ,解密时使用 M = C^d mod n 。具体代码示例如下:

# 消息转换为块
message_block = 957285919
# 公钥
n = 1162845649586043152586764918142848831759
e = 13805220545651593223
# 加密
encrypted_block = pow(message_block, e, n)
print(encrypted_block)

# 私钥
d = 72424475949690145396970707764378340583
# 解密
decrypted_block = pow(encrypted_block, d, n)
print(decrypted_block)
公钥加密的应用场景和注意事项
应用场景
  • 安全通信 :公钥加密可以用于在不安全的网络上安全地传输信息。例如,在电子邮件通信中,发送方可以使用接收方的公钥加密邮件内容,只有接收方使用自己的私钥才能解密邮件,从而保证了邮件内容的机密性。
  • 数字签名 :公钥加密可以用于实现数字签名,确保消息的完整性和发送方的身份验证。发送方使用自己的私钥对消息进行签名,接收方使用发送方的公钥验证签名。
注意事项
  • 密钥管理 :公钥可以公开分发,但私钥必须严格保密。如果私钥泄露,攻击者可以解密所有使用该私钥加密的消息。
  • 密钥长度 :密钥长度越长,加密的安全性越高,但加密和解密的速度也会越慢。在实际应用中,需要根据具体情况选择合适的密钥长度。
  • 实际安全性 :虽然公钥加密在理论上是安全的,但在实际应用中,还需要考虑其他因素,如实现细节、系统漏洞等。因此,在使用公钥加密时,需要选择经过严格测试和验证的加密库。
总结

公钥加密是一种重要的加密技术,它通过使用公钥和私钥对消息进行加密和解密,保证了信息的安全性和完整性。在本文中,我们详细介绍了公钥生成程序、公钥密码的工作原理、加密和解密的数学原理,以及无法破解公钥密码的原因。同时,我们还分析了公钥加密程序的实现细节、应用场景和注意事项。

公钥加密在安全通信、数字签名等领域具有广泛的应用前景,但在使用时需要注意密钥管理、密钥长度和实际安全性等问题。通过合理使用公钥加密技术,可以有效地保护信息的安全,为我们的生活和工作带来便利。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值