VC++网络安全编程范例(9)-基于OPENSSL实现对称算法与BASE64编码

对称密码算法有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,反过来也成立。在大多数对称算法中,加密解密密钥是相同的。这些算法也叫秘密密钥算法或单密钥算法,它要求发送者和接收者在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都能对消息进行加密解密。只要通信需要保密,密钥就必须保密。

 

对称算法的加密和解密表示为:

Ek(M)=C

Dk(C)=M

对称算法可分为两类。一次只对明文中的单个位(有时对字节)运算的算法称为序列算法或序列密码。另一类算法是对明文的一组位进行运算,这些位组称为分组,相应的算法称为分组算法或分组密码。现代计算机密码算法的典型分组长度为64位――这个长度大到足以防止分析破译,但又小到足以方便作用。

这种算法具有如下的特性:

Dk(Ek(M))=M

常用的采用对称密码术的加密方案有5个组成部分(如图所示)

l)明文:原始信息。

2)加密算法:以密钥为参数,对明文进行多种置换和转换的规则和步骤,变换结果为密文。

3)密钥:加密与解密算法的参数,直接影响对明文进行变换的结果。

4)密文:对明文进行变换的结果。

5)解密算法:加密算法的逆变换,以密文为输入、密钥为参数,变换结果为明文。

 

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。


 

请见代码实现案例

 

 #include <stdio.h>
 #include <string.h>
 #include <openssl/evp.h>

//base64中每行的长度,最后一位是换行符号
#define CHARS_PER_LINE_BASE64 65  //64+1(\r)

void print(const char *promptStr,unsigned char *data,int len)
{
    int i;
    printf("======%s[长度=%d]======\n",promptStr,len);
    for(i = 0; i < len; i++) printf("%02x", data[i]);
    printf("\n===============\n");
}

//base64编码
void encode(unsigned char* outData,
            int * outlen,
            const unsigned char* data,
            int datalen)
{
    int tmp=0;
    EVP_ENCODE_CTX base64;
    EVP_EncodeInit(&base64);//base64编码初始化
    //编码数据,由于数据不多,所以没有使用循环
    EVP_EncodeUpdate(&base64,//base64编码上下文对象
        outData,//编码后的数据
        outlen, //编码后的数据长度
        data,   //要编码的数据
        datalen //要编码的数据长度
    );
    tmp=*outlen;
    //结束base64编码,事实上此时数据已经编码完全
    EVP_EncodeFinal(&base64,outData+*outlen,outlen);
    *outlen+=tmp;
    outData[*outlen]=0;
    printf("base64编码后:",outData,*outlen);
}

//base64解码
bool decode(unsigned char* outData,
            int * outlen,
            const unsigned char* data,
            int datalen)
{
    int tmp=0,i=0,lines=0,currpos=0;
    EVP_ENCODE_CTX base64;
    EVP_DecodeInit(&base64);//base64解码初始化
	//假定outData缓冲区能够容纳所有的结果
    for (;;)
	{
        currpos+=CHARS_PER_LINE_BASE64*lines++;
		//下面函数的返回值中:i=1 表示还有更多行需要解码
		//i=0 表示没有进一步的数据需要解码
        i=EVP_DecodeUpdate(&base64,//base64解码上下文对象
            outData+tmp,     //解码后的数据
            outlen,          //解码后的数据长度
            data+currpos,    //要解码的数据
            datalen-currpos);//要解码的数据长度
	    if (i < 0)
        {
            printf("解码错误!\n");
            return false;
        }
        tmp+=*outlen;
        if (i == 0) break;//数据结束
    }
    //结束base64解码
    EVP_DecodeFinal(&base64,outData+tmp,outlen);
    *outlen=tmp;
    outData[*outlen]=0;
    print("base64解码后:",outData,*outlen);
    return true;
}

void main(int argc, char *argv[])
{
    const int ITERATIVE_ROUND_FOR_KEY=3;
    unsigned char key[EVP_MAX_KEY_LENGTH];//密钥
    unsigned char iv[EVP_MAX_IV_LENGTH];//初始向量
    EVP_CIPHER_CTX ctx;//加密上下文对象
    unsigned char out[512+8];
    int outl;
    unsigned char txtAfterDecrypt[512];
    int txtLenAfterDecrypt;

    char simpleText[]="Let's pray for peace of our lovely world";
    unsigned char txtAfterBase64[sizeof(simpleText)*3];

    //密码
    const char *passwd="a78b5C";//用于产生密钥的口令字符串
    const EVP_CIPHER *type;//加密类型对象
    OpenSSL_add_all_ciphers();//加载加密算法
    OpenSSL_add_all_digests();//加载摘要计算算法
    printf("密码是:%s\n",passwd);                                                                                                      
    type=EVP_des_ede3_cbc();                                                               
    printf("密钥长度=%d,向量长度=%d\n",type->key_len,type->iv_len);
	//从文本密码中产生 密钥/向量
    //这个例程使用MD5并且采用来自RSA的PCKS#5的标准
    EVP_BytesToKey(type,//密钥类型
        EVP_md5(),//摘要计算类型
        NULL,
        (const unsigned char *)passwd,//口令串
        (int)strlen(passwd),//口令串长度
        ITERATIVE_ROUND_FOR_KEY,//迭代轮数
        key,//输出的密钥
        iv  //输出的初始向量
        );
    //加密初始化,ctx是加密上下文对象
    EVP_EncryptInit(&ctx,type,key,iv);

    int tmp=(int)strlen(simpleText);
    //由于数据量少,不用循环加入数据
	EVP_EncryptUpdate(&ctx,//加密上下文对象
        out,//加密后的内容
        &outl, //加密后的内容长度
        (const unsigned char*)simpleText, //要加密的内容
        (int)strlen(simpleText)  //要加密的内容长度
        );
    tmp=outl;
    //结束加密
    EVP_EncryptFinal(&ctx,out+outl,&outl);
    outl+=tmp;
    //清除加密上下文,因为下文还要重用
    EVP_CIPHER_CTX_cleanup(&ctx);

    print("加密之后的结果:",out,outl);

    //进行base64编码
    encode(txtAfterBase64,&tmp,out,outl);
    memset(out,0,sizeof(out));
    //进行base64解码
    decode(out,&outl,txtAfterBase64,tmp);

	//解密初始化,解密类型,密钥,初始向量必需和加密时相同,否则解密不能成功
    EVP_DecryptInit(&ctx,type,key,iv);

	EVP_DecryptUpdate(&ctx,//解密上下文对象
        txtAfterDecrypt,   //解密后的内容
        &txtLenAfterDecrypt,//解密后的内容长度
        out,                //要解密的内容
        outl                //要解密的内容长度
        );
    tmp=txtLenAfterDecrypt;
    //结束解密
    EVP_DecryptFinal(&ctx,txtAfterDecrypt+txtLenAfterDecrypt,&txtLenAfterDecrypt);
    txtLenAfterDecrypt+=tmp;
    EVP_CIPHER_CTX_cleanup(&ctx);
    txtAfterDecrypt[txtLenAfterDecrypt]=0;

    printf("解密之后(长度=%d):\n[%s]\n",txtLenAfterDecrypt,txtAfterDecrypt);
    printf("click any key to continue.");
	//相当于暂停,观察运行结果
    getchar();
}
 


 


原文链接: http://blog.csdn.net/yincheng01/article/details/7079835

你可能感兴趣的:(VC++网络安全编程范例(9)-基于OPENSSL实现对称算法与BASE64编码)