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

  • 提示文档:
    实验已给出明文和密文,如下所示,并且已知加密方法为 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 
#include 
#include 
#include  
#include  
#include 
#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; 
}

你可能感兴趣的:(信息安全:使用 Openssl 加密库进行编程)