现代密码学 第四章——公钥密码【上】

一、公钥密码基本概念

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;
}
相关推荐
aaaffaewrerewrwer4 小时前
在线HEIC转JPG工具推荐:快速批量转换 + 浏览器本地处理
安全·个人开发
岁岁的O泡奶6 小时前
NSSCTF_crypto_[LitCTF 2023]babyLCG
经验分享·python·算法·密码学·crypto·流密码
AIGC设计所7 小时前
网络安全8大就业领域和待遇对比!
运维·开发语言·网络·安全·web安全·php
网安薯条7 小时前
Kali Linux 虚拟机安装与基础配置保姆级图文教程
linux·运维·网络·安全·web安全·网络安全
一拳一个娘娘腔9 小时前
从sudo配置到Root Shell:Linux Sudo提权全景深度解析与防御指南
linux·网络·安全
YaBingSec9 小时前
网络安全靶场WP:Grafana 任意文件读取漏洞(CVE-2021-43798)
android·笔记·安全·web安全·ssh·grafana
qcx2310 小时前
【AI Agent通识九课】 04 · AI 的双车道 — 安全怎么保
人工智能·安全·agent·ai agent·warp
Zevalin爱灰灰10 小时前
现代密码学 第一章——概述
密码学
西洼工作室11 小时前
安全认证全解析:从Basic到OAuth
安全·全栈·认证授权