密码学系列之流密码&RSA&ECC等

0 阅读2分钟

Snipaste_2026-03-31_19-58-43 注意本篇大多数的题解都是直接在VsCode点击按钮运行的,如果控制台终端输入python ABC.py(ABC.py为你写的脚本的名称)很可能会报一些小错误。这里我也不知道为什么,真的想不懂。

LSFR

题目:3级线性反馈移位寄存器在c3=1时有4种线性反馈函数,设其初始状态为(a1,a2,a3)=(1,0,1),求各线性反馈函数的输出序列及周期,输出他们的密钥流,并利用生成的密钥流对明文'0x0123456789ABCDEF'进行加密,输出加密后的结果,再对密文进行解密,输出解密后的结果。 已知:

  • 寄存器长度:n = 3
  • 状态:(a1, a2, a3)
  • 初始状态:(1, 0, 1)
  • 条件:c3 = 1

LFSR 的反馈函数是:f=c1a1⊕c2a2⊕c3a3。因为:c3=1,所以:f=c1a1⊕c2a2⊕a3

因为:c1{0,1}c_1 \in \{0,1\}c2{0,1}c_2 \in \{0,1\},所以一共有4种情况,对应4 个反馈函数。

编号(c1,c2,c3)(c_1,c_2,c_3)反馈函数周期
1(0,0,1)(0,0,1)a3a_3很短
2(0,1,1)(0,1,1)a2a3a_2 \oplus a_3较短
3(1,0,1)(1,0,1)a1a3a_1 \oplus a_3可能最大
4(1,1,1)(1,1,1)a1a2a3a_1 \oplus a_2 \oplus a_3最大周期7(m序列)

状态更新原则:

(a1,a2,a3)(a2,a3,f)(a_1, a_2, a_3) \rightarrow (a_2, a_3, f)

每一轮输出值:

输出值为a1\text{输出值} 为 a_1
def lfsr_step(state, c1, c2):
    a1, a2, a3 = state
    f = (c1 & a1) ^ (c2 & a2) ^ a3
    return (a2, a3, f)


def generate_sequence(init_state, c1, c2):
    state = init_state
    seen = []
    output = []

    while state not in seen:
        seen.append(state)
        output.append(state[0])
        state = lfsr_step(state, c1, c2)

    return output, len(seen)


def bits_to_bytes(bits):
    res = []
    for i in range(0, len(bits), 8):
        byte = 0
        for j in range(8):
            if i + j < len(bits):
                byte = (byte << 1) | bits[i + j]
        res.append(byte)
    return res


def encrypt(hex_str, keystream_bits):
    data = bytes.fromhex(hex_str[2:])
    ks = bits_to_bytes(keystream_bits)
    return bytes([d ^ ks[i] for i, d in enumerate(data)]).hex()


def decrypt(cipher_hex, keystream_bits):
    data = bytes.fromhex(cipher_hex)
    ks = bits_to_bytes(keystream_bits)
    return bytes([d ^ ks[i] for i, d in enumerate(data)]).hex()


# ==========================
# 主程序
# ==========================
init_state = (1, 0, 1)
plaintext = "0x0123456789ABCDEF"

configs = [
    (0, 0),
    (0, 1),
    (1, 0),
    (1, 1)
]

for c1, c2 in configs:
    print("=" * 40)
    print(f"反馈函数: f = {c1}*a1 ⊕ {c2}*a2 ⊕ a3")

    seq, period = generate_sequence(init_state, c1, c2)

    print("输出序列:", seq)
    print("周期:", period)

    # 生成64bit密钥流
    keystream = (seq * (64 // len(seq) + 1))[:64]
    print("密钥流(bit):", keystream)

    # 加密
    cipher = encrypt(plaintext, keystream)
    print("密文:", cipher)

    # 解密
    plain = decrypt(cipher, keystream)
    print("解密:", plain)


Snipaste_2026-03-31_16-52-25

NFLSR

题目:设n=4,f(a1,a2,a3,a4)=a1* a4^(a2 * a3),初始状态为(a1,a2,a3,a4)=(1,1,0,1),求此非线性反馈移位寄存器的输出序列及周期,输出他的密钥流,并利用生成的密钥流对明文'0x0123456789ABCDEF'进行加密,输出加密后的结果,再对密文进行解密,输出解密后的结果。 流密码原理 1)生成密钥流(keystream);2)明文 XOR 密钥流 → 密文 3)密文 XOR 密钥流 → 明文。 加密:cipher = plaintext XOR keystream 解密:decrypt(cipher) == plaintext

  • 寄存器长度:n=4n = 4
  • 状态:(a1,a2,a3,a4)(a_1, a_2, a_3, a_4)
  • 反馈函数:
f(a1,a2,a3,a4)=a1a4(a2a3)f(a_1, a_2, a_3, a_4) = a_1 \cdot a_4 \oplus (a_2 \cdot a_3)

状态更新原则:

(a1,a2,a3,a4)(a2,a3,a4,f)(a_1, a_2, a_3, a_4) \rightarrow (a_2, a_3, a_4, f)

输出序列一般取:

输出=a1(最左边)\text{输出} = a_1 \quad (\text{最左边})
def nlfsr_step(state):
    a1, a2, a3, a4 = state
    # 非线性反馈函数
    f = (a1 & a4) ^ (a2 & a3)
    # 移位
    return (a2, a3, a4, f)


def generate_sequence(init_state):
    state = init_state
    seen = []
    output_seq = []

    while state not in seen:
        seen.append(state)
        output_seq.append(state[0])  # 输出 a1
        state = nlfsr_step(state)

    period = len(seen)
    return output_seq, period


def bits_to_bytes(bits):
    res = []
    for i in range(0, len(bits), 8):
        byte = 0
        for j in range(8):
            if i + j < len(bits):
                byte = (byte << 1) | bits[i + j]
        res.append(byte)
    return res


def encrypt(plaintext_hex, keystream_bits):
    plaintext = bytes.fromhex(plaintext_hex[2:])
    keystream_bytes = bits_to_bytes(keystream_bits)

    cipher = bytes([p ^ keystream_bytes[i] for i, p in enumerate(plaintext)])
    return cipher.hex()


def decrypt(cipher_hex, keystream_bits):
    cipher = bytes.fromhex(cipher_hex)
    keystream_bytes = bits_to_bytes(keystream_bits)

    plain = bytes([c ^ keystream_bytes[i] for i, c in enumerate(cipher)])
    return plain.hex()


# ==========================
# 主流程
# ==========================
init_state = (1, 1, 0, 1)

# 生成序列
seq, period = generate_sequence(init_state)

print("输出序列:", seq)
print("周期:", period)

# 生成足够长的密钥流(明文8字节=64bit)
keystream_bits = (seq * (64 // len(seq) + 1))[:64]

print("密钥流(bit):\n", keystream_bits)

# 明文
plaintext = "0x0123456789ABCDEF"

# 加密
cipher = encrypt(plaintext, keystream_bits)
print("密文:", cipher)

# 解密
decrypted = decrypt(cipher, keystream_bits)
print("解密结果:", decrypted)


Snipaste_2026-03-31_16-47-07

ECC

题目:已知椭圆曲线E11(1,6),编程求其上所有的点。

这个问题本质是在有限域 F11\mathbb{F}_{11} 上求椭圆曲线

E:y2x3+x+6(mod11)E: y^2 \equiv x^3 + x + 6 \pmod{11}

的所有点。

思路:

  1. 枚举 x[0,10]x \in [0,10]
  2. 计算右边
    rhs=x3+x+6(mod11)rhs = x^3 + x + 6 \pmod{11}
  3. 枚举 y[0,10]y \in [0,10],找满足以下 条件的解
    y2rhs(mod11)y^2 \equiv rhs \pmod{11}
  4. 加上无穷远点 OO
#include <stdio.h>

#define p 11
#define a 1
#define b 6

typedef struct {
    int x;
    int y;
} Point;

int isOnCurve(Point point) {
    int left = (point.y * point.y) % p;
    int right = (point.x * point.x * point.x + a * point.x + b) % p;
    return left == right;  
}

int main() {
    int count = 0;

    for (int x = 0; x < p; x++) {
        for (int y = 0; y < p; y++) {
            Point point = {x, y};
            if (isOnCurve(point)) {
                printf("(%d, %d)\n", point.x, point.y);
                count++;
            }
        }
    }

    printf("Point at infinity: O\n"); //注意,必须添加无穷远点。
    printf("Total points (including O): %d\n", count + 1);

    return 0;
}


Snipaste_2026-03-31_17-02-38

p = 11
a = 1
b = 6

points = []

for x in range(p):
    rhs = (x**3 + a*x + b) % p
    for y in range(p):
        if (y*y) % p == rhs:
            points.append((x, y))

# 加上无穷远点
points.append("O")

print("椭圆曲线上的点:")
for pt in points:
    print(pt)

print("\n点的总数:", len(points))


Snipaste_2026-03-31_17-11-29

背包

题目:编程实现背包密码的加密和解密,假设选取的私钥为超递增背包向量 A=[1, 3, 5, 11, 21, 44, 87, 175, 349, 701],选取模数k = 1590和乘数t = 43,计算新的背包向量B == t * A (mod k)作为公钥。利用上述密码算法对明文“SAUNA AND HEALTH”进行加密,输出密文,并对密文进行解密。

实现一个公钥加密系统

  • 私钥:超递增序列 A
  • 公钥:B = t·A mod k
  • 加密:用 B 做“子集和”
  • 解密:用 A 做“贪心恢复”
加解密原理:
超递增序列(私钥)。A = [1, 3, 5, 11, 21, 44, 87, 175, 349, 701] 。 满足每个元素 > 前面所有元素之和
保证子集和可唯一反推(贪心)。
↓
公钥生成 Bi​=(t⋅Ai​)mod k , k = 1590,t = 43(i是下标)
↓
加密。把字符 → 二进制(10 bit,对应 A 长度) C=∑bi​⋅Bi​
↓
解密。1. 求逆元:t^-1 modk
     2. 还原:C′=C⋅t^−1 modk
     3. 用 A 贪心恢复 bit
# 私钥
A = [1, 3, 5, 11, 21, 44, 87, 175, 349, 701]

# 参数
k = 1590
t = 43


# 求逆元(扩展欧几里得)
def modinv(a, m):
    def egcd(a, b):
        if b == 0:
            return a, 1, 0
        g, x1, y1 = egcd(b, a % b)
        return g, y1, x1 - (a // b) * y1

    g, x, _ = egcd(a, m)
    if g != 1:
        raise Exception("无逆元")
    return x % m


# 生成公钥
B = [(t * ai) % k for ai in A]
print("公钥 B:", B)


# 字符转10bit
def char_to_bits(c):
    val = ord(c)
    return [(val >> i) & 1 for i in reversed(range(10))]


# bits转字符
def bits_to_char(bits):
    val = 0
    for b in bits:
        val = (val << 1) | b
    return chr(val)


# 加密
def encrypt(plaintext):
    ciphertext = []
    for ch in plaintext:
        bits = char_to_bits(ch)
        c = sum(b * bi for b, bi in zip(bits, B))
        ciphertext.append(c)
    return ciphertext


# 解密
def decrypt(ciphertext):
    inv_t = modinv(t, k)
    plaintext = ""

    for c in ciphertext:
        c_prime = (c * inv_t) % k

        # 贪心恢复
        bits = [0] * len(A)
        for i in reversed(range(len(A))):
            if c_prime >= A[i]:
                bits[i] = 1
                c_prime -= A[i]

        plaintext += bits_to_char(bits)

    return plaintext


# ==========================
# 主程序
# ==========================
plaintext = "SAUNA AND HEALTH"

print("明文:", plaintext)

cipher = encrypt(plaintext)
print("密文:", cipher)

decrypted = decrypt(cipher)
print("解密:", decrypted)


Snipaste_2026-03-31_17-39-48

ElGamal

题目:编程实现ElGamal的加密和解密,假设用户A选择素数p=11和本原根g=2,并且选择私钥α=5,输出A的公钥;若用户B向用户A发送消息m=6,随机数k=7,输出对该消息加密后的密文,以及对密文进行解密的明文。

已知:

  • 素数:p=11
  • 本原根:g=2
  • A 的私钥:α=5
生成公钥。β=g^α modp,计算β=2^5 mod 11= 32 mod 11= 10,所以A的公钥为(p, g, β) = (11, 2, 10)
↓
加密(B → A)。给定,明文:m = 6,随机数:k = 7。计算 c1​=g^k mod p= 2^7 mod 11= 7,c2​=m⋅β^k mod p=6*10^7 mod 11=5。所以密文为(c1, c2) = (7, 5)
↓
解密(A)。m=c2​⋅(c1^α​)^−1 mod p=5*(7^5)^-1 mod 11=5*(7^5mod 11)^-1 mod 11=5*10^-1 mod 11=6
# 参数
p = 11
g = 2
alpha = 5  # 私钥

# 快速幂
def mod_exp(base, exp, mod):
    result = 1
    base %= mod
    while exp > 0:
        if exp & 1:
            result = (result * base) % mod
        base = (base * base) % mod
        exp >>= 1
    return result


# 求逆元
def modinv(a, p):
    for i in range(1, p):
        if (a * i) % p == 1:
            return i
    return None


# ==========================
# 1. 生成公钥
# ==========================
beta = mod_exp(g, alpha, p)
print("公钥 (p, g, β):", (p, g, beta))


# ==========================
# 2. 加密
# ==========================
m = 6
k = 7

c1 = mod_exp(g, k, p)
c2 = (m * mod_exp(beta, k, p)) % p

print("密文 (c1, c2):", (c1, c2))


# ==========================
# 3. 解密
# ==========================
s = mod_exp(c1, alpha, p)
s_inv = modinv(s, p)

m_decrypted = (c2 * s_inv) % p

print("解密后的明文:", m_decrypted)


Snipaste_2026-03-31_17-44-24

RSA

题目:编程实现RSA的加密和解密,选择参数p=71593,q=77041,e=1757316971,输出公钥和私钥,并对消息“I need your best time”进行加密,输出密文。最后对密文进行解密,输出明文。 已知:

  • 两个大素数 p=71593,q=77041
  • 公钥指数 e=1757316971
RSA 核心原理:

1.n=p⋅q
1. ϕ(n)=(p−1)(q−1)
2. 私钥 d 满足:e⋅d ≡1(modϕ(n))

3. 加密:c=m^e mod n

4. 解密:m=c^d mod n  其中 m 是明文整数。字符串 → 数字需 ASCII 编码 或 utf-8
# 参数
p = 71593
q = 77041
e = 1757316971

# 计算 n 和 phi
n = p * q
phi = (p - 1) * (q - 1)

# 求逆元 d
def modinv(a, m):
    def egcd(a, b):
        if b == 0:
            return a, 1, 0
        g, x1, y1 = egcd(b, a % b)
        return g, y1, x1 - (a // b) * y1
    g, x, _ = egcd(a, m)
    if g != 1:
        raise Exception("No modular inverse")
    return x % m

d = modinv(e, phi)

print("公钥 (n, e):", (n, e))
print("私钥 d:", d)


# ==========================
# 分块加密
# ==========================
message = "I need your best time"
message_bytes = message.encode('utf-8')

# 每块最大长度(保证 m < n)
max_block_size = (n.bit_length() - 1) // 8
blocks = [message_bytes[i:i+max_block_size] for i in range(0, len(message_bytes), max_block_size)]

cipher_blocks = []
for block in blocks:
    m_int = int.from_bytes(block, 'big')
    c = pow(m_int, e, n)
    cipher_blocks.append(c)

print("密文分块:", cipher_blocks)

# ==========================
# 分块解密
# ==========================
decrypted_bytes = b''
for c in cipher_blocks:
    m_decrypted = pow(c, d, n)
    length = (m_decrypted.bit_length() + 7) // 8
    decrypted_bytes += m_decrypted.to_bytes(length, 'big')

decrypted_message = decrypted_bytes.decode('utf-8')
print("解密后的明文:", decrypted_message)


Snipaste_2026-03-31_18-59-50

DH

题目:编程计算25的所有本原根。

  1. 本原根定义

对于整数 nngg(模 nn),如果 gg 的阶等于欧拉函数 ϕ(n)\phi(n),则称 ggnn 的本原根:

g1,g2,...,gϕ(n)modng^1, g^2, ..., g^{\phi(n)} \mod n

会生成模 nn 的所有互质剩余类(即整数 1 到 n1n-1nn 互质的整数)。

  1. 计算步骤
  • n=25n = 25
  • 计算 ϕ(25)=25(11/5)=20\phi(25) = 25 \cdot (1 - 1/5) = 20
  • 检查每个 g[1,24]g \in [1, 24],若:
g20/p1(mod25)p 是 20 的质因子g^{20/p} \neq 1 \pmod{25} \quad \forall p \text{ 是 } 20 \text{ 的质因子}

gg 是本原根。

  • 20 的质因子:2, 5。
def euler_phi(n):
    """计算欧拉函数 φ(n)"""
    result = n
    p = 2
    temp = n
    while p * p <= temp:
        if temp % p == 0:
            while temp % p == 0:
                temp //= p
            result -= result // p
        p += 1
    if temp > 1:
        result -= result // temp
    return result

def prime_factors(n):
    """返回 n 的质因子集合"""
    i = 2
    factors = set()
    while i * i <= n:
        if n % i == 0:
            factors.add(i)
            while n % i == 0:
                n //= i
        i += 1
    if n > 1:
        factors.add(n)
    return factors

def is_primitive_root(g, n):
    """判断 g 是否为 n 的本原根"""
    if gcd(g, n) != 1:
        return False
    phi = euler_phi(n)
    for p in prime_factors(phi):
        if pow(g, phi // p, n) == 1:
            return False
    return True

def gcd(a, b):
    while b:
        a, b = b, a % b
    return a

# =====================
n = 25
roots = []
for g in range(1, n):
    if is_primitive_root(g, n):
        roots.append(g)

print(f"{n} 的所有本原根:",roots)

Snipaste_2026-03-31_19-08-47

题目:编程实现Diffie-Hellman密钥交换协议,假设共享素数p=19,它的一个本原元g =3,A选秘密的随机数x=5,B选秘密的随机数y=7,输出A和B共享的密钥。

  • 素数:p=19
  • 本原元:g=3
  • A 的私钥:x=5
  • B 的私钥:y=7

A计算并发送15

A=gxmodp=35mod19=15A = g^x \mod p = 3^5 \mod 19 = 15

B计算并发送2

B=gymodp=37mod19=2B = g^y\mod p = 3^7 \mod 19 =2

计算共享密钥 A计算

K=Bxmodp=25mod19=13K = B^x \mod p = 2^5 \mod 19 = 13

B计算

K=Aymodp=157mod19=13K = A^y \mod p = 15^7 \mod 19 = 13

所以最终的共享密钥就是K=13

# 参数
p = 19
g = 3
x = 5  # A的私钥
y = 7  # B的私钥

# 快速幂
def mod_exp(base, exp, mod):
    result = 1
    base %= mod
    while exp > 0:
        if exp & 1:
            result = (result * base) % mod
        base = (base * base) % mod
        exp >>= 1
    return result

# A计算并发送
A = mod_exp(g, x, p)
print("A发送:", A)

# B计算并发送
B = mod_exp(g, y, p)
print("B发送:", B)

# 共享密钥
K_A = mod_exp(B, x, p)
K_B = mod_exp(A, y, p)

print("A计算的共享密钥:", K_A)
print("B计算的共享密钥:", K_B)


Snipaste_2026-03-31_19-12-36