欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

信息安全:使用 Openssl 加密库进行编程

程序员文章站 2022-07-12 22:42:09
...
  • 提示文档:
    实验已给出明文和密文,如下所示,并且已知加密方法为 aes-128-cbc,IV 全由 0 组成,以及 key 的长度小于 16 个字母,该单词可以从一般的英文词典中得到。由于该单词小于 16 个字母(128bits)所以在其后追加了空格字符(对应 0x20)以达到 128bit 的长度。本例中词典已给出,文件名为word.txt.

  • 任务:
    写一个程序找到加***key。鼓励自己写程序,也可以使用实验楼中的代码,本实验即文件key.c,请调通key.c,给程序中每条语句添加注释,并画出程序的流程图。
    明文 (21 个字符): This is a top secret.
    密文 (十六进制形式): 8d20 e505 6a8d 24d0 462c e74e 4904 c1b5 13e1 0d1d f4a2 ef2a d454 0fae 1ca0 aaf9

  • 备注:
    1: 明、密文对都直接放在了程序中。如果你打算将明文存储在文件中读取,可能会有一些麻烦。
    2: 为了编译代码,可以在linux平台需要写 makefile,如下。

NC=/usr/local/ssl/include/
LIB=/usr/local/ssl/lib/
all:
gcc -I$(INC) -L$(LIB) -o enc yourcode.c -lcrypto –ldl

也可以直接在linux平台下直接运行带有相关参数的gcc命令。
如果使用另一种情形在windows平台下,可以使用codeblocks来作为编辑器,并加载已编译好的带有OpenSSL的MinGW编译器来编译你写的代码,编译的过程和普通的C程序是一样的。

3:编写的程序代码可以参考实验楼平台的《**加解密实验 下》,本实验中给出该程序key.c,作为参考。但程序运行中可能会出现语法错误,需调试。Linux平台上key.c的错误可能少些,windows平台错误可能多些。此类错误均为由于不同平台下的C的语法稍有不同产生的语法错,而不是程序的逻辑错误。

  • 代码如下:
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h>
#define True 1 
#define False 0 

void handleErrors(void) { 
	ERR_print_errors_fp(stderr); 
	abort(); 
} 

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) { 
	
	EVP_CIPHER_CTX *ctx; 

	int len; 

	int ciphertext_len; 
	//创建和初始化
	if(!(ctx = EVP_CIPHER_CTX_new())) 
		handleErrors(); 
	//初始化加密操作,确保使用key和iv是256位key,128位vi
	if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)) 
		handleErrors(); 
	//提供要加密的消息,并获得加密输出
	if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) 
		handleErrors(); 
		ciphertext_len = len; 
	//最终加密,可缩写进一步的密文字节
	if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) 
		handleErrors(); 
	ciphertext_len += len; 
	//清空
	EVP_CIPHER_CTX_free(ctx); 
	return ciphertext_len; 
} 

//判断buffer是否符合密码长度的要求,并将buffer数组全部置空
int append(char* buffer){ 
	int length = (int)strlen(buffer); 
    //设置key的长度小于 16 个字母,该单词可以从一般的英文词典中得到。
	if (length > 16) 
		return False; 
    //单词小于16个字母(128bits)时,在其后追加了空格字符(对应 0x20)以达到 128bit 的长度。
	memset(buffer+strlen(buffer),' ', 16-length); 
	buffer[16] = '\0'; 
	return True; 
}


int main(int argc, char const *argv[]) { 
	//key的存储空间
	char buffer[50]; 
	//循环标志
	int i = 0; 
	//向量
	char iv[17]; 
    //初始化
	memset(iv, 0, 17);     
    //待加密的文件内容  (明文)      
	unsigned char *plaintext = "This is a top secret."; 
    //密文文本空间
	unsigned char ciphertext[100]; 
	//密文
	unsigned char *cryptotext="8d20e5056a8d24d0462ce74e4904c1b513e10d1df4a2ef2ad4540fae1ca0aaf9"; 
    //加载可读的错误字符串
	ERR_load_crypto_strings(); 
    //将所有的算法添加到表中(摘要和密码),无返回值
	OpenSSL_add_all_algorithms(); 
    //加载配置文件,以及其他重要的初始化,使用默认名称配置openssl
	OPENSSL_config(NULL); 

    //密文长度
	int ciphertext_len; 
    //以只读方式打开word.txt
	FILE* fp = fopen("words.txt", "r"); 
	//从fp中读取一行字符放入buffer中
	while (fscanf(fp, "%s\n", buffer) != EOF){ 
		//判断buffer是否符合密码要求
		if (!append(buffer)) 
			continue; 
	     //加密plaintext
		ciphertext_len = encrypt(plaintext, strlen(plaintext), buffer, iv, ciphertext); 
	    //加密十六进制
		unsigned char cryptohex[50]; 

		for (i = 0; i < ciphertext_len; i++) { 
		    //以2位十六进制形式将加密结果ciphertext格式化输出到cryptohex中、ciphertext格式化输出到cryptohex中。
			sprintf(cryptohex+i*2,"%02x", ciphertext[i]); 
		} 
		//设置结束符
		cryptohex[ciphertext_len*2] = '\0'; 
	     //判断加密后生成的十六进制文件cryptohex和给定的cryptotext是否相同
		if (0 == strcmp(cryptohex, cryptotext)){ 
			//如果相同则当前的key为**,即返回找的秘钥
			printf("The key is: %s\n", buffer); 
			break; 
		} 
	} 
     //删除所有摘要和密码
	EVP_cleanup(); 
    //删除错误的字符串
	ERR_free_strings(); 
	return 0; 
}