《信息系统安全》课程实验指导
第1关:实验一:古典密码算法---代换技术
任务描述
本关任务:了解古典密码体制技术中的代换技术,并编程实现代换密码的加解密功能。
注意所有明文字符为26个小写字母,也就是说字母表为26个小写字母。
相关知识
为了完成本关任务,你需要掌握:1.古典密码算法,2.代换密码。
古典密码算法
古典密码算法历史上曾被广泛应用,大都使用手工和机械操作来实现加密和解密,比较简单。古典密码主要是利用密码算法实现文字信息的加密和解密,本实验运用两种常见的具有代表性的古典密码技术——代换密码技术,以帮助学员对密码算法建立一个初步的认识和印象。
代换密码
代换密码算法的原理是使用替代法进行加密,就是将明文中的字符用其它字符替代后形成密文。例如:明文字母a,b,c,d,用D,E,F,G做对应替换后形成密文。
代换密码包括多种类型,如单表替代密码,多明码替代密码,多字母替代密码,多表替代密码等。本实验利用一种典型的单表替代密码——恺撒caesar密码,又叫循环移位密码,加密方法是将明文中的每个字符,用此字符在字母表中后面第k个字母替代,加密过程可以表示为下面的函数:
E(m)=(m+k)(modn)
其中:m为明文字母在字母表中的位置数;n为字母表中的字母个数;k为密钥;E(m)为密文字母在字母表中对应的位置数。
例如,对于明文字母H,其在字母表中的位置数为8,设k=4,则按照上式计算出来的密文为L:
E(8)=(m+k)(modn)=(8+4)(mod26)=12=L
编程要求
本关的编程任务是补全右侧代码片段Encrypt和Dencrypt中Begin至End中间的代码,具体要求如下:
在Encrypt中,根据实验原理部分对凯撒密码算法的介绍,将明文字符串参数clearText通过密钥参数K加密转换成密文,并存入密文字符串参数变量cipherText。
在Dencrypt中,与Encrypt函数相对,将密文字符串参数cipherText通过密钥参数K解密转换成明文,并存入明文字符串参数变量clearText。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:
4
internet
预期输出:
密钥:4
明文:internet
密文:mrxivrix
解密:internet输入格式:
第1行:整数k,表示密钥
第2行:待加密明文
输出格式:
第1行:输出密钥k
第2行:输出原始明文
第3行:输出加密后的密文
第4行:输出解密后的明文
开始你的任务吧,祝你成功!
//
// main.cpp
// step1
//
// Created by ljpc on 2018/10/16.
// Copyright © 2018年 ljpc. All rights reserved.
//#include <iostream>
#include <stdio.h>
#include <string.h>
#define N 26void Encrypt(int K, char* clearText, char* cipherText)
{// 请在这里补充代码,完成本关任务/********* Begin *********/int len = strlen(clearText);for (int i = 0; i < len; i++) {if (clearText[i] >= 'a' && clearText[i] <= 'z') {cipherText[i] = ((clearText[i] - 'a' + K) % N) + 'a';}else {cipherText[i] = clearText[i];}}cipherText[len] = '\0';/********* End *********/
}void Dencrypt(int K, char* clearText, char* cipherText)
{// 请在这里补充代码,完成本关任务/********* Begin *********/int len = strlen(cipherText);for (int i = 0; i < len; i++) {if (cipherText[i] >= 'a' && cipherText[i] <= 'z') {int temp = cipherText[i] - 'a' - K;if (temp < 0) temp += N;clearText[i] = temp + 'a';} else {clearText[i] = cipherText[i];}}clearText[len] = '\0';/********* End *********/
}int main(int argc, const char * argv[]) {int K;char ClearText[100];char ClearText2[100];char CipherText[100];scanf("%d", &K);scanf("%s", ClearText);printf("密钥:%d\n", K);printf("明文:%s\n", ClearText);Encrypt(K, ClearText, CipherText);printf("密文:%s\n", CipherText);Dencrypt(K, ClearText2, CipherText);printf("解密:%s\n", ClearText2);return 0;
}
第2关:实验二:古典密码算法---置换技术
任务描述
本关任务:了解古典密码体制技术中的置换技术,并编程实现置换密码的加解密功能。
相关知识
为了完成本关任务,你需要掌握:1.古典密码算法,2.置换密码。
古典密码算法
古典密码算法历史上曾被广泛应用,大都使用手工和机械操作来实现加密和解密,比较简单。古典密码主要是利用密码算法实现文字信息的加密和解密,本实验运用常见的具有代表性的古典密码技术——置换密码技术,以帮助学员对密码算法建立一个初步的认识和印象。
置换密码
置换密码又称为换位密码,算法的原理是不改变、替换明文字符,只将字符在明文中的排列顺序改变,从而实现明文信息的加密。
矩阵换位法是实现置换密码的一种常用方法(类似于教材中的双换位密码)。它将明文中的字母按照给定的顺序安排在一个矩阵中,然后用根据密钥提供的顺序重新组合矩阵中字母,从而形成密文。
例如,明文为attackbeginsatfive,密钥为1 4 5 3 2 6,将明文按照每行6列的形式排在矩阵中,形成如下形式:
根据密钥1 4 5 3 2 6给定一个置换:
根据上面的置换,将原有矩阵中的字母按照第1列,第4列,第5列,第3列,第2列,第6列的顺序排列,则有下面形式:
从而得到密文:abatgftetcnvaiikse。
其解密的过程是根据密钥的字母数作为列数,将密文按照列,行的顺序写出,再根据由密钥给出的矩阵置换产生新的矩阵,从而恢复明文。
注意,本实验为了迎合程序中下标使用惯例,所有索引从0开始,另外本实验重在实现置换的过程,所以本样例中的明文长度和密钥长度一直,无需重组为矩阵,详情参看样例。
编程要求
本关的编程任务是补全右侧代码片段Encrypt和Dencrypt中Begin至End中间的代码,具体要求如下:
在Encrypt中,根据实验原理部分对置换密码算法的介绍,将明文字符串参数clearText通过密钥表参数cipherTab加密转换成密文,并存入密文字符串参数变量cipherText。
在Dencrypt中,与Encrypt函数功能相反,将密文字符串参数cipherText通过密钥表参数cipherTab解密转换成明文,并存入明文字符串参数变量clearText。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:
internet
4 7 3 1 2 6 0 5
预期输出:
密钥:
0 1 2 3 4 5 6 7
4 7 3 1 2 6 0 5
明文:internet
密文:rtentein
解密:internet输入格式:
第1行:待加密的明文
第2行:置换密钥,索引从0开始,密钥表大小等于与明文长度一直
输出格式:
第1~3行:密钥表信息
第4行:明文
第5行:密文
第6行:解密
开始你的任务吧,祝你成功!
第3关:实验三:DES加解密算法的实现
任务描述
本关任务:掌握DES加密算法的加解密过程,并且实现DES加解密算法中的各个功能模块。
相关知识
为了完成本关任务,你需要掌握:1.DES算法,2.DES加密,3.DES解密,4.子密钥的生成算法。
DES算法
DES(Data Encryption Standard)算法,于1977年得到美国政府的正式许可,是一种用56位密钥来加密64位数据的方法。DES算法以被应用于许多需要安全加密的场合。
DES加密
DES算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位,其功能是把输入的64位数据块按位重新组合,并把输出分为L0 、R0
两部分,每部分各长32位,其置换规则见下表:
58,50,12,34,26,18,10,2,60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,
57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7,
即将输入的第58位换到第1位,第50位换到第2位,……,依此类推,最后一位是原来的第7位。L0
,R0则是换位输出后的两部分,L0是输出的左32位,R0是右32位,经过16次迭代运算后,得到L(16)和R(16),将此作为输入,进行逆置换,即得到密文输出。
其中每一轮迭代的结构如下图所示:
迭代中的F函数如下图所示:
F函数中用到的8个BOX置换如下图所示:
DES解密
DES算法的解密过程是一样的,区别仅仅在于第一次迭代时用子密钥K16,第二次K15、……,最后一次用K1,算法本身并没有任何变化。
子密钥的生成算法
子密钥Ki(48bit)的生成算法初始Key值为64位,但DES算法规定,其中第8、16、......64位是奇偶校验位,不参与DES运算,故Key实际可用位数便只有56位。
将56位分为C0、D0两部分,各28位,然后分别进行第1次循环左移,得到C1、D1,将C1(28位)、D1(28位)合并得到56位,再经过缩小选择换位2,从而便得到了密钥K 1(48位),依此类推,便可得到K 1、K2、......、K16。
需要注意的是,16次循环左移对应的左移位数要依据下述规则进行:循环左移位数1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1。
其中置换选择1表如下:
置换选择2表如下:
编程要求
本关的编程任务是补全右侧代码片段ByteToBit、BitToByte、CYCLELEFT、SETKEY、Set_SubKey、S_BOXF、XOR、F_FUNCTION和DES中Begin至End中间的代码,具体要求如下:
- 在ByteToBit中,将字节组In转化成位组Outs,其中参数bits是每个字符占的位数,通常设置为8。
- 在BitToByte中,将位组In转换成字节组Outs,其中参数bits是每个字符占的位数,通常设置为8。
- 在CYCLELEFT中,循环左移位组In,所有位向左移动loop步,其中len是位组长度。
- 在SETKEY中,根据8个字节的字符串参数变量Key_C产生64位bool类型的密钥,每个字符占8位,左边高位,右边低位,并存入位组参数变量Key_B。
- 在Set_SubKey中,根据64位位组密钥生成16个48位的子密钥位组。
- 在S_BOXF中,根据S_BOX置换表,将48位位组In置换为32位位组Out。
- 在XOR中,将位组InA和InB按位异或,并将结果存入InA位组中,其中len是位组的长度。
- 在F_FUNCTION中,实现F函数里的扩展置换(EXPAND_32to48)、S盒置换(S_BOX)以及P盒置换(TRANS_32to32)。
- 在DES中,实现加解密算法,并通过Type参数来判断执行加密true还是解密false功能。
因为有些函数的实现存在多种方式,故生成的密钥会因程序具体实现而不同,主程序通过调用这些函数判断整个DES算法实现是否正确。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:
romantic
2018helo
预期输出:
明文:romantic
明文:0x72 0x6f 0x6d 0x61 0x6e 0x74 0x69 0x63
明文:0111001001101111011011010110000101101110011101000110100101100011
密钥:2018helo
密钥:0x32 0x30 0x31 0x38 0x68 0x65 0x6c 0x6f
密钥:0011001000110000001100010011100001101000011001010110110001101111
解密:romantic
解密:0x72 0x6f 0x6d 0x61 0x6e 0x74 0x69 0x63
解密:0111001001101111011011010110000101101110011101000110100101100011
输入格式:
第1行:8字节长度的明文,8个字符
第2行:8字节长度的密钥,8个字符
输出格式:
如上样例输出
开始你的任务吧,祝你成功!
//
// des.cpp
// step3
//
// Created by ljpc on 2018/10/17.
// Copyright © 2018年 ljpc. All rights reserved.
//
#include "des.h"
bool flag = true;
void print_bool(char* s, const bool *out, int len){printf("%s: ", s);for (int i=0; i<len; i++) {printf("%d", out[i]);}printf("\n");
}
void SETKEY(const char Key_C[8], bool Key_B[64])
// Key_C: 2018helo
// ascii: 0x32 0x30 0x31 0x38 0x68 0x65 0x6c 0x6f
// 8bits: 00110010 00110000 00110001 00111000 01101000 01100101 01101100 01101111
// Key_B: 0011001000110000001100010011100001101000011001010110110001101111
{// 请在这里补充代码,完成本关任务/********* Begin *********/for(int i=0; i<8; i++)for(int j=0; j<8; ++j)//Key_B[63-i*8-j] = ((Key_C[i]>>j) & 1);Key_B[i*8+7-j] = ((Key_C[i]>>j) & 1);/********* End *********/
}
void ByteToBit(bool *Outs, const char *In, int bits)
// In: password
// ascii: 0x70 0x61 0x73 0x73 0x77 0x6f 0x72 0x64
// 8bits: 01110000 01100001 01110011 01110011 01110111 01101111 01110010 01100100
// Outs: 0111000001100001011100110111001101110111011011110111001001100100
{// 请在这里补充代码,完成本关任务/********* Begin *********/for(int i=0; i<bits; i++)for(int j=0; j<bits; ++j)//Outs[63-i*bits-j] = ((In[i]>>j) & 1);Outs[i*bits+bits-1-j] = ((In[i]>>j) & 1);/********* End *********/
}
void BitToByte(char *Outs, const bool *In, int bits)
// In: 0111000001100001011100110111001101110111011011110111001001100100
// 8bits: 01110000 01100001 01110011 01110011 01110111 01101111 01110010 01100100
// ascii: 0x70 0x61 0x73 0x73 0x77 0x6f 0x72 0x64
// Outs: password
{// 请在这里补充代码,完成本关任务/********* Begin *********/for(int i=0; i<bits; i++){int val = 0;for (int j=0; j<bits; j++) {//val = (val<<1) | In[63-i*bits-(bits-1-j)];val = (val<<1) | In[i*bits+j];}Outs[i] = val;}Outs[bits] = '\0';/********* End *********/
}
void CYCLELEFT(bool *In, int len, int loop) // 循环左移函数
// before: 0000000011110000111111110000
// loop: 1
// after: 0000000111100001111111100000
{// 请在这里补充代码,完成本关任务/********* Begin *********/bool tmp[28];memcpy(tmp, In, sizeof(tmp));for (int i=0; i<len; i++) {In[i] = tmp[(i+loop)%len];}/********* End *********/
}
void Set_SubKey(bool subKey[16][48], bool Key[64]) // 设置子密钥
// Key: 0011001000110000001100010011100001101000011001010110110001101111
// SubKey: 011000000011110001100100010111000101100101000100
// SubKey: 010000001011010001110100010111001000100011100100
// SubKey: 110001001100010001110110110000001110110011011001
// SubKey: 111001101100001100100010001010111011011000011001
// SubKey: 101010101001001100100011101110110101010100100010
// SubKey: 101010010001001001011011000011000100101100100110
// SubKey: 001001010101001011011000110101000110100011010100
// SubKey: 000101100101100111010000111000011000001011011001
// SubKey: 000101100100100101010001111000111010011010011000
// SubKey: 000011110110100100010101001110010001011100001111
// SubKey: 000011110010010110001101000111100101000010100110
// SubKey: 010110110000010010101001010001000110100111100101
// SubKey: 110110011000100010101000101000101010100011011001
// SubKey: 100100001010101010001110111000111001011100010011
// SubKey: 001100000011111000000110000111110000011100101010
// SubKey: 011100000011111000000100000101000101011101100110
{// 请在这里补充代码,完成本关任务/********* Begin *********/bool realKey[56];bool left[28];bool right[28];bool compressKey[48]; // 去掉奇偶标记位,将64位密钥变成56位for (int i=0; i<56; i++){realKey[i] = Key[TRANS_64to56[i]-1];}// 生成子密钥,保存在 subKeys[16] 中for(int round=0; round<16; round++){// 前28位与后28位for(int i=0; i<28; i++)left[i] = realKey[i];for(int i=28; i<56; i++)right[i-28] = realKey[i];// 左移CYCLELEFT(left, 28, SHIFT_TAB[round]);CYCLELEFT(right, 28, SHIFT_TAB[round]);for(int i=0; i<28; i++)realKey[i] = left[i];for(int i=28; i<56; i++)realKey[i] = right[i-28];// 压缩置换,由56位得到48位子密钥for(int i=0; i<48; i++)compressKey[i] = realKey[TRANS_56to48[i]-1];for (int i=0; i<48; i++) {subKey[round][i] = compressKey[i];}}/********* End *********/
}
void XOR(bool *InA, const bool *InB, int len) // 异或函数
// Before InA: 000000000001011111111110100100000000001111111000
// Before InB: 011000000011110001100100010111000101100101000100
// Before InA: 011000000010101110011010110011000101101010111100
// Before InB: 011000000011110001100100010111000101100101000100
{// 请在这里补充代码,完成本关任务/********* Begin *********/for (int i=0; i<len; i++) {InA[i] = InA[i] ^ InB[i];}/********* End *********/
}
void S_BOXF(bool Out[32], const bool In[48])// S-盒代替函数
{// 请在这里补充代码,完成本关任务/********* Begin *********/int x = 0;for(int i=0; i<48; i=i+6){int row = In[i+0]*2 + In[i+5];int col = In[i+1]*8 + In[i+2]*4 + In[i+3]*2 + In[i+4];int num = S_BOX[i/6][row][col];for (int k=3; k>=0; k--) {Out[x+k] = num%2;num /= 2;}x += 4;}/********* End *********/
}
void F_FUNCTION(bool In[32], const bool Ki[48]) // f 函数完成扩展置换、S-盒代替和P盒置换
{// 请在这里补充代码,完成本关任务/********* Begin *********/// 第一步:扩展置换,32 -> 48bool expandR[48];for(int i=0; i<48; i++)//expandR[47-i] = In[32-EXPAND_32to48[i]]; // 0x8c 0x22 0xe2 0x86 0x48 0x5a 0x4b 0xaeexpandR[i] = In[EXPAND_32to48[i]-1]; // 0x8c 0x22 0xe2 0x86 0x48 0x5a 0x4b 0xae// 第二步:异或XOR(expandR, Ki, 48);// 第三步:查找S_BOX置换表bool output[32];S_BOXF(output, expandR);// 第四步:P-置换,32 -> 32for(int i=0; i<32; i++){In[i] = output[TRANS_32to32[i]-1];}/********* End *********/
}
void DES(char Out[8], char In[8], const bool subKey[16][48], bool Type) // 标准DES Type: True加密/False解密
{// 请在这里补充代码,完成本关任务/********* Begin *********/bool plain[64];bool left[32];bool right[32];bool newLeft[32];bool cipher[64];bool currentBits[64];ByteToBit(plain, In, 8);// 第一步:初始置换IPfor(int i=0; i<64; i++)currentBits[i] = plain[TRANS_INIT[i]-1];// 第二步:获取 Li 和 Rifor(int i=0; i<32; i++)left[i] = currentBits[i];for(int i=32; i<64; i++)right[i-32] = currentBits[i];// 第三步:共16轮迭代if (Type == true) { // 加密for(int round=0; round<16; round++){memcpy(newLeft, right, sizeof(newLeft));F_FUNCTION(right,subKey[round]);XOR(right, left, 32);memcpy(left, newLeft, sizeof(left));}}if (Type == false) { // 解密for(int round=15; round>=0; round--){memcpy(newLeft, right, sizeof(newLeft));F_FUNCTION(right,subKey[round]);XOR(right, left, 32);memcpy(left, newLeft, sizeof(left));}}// 第四步:合并L16和R16,注意合并为 R16L16for(int i=0; i<32; i++)//cipher[63-i] = left[31-i];cipher[i] = right[i];for(int i=32; i<64; i++)//cipher[63-i] = right[31-(i-32)];cipher[i] = left[(i-32)];// 第五步:结尾置换IP-1for(int i=0; i<64; i++)currentBits[i] = cipher[i];for(int i=0; i<64; i++)cipher[i] = currentBits[TRANS_END[i]-1];BitToByte(Out, cipher, 8);/********* End *********/
}
第4关:实验四:RSA加解密算法的实现
任务描述
本关任务:掌握RSA加密算法的加解密过程,并且实现RSA加解密算法中的各个功能模块。
相关知识
为了完成本关任务,你需要掌握:1.RSA加密算法,2.公钥和私钥的产生,3.加解密消息。
RSA加密算法
RSA加密算法是一种非对称加密算法。在公钥加密标准和电子商业中RSA被广泛使用。RSA是1977年由罗纳德•李维斯特(Ron Rivest)、阿迪•萨莫尔(Adi Shamir)和伦纳德•阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作,RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA算法的可靠性基于分解极大的整数是很困难的。假如有人找到一种很快的分解因子的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。
公钥和私钥的产生
假设Alice想要通过一个不可靠的媒体接收Bob的一条私人讯息。她可以用以下的方式来产生一个公钥和一个密钥:
step1:随意选择两个大的质数p和q,p不等于q,计算N=pq。
step2:根据欧拉函数,不大于N且与N互质的整数个数为(p−1)(q−1)。
step3:选择一个整数e与(p−1)(q−1)互质,并且e小于(p−1)(q−1)。
step4:用以下这个公式计算d:d×e≡1(mod(p−1)(q−1))。
step5:将p和q的记录销毁。
其中e是公钥,d是私钥。d是秘密的,而N是公众都知道的,Alice将她的公钥传给Bob,而将她的私钥藏起来。
加解密消息
假设Bob想给Alice送一个消息m,他知道Alice产生的N和e,用下面这个公式他可以将m加密为c:
c=m
e
(modn)
计算c并不复杂,Bob算出c后就可以将它传递给Alice。
Alice得到Bob的消息c后就可以利用她的密钥d来解码,她可以用以下这个公式来将c转换为m:
m=c
d
((modn))
最终她可以将原来的信息m重新复原。
编程要求
本关的编程任务是补全右侧代码片段PRIME、mod、exgcd、Inv、GCD和ModPow中Begin至End中间的代码,具体要求如下:
在PRIME中,借助全局数组变量p用素数筛法求10000以内的所有素数,并存入全局数组变量prime中。
在mod中,计算64位整型参数变量a在参数变量n下的模。
在exgcd中,根据参数a、b、c实现扩展欧几里得ax+by=c,并将结果存入x、y。
在Inv中,借助exgcd函数计算参数a在模n下的逆元。
在GCD中,求两个整数a和b的最大公约数。
在ModPow中,计算a的b次幂在模n下的结果x≡a
b
(modn)。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:
14 16
465
预期输出:
素数:47 59
公开N:2773
欧拉T:2668
公钥E:3
私钥D:1779
明文:465
密文:1191
解密:465输入格式:
第1行:整数p1和p2,表示素数表中的第一个素数
第2行:整型数据,明文
输出格式:
如上样例8行输出
开始你的任务吧,祝你成功!
//
// main.cpp
// step4
//
// Created by ljpc on 2018/10/16.
// Copyright © 2018年 ljpc. All rights reserved.
//
#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
#define int64 long long
int prime[2001]; //存放素数
int p[10001]; //用筛选法求素数
void PRIME()
{// 请在这里补充代码,完成本关任务/********* Begin *********/int i,i2,k;for(i=0;i<=10000;i+=2)p[i]=0;for(i=1;i<=10000;i+=2)p[i]=1;p[2]=1;p[1]=0;for(i=3;i<=100;i+=2){if(p[i]==1){i2=i+i;k=i2+i;while(k<=10000){p[k]=0;k+=i2;}}}int t = 0;prime[t++]=2;for(i=3;i<=10000;i+=2)if(p[i])prime[t++]=i;/********* End *********/}
int64 mod(int64 a,int64 n)
{// 请在这里补充代码,完成本关任务/********* Begin *********/return (a%n+n)%n;/********* End *********/
}
void exgcd(int64 a,int64 b,int64 &d,int64 &x,int64 &y)
{// 请在这里补充代码,完成本关任务/********* Begin *********/if(b==0){d=a;x=1;y=0;return;}exgcd(b,a%b,d,y,x);y-=x*(a/b);/********* End *********/
}
//a-1 mod n
int64 Inv(int64 a,int64 n) // 计算逆元素
{// 请在这里补充代码,完成本关任务/********* Begin *********/int64 d,x,y;exgcd(a,n,d,x,y);if(d==1)return mod(x,n);elsereturn -1;/********* End *********/
}
//求两个数的最大公约数
int64 GCD(int64 n,int64 m)
{// 请在这里补充代码,完成本关任务/********* Begin *********/int64 t,r;if(n<m){t=n;n=m;m=t;}while((r=n%m)!=0){n=m;m=r;}return m;/********* End *********/
}
//x=a^b(mod n)
int64 ModPow(int64 a,int64 b,int64 n)
{// 请在这里补充代码,完成本关任务/********* Begin *********/int64 d=1,i=0;while(b>=(1<<i)) i++;for(--i;i>=0;--i){d=d*d%n;if(b&(1<<i))d=d*a%n;}return d;/********* End *********/
}
int main(int argc, const char * argv[]) {PRIME();int64 P1, P2;int64 T;int64 N;int64 E;int64 D;int64 M;int64 C;int64 m;scanf("%lld %lld", &P1, &P2);scanf("%lld", &M);P1 = prime[P1];P2 = prime[P2];T = (P1-1)*(P2-1);N = P1 * P2;for(int64 i=2; i<T; i++)if(GCD(T, i)==1){E = i;break;}D = Inv(E, T);C = ModPow(M,E,N);m = ModPow(C,D,N);printf("素数:%lld %lld\n", P1, P2);printf("公开N:%lld\n",N);printf("欧拉T:%lld\n",T);printf("公钥E:%lld\n",E);printf("私钥D:%lld\n",D);printf("明文:%lld\n",M);printf("密文:%lld\n",C);printf("解密:%lld\n",m);return 0;
}
相关文章:

《信息系统安全》课程实验指导
第1关:实验一:古典密码算法---代换技术 任务描述 本关任务:了解古典密码体制技术中的代换技术,并编程实现代换密码的加解密功能。 注意所有明文字符为26个小写字母,也就是说字母表为26个小写字母。 相关知识 为了完…...

Accelerated Soft Error Testing 介绍
加速软错误测试(Accelerated Soft Error Testing, ASET)是一种评估半导体器件或集成电路(ICs)在高辐射环境中发生软错误率(Soft Error Rate, SER)的方法。这种测试方法通过模拟或加速软错误的发生,以便在较短时间内评估器件的可靠性。软错误指的是那些不会对硬件本身造成…...

Redis缓存常用的读写策略
缓存常用的读写策略 缓存与DB的数据不一致问题,大多数都是指DB的数据已经修改,而缓存中的数据还是旧数据的情况。 旁路缓存模式 对于读操作:基本上所有模式都是先尝试从缓存中读,没有的话再去DB读取,然后写到缓存中…...

9月产品更新 | 超10项功能升级,快来看看你的需求上线了吗?
Smartbi用户可以在官网(PC端下载),更新后便可以使用相关功能,也可以在官网体验中心体验相关功能。 接下来,我们一起来看看都有哪些亮点功能更新吧。 ▎插件商城 Smartbi麦粉社区的应用市场新增了“插件”模块…...

ARP协议工作原理析解 (详细抓包分析过程)
目录 1. ARP 协议 2. 工作原理 3. ARP 协议报文格式 4. ARP 缓存的查看和修改 5. tcpdump 抓包分析 ARP 协议工作原理 5.1 搭建 2 台虚拟机 5.2 在主机 192.168.0.155 打开一个shell命令行开启抓包监听 5.3 在主机 192.168.0.155 打开另一个shell命令行 telnet 192.168.…...

axure动态面板
最近转管理岗了,作为项目负责人,需要常常与客户交流沟通,这时候画原型的能力就是不可或缺的本领之一了,关于axure可能很多it行业者都不是很陌生,简单的功能呢大家就自行去摸索,我们这次从动态面板开始讲起。…...

[论文笔记]Making Large Language Models A Better Foundation For Dense Retrieval
引言 今天带来北京智源研究院(BAAI)团队带来的一篇关于如何微调LLM变成密集检索器的论文笔记——Making Large Language Models A Better Foundation For Dense Retrieval。 为了简单,下文中以翻译的口吻记录,比如替换"作者"为"我们&quo…...

Linux平台屏幕|摄像头采集并实现RTMP推送两种技术方案探究
技术背景 随着国产化操作系统的推进,市场对国产化操作系统下的生态构建,需求越来越迫切,特别是音视频这块,今天我们讨论的是如何在linux平台实现屏幕|摄像头采集,并推送至RTMP服务。 我们知道,Linux平台&…...

梧桐数据库|中秋节活动·抽奖领取大闸蟹
有话说 众所周不知,我的工作就是做一个国产的数据库产品—中国移动梧桐数据库(简称WuTongDB)。 近期我们举办了一次小活动,来提升梧桐数据库的搜索量和知名度,欢迎大家来参加,免费抽奖领取大闸蟹哦~~~ 具…...

Python怎么发送邮件:基础步骤与详细教程?
Python怎么发送邮件带附件?怎么使用Python发送邮件? 无论是工作中的通知、报告,还是生活中的问候、邀请,电子邮件都扮演着不可或缺的角色。那么,Python怎么发送邮件呢?AokSend将详细介绍Python发送邮件的基…...

[译] 大模型推理的极限:理论分析、数学建模与 CPU/GPU 实测(2024)
译者序 本文翻译自 2024 年的一篇文章: LLM inference speed of light, 分析了大模型推理的速度瓶颈及量化评估方式,并给出了一些实测数据(我们在国产模型上的实测结果也大体吻合), 对理解大模型推理内部工…...

vue3 响应式 API:readonly() 与 shallowReadonly()
readonly() readonly()是一个用于创建只读代理对象的函数。它接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。 类型 function readonly<T extends object>(target: T ): DeepReadonly<UnwrapNestedRefs<T>>以下…...
迁移学习与知识蒸馏对比
应用场景不同 迁移学习:通常用于不同但相关的任务之间的知识迁移。特别是当目标任务的数据量不足时,可以从一个已经在大规模数据上训练好的模型中获取有用的特征或参数。典型场景包括计算机视觉任务,比如你在ImageNet上训练了一个ResNet&…...

【Java-反射】
什么是反射? JAVA反射机制是在运行状态中,创建任意一个类,能获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言…...

移动UI设计要求越来越高,最为设计师应如何迎头赶上
一、引言 在当今数字化高速发展的时代,移动设备已经成为人们生活中不可或缺的一部分。随着科技的不断进步和用户需求的日益增长,移动 UI 设计的要求也越来越高。作为移动 UI 设计师,我们面临着巨大的挑战,需要不断提升自己的能力…...

大数据-121 - Flink Time Watermark 详解 附带示例详解
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

国行 iPhone 15 Pro 开启苹果 Apple Intelligence 教程
一、前言苹果在 iOS 18.1 测试版上正式开启了 Apple Intelligence 的内测,但国行设备因政策原因不支持,且国行设备在硬件上被锁定。不过,我们可以通过一些方法来破解国行 iPhone 15 Pro,使其能够开启 Apple Intelligence。 以下是…...

conda、anaconda、pip、torch、pytorch、tensorflow到底是什么东西?(转载自本人的知乎回答)
转载自本人的知乎回答(截止2024年9月,1700赞同,2400收藏) https://www.zhihu.com/question/566592612/answer/3063465880 如果你是一个大四的CS准研究生回去补基础课,假如是科班CS甚至科班EE的话那你基础也太差了。你…...

数据库系列之GaussDB数据库中逻辑对象关系简析
初次接触openGauss或GaussDB数据库的逻辑对象,被其中的表空间、数据库、schema和用户之间的关系,以及授权管理困惑住了,与熟悉的MySQL数据库的逻辑对象又有明显的不同。本文旨在简要梳理下GaussDB数据库逻辑对象之间的关系,以加深…...

如何进行不同数据库的集群操作?--从部署谈起,今天来看MySQL和NoSql数据库Redis的集群
篇幅较长,主要分为mysql和Redis两部分。找想要的部分可见目录食用。。 目录 什么是集群?为什么要集群? 1.1 数据库主要分为两大类:关系型数据库与 NoSQL 数据库 1.2 为什么还要用 NoSQL 数据库呢? ----------------…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...