密码学

警告

本模块仅用于教育目的。请勿将此模块中的函数用于实际的加密应用。如果您希望加密真实数据,我们推荐使用 cryptography 模块。

加密是隐藏信息的过程,而密码是实现这一目的的手段。本模块中包含了块密码和流密码:

  • 移位密码

  • 仿射密码

  • 替代密码

  • Vigenere’s cipher

  • 希尔密码

  • 双字母替换密码

  • RSA

  • Kid RSA

  • 线性反馈移位寄存器 (用于流密码)

  • ElGamal 加密

替换密码 中,明文的“单元”(不一定是单个字符)根据一个常规系统被替换为密文。

一个 换位密码 是一种加密方法,通过这种方法,明文“单位”的位置被替换为明文的一个排列。也就是说,单位顺序通过在字符位置上使用双射函数来改变,以执行加密。

一个 单字母密码 在整个消息中使用固定的替换,而一个 多字母密码 在消息的不同时间使用多个替换。

sympy.crypto.crypto.AZ(s=None)[源代码][源代码]

返回 s 的大写字母。如果传递了多个字符串,每个字符串都将被处理,并返回一个大写字符串列表。

示例

>>> from sympy.crypto.crypto import AZ
>>> AZ('Hello, world!')
'HELLOWORLD'
>>> AZ('Hello, world!'.split())
['HELLO', 'WORLD']
sympy.crypto.crypto.padded_key(key, symbols)[源代码][源代码]

返回一个由 symbolskey 中不同字符组成的字符串,其中 key 中的字符优先出现。如果 a) symbols 中有重复字符,或者 b) key 中有不在 symbols 中的字符,则会引发 ValueError。

示例

>>> from sympy.crypto.crypto import padded_key
>>> padded_key('PUPPY', 'OPQRSTUVWXY')
'PUYOQRSTVWX'
>>> padded_key('RSA', 'ARTIST')
Traceback (most recent call last):
...
ValueError: duplicate characters in symbols: T
sympy.crypto.crypto.check_and_join(phrase, symbols=None, filter=None)[源代码][源代码]

phrase 中的字符连接起来,如果给出了 symbols,则在 phrase 中的任何字符不在 symbols 中时引发错误。

参数:
短语

要作为字符串返回的字符串或字符串列表。

符号

phrase 中允许的字符的可迭代对象。

如果 symbolsNone ,则不进行检查。

示例

>>> from sympy.crypto.crypto import check_and_join
>>> check_and_join('a phrase')
'a phrase'
>>> check_and_join('a phrase'.upper().split())
'APHRASE'
>>> check_and_join('a phrase!'.upper().split(), 'ARE', filter=True)
'ARAE'
>>> check_and_join('a phrase!'.upper().split(), 'ARE')
Traceback (most recent call last):
...
ValueError: characters in phrase but not symbols: "!HPS"
sympy.crypto.crypto.cycle_list(k, n)[源代码][源代码]

返回列表 range(n) 向左移动 k 个位置的元素(因此列表从 k (mod n) 开始)。

示例

>>> from sympy.crypto.crypto import cycle_list
>>> cycle_list(3, 10)
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
sympy.crypto.crypto.encipher_shift(msg, key, symbols=None)[源代码][源代码]

对明文消息执行移位密码加密,并返回密文。

参数:
关键整数

密钥。

消息str

大写字母的纯文本。

返回:
str

大写字母的密文。

注释

算法:

步骤:
  1. 将字母表的字母从0编号,…,N

  2. 从字符串 msg 计算出对应的整数列表 L1

  3. 从列表 L1 计算出一个新列表 L2,通过将 (k mod 26) 加到 L1 中的每个元素上。

  4. 从列表 L2 计算出对应的字母字符串 ct

移位密码也被称为凯撒密码,以尤利乌斯·凯撒命名,据苏埃托尼乌斯所述,他使用移位量为三的密码来保护具有军事意义的讯息。凯撒的侄子奥古斯都据报道使用了类似的密码,但移位量为右移1。

参考文献

示例

>>> from sympy.crypto.crypto import encipher_shift, decipher_shift
>>> msg = "GONAVYBEATARMY"
>>> ct = encipher_shift(msg, 1); ct
'HPOBWZCFBUBSNZ'

要解密移位后的文本,请改变密钥的符号:

>>> encipher_shift(ct, -1)
'GONAVYBEATARMY'

还有一个便捷函数,可以使用原始键来完成此操作:

>>> decipher_shift(ct, 1)
'GONAVYBEATARMY'
sympy.crypto.crypto.decipher_shift(msg, key, symbols=None)[源代码][源代码]

通过将 msg 中的字符向左移动 key 给定的数量来返回文本。

示例

>>> from sympy.crypto.crypto import encipher_shift, decipher_shift
>>> msg = "GONAVYBEATARMY"
>>> ct = encipher_shift(msg, 1); ct
'HPOBWZCFBUBSNZ'

要解密移位后的文本,请改变密钥的符号:

>>> encipher_shift(ct, -1)
'GONAVYBEATARMY'

或者使用原始键调用此函数:

>>> decipher_shift(ct, 1)
'GONAVYBEATARMY'
sympy.crypto.crypto.encipher_rot13(msg, symbols=None)[源代码][源代码]

对给定的明文 msg 执行 ROT13 加密。

参考文献

sympy.crypto.crypto.decipher_rot13(msg, symbols=None)[源代码][源代码]

对给定的明文 msg 执行 ROT13 解密。

示例

>>> from sympy.crypto.crypto import encipher_rot13, decipher_rot13
>>> msg = 'GONAVYBEATARMY'
>>> ciphertext = encipher_rot13(msg);ciphertext
'TBANILORNGNEZL'
>>> decipher_rot13(ciphertext)
'GONAVYBEATARMY'
>>> encipher_rot13(msg) == decipher_rot13(msg)
True
>>> msg == decipher_rot13(ciphertext)
True
sympy.crypto.crypto.encipher_affine(
msg,
key,
symbols=None,
_inverse=False,
)[源代码][源代码]

对明文 msg 执行仿射密码加密,并返回密文。

参数:
消息str

出现在 symbols 中的字符。

a, bint, int

一对整数,满足 ``gcd(a, N) = 1``(即秘密密钥)。

符号

字符串(默认 = 大写字母)。

当没有给出符号时,msg 会被转换为大写字母,而所有其他字符都会被忽略。

返回:
ct

字符串(密文消息)

注释

算法:

步骤:
  1. 将字母表的字母从0编号,…,N

  2. 从字符串 msg 计算出对应的整数列表 L1

  3. 从列表 L1 计算一个新的列表 L2,通过将 L1 中的每个元素 x 替换为 a*x + b (mod N) 得到。

  4. 从列表 L2 计算出对应的字母字符串 ct

这是移位密码的一个直接推广,增加了需要解密2个字符才能恢复密钥的复杂性。

参考文献

sympy.crypto.crypto.decipher_affine(msg, key, symbols=None)[源代码][源代码]

返回通过映射 \(x ightarrow ax+b\) (mod \(N\)) 解密后的文本,其中 N 是字母表中的字符数。解密是通过使用新密钥重新加密完成的:\(x ightarrow cx+d\) (mod \(N\)),其中 \(c = a^{-1}\) (mod \(N\)) 和 \(d = -a^{-1}b\) (mod \(N\))。

示例

>>> from sympy.crypto.crypto import encipher_affine, decipher_affine
>>> msg = "GO NAVY BEAT ARMY"
>>> key = (3, 1)
>>> encipher_affine(msg, key)
'TROBMVENBGBALV'
>>> decipher_affine(_, key)
'GONAVYBEATARMY'
sympy.crypto.crypto.encipher_atbash(msg, symbols=None)[源代码][源代码]

将给定的 msg 加密为其 Atbash 密文并返回。

sympy.crypto.crypto.decipher_atbash(msg, symbols=None)[源代码][源代码]

使用Atbash密码解密给定的 msg 并返回结果。

参考文献

示例

>>> from sympy.crypto.crypto import encipher_atbash, decipher_atbash
>>> msg = 'GONAVYBEATARMY'
>>> encipher_atbash(msg)
'TLMZEBYVZGZINB'
>>> decipher_atbash(msg)
'TLMZEBYVZGZINB'
>>> encipher_atbash(msg) == decipher_atbash(msg)
True
>>> msg == encipher_atbash(encipher_atbash(msg))
True
sympy.crypto.crypto.encipher_substitution(msg, old, new=None)[源代码][源代码]

返回通过将 old 中出现的每个字符替换为 new 中相应字符而获得的密文。如果 old 是一个映射,那么 new 将被忽略,并使用 old 定义的替换。

参考文献

示例

>>> from sympy.crypto.crypto import encipher_substitution, AZ
>>> old = 'OEYAG'
>>> new = '034^6'
>>> msg = AZ("go navy! beat army!")
>>> ct = encipher_substitution(msg, old, new); ct
'60N^V4B3^T^RM4'

要解密一个替换,反转最后两个参数:

>>> encipher_substitution(ct, new, old)
'GONAVYBEATARMY'

oldnew 是顺序为2的排列(表示字符的转置)的特殊情况下,它们的顺序无关紧要:

>>> old = 'NAVY'
>>> new = 'ANYV'
>>> encipher = lambda x: encipher_substitution(x, old, new)
>>> encipher('NAVY')
'ANYV'
>>> encipher(_)
'NAVY'

替换密码,一般来说,是一种方法,其中明文的“单位”(不一定是单个字符)根据一个规则系统被替换为密文。

>>> ords = dict(zip('abc', ['\\%i' % ord(i) for i in 'abc']))
>>> print(encipher_substitution('abc', ords))
\97\98\99
sympy.crypto.crypto.encipher_vigenere(msg, key, symbols=None)[源代码][源代码]

对明文 msg 执行 Vigenere 密码加密,并返回密文。

参考文献

示例

>>> from sympy.crypto.crypto import encipher_vigenere, AZ
>>> key = "encrypt"
>>> msg = "meet me on monday"
>>> encipher_vigenere(msg, key)
'QRGKKTHRZQEBPR'

中央情报局总部Kryptos雕塑的第一部分使用了这种密码,并且还改变了字母的顺序 [2]。以下是该部分雕塑的第一行:

>>> from sympy.crypto.crypto import decipher_vigenere, padded_key
>>> alp = padded_key('KRYPTOS', AZ())
>>> key = 'PALIMPSEST'
>>> msg = 'EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJ'
>>> decipher_vigenere(msg, key, alp)
'BETWEENSUBTLESHADINGANDTHEABSENC'
sympy.crypto.crypto.decipher_vigenere(msg, key, symbols=None)[源代码][源代码]

使用维吉尼亚密码进行解码。

示例

>>> from sympy.crypto.crypto import decipher_vigenere
>>> key = "encrypt"
>>> ct = "QRGK kt HRZQE BPR"
>>> decipher_vigenere(ct, key)
'MEETMEONMONDAY'
sympy.crypto.crypto.encipher_hill(msg, key, symbols=None, pad='Q')[源代码][源代码]

返回 msg 的希尔密码加密结果。

参数:
消息

包含 \(n\) 个大写字母的纯文本消息。

关键

一个 \(k imes k\) 的可逆矩阵 \(K\),其所有元素都在 \(Z_{26}\) 中(或任何使用的符号数量)。

填充

用于使文本长度成为 k 的倍数的字符(默认 “Q”)。

返回:
ct

大写字母的密文。

参见

decipher_hill

注释

算法:

步骤:
  1. 将字母表的字母从0编号,…,N

  2. 从字符串 msg 计算出对应的整数列表 L 。设 n = len(L)

  3. 将列表 L 分解为 t = ceiling(n/k) 个子列表 L_1, …, L_t,每个子列表的大小为 k``(最后一个列表会被“填充”以确保其大小为 ``k)。

  4. 计算新列表 C_1, …, C_t,由 C[i] = K*L_i 给出(算术运算在模 N 下进行),对于每个 i

  5. 将这些连接成一个列表 C = C_1 + ... + C_t

  6. C 计算出相应字母的字符串 ct 。其长度为 k*t

参考文献

[2]

Lester S. Hill, 代数字母表中的密码学, 美国数学月刊 第36卷, 1929年6月-7月, 第306-312页。

sympy.crypto.crypto.decipher_hill(msg, key, symbols=None)[源代码][源代码]

解密与加密相同,但使用密钥矩阵的逆矩阵。

参见

encipher_hill

示例

>>> from sympy.crypto.crypto import encipher_hill, decipher_hill
>>> from sympy import Matrix
>>> key = Matrix([[1, 2], [3, 5]])
>>> encipher_hill("meet me on monday", key)
'UEQDUEODOCTCWQ'
>>> decipher_hill(_, key)
'MEETMEONMONDAY'

当明文的长度(去除无效字符后)不是密钥维度的倍数时,加密和解密后的文本末尾会出现额外的字符。为了解密文本,这些字符必须包含在待解密的文本中。在下文中,密钥的维度为4,但文本比4的倍数少了2个字符,因此将添加两个字符。

>>> key = Matrix([[1, 1, 1, 2], [0, 1, 1, 0],
...               [2, 2, 3, 4], [1, 1, 0, 1]])
>>> msg = "ST"
>>> encipher_hill(msg, key)
'HJEB'
>>> decipher_hill(_, key)
'STQQ'
>>> encipher_hill(msg, key, pad="Z")
'ISPK'
>>> decipher_hill(_, key)
'STZZ'

如果在任何情况下都忽略密文的最后两个字符,将会恢复错误的明文:

>>> decipher_hill("HD", key)
'ORMV'
>>> decipher_hill("IS", key)
'UIKY'
sympy.crypto.crypto.encipher_bifid(msg, key, symbols=None)[源代码][源代码]

对明文 msg 执行 Bifid 密码加密,并返回密文。

这是使用 \(n imes n\) 波利比乌斯方格的二分密码版本。

参数:
消息

纯文本字符串。

关键

短字符串作为键。

重复的字符将被忽略,然后用不在短键中的 symbols 中的字符进行填充。

符号

定义字母表的 \(n imes n\) 个字符。

(默认是 string.printable)

返回:
密文

使用无空格的 Bifid5 密码的密文。

参考文献

[1]

https://en.wikipedia.org/wiki/双字母加密法

sympy.crypto.crypto.decipher_bifid(msg, key, symbols=None)[源代码][源代码]

对密文 msg 执行 Bifid 密码解密,并返回明文。

这是使用 \(n imes n\) 波利比乌斯方阵的二分密码版本。

参数:
消息

密文字符串。

关键

短字符串作为键。

重复的字符将被忽略,然后用短键中不存在的符号字符进行填充。

符号

定义字母表的 \(n imes n\) 个字符。

(默认=string.printable,一个 \(10 imes 10\) 矩阵)

返回:
解密

解密文本。

示例

>>> from sympy.crypto.crypto import (
...     encipher_bifid, decipher_bifid, AZ)

使用 bifid5 字母表进行加密:

>>> alp = AZ().replace('J', '')
>>> ct = AZ("meet me on monday!")
>>> key = AZ("gold bug")
>>> encipher_bifid(ct, key, alp)
'IEILHHFSTSFQYE'

在输入明文或密文时,空格会被忽略,因此可以按所需格式化。从前面重新输入密文,每行4个字符并用额外的J填充,不会对解密造成问题:

>>> decipher_bifid('''
... IEILH
... HFSTS
... FQYEJ''', key, alp)
'MEETMEONMONDAY'

当未指定字母表时,将使用所有100个可打印字符:

>>> key = ''
>>> encipher_bifid('hello world!', key)
'bmtwmg-bIo*w'
>>> decipher_bifid(_, key)
'hello world!'

如果密钥被更改,将得到不同的加密:

>>> key = 'gold bug'
>>> encipher_bifid('hello world!', 'gold_bug')
'hg2sfuei7t}w'

如果用于解密消息的密钥不准确,将无法完美地获取原始文本:

>>> decipher_bifid(_, 'gold pug')
'heldo~wor6d!'
sympy.crypto.crypto.bifid5_square(key=None)[源代码][源代码]

5x5 波利比乌斯方阵。

生成 \(5 imes 5\) 双密码的波利比乌斯方阵。

示例

>>> from sympy.crypto.crypto import bifid5_square
>>> bifid5_square("gold bug")
Matrix([
[G, O, L, D, B],
[U, A, C, E, F],
[H, I, K, M, N],
[P, Q, R, S, T],
[V, W, X, Y, Z]])
sympy.crypto.crypto.encipher_bifid5(msg, key)[源代码][源代码]

对明文 msg 执行 Bifid 密码加密,并返回密文。

参数:
消息str

纯文本字符串。

转换为大写并过滤掉除J以外的所有字母。

关键

短字符串用于键;非字母字符、J 和重复字符被忽略,然后,如果长度小于 25 个字符,则用字母表中的其他字母(按字母顺序)填充。

返回:
ct

密文(全大写,无空格)。

注释

双密码大约在1901年由费利克斯·德拉斯特尔发明。它是一种*分段替换*密码,其中字母被一个小字母表中的符号对替换。该密码使用一个`5 imes 5`的方阵,其中填充了字母的某种顺序,除了“J”被替换为“I”(这是一个所谓的波利比乌斯方阵;如果你重新加入“J”并将数字0, 1, …, 9附加到通常的26个字母字母表中,则有一个`6 imes 6`的类似方阵)。根据海伦·盖恩斯的《密码分析》一书,这种类型的密码在第一次世界大战期间被德国陆军在战场上使用。

示例

>>> from sympy.crypto.crypto import (
...     encipher_bifid5, decipher_bifid5)

除非用其他内容替换,否则“J”将被省略:

>>> round_trip = lambda m, k: \
...     decipher_bifid5(encipher_bifid5(m, k), k)
>>> key = 'a'
>>> msg = "JOSIE"
>>> round_trip(msg, key)
'OSIE'
>>> round_trip(msg.replace("J", "I"), key)
'IOSIE'
>>> j = "QIQ"
>>> round_trip(msg.replace("J", j), key).replace(j, "J")
'JOSIE'
sympy.crypto.crypto.decipher_bifid5(msg, key)[源代码][源代码]

返回 msg 的 Bifid 密码解密结果。

参数:
消息

密文字符串。

关键

短字符串作为键;重复的字符被忽略,如果长度小于25个字符,则将用字母表中的其他字母填充,省略“J”。非字母字符被忽略。

返回:
plaintext

来自Bifid5密码的纯文本(全大写,无空格)。

示例

>>> from sympy.crypto.crypto import encipher_bifid5, decipher_bifid5
>>> key = "gold bug"
>>> encipher_bifid5('meet me on friday', key)
'IEILEHFSTSFXEE'
>>> encipher_bifid5('meet me on monday', key)
'IEILHHFSTSFQYE'
>>> decipher_bifid5(_, key)
'MEETMEONMONDAY'
sympy.crypto.crypto.encipher_bifid6(msg, key)[源代码][源代码]

对明文 msg 执行 Bifid 密码加密,并返回密文。

这是使用 \(6 imes 6\) 波利比乌斯方阵的二分密码版本。

参数:
消息

纯文本字符串(数字可以)。

关键

短字符串作为键(数字也可以)。

如果 key 的长度小于36个字符,方块将被填充字母A到Z和数字0到9。

返回:
密文

来自Bifid密码的密文(全大写,无空格)。

sympy.crypto.crypto.decipher_bifid6(msg, key)[源代码][源代码]

对密文 msg 执行 Bifid 密码解密,并返回明文。

这是使用 \(6 imes 6\) 波利比乌斯方阵的二分密码版本。

参数:
消息

密文字符串(数字可以);转换为大写

关键

短字符串作为键(数字也可以)。

如果 key 的长度小于36个字符,方块将被字母A到Z和数字0到9填充。所有字母都将转换为大写。

返回:
plaintext

来自Bifid密码的纯文本(全大写,无空格)。

示例

>>> from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6
>>> key = "gold bug"
>>> encipher_bifid6('meet me on monday at 8am', key)
'KFKLJJHF5MMMKTFRGPL'
>>> decipher_bifid6(_, key)
'MEETMEONMONDAYAT8AM'
sympy.crypto.crypto.bifid6_square(key=None)[源代码][源代码]

6x6 波利比乌斯方阵。

生成 \(6 imes 6\) 双面密码的波利比乌斯方阵。假设符号字母表为 “A”, …, “Z”, “0”, …, “9”。

示例

>>> from sympy.crypto.crypto import bifid6_square
>>> key = "gold bug"
>>> bifid6_square(key)
Matrix([
[G, O, L, D, B, U],
[A, C, E, F, H, I],
[J, K, M, N, P, Q],
[R, S, T, V, W, X],
[Y, Z, 0, 1, 2, 3],
[4, 5, 6, 7, 8, 9]])
sympy.crypto.crypto.rsa_public_key(*args, **kwargs)[源代码][源代码]

返回 RSA 公钥 对,\((n, e)\)

参数:
参数自然数

如果指定为 \(p, q, e\),其中 \(p\)\(q\) 是不同的质数,\(e\) 是所需的 RSA 公钥指数,则 \(n = p q\)\(e\) 将根据总和 \(\phi(n)`(欧拉总和)或 `\lambda(n)`(卡迈克尔总和)进行验证,以确保 `\gcd(e, \phi(n)) = 1\)\(\gcd(e, \lambda(n)) = 1\)

如果指定为 \(p_1, p_2, \dots, p_n, e\),其中 \(p_1, p_2, \dots, p_n\) 被指定为素数,\(e\) 被指定为 RSA 的期望公钥指数,它将能够形成一个多素数 RSA,这是流行的 2 素数 RSA 的更一般化的形式。

也可以通过将参数指定为 \(p, e\) 来形成一个单素数RSA,这可以被视为多素数RSA的一个特例。

此外,通过指定两对或更多对相同的素数,可以形成一个多权重的RSA。然而,与两不同素数RSA或多素数RSA不同,并非完整剩余系统(\(\mathbb{Z}_n\))中的每个数都能被解密,因为映射 \(\mathbb{Z}_{n} \rightarrow \mathbb{Z}_{n}\) 不是双射的。(除非在平凡情况下,即 \(e = 1\) 或更一般地,

\[e \in \left \{ 1 + k \lambda(n) \mid k \in \mathbb{Z} \land k \geq 0 \right \}\]

当RSA简化为单位元时。)然而,对于简化剩余系中的数(\(\mathbb{Z}_n^{\times}\)),RSA仍然可以解密,因为映射 \(\mathbb{Z}_{n}^{\times} \rightarrow \mathbb{Z}_{n}^{\times}\) 仍然可以是双射的。

如果你将一个非质数整数传递给参数 \(p_1, p_2, \dots, p_n\),这个特定的数字将被质因数分解,并且它将根据乘积是否等于其根号,变成其规范形式下的多质数RSA或多幂RSA。\(p_1 p_2 \dots p_n = \text{rad}(p_1 p_2 \dots p_n)\)

欧拉函数bool, 可选

如果 'Euler',它使用欧拉的 totient \(\phi(n)\),即 SymPy 中的 sympy.functions.combinatorial.numbers.totient()

如果 'Carmichael',它使用卡迈克尔函数 \(\lambda(n)\),即 SymPy 中的 sympy.functions.combinatorial.numbers.reduced_totient()

与私钥生成不同,这是公钥生成的一个微不足道的关键词,因为 \(\gcd(e, \phi(n)) = 1 \iff \gcd(e, \lambda(n)) = 1\)

索引非负整数,可选

返回在索引 \(0, 1, 2, \dots\) 处指定的 RSA 公钥的任意解。此参数需要与 totient='Carmichael' 一起指定。

类似于在 rsa_private_key()index 参数文档中描述的 RSA 私钥的非唯一性,RSA 公钥也不是唯一的,并且有无限数量的 RSA 公钥指数可以表现出相同的行为。

从任意给定的RSA公钥指数`e`,可以有另一个RSA公钥指数`e + k lambda(n)`,其中`k`是整数,`lambda`是卡迈克尔函数。

然而,仅考虑正数情况,RSA公钥指数 \(e_0\)\(0 < e_0 < \lambda(n)\) 范围内可以有一个主解,其他所有解都可以规范化为 \(e_0 + k \lambda(n)\) 的形式。

index 指定了 \(k\) 表示法,以生成RSA公钥可能具有的任何可能值。

计算任意RSA公钥的示例:

>>> from sympy.crypto.crypto import rsa_public_key
>>> rsa_public_key(61, 53, 17, totient='Carmichael', index=0)
(3233, 17)
>>> rsa_public_key(61, 53, 17, totient='Carmichael', index=1)
(3233, 797)
>>> rsa_public_key(61, 53, 17, totient='Carmichael', index=2)
(3233, 1577)
multipowerbool, 可选

在RSA规范中发现的任何一对非不同的素数都将限制密码系统的域,如参数 args 的解释中所述。

SymPy RSA 密钥生成器在将其作为多幂 RSA 分发之前可能会发出警告,但是,如果您将 True 传递给此关键字,则可以禁用警告。

返回:
(n, e)int, int

\(n\) 是作为参数给出的任意数量的素数的乘积。

\(e\) 与欧拉总计函数 \(\phi(n)\) 互质(互素)。

如果给定的参数少于两个,或者 \(e\) 与模数不是互质的,则返回。

注释

尽管RSA可以在任何模数 \(n\) 上进行推广,但使用两个大素数已经成为最流行的规范,因为两个大素数的乘积通常是相对于 \(n\) 的位数来说最难分解的。

然而,要验证这一说法,可能需要进一步理解每种质因数分解算法的时间复杂度。

参考文献

示例

>>> from sympy.crypto.crypto import rsa_public_key

一个两素数的RSA公钥:

>>> p, q, e = 3, 5, 7
>>> rsa_public_key(p, q, e)
(15, 7)
>>> rsa_public_key(p, q, 30)
False

多素数RSA的公钥:

>>> primes = [2, 3, 5, 7, 11, 13]
>>> e = 7
>>> args = primes + [e]
>>> rsa_public_key(*args)
(30030, 7)
sympy.crypto.crypto.rsa_private_key(*args, **kwargs)[源代码][源代码]

返回RSA的*私钥*对,\((n, d)\)

参数:
参数自然数

该关键字与 rsa_public_key() 中的 args 相同。

欧拉函数bool, 可选

如果为 'Euler',则使用欧拉的互质函数约定 \(\phi(n)\),该函数在 SymPy 中为 sympy.functions.combinatorial.numbers.totient()

如果 'Carmichael',它使用 Carmichael 的 totient 惯例 \(\lambda(n)\),这在 SymPy 中是 sympy.functions.combinatorial.numbers.reduced_totient()

私钥生成的输出可能会有一些差异,如下例所示。

使用欧拉函数的示例:

>>> from sympy.crypto.crypto import rsa_private_key
>>> rsa_private_key(61, 53, 17, totient='Euler')
(3233, 2753)

使用 Carmichael 的 totient 的示例:

>>> from sympy.crypto.crypto import rsa_private_key
>>> rsa_private_key(61, 53, 17, totient='Carmichael')
(3233, 413)
索引非负整数,可选

返回在索引 \(0, 1, 2, \dots\) 指定的 RSA 私钥的任意解。此参数需要与 totient='Carmichael' 一起指定。

RSA私钥指数是方程 \(e d \mod \lambda(n) = 1\) 的非唯一解,它可以表示为 \(d + k \lambda(n)\) 的任意形式,其中 \(d\) 是另一个已计算的私钥指数,\(\lambda\) 是卡迈克尔函数,\(k\) 是任意整数。

然而,仅考虑正数情况,RSA私钥指数`d_0`在`0 < d_0 < lambda(n)`范围内可以有一个主解,其他所有解都可以规范化为`d_0 + k lambda(n)`的形式。

index 指定 \(k\) 表示法以生成 RSA 私钥可能具有的任何值。

计算任意RSA私钥的示例:

>>> from sympy.crypto.crypto import rsa_private_key
>>> rsa_private_key(61, 53, 17, totient='Carmichael', index=0)
(3233, 413)
>>> rsa_private_key(61, 53, 17, totient='Carmichael', index=1)
(3233, 1193)
>>> rsa_private_key(61, 53, 17, totient='Carmichael', index=2)
(3233, 1973)
multipowerbool, 可选

该关键字与 rsa_public_key() 中的 multipower 相同。

返回:
(n, d)int, int

\(n\) 是作为参数给出的任意数量的素数的乘积。

\(d\)\(e\) 的逆元(模 \(\phi(n)\)),其中 \(e\) 是给定的指数,而 \(\phi\) 是欧拉函数。

如果给定的参数少于两个,或者 \(e\) 与模数的欧拉函数不是互质的,则返回。

参考文献

示例

>>> from sympy.crypto.crypto import rsa_private_key

一个两素数RSA的私钥:

>>> p, q, e = 3, 5, 7
>>> rsa_private_key(p, q, e)
(15, 7)
>>> rsa_private_key(p, q, 30)
False

多素数RSA的私钥:

>>> primes = [2, 3, 5, 7, 11, 13]
>>> e = 7
>>> args = primes + [e]
>>> rsa_private_key(*args)
(30030, 823)
sympy.crypto.crypto.encipher_rsa(i, key, factors=None)[源代码][源代码]

使用RSA加密明文。

参数:
i整数

要加密的纯文本。

关键(n, e) 其中 n, e 是整数

\(n\) 是密钥的模数,\(e\) 是密钥的指数。加密是通过 \(i^e \bmod n\) 计算的。

密钥可以是公钥或私钥,然而,用公钥加密的消息只能用私钥解密,反之亦然,因为RSA是一种非对称加密系统。

因素互质整数列表

这与 decipher_rsa() 中的关键字 factors 相同。

注释

某些规范可能会使RSA失去密码学上的意义。

例如,\(0\)\(1\) 在经过任意次数的幂运算后将始终保持不变,因此应避免使用。

此外,如果 \(i^e < n\),可以通过取 \(e\) 次根来轻松计算出 \(i\)

并且,将指数指定为 \(1\) 或更一般的形式 \(1 + k \lambda(n)\),其中 \(k\) 是非负整数,\(\lambda\) 是卡迈克尔函数,RSA 就变成了恒等映射。

示例

>>> from sympy.crypto.crypto import encipher_rsa
>>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key

公钥加密:

>>> p, q, e = 3, 5, 7
>>> puk = rsa_public_key(p, q, e)
>>> msg = 12
>>> encipher_rsa(msg, puk)
3

私钥加密:

>>> p, q, e = 3, 5, 7
>>> prk = rsa_private_key(p, q, e)
>>> msg = 12
>>> encipher_rsa(msg, prk)
3

使用中国剩余定理进行加密:

>>> encipher_rsa(msg, prk, factors=[p, q])
3
sympy.crypto.crypto.decipher_rsa(i, key, factors=None)[源代码][源代码]

使用RSA解密密文。

参数:
i整数

要解密的密文。

关键(n, d) 其中 n, d 是整数

\(n\) 是密钥的模数,\(d\) 是密钥的指数。解密是通过 \(i^d \bmod n\) 计算的。

密钥可以是公钥或私钥,然而,用公钥加密的消息只能用私钥解密,反之亦然,因为RSA是一种非对称加密系统。

因素互质整数列表

由于RSA密钥生成中创建的模数`n`由任意素因子组成,即`n = {p_1}^{k_1}{p_2}^{k_2}dots{p_n}^{k_n}`,其中`p_1, p_2, dots, p_n`是不同的素数,\(k_1, k_2, \dots, k_n`是正整数,可以使用中国剩余定理从碎片化的模运算中计算`i^d \bmod n\)

\[i^d \bmod {p_1}^{k_1}, i^d \bmod {p_2}^{k_2}, \dots, i^d \bmod {p_n}^{k_n}\]

或像

\[i^d \bmod {p_1}^{k_1}{p_2}^{k_2}, i^d \bmod {p_3}^{k_3}, \dots , i^d \bmod {p_n}^{k_n}\]

只要每个模数之间没有共同的除数。

在生成RSA密钥对时使用的原始质数可以是一个不错的选择。

请注意,使用这种方法的速度优势仅适用于非常大的情况(例如2048位RSA密钥),因为使用纯Python实现的 sympy.ntheory.modular.crt() 的开销可能会抵消理论上的速度优势。

参见

encipher_rsa

注释

请参阅 encipher_rsa() 文档中的 Notes 部分

示例

>>> from sympy.crypto.crypto import decipher_rsa, encipher_rsa
>>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key

公钥加密与解密:

>>> p, q, e = 3, 5, 7
>>> prk = rsa_private_key(p, q, e)
>>> puk = rsa_public_key(p, q, e)
>>> msg = 12
>>> new_msg = encipher_rsa(msg, prk)
>>> new_msg
3
>>> decipher_rsa(new_msg, puk)
12

私钥加密与解密:

>>> p, q, e = 3, 5, 7
>>> prk = rsa_private_key(p, q, e)
>>> puk = rsa_public_key(p, q, e)
>>> msg = 12
>>> new_msg = encipher_rsa(msg, puk)
>>> new_msg
3
>>> decipher_rsa(new_msg, prk)
12

使用中国剩余定理进行解密:

>>> decipher_rsa(new_msg, prk, factors=[p, q])
12
sympy.crypto.crypto.kid_rsa_public_key(a, b, A, B)[源代码][源代码]

Kid RSA 是 RSA 的一个版本,适用于教小学生,因为它不涉及指数运算。

示例

>>> from sympy.crypto.crypto import kid_rsa_public_key
>>> a, b, A, B = 3, 4, 5, 6
>>> kid_rsa_public_key(a, b, A, B)
(369, 58)
sympy.crypto.crypto.kid_rsa_private_key(a, b, A, B)[源代码][源代码]

计算 \(M = a b - 1\), \(e = A M + a\), \(d = B M + b\), \(n = (e d - 1) / M\)私钥\(d\),鲍勃将其保密。

示例

>>> from sympy.crypto.crypto import kid_rsa_private_key
>>> a, b, A, B = 3, 4, 5, 6
>>> kid_rsa_private_key(a, b, A, B)
(369, 70)
sympy.crypto.crypto.encipher_kid_rsa(msg, key)[源代码][源代码]

这里 msg 是明文,而 key 是公钥。

示例

>>> from sympy.crypto.crypto import (
...     encipher_kid_rsa, kid_rsa_public_key)
>>> msg = 200
>>> a, b, A, B = 3, 4, 5, 6
>>> key = kid_rsa_public_key(a, b, A, B)
>>> encipher_kid_rsa(msg, key)
161
sympy.crypto.crypto.decipher_kid_rsa(msg, key)[源代码][源代码]

这里 msg 是明文,而 key 是私钥。

示例

>>> from sympy.crypto.crypto import (
...     kid_rsa_public_key, kid_rsa_private_key,
...     decipher_kid_rsa, encipher_kid_rsa)
>>> a, b, A, B = 3, 4, 5, 6
>>> d = kid_rsa_private_key(a, b, A, B)
>>> msg = 200
>>> pub = kid_rsa_public_key(a, b, A, B)
>>> pri = kid_rsa_private_key(a, b, A, B)
>>> ct = encipher_kid_rsa(msg, pub)
>>> decipher_kid_rsa(ct, pri)
200
sympy.crypto.crypto.encode_morse(msg, sep='|', mapping=None)[源代码][源代码]

将明文编码为流行的摩尔斯电码,字母之间用 sep 分隔,单词之间用双 sep 分隔。

参考文献

示例

>>> from sympy.crypto.crypto import encode_morse
>>> msg = 'ATTACK RIGHT FLANK'
>>> encode_morse(msg)
'.-|-|-|.-|-.-.|-.-||.-.|..|--.|....|-||..-.|.-..|.-|-.|-.-'
sympy.crypto.crypto.decode_morse(msg, sep='|', mapping=None)[源代码][源代码]

将摩尔斯电码解码为明文,字母之间用 sep 分隔(默认是 ‘|’),单词之间用 \(word_sep\) 分隔(默认是 ‘||’)。

参考文献

示例

>>> from sympy.crypto.crypto import decode_morse
>>> mc = '--|---|...-|.||.|.-|...|-'
>>> decode_morse(mc)
'MOVE EAST'
sympy.crypto.crypto.lfsr_sequence(key, fill, n)[源代码][源代码]

此函数创建一个LFSR序列。

参数:
关键列表

有限域元素列表,\([c_0, c_1, \ldots, c_k]\)

填充列表

LFSR序列的初始项列表,\([x_0, x_1, \ldots, x_k].\)

n

函数返回的序列项数。

返回:
L

\(x_{n+1} = c_k x_n + \ldots + c_0 x_{n-k}\) 定义的 LFSR 序列,其中 \(n \leq k\)

注释

S. Golomb [G] gives a list of three statistical properties a sequence of numbers \(a = \{a_n\}_{n=1}^\infty\), \(a_n \in \{0,1\}\), should display to be considered “random”. Define the autocorrelation of \(a\) to be

\[C(k) = C(k,a) = \lim_{N\rightarrow \infty} {1\over N}\sum_{n=1}^N (-1)^{a_n + a_{n+k}}.\]

\(a\) 是周期为 \(P\) 的情况下,这简化为

\[C(k) = {1\over P}\sum_{n=1}^P (-1)^{a_n + a_{n+k}}.\]

假设 \(a\) 是周期为 \(P\) 的周期函数。

  • 平衡:

    \[\left|\sum_{n=1}^P(-1)^{a_n}\right| \leq 1.\]
  • 低自相关:

    \[\begin{split}C(k) = \left\{ \begin{array}{cc} 1,& k = 0,\\ \epsilon, & k \ne 0. \end{array} \right.\end{split}\]

    (对于满足前两个性质的序列,已知 \(\epsilon = -1/P\) 必须成立。)

  • 比例运行特性:在每个周期中,一半的运行长度为 \(1\),四分之一的运行长度为 \(2\),依此类推。此外,\(1\) 的运行次数与 \(0\) 的运行次数相同。

参考文献

[G]

Solomon Golomb,《移位寄存器序列》,Aegean Park Press,Laguna Hills,Ca,1967

示例

>>> from sympy.crypto.crypto import lfsr_sequence
>>> from sympy.polys.domains import FF
>>> F = FF(2)
>>> fill = [F(1), F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(0), F(1)]
>>> lfsr_sequence(key, fill, 10)
[1 mod 2, 1 mod 2, 0 mod 2, 1 mod 2, 0 mod 2,
1 mod 2, 1 mod 2, 0 mod 2, 0 mod 2, 1 mod 2]
sympy.crypto.crypto.lfsr_autocorrelation(L, P, k)[源代码][源代码]

此函数计算 LFSR 自相关函数。

参数:
L

一个 \(GF(2)\) 元素的周期序列。L 的长度必须大于 P。

P

The period of L.

k整数

一个整数 \(k\) (\(0 < k < P\))。

返回:
自相关

LFSR L 的自相关函数的第 k 个值。

示例

>>> from sympy.crypto.crypto import (
...     lfsr_sequence, lfsr_autocorrelation)
>>> from sympy.polys.domains import FF
>>> F = FF(2)
>>> fill = [F(1), F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_autocorrelation(s, 15, 7)
-1/15
>>> lfsr_autocorrelation(s, 15, 0)
1
sympy.crypto.crypto.lfsr_connection_polynomial(s)[源代码][源代码]

此函数计算LFSR连接多项式。

参数:
s

一个元素长度为偶数的序列,其条目在有限域中。

返回:
C(x)

产生 s 的最小 LFSR 的连接多项式。

这实现了J. L. Massey的文章[R517fc2db3840-M]_中第3节的算法。

参考文献

[M]

James L. Massey, “移位寄存器综合与BCH解码。” IEEE信息论汇刊,第15卷(第1期),第122-127页,1969年1月。

示例

>>> from sympy.crypto.crypto import (
...     lfsr_sequence, lfsr_connection_polynomial)
>>> from sympy.polys.domains import FF
>>> F = FF(2)
>>> fill = [F(1), F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**4 + x + 1
>>> fill = [F(1), F(0), F(0), F(1)]
>>> key = [F(1), F(1), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**3 + 1
>>> fill = [F(1), F(0), F(1)]
>>> key = [F(1), F(1), F(0)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**3 + x**2 + 1
>>> fill = [F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**3 + x + 1
sympy.crypto.crypto.elgamal_public_key(key)[源代码][源代码]

返回三个数字元组作为公钥。

参数:
关键(p, r, e)

elgamal_private_key 生成的元组。

返回:
元组(p, r, e)

\(e = r**d \bmod p\)

\(d\) 是私钥中的一个随机数。

示例

>>> from sympy.crypto.crypto import elgamal_public_key
>>> elgamal_public_key((1031, 14, 636))
(1031, 14, 212)
sympy.crypto.crypto.elgamal_private_key(digit=10, seed=None)[源代码][源代码]

返回一个包含三个数字的元组作为私钥。

参数:
数字整数

密钥所需的最小二进制位数。

返回:
元组(p, r, d)

p = 质数。

r = 原根。

d = 随机数。

注释

出于测试目的,可以将 seed 参数设置为控制此例程的输出。参见 sympy.core.random._randrange。

示例

>>> from sympy.crypto.crypto import elgamal_private_key
>>> from sympy.ntheory import is_primitive_root, isprime
>>> a, b, _ = elgamal_private_key()
>>> isprime(a)
True
>>> is_primitive_root(b, a)
True
sympy.crypto.crypto.encipher_elgamal(i, key, seed=None)[源代码][源代码]

使用公钥加密消息。

参数:
消息

编码消息的整数。

关键

公钥。

返回:
元组(c1, c2)

编码成两个数字。

注释

出于测试目的,可以将 seed 参数设置为控制此例程的输出。参见 sympy.core.random._randrange。

示例

>>> from sympy.crypto.crypto import encipher_elgamal, elgamal_private_key, elgamal_public_key
>>> pri = elgamal_private_key(5, seed=[3]); pri
(37, 2, 3)
>>> pub = elgamal_public_key(pri); pub
(37, 2, 8)
>>> msg = 36
>>> encipher_elgamal(msg, pub, seed=[3])
(8, 6)
sympy.crypto.crypto.decipher_elgamal(msg, key)[源代码][源代码]

使用私钥解密消息。

\(msg = (c_{1}, c_{2})\)

\(key = (p, r, d)\)

根据扩展欧几里得定理,\(u c_{1}^{d} + p n = 1\)

\(u \equiv 1/{{c_{1}}^d} \pmod p\)

\(u c_{2} \equiv \frac{1}{c_{1}^d} c_{2} \equiv \frac{1}{r^{ad}} c_{2} \pmod p\)

\(\frac{1}{r^{ad}} m e^a \equiv \frac{1}{r^{ad}} m {r^{d a}} \equiv m \pmod p\)

示例

>>> from sympy.crypto.crypto import decipher_elgamal
>>> from sympy.crypto.crypto import encipher_elgamal
>>> from sympy.crypto.crypto import elgamal_private_key
>>> from sympy.crypto.crypto import elgamal_public_key
>>> pri = elgamal_private_key(5, seed=[3])
>>> pub = elgamal_public_key(pri); pub
(37, 2, 8)
>>> msg = 17
>>> decipher_elgamal(encipher_elgamal(msg, pub), pri) == msg
True
sympy.crypto.crypto.dh_public_key(key)[源代码][源代码]

返回三个数字元组作为公钥。

这是爱丽丝发送给鲍勃的元组。

参数:
关键(p, g, a)

dh_private_key 生成的元组。

返回:
元组整数, 整数, 整数

一个包含 \((p, g, g^a \mod p)\) 的元组,其中 \(p\)\(g\)\(a\) 作为参数给出。

示例

>>> from sympy.crypto.crypto import dh_private_key, dh_public_key
>>> p, g, a = dh_private_key();
>>> _p, _g, x = dh_public_key((p, g, a))
>>> p == _p and g == _g
True
>>> x == pow(g, a, p)
True
sympy.crypto.crypto.dh_private_key(digit=10, seed=None)[源代码][源代码]

返回一个包含三个整数的元组作为私钥。

参数:
数字

密钥中所需的最小二进制位数。

返回:
元组(p, g, a)

p = 质数。

g = p 的原根。

a = 从2到p-1之间的随机数。

注释

出于测试目的,可以将 seed 参数设置为控制此例程的输出。参见 sympy.core.random._randrange。

示例

>>> from sympy.crypto.crypto import dh_private_key
>>> from sympy.ntheory import isprime, is_primitive_root
>>> p, g, _ = dh_private_key()
>>> isprime(p)
True
>>> is_primitive_root(g, p)
True
>>> p, g, _ = dh_private_key(5)
>>> isprime(p)
True
>>> is_primitive_root(g, p)
True
sympy.crypto.crypto.dh_shared_key(key, b)[源代码][源代码]

返回一个整数,该整数是共享密钥。

这是Bob和Alice都可以使用他们从对方那里收到的公钥和他们的私钥计算出来的内容。

参数:
关键(p, g, x)

dh_public_key 生成的元组 \((p, g, x)\)

b

范围在 \(2\)\(p - 1\) 之间的随机数(由第二次密钥交换的成员(Bob)选择)。

返回:
整数

一个共享密钥。

示例

>>> from sympy.crypto.crypto import (
...     dh_private_key, dh_public_key, dh_shared_key)
>>> prk = dh_private_key();
>>> p, g, x = dh_public_key(prk);
>>> sk = dh_shared_key((p, g, x), 1000)
>>> sk == pow(x, 1000, p)
True
sympy.crypto.crypto.gm_public_key(p, q, a=None, seed=None)[源代码][源代码]

pq 计算公钥。注意在 Goldwasser-Micali 加密中,公钥是随机选择的。

参数:
p, q, a整数, 整数, 整数

初始化变量。

返回:
元组(a, N)

a 是输入 a 如果它不是 None 否则是与 pq 互质的随机整数。

Npq 的乘积。

sympy.crypto.crypto.gm_private_key(p, q, a=None)[源代码][源代码]

检查 pq 是否可以用作 Goldwasser-Micali 加密的私钥。该方法大致如下工作。

参数:
p, q, a

初始化变量。

返回:
元组(p, q)

输入值 pq

Raises:
ValueError

如果 pq 不是不同的奇素数。

sympy.crypto.crypto.encipher_gm(i, key, seed=None)[源代码][源代码]

使用公钥 ‘key’ 加密整数 ‘i’ 注意 gm 使用随机加密。

参数:
i整数

要加密的消息。

关键(a, N)

公钥。

返回:
列表整数列表

随机加密的消息。

sympy.crypto.crypto.decipher_gm(message, key)[源代码][源代码]

使用公钥 ‘key’ 解密消息 ‘message’。

参数:
消息整数列表

随机加密的消息。

关键(p, q)

私钥。

返回:
整数

加密的消息。

sympy.crypto.crypto.encipher_railfence(message, rails)[源代码][源代码]

对明文执行栅栏加密并返回密文

参数:
消息string, 要加密的消息。
railsint, 轨道数量。
返回:
加密的字符串消息。

参考文献

示例

>>> from sympy.crypto.crypto import encipher_railfence
>>> message = "hello world"
>>> encipher_railfence(message,3)
'horel ollwd'
sympy.crypto.crypto.decipher_railfence(ciphertext, rails)[源代码][源代码]

使用给定的栅栏解密消息

参数:
消息string, 要加密的消息。
railsint, 轨道数量。
返回:
解密后的字符串消息。

示例

>>> from sympy.crypto.crypto import decipher_railfence
>>> decipher_railfence("horel ollwd",3)
'hello world'