公钥加密:原理、实现与安全性分析
公钥生成程序
公钥加密在安全通信中扮演着重要角色,而生成公钥和私钥是其基础步骤。以下是生成公钥和私钥的具体步骤:
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)
公钥加密的应用场景和注意事项
应用场景
- 安全通信 :公钥加密可以用于在不安全的网络上安全地传输信息。例如,在电子邮件通信中,发送方可以使用接收方的公钥加密邮件内容,只有接收方使用自己的私钥才能解密邮件,从而保证了邮件内容的机密性。
- 数字签名 :公钥加密可以用于实现数字签名,确保消息的完整性和发送方的身份验证。发送方使用自己的私钥对消息进行签名,接收方使用发送方的公钥验证签名。
注意事项
- 密钥管理 :公钥可以公开分发,但私钥必须严格保密。如果私钥泄露,攻击者可以解密所有使用该私钥加密的消息。
- 密钥长度 :密钥长度越长,加密的安全性越高,但加密和解密的速度也会越慢。在实际应用中,需要根据具体情况选择合适的密钥长度。
- 实际安全性 :虽然公钥加密在理论上是安全的,但在实际应用中,还需要考虑其他因素,如实现细节、系统漏洞等。因此,在使用公钥加密时,需要选择经过严格测试和验证的加密库。
总结
公钥加密是一种重要的加密技术,它通过使用公钥和私钥对消息进行加密和解密,保证了信息的安全性和完整性。在本文中,我们详细介绍了公钥生成程序、公钥密码的工作原理、加密和解密的数学原理,以及无法破解公钥密码的原因。同时,我们还分析了公钥加密程序的实现细节、应用场景和注意事项。
公钥加密在安全通信、数字签名等领域具有广泛的应用前景,但在使用时需要注意密钥管理、密钥长度和实际安全性等问题。通过合理使用公钥加密技术,可以有效地保护信息的安全,为我们的生活和工作带来便利。
超级会员免费看
1241

被折叠的 条评论
为什么被折叠?



