信安实验
模指数
Eratosthenes筛选法
- 构造一个从2 到 sqrt(a)的集合,然后从2开始去掉集合中的倍数,最后看看a是否能整除这个集合中的数字
- memset(res,value,数量) 是从字节开始赋值,所以一般赋值0合适一点,尤其是int型数组
- 一定到考虑错误比如小于2以及其他情况的判断!!!!!!
- unsigned 2^32-1==4294967295(这是上限) int 2^31 -1
- 为了防止计算溢出,采用unsigned long long 2^64-1 (long long 2^63-1) 差的都是符号位置
米勒拉宾素性检测
- 判断a的范围,1<a<n-1,1<=j<=k
- 看清上下角标
- pow在std中已经被定义过了
- 总共要判断两次
string miller_rabin_prime_test(unsigned int n, unsigned int a) { if(n<2 || a>=n-1) { return "error"; } unsigned k=0,q; while(1) { q=(n-1)/int(pow(2,k)); if(q%2==1) { break; } k++; } if(mod_exp(a,q,n)==1) { return "uncertain"; } for(int j=1;j<=k;j++) { if(mod_exp(a,int(pow(2,j-1))*q,n)==n-1) { return "uncertain"; } } return "not_prime"; }
|
扩展欧几里得求逆元
先用欧几里得求出gcd以及x,y
然后对x进行非负判断
注意gcd不是1,即不是互素,要进行判错
int ex_gcd(int a,int m,int &x,int &y) { if(m==0) { x=1,y=0; return a; } int gcd=ex_gcd(m,a%m,y,x); y=y-(a/m)*x; return gcd; } int euclid_mod_reverse(int a, int m) { if(a<0 || m<0) { return -1; } int x,y; if(ex_gcd(a,m,x,y)!=1) { return -1; } else { return (x%m+m)%m; } }
|
线性同余
BBS
unsigned int bbs_rand(int flag) { if(flag!=0 && flag!=1 && flag!=2) { return 0; } int res_1[33],res_2[33],res_3[33]; int tep=3; for(int i=0;i<32;i++) { tep=(tep*tep)%(_p*_q); cout<<tep; string tep_dec=de_2_bn(tep); if(tep_dec[tep_dec.length()-1]=='1') { res_1[i]=1; } else { res_1[i]=0; } if(one_in_dec(tep_dec)%2==0) { res_2[i]=1; res_3[i]=0; } else { res_2[i]=0; res_3[i]=1; } } if(flag==0) { int res=0; for(int i=0;i<32;i++) { res+=pow(2,31-i)*res_1[i]; } return res; } if(flag==1) { int res=0; for(int i=0;i<32;i++) { res+=pow(2,31-i)*res_2[i]; } return res; } if(flag==2) { int res=0; for(int i=0;i<32;i++) { res+=pow(2,31-i)*res_3[i]; } return res; }
}
|
编译过程
预处理
编译过程的第一个阶段就是预处理阶段。该阶段要完成的任务:
将#include关键字标示的含有定义的文件(包括文件或头文件)包含到源代码文件中。
将#include语句指定的值转换成常量。
在代码中调用宏的位置将宏定义转换成代码。
根据#if、#elif、#endif包含或排除特定部分的代码
经过预处理阶段之后会形成一系列的.i文件
处理宏定义指令
将已经定义过的参数变换成宏
处理条件编译指令
防止头文件的重复定义
头文件以h结尾
gcc -E .i文件 1203.
生成预处理代码
参考:【精选】什么是预处理_预处理阶段-CSDN博客
三、编译预处理阶段_scx_link的博客-CSDN博客
编译
将i文件处理为s文件
gcc -S ** **
汇编
将汇编语言转换成机器语言 生成目标文件 .O 也称 可重定位文件
链接
- 将各个目标文件组合到一起的过程
- 可执行文件windows后缀为.exe,Linux后缀为.out
链接器将各种.o文件进行合并并生成可执行目标文件,可以被加载到内存中,由系统进行执行。
连接目标代码,生成可执行程序。
静态库
动态库
预处理、编译、汇编和链接是计算机程序的构建过程中的四个主要阶段。它们按照顺序依次执行,最终将高级编程语言的源代码转化为可执行文件。下面是对每个阶段的详细介绍:
预处理(Preprocessing):
- 任务: 预处理是在源代码被编译之前的第一步,它主要负责对源代码进行一些文本替换和处理,以生成被编译器进一步处理的中间代码。
- 过程: 预处理器通常会执行以下任务:
- 宏替换: 展开程序中的宏定义。
- 文件包含: 处理
#include
指令,将包含的头文件内容插入到源文件中。
- 条件编译: 处理
#if
、#else
、#endif
等条件编译指令,根据条件选择性地包含或排除代码。
- 注释去除: 去除注释,将注释后的内容删除。
编译(Compiling):
- 任务: 编译阶段将预处理后的源代码转化为汇编代码,该代码是特定于目标机器架构的低级中间代码。
- 过程: 编译器执行以下关键任务:
- 词法分析: 将源代码转化为标记(tokens)。
- 语法分析: 构建抽象语法树(Abstract Syntax Tree,AST),检查语法错误。
- 语义分析: 检查语法结构的语义正确性,进行类型检查。
- 优化: 对代码进行一些优化,以提高执行效率。
- 代码生成: 生成与目标机器体系结构相关的汇编代码。
汇编(Assembling):
- 任务: 汇编阶段将编译生成的汇编代码翻译成机器语言指令,生成可重定位的目标文件。
- 过程: 汇编器执行以下主要步骤:
- 符号解析: 将代码中使用的符号(变量、函数名等)映射到内存地址。
- 地址解析: 为指令生成实际的内存地址。
- 生成目标文件: 将汇编代码转化为目标文件,包含机器语言指令和相关的元信息。
链接(Linking):
- 任务: 链接阶段将多个目标文件和库文件组合成一个可执行文件。
- 过程: 链接器执行以下主要任务:
- 地址解析: 解析和分配程序中使用的符号的最终内存地址。
- 符号解析: 解决在不同目标文件中定义的符号之间的引用关系。
- 重定位: 调整目标文件中的地址,使得各个目标文件中的地址能够正确地映射到最终的内存地址。
- 生成可执行文件: 将所有目标文件和必要的库文件链接在一起,生成最终的可执行文件。
综合来说,这四个阶段协同工作,将高级编程语言的源代码转化为可在计算机上执行的机器语言,并最终生成可执行文件。
当你在预处理过程中使用了尚未定义的函数时,预处理阶段本身不会报错。这是因为预处理阶段主要处理一些文本替换和条件编译等任务,而不会对代码的语法和语义进行深入检查。
具体来说,在预处理阶段,如果你使用了某个函数的声明,而该函数的定义在当前文件或包含的头文件中尚未出现,预处理器不会引发错误。预处理器只是简单地展开宏、处理条件编译指令、执行文件包含等操作。
OPENSSL
man
是一个用于查看 Unix/Linux 系统上的手册页面的命令,但是在某些系统上,特别是一些较小或定制化的系统上,可能并没有完整的手册页面。如果你在使用 man
命令时无法查询到 OpenSSL 库函数的手册页面,有几种可能的原因和替代方法:
手册页面不存在: 确保 OpenSSL 库已经正确安装,并且你的系统支持 OpenSSL 的手册页面。你可以尝试安装 OpenSSL 的手册页面,具体方法可能因系统而异。例如,在基于 Debian 的系统上,你可以运行以下命令安装 OpenSSL 的手册页面:
sudo apt-get install libssl-doc
|
2.openssl 安装
sudo apt-get install libssl-dev
|
声明
BIGNUM *a_ = BN_new()
这行代码在使用 OpenSSL 库中进行大数运算时创建了一个 BIGNUM 对象,其中:
BIGNUM
是 OpenSSL 库中用于表示大整数的数据类型。
BN_new()
是 OpenSSL 提供的函数,用于创建一个新的 BIGNUM 对象。
模指数
int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx);
|
返回值是1或者错误返回
注意最后一个参数为 BN_CTX_new()
最后要释放参数
string mod_exp(string a, string e, string m)
{
BIGNUM *an,*en,*mn,*res;
an=BN_new();
en=BN_new();
mn=BN_new();
res=BN_new();
BN_dec2bn(&an,a.c_str());
BN_dec2bn(&en,e.c_str());
BN_dec2bn(&mn,m.c_str());
if(BN_mod_exp(res, an, en,mn, BN_CTX_new()))
{
char *result;
result=BN_bn2dec(res);
return result;
}
else
{
return "error";
}
BN_free(an);
BN_free(en);
BN_free(mn);
BN_free(res);
}
### 逆元
```c++ BIGNUM *BN_mod_inverse(BIGNUM *r, BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
|
返回值是大数指针或者错误返回
注意最后一个参数为 BN_CTX_new()
string mod_inverse(string a, string m) { BIGNUM *an,*mn,*res; an=BN_new(); mn=BN_new(); res=BN_new(); BN_dec2bn(&an,a.c_str()); BN_dec2bn(&mn,m.c_str()); if( BN_mod_inverse(res, an, mn,BN_CTX_new())) { char * result; result=BN_bn2dec(res); return result; } else { return "error"; } BN_free(an); BN_free(en); BN_free(mn); BN_free(res); }
|
RSA加解密以及数字签名
#include <bits/stdc++.h> #include <openssl/bn.h> #include <openssl/pem.h> #include <openssl/rsa.h>
#define PUBLICKEY "../keys/public.pem" #define PRIVATEKEY "../keys/private.pem"
using namespace std;
RSA* rsa_private_key = NULL; RSA* rsa_public_key = NULL;
bool load_RSA_keys() { FILE *p=NULL,*s=NULL; const char* rsa_public_path=PUBLICKEY; const char* rsa_private_path=PRIVATEKEY; p=fopen(rsa_public_path,"r"); s=fopen(rsa_private_path,"r"); if(p!=NULL && s!=NULL) { PEM_read_RSA_PUBKEY(p,&rsa_public_key,NULL,NULL); PEM_read_RSAPrivateKey(s,&rsa_private_key,NULL,NULL); } else{ return false; } fclose(p); fclose(s); return true; }
string RSA_Encryption(string plaintext) { load_RSA_keys(); int flen=plaintext.length(),elen; const char * plaintext_cstr=plaintext.c_str(); unsigned char res[1000]; elen=RSA_public_encrypt(flen,reinterpret_cast<const unsigned char *>(plaintext_cstr),res,rsa_public_key,RSA_PKCS1_PADDING); string str(reinterpret_cast< char*>(res),elen); return str; }
string RSA_Decryption(string ciphertext) { load_RSA_keys(); int flen=ciphertext.length(); int mlen; const char* ciphertext_cstr=ciphertext.c_str(); unsigned char res[1000]; mlen= RSA_private_decrypt(flen,reinterpret_cast<const unsigned char*>(ciphertext_cstr),res,rsa_private_key,RSA_PKCS1_PADDING); string str(reinterpret_cast<char *>(res),mlen); return str; }
string RSA_signature_signing(string input) { load_RSA_keys(); int flen=input.length(); int elen; const char* input_cstr=input.c_str(); unsigned char res[1000]; elen=RSA_private_encrypt(flen,reinterpret_cast<const unsigned char*>(input_cstr),res,rsa_private_key,RSA_PKCS1_PADDING); string str(reinterpret_cast<char *>(res),elen); return str; }
bool RSA_signature_verify(string message, string signature) { load_RSA_keys(); int flen=signature.length(),elen; const char * signature_cstr=signature.c_str(); unsigned char res[1000]; elen=RSA_public_dncrypt(flen,reinterpret_cast<const unsigned char *>(signature_cstr),res,rsa_public_key,RSA_PKCS1_PADDING); string str(reinterpret_cast< char*>(res),elen); return str==message;
}
|
gcc rsa_test.cpp -o try -lstdc++ -lcrypto//编译
// 生成RSA私钥,存入PEM文件 $ openssl genrsa -out rsa_pri.pem 2048 // 从RSA私钥中提取公钥,存入PEM文件 $ openssl rsa -in rsa_pri.pem -pubout -out rsa_pub.pem
|
RC4
string rc4_encrypt(string data, string secret_key) { if(data=="" || secret_key=="") { return ""; } RC4_KEY* key_m=new RC4_KEY; const char* secret_key_cstr=secret_key.c_str(); const char* data_cstr=data.c_str(); RC4_set_key( key_m, secret_key.length(), reinterpret_cast<const unsigned char*>(secret_key_cstr)); unsigned char outdata[data.length()+1]; RC4( key_m, data.length(), reinterpret_cast<const unsigned char*>(data_cstr),outdata); string str(reinterpret_cast<const char*>(outdata),data.length()); return str; } string rc4_decrypt(string data, string secret_key) { return rc4_encrypt(data, secret_key); }
|
DES
去看ppt
void convert_string_to_des_block(string str, DES_cblock &output) { for(int i = 0; i < 8; ++i) { output[i] = str[i]; } }
string des_encrypt(string plain, string secret_key) { DES_cblock input,key_,output; DES_key_schedule schedule; convert_string_to_des_block(plain,input); DES_string_to_key(secret_key.c_str(), &key_); DES_set_key_unchecked(&key_, &schedule); DES_ecb_encrypt(&input,&output,&schedule, DES_ENCRYPT); string str(reinterpret_cast<const char*>(output),plain.length()); return str;
}
string des_decrypt(string cipher, string secret_key) { DES_cblock input,key_,output; DES_key_schedule schedule; convert_string_to_des_block(cipher,input); DES_string_to_key(secret_key.c_str(), &key_); DES_set_key_unchecked(&key_, &schedule); DES_ecb_encrypt(&input,&output,&schedule, DES_DECRYPT); string str(reinterpret_cast<const char*>(output),cipher.length()); return str; }
|
SHA1
string sha1_digest(string msg) { SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, msg.c_str(), msg.length());
unsigned char hash[SHA_DIGEST_LENGTH]; SHA1_Final(hash, &ctx);
return string(reinterpret_cast<const char*>(hash), SHA_DIGEST_LENGTH); }
|
密码学基础知识回顾
密码的四个性质:保密性、完整性、认证性、不可否认性
- 唯密文攻击:只知道密文
- 已知明文攻击:一些明文和对应的密文
- 选择明文攻击:可以选择一些明文,并且得到相应的密文
- 选择密文攻击:选择密文得到相应的明文