密码学基础练习五道 RSA、elgamal、elgamal数字签名、DSA数字签名、有限域(GF)上的四则运算

本文主要是介绍密码学基础练习五道 RSA、elgamal、elgamal数字签名、DSA数字签名、有限域(GF)上的四则运算,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.RSA

#include <stdlib.h>#include <stdio.h>#include <string.h>#include <math.h>#include <time.h>#define PRIME_MAX 200      //生成素数范围#define EXPONENT_MAX 200       //生成指数e范围#define Element_Max 127       //加密单元的最大值,这里为一个char, 即1Bytechar str_read[100]="hello world !";      //待加密的明文int str_encrypt[100];      //存放加密后的内容char str_decrypt[100];      //存放解密出来的内容int str_read_len;      //str_read 的长度int prime1, prime2;      //随机生成的两个质数int mod,eular;      //模数和欧拉数int pubKey, priKey;      //公钥指数和私钥指数//生成随机素数int randPrime(){int prime,prime2,i;next:prime=rand()%PRIME_MAX;      //随机产生数if (prime <= 1) goto next;      //不是质数,生成下一个随机数if (prime == 2 || prime == 3)return prime;prime2=prime/2;      //注:prime>=4, prime2 的平方必定大于 prime , 因此只检查小于等于prime2的数for (i=2;i<=prime2;i++)      //判断是否为素数{if(i*i>prime)return prime;if(prime%i==0)goto next;      //不是质数,生成下一个随机数}}// 欧几里德算法,判断a,b互质int gcd(int a, int b){int temp;while (b!=0){temp=b;b=a%b;a=temp;}return a;}//生成公钥,条件是 1< e < 欧拉数,且与欧拉数互质。int randExponent(){int e;while (1){e=rand()%eular;if(e<EXPONENT_MAX)break;}while (1){if(gcd(e, eular)==1)return e;e=(e+1)%eular;if(e==0||e>EXPONENT_MAX)e = 2;}}//生成私钥指数int inverse(){int d,x;while (1){d=rand()%eular;x=pubKey*d%eular;if(x==1){return d;}}}//加密函数void jiami(){str_read_len = strlen(str_read);//从参数表示的地址往后找,找到第一个'\0',即串尾.计算'\0'至首地址的“距离”,即隔了几个字符,从而得出长度.printf("密文是:");for(int i=0;i<str_read_len;i++){int C=1;int a=str_read[i],b=a%mod;for(int j=0;j<pubKey;j++)      //实现加密{C=(C*b)%mod;}str_encrypt[i]=C;printf("%d",str_encrypt[i]);}printf("\n");}//解密函数void jiemi(){int i=0;for(i=0;i<str_read_len;i++){int C=1;int a=str_encrypt[i],b=a%mod;for(int j=0;j<priKey;j++){C=(C*b)%mod;}str_decrypt[i]=C;}str_decrypt[i]='\0';printf("解密文是:%s\n",str_decrypt);}//主函数int main(){srand(time(NULL));while (1){prime1=randPrime();prime2=randPrime();printf("随机产生两个素数:prime1=%d,prime2=%d",prime1,prime2);mod=prime1*prime2;printf("模数:mod=prime1*prime2=%d\n",mod);if(mod>Element_Max)break;      //模数要大于每个加密单元的值}eular=(prime1-1)*(prime2-1);printf("欧拉数:eular=(prime1-1)*(prime2-1)=%d\n",eular);pubKey=randExponent();printf("公钥指数pubKey=%d\n",pubKey);priKey=inverse();printf("私钥指数:priKey=%d\n  私钥为(%d, %d)\n", priKey, priKey, mod);jiami();jiemi();return 0;}

流程图:

2.elgamal

#include<stdio.h>#include<stdlib.h>#include<math.h>//模重复平方算法,计算a^b mod pint pow_mod(int a,int b,int p){int ans=1;int tmp=a%p;while(b){if(b&1)ans=ans*tmp%p;b>>=1;tmp=tmp*tmp%p;}return ans%p;}//elgamal加密算法,k为任意整数,m为明文,pub为公钥,p为大素数,g为生成元,c1,c2为密文void elgamal_en(int m,int pub,int p,int g,int *c1,int *c2){int k=5;*c1=pow_mod(g,k,p);*c2=m*pow_mod(pub,k,p)%p;}//elgamal解密算法,m_为解密后的数据,p为大素数,g为生成元,c1_为c1模p的逆元,pr为私钥int elgamal_de(int c1,int c2,int pr,int p,int g){int m;int c1_=pow_mod(c1,p-2,p);m=c2*pow_mod(c1_,pr,p)%p;return m;}//判断是否为素数(为了严谨性而存在的函数,题中所给出的测试数据已经是素数了)int is_prime(int p){int i;for(i=2;i<=sqrt(p);i++){if(p%i==0)return 0;}return 1;}int main(){int p=1069;      //必须为素数int g=2;      //本原元do{printf("请输入一个素数:%d\n",p);}while(!is_prime(p));int pr=123;      //用户A的私钥printf("输入用户A的私钥:%d\n",pr);int pub;pub=pow_mod(g,pr,p);printf("用户A的公钥为:%d\n",pub);int m=677;      //明文要小于pint c1,c2;elgamal_en(m,pub,p,g,&c1,&c2);printf("用公钥加密后的密文为:c1=%d,c2=%d\n",c1,c2);int m_=elgamal_de(c1,c2,pr,p,g);printf("用私钥解密后的明文为:%d\n",m_);}

流程图:

3.elgamal数字签名:

#include <stdio.h>#include <stdlib.h>#include <time.h>#include <math.h>int xy[22];int myPow(int a, int b, int m) {int res=1;a%=m;while(b!=0) {if((b&1)==1)res=(res*a)%m;a=(a*a)%m;b>>=1;}return res;}//判断两个数是否互质int Coprime(int a, int b) {return b==0?a:Coprime(b,a%b);}int calculate3(int y,int k,int p) {printf("...%d %d %d\n",y,k,p);int l=1;for(int i = 0; i<k; i++) {l=l*y;l=l%p;}printf("l=%d\n",l);return l;}//求 a mod b 的逆元void exGcd(int a, int b) {if(b==0) {xy[0]=1;xy[1]=0;} else {exGcd(b,a%b);int x=xy[0];xy[0]=xy[1];xy[1]=x-(a/b)*xy[1];}}//主函数int main() {int p=1669,m=101,q=2;        //p为大素数,m为消息,q为本原元int x,y,k,k1,r,a;int k2,ni;int s;srand(time(NULL));      //随机数种子x=15;      //rand()%p-1+2 ;printf("x=%d\n",x);y=myPow(q,x,p);      //y是公开密钥printf("公开密钥y=%d\n",y);k=11;      //rand()%p-1+1 ;while(Coprime(k,p-1)!=1) {k=rand()%p-1+1;}printf("k=%d\n",k);//求r :r = g^k mod pr=myPow(q,k,p);printf("r=%d\n",r);//加密过程s=calculate3(y,k,p);if(s<0)s=(s+(p-1))%(p-1);s=s*m%p;printf("发送密文(%d,%d)\n",r,s);//解密过程k2=myPow(r,x,p);printf("k2=%d\n",k2);exGcd(r,p);ni=xy[0];if(ni<0)ni=ni+p;printf("ni=%d\n",ni);m=myPow(ni,x,p)*s;printf("m=%d\n",m%p);//签名过程// 计算k^-1 mod p-1exGcd(k,(p-1));k1=xy[0];if(k1<0)k1+=(p-1);printf("k1=%d\n",k1);// s = k^(-1)*(m-rx)(mod p-1)s=(k1*(m-r*x))%(p-1); // (m,r,s)为对消息m的数字签名printf("s=%d\n",s);//s可能为负值,所以要将其转化为正数,利用a%b=(a%b+b)%bif(s<0)s=(s%(p-1)+(p-1))%(p-1);printf("签名为(%d,%d)\n",r,s);if((myPow(y,r,p)*myPow(r,s,p))%p==myPow(q,m,p))printf("接受签名\n");elseprintf("拒绝签名\n");}

流程图:

4.DSA数字签名算法:

#include <stdlib.h>#include <stdio.h>#include <time.h>int xy[22];//乘法逆元int myPow(int a, int b, int m) {int res=1;a%=m;while(b!=0){if((b&1)==1)res=(res*a)%m;a=(a*a)%m;b>>=1;}return res;}int calculate(int h,int p,int q){int a=(p-1)/q;long int k=1;for(int i=0;i<a;i++){k=k*h;}return k%p;}int calculate1(int g,int x,int p){long int k=1;for(int i=0;i<x;i++){k=k*g;}return k%p;}// 求 a mod b 的逆元void exGcd(int a, int b) {if (b == 0) {xy[0] = 1;xy[1] = 0;} else {exGcd(b, a % b);int x = xy[0];xy[0] = xy[1];xy[1] = x - (a / b) * xy[1];}}//主函数int main(){int p=23;short q=11;      //p q为两个大素数,且满足(p-1)能够被q整除(这里为了方便选取了两个较小数,也可取p=7879,q=101)int g,x,y,s,k,m,w,u1,u2,v,h,r;      //对出现的变量进行初始化printf("请输入大素数p=%d和q=%d ,满足(p-1)能够被q整除\n",p,q);srand(time(NULL));      //随机数种子h=12;      //rand()%p-1+2 ;//随机数g=calculate(h,p,q);x=10;      //rand()%p-1+2 ;//私钥y=calculate1(g,x,p);      //计算公钥printf("公钥是(%d,%d,%d,%d)\n",p,q,g,y);printf("私钥为%d\n",x);//签名过程k=9;      //rand()%p-1+2 ;//随机数kr=calculate1(g,k,p)%q;exGcd(k, q);k = xy[0];if(k < 0) k += (p-1);  m=13;s=(m+x*r)*k%q;printf("签名为(%d,%d)\n",r,s);//验证程序exGcd(s,q);w =xy[0];if(w < 0) w += (q);u1=(m*w)%q;u2=r*w%q;v=myPow(g, u1, p)*myPow(y, u2, p)%p%q;printf("(w,u1,u2,v)=(%d,%d,%d,%d)\n",w,u1,u2,v);if(v==r){printf("接受");}else{printf("不接受");}}

流程图:

5.有限域(GF)上的加、减、乘法计算器

#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>#include<vector>#include<cmath>#include<bits/stdc++.h>int hex1=0x57,hex2=0x83;void jiafa(int hex1,int hex2){printf("请输入两个十六进制串:%x %x\n",hex1,hex2);printf("\n得到有限域内相加结果 : %#X\n\n",hex1^hex2);}//a减去b,其实就是a加上b的加法逆元,关键是找到b的加法逆元。void chengfa(int hex1,int hex2){int a[16],b[16],s[32];printf("请输入两个十六进制串:%x %x\n",hex1,hex2);int n=hex2,cnt=0;while(n)///转化为二进制{s[cnt++]=n%2;n/=2;}a[1]=0x01,b[1]=hex1;for(int i=2; i<=8; i++)a[i]=a[i-1]<<1;///得到0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80for(int i=2; i<=8; i++){if(b[i-1]&0x80)///如果最高为为1就对不可约多项式取模,否则直接左移b[i]=((b[i-1]<<1)^0x1B);elseb[i]=b[i-1]<<1;b[i]&=0xFF;///直接取后两位}int hex=0x00;for(int i=7; i>=0; i--){if(s[i]==1)///当二进制的这一位为1的时候才能异或hex^=b[i+1];}printf("\n得到有限域内相乘结果 : %#X\n\n",hex);}int main(){while(1){printf("请选择进行的运算: 0.退出运算  1.加/减法运算  2.乘法运算 \n\n");int ch;scanf("%d",&ch);switch(ch){case 0:system("cls");printf("\n谢谢使用!\n");exit(0);case 1:system("cls");jiafa(hex1,hex2);break;case 2:system("cls");chengfa(hex1,hex2);break;default :system("cls");printf("\n输入错误!请重新输入:\n\n");break;}}return 0;}

流程图:

这篇关于密码学基础练习五道 RSA、elgamal、elgamal数字签名、DSA数字签名、有限域(GF)上的四则运算的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/956273

相关文章

RedHat运维-Linux文本操作基础-AWK进阶

你不用整理,跟着敲一遍,有个印象,然后把它保存到本地,以后要用再去看,如果有了新东西,你自个再添加。这是我参考牛客上的shell编程专项题,只不过换成了问答的方式而已。不用背,就算是我自己亲自敲,我现在好多也记不住。 1. 输出nowcoder.txt文件第5行的内容 2. 输出nowcoder.txt文件第6行的内容 3. 输出nowcoder.txt文件第7行的内容 4. 输出nowcode

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

ps基础入门

1.基础      1.1新建文件      1.2创建指定形状      1.4移动工具          1.41移动画布中的任意元素          1.42移动画布          1.43修改画布大小          1.44修改图像大小      1.5框选工具      1.6矩形工具      1.7图层          1.71图层颜色修改          1

[FPGA][基础模块]跨时钟域传播脉冲信号

clk_a 周期为10ns clk_b 周期为34ns 代码: module pulse(input clk_a,input clk_b,input signal_a,output reg signal_b);reg [4:0] signal_a_widen_maker = 0;reg signal_a_widen;always @(posedge clk_a)if(signal_a)

00 - React 基础

1. React 基础 安装react指令 可参考: 官网官网使用教程 如: npx create-react-app 项目名如:npx create-react-app react-redux-pro JSX JSX 是一种 JavaScript 的语法扩展,类似于 XML 或 HTML,允许我们在 JavaScript 代码中编写 HTML。 const element =

AI赋能天气:微软研究院发布首个大规模大气基础模型Aurora

编者按:气候变化日益加剧,高温、洪水、干旱,频率和强度不断增加的全球极端天气给整个人类社会都带来了难以估计的影响。这给现有的天气预测模型提出了更高的要求——这些模型要更准确地预测极端天气变化,为政府、企业和公众提供更可靠的信息,以便做出及时的准备和响应。为了应对这一挑战,微软研究院开发了首个大规模大气基础模型 Aurora,其超高的预测准确率、效率及计算速度,实现了目前最先进天气预测系统性能的显著

【软考】信息系统项目管理师(高项)备考笔记——信息系统项目管理基础

信息系统项目管理基础 日常笔记 项目的特点:临时性(一次性)、独特的产品、服务或成果、逐步完善、资源约束、目的性。 临时性是指每一个项目都有确定的开始和结束日期独特性,创造独特的可交付成果,如产品、服务或成果逐步完善意味着分步、连续的积累。例如,在项目早期,项目范围的说明是粗略的,随着项目团队对目标和可交付成果的理解更完整和深入时,项目的范围也就更具体和详细。 战略管理包括以下三个过程

众所周知,配置即代码≠基础设置即代码

​前段时间翻到几条留言,问: “配置即代码和基础设施即代码一样吗?” “配置即代码是什么?怎么都是基础设施即代码?” 我们都是知道,DevOp的快速发展,让服务器管理与配置的时间大大减少,配置即代码和基础设施即代码作为DevOps的重要实践,在其中起到了关键性作用。 不少人将二者看作是一件事,配置即大代码是关于管理特定的应用程序配置设置本身,而基础设施即代码更关注的是部署支持应用程序环境所需的

Linux基础 - 常用命令

目录 零. 简介 一 . 常见 Ubuntu 命令 二. apt-get 下载 三. 网络命令 四. 常用命令的总结 零. 简介 在 Ubuntu 中,命令是用于与操作系统进行交互和执行各种操作的指令。通过在终端中输入命令,可以完成文件管理、系统配置、软件安装、进程管理等各种任务。 一 . 常见 Ubuntu 命令 sudo:“sudo”是“superuser do”