一、公钥密码基本概念
1、传统的对称密码体制的缺陷
(1)密钥分发问题:
上一章中介绍的DES和AES算法都属于对称密码体制,它们的特点是通信双方必须提前共享同一个密钥,但在现实中,怎么安全地把密钥发给对方便成了难题,在互联网上几乎没法直接安全地分发密钥
(2)密钥管理的爆炸问题:
假设有N个用户,两两之间都要安全通信,如果使用对称密码,每个用户需要保存N-1个密钥,整个系统需要管理N(N-1)/2个密钥,如果N为100,那么系统需要管理4950个密钥,这显然太夸张了
(3)不支持"开放系统":
两个素未谋面的用户没法提前共享密钥,也就没法用对称密码安全通信
2、公钥密码体制
(1)公钥密码体制的思想:
公钥密码的基础是非对称问题:一个方向计算很容易,反向计算极难,例如,两个大整数相乘很容易,但把一个大合数分解成两个质数(因式分解)却非常困难
这种"单向性"被用来设计公钥密码,公钥加密容易,但只有持有私钥的人才能解密
(2)公钥密码的核心机制:
每个用户自行生成一个密钥对------一个公钥pk和一个对应的私钥sk,公钥将在系统内被公开,私钥由用户本人安全保管
私钥由用户本人使用,而公钥则由系统中的其它用户使用
公钥密码体制也被称为非对称密码体制
(3)公钥密码体制的通信流程举例:
如下图所示,Bob从系统中拿到Alice公开的公钥,用Alice的公钥加密明文生成密文,将密文发给Alice,Alice用自己的私钥解密密文得到明文,传输过程中即使攻击者截获密文也没法解密

(4)公钥密码的三大优势:
①密钥分发简单:公钥可以直接公开传输,不需要提前共享,解决了分发难题。
②密钥管理高效:N个用户的系统里,只需要维护N个公钥,每个用户只需保管自己的私钥,规模再大也不会爆炸。
③支持开放系统:没有预先关系的用户,只要拿到对方的公钥,就能直接安全通信,完美适配互联网场景。
二、信息安全数学基础------完全剩余系
1、同余类
(1)同余类的定义:
给定正整数m,全体整数可按照模m是否同余(余数相同)分为若干两两不相交(交集为0)的集合,使得每一个集合中的任意两个正整数对模m一定同余,而属于不同集合的任意两个整数对模m不同余,每一个这样的集合称为模m的同余类或剩余类
比如模m为7,那么任何整数除以7,余数只能是0/1/2/3/4/5/6,所有余0的数(...-14、-7、0、7、14...)归为一组,这一组就是同余类[0]
(2)对于给定的正整数m,有且恰有m个不同的模m的剩余类。
2、完全剩余系
(1)完全剩余系的定义:


(2)完全剩余系的性质:
①集合中的数,两两模m不同余。
②任意正数都和集合中的其中一个数模m同余。
(3)完全剩余系举例:

(4)定理:

三、信息安全数学基础------简化剩余系
1、简化剩余系
(1)简化剩余系的定义:

(2)既约剩余系举例:

(3)定理:

2、其它补充定理及欧拉定理
(1)定理1:

(2)定理2:



(3)欧拉定理:

四、RSA加密算法
1、RSA加密体制
(1)密钥生成(生成公私钥对):

(2)使用公钥加密明文:

(3)使用私钥解密密文:

2、RSA算法的C语言实现
cpp
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// ------------------- 64位模幂运算(快速幂) -------------------
// 计算 (base^exp) % mod
uint64_t pow_mod(uint64_t base, uint64_t exp, uint64_t mod) {
uint64_t result = 1;
base %= mod;
while (exp > 0) {
if (exp & 1) {
result = (result * base) % mod;
}
base = (base * base) % mod;
exp >>= 1;
}
return result;
}
// ------------------- 素性测试(Miller-Rabin,适用于64位) -------------------
// 对64位整数确定性判别(基于已知基集)
uint64_t mul_mod(uint64_t a, uint64_t b, uint64_t m) {
uint64_t res = 0;
a %= m;
while (b) {
if (b & 1) res = (res + a) % m;
a = (a << 1) % m;
b >>= 1;
}
return res;
}
// 快速幂模(用于 Miller-Rabin 内部)
uint64_t pow_mod_mr(uint64_t a, uint64_t d, uint64_t n) {
uint64_t res = 1;
a %= n;
while (d) {
if (d & 1) res = mul_mod(res, a, n);
a = mul_mod(a, a, n);
d >>= 1;
}
return res;
}
// Miller-Rabin 确定性基(对 < 2^64 有效)
int is_prime(uint64_t n) {
if (n < 2) return 0;
if (n == 2 || n == 3) return 1;
if (n % 2 == 0) return 0;
// 将 n-1 写成 d * 2^s
uint64_t d = n - 1;
int s = 0;
while (d % 2 == 0) {
d /= 2;
s++;
}
// 测试基(针对64位)
static const uint64_t bases[] = { 2, 325, 9375, 28178, 450775, 9780504, 1795265022 };
int num_bases = 7;
for (int i = 0; i < num_bases; i++) {
uint64_t a = bases[i] % n;
if (a == 0) continue;
uint64_t x = pow_mod_mr(a, d, n);
if (x == 1 || x == n - 1) continue;
int composite = 1;
for (int r = 1; r < s; r++) {
x = mul_mod(x, x, n);
if (x == n - 1) {
composite = 0;
break;
}
}
if (composite) return 0;
}
return 1;
}
// ------------------- 随机生成一个指定位数的素数 -------------------
uint64_t random_prime(int bits) {
if (bits < 2) bits = 2;
uint64_t min = 1ULL << (bits - 1);
uint64_t max = (1ULL << bits) - 1;
uint64_t p;
do {
p = min + rand() % (max - min + 1);
if (p % 2 == 0) p++; // 跳过偶数
} while (!is_prime(p));
return p;
}
// ------------------- 扩展欧几里得算法求逆元 -------------------
// 求 a 模 m 的逆元 (a,m互质)
uint64_t mod_inverse(uint64_t a, uint64_t m) {
int64_t m0 = m, t, q;
int64_t x0 = 0, x1 = 1;
if (m == 1) return 0;
while (a > 1) {
q = a / m;
t = m;
m = a % m;
a = t;
t = x0;
x0 = x1 - q * x0;
x1 = t;
}
if (x1 < 0) x1 += m0;
return (uint64_t)x1;
}
// ------------------- RSA 密钥生成 -------------------
// 输入:bit_len(素数位数,通常足够小以确保乘积不溢出64位)
// 输出:n, e, d
int rsa_gen_keys(int bit_len, uint64_t *n, uint64_t *e, uint64_t *d) {
srand((unsigned)time(NULL));
uint64_t p, q;
// 生成两个不同的素数
do {
p = random_prime(bit_len);
q = random_prime(bit_len);
} while (p == q);
*n = p * q;
uint64_t phi = (p - 1) * (q - 1);
// 选择 e = 65537 (常用公钥指数)
*e = 65537;
// 检查 gcd(e, phi) 是否为1
// 如果 e 与 phi 不互质,则尝试 e=3 或重新生成素数
if (phi % (*e) == 0) {
// 简单处理:改用 3 或 17 等
*e = 3;
while (phi % (*e) == 0) (*e) += 2;
}
*d = mod_inverse(*e, phi);
if (*d == 0) return 0;
return 1;
}
// ------------------- RSA 加密 -------------------
uint64_t rsa_encrypt(uint64_t msg, uint64_t e, uint64_t n) {
return pow_mod(msg, e, n);
}
// ------------------- RSA 解密 -------------------
uint64_t rsa_decrypt(uint64_t cipher, uint64_t d, uint64_t n) {
return pow_mod(cipher, d, n);
}
// ------------------- 简单测试 -------------------
int main() {
int bits;
printf("RSA算法演示(64位整数限制,请选择素数位数 ≤ 15 以保证乘积不溢出64位)\n");
printf("建议位数: 8~12\n");
printf("请输入素数位数: ");
scanf("%d", &bits);
if (bits > 15) {
printf("位数过大可能导致溢出,强制设为15\n");
bits = 15;
}
uint64_t n, e, d;
if (!rsa_gen_keys(bits, &n, &e, &d)) {
printf("密钥生成失败\n");
return 1;
}
printf("\n=== 生成的密钥 ===\n");
printf("n = %llu\n", n);
printf("e = %llu\n", e);
printf("d = %llu\n", d);
// 输入明文(必须小于 n)
uint64_t plain, cipher, decrypted;
printf("\n请输入要加密的整数(0 < plain < n): ");
scanf("%llu", &plain);
if (plain >= n) {
printf("明文必须小于模数 n\n");
return 1;
}
cipher = rsa_encrypt(plain, e, n);
printf("加密结果: %llu\n", cipher);
decrypted = rsa_decrypt(cipher, d, n);
printf("解密结果: %llu\n", decrypted);
if (plain == decrypted)
printf("\nRSA加解密成功!\n");
else
printf("\nRSA加解密失败!\n");
return 0;
}