首页
社区
课程
招聘
[原创]Crypto API 学习笔记三
2006-9-4 15:36 16865

[原创]Crypto API 学习笔记三

jdxyw 活跃值
19
2006-9-4 15:36
16865
Crypto API 学习笔记三
Encoding and Decoding Data
下面逐渐进入主题了,现在来讲讲是如何对数据进行Encoding and Decoding的。依旧是从一段程序中开始。
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);

void main(void)
{
HCRYPTMSG hMsg;                              指向一个消息句柄
BYTE* pbContent;                                                             一个BYTE指针指向消息
DWORD cbContent;                                                             消息长度
DWORD cbEncodedBlob;                          ECODE的BLOB的大小
BYTE *pbEncodedBlob;                           一个BYTE指针指向ENCODE BLOB

DWORD cbData = sizeof(DWORD);                 数据大小
DWORD cbDecoded;                              Decode内容大小
BYTE *pbDecoded;                               指向Decode的指针

pbContent = (BYTE*) "Security is our only business";
cbContent = strlen((char *) pbContent)+1;

printf("The original message => %s\n",pbContent);  

if(cbEncodedBlob = CryptMsgCalculateEncodedLength(
             MY_ENCODING_TYPE,      指定Encode类型,在程序的开头已经预定义了,MY_ENCODING_TYPE 就是 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING
             0,                      // Flags
             CMSG_DATA,                      定义了数据的类型,这里指定为BYTE型的字符串
             NULL,                  
             NULL,                  
             cbContent))               内容的大小
这里的的函数的作用是计算指定消息Encode所需要的最大的长度,通过计算,为一个BLOB分配内存空间。
{
    printf("The length of the data has been calculated. \n");
}
else
{
    MyHandleError("Getting cbEncodedBlob length failed");
}
为encode blob分配内存空间

if(pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob))
{
   printf("Memory has been allocated for the signed message. \n");
}
else
{
   MyHandleError("Memory allocation failed");
}

if(hMsg = CryptMsgOpenToEncode(                 CryptMsgOpenToEncode为Encode,开一个消息
          MY_ENCODING_TYPE,                        Encode类型,文件开始有说明
          0,                       // Flags
          CMSG_DATA,                        指定Message的类型,CMSG_DATA说明类型没用到
          NULL,                                    现在没有到,为NULL
          NULL,                                    同上
          NULL))                                   不是流加密,这个参数为NULL
{
    printf("The message to be encoded has been opened. \n");
}
else
{
     MyHandleError("OpenToEncode failed");
}
if(CryptMsgUpdate(                              CryptMsgUpdate将数据加到消息中,可以通过循环,将数据一段段的加得到消息中
        hMsg,                                  一个小心句柄
        pbContent,                              指向数据的指针
        cbContent,                               数据的大小
        TRUE))                                 TRUE表明这个是最后一段数据,在开个消息的时候,如果CMSG_DETACHED_FLAG有使用到,这设为FALSE,否则为TRUE。
{
     printf("Content has been added to the encoded message. \n");
}
else
{
      MyHandleError("MsgUpdate failed");
}

if(CryptMsgGetParam(                             CryptMsgGetParam是获取一个消息中的参数
               hMsg,                                      一个消息句柄
               CMSG_BARE_CONTENT_PARAM,  指定要获取的参数的类型
               0,                        
               pbEncodedBlob,                   一个接受数据的内存地址
               &cbEncodedBlob))                 BLOB的大小,即是上面接受的数据的大小
{
    printf("Message encoded successfully. \n");
}
else
{
      MyHandleError("MsgGetParam failed");
}
                                                释放消息句柄
if(hMsg)
    CryptMsgClose(hMsg);

if(hMsg = CryptMsgOpenToDecode(                  开个Decode的小心句柄,参数和上面的Encode一样
               MY_ENCODING_TYPE,      
               0,                                   
CMSG_DATA,            
               NULL,                  
               NULL,                 
               NULL))               
{
     printf("The message to decode is open. \n");
}
else
{
    MyHandleError("OpenToDecode failed");
}
下面的过程和Encode类似,调用的函数和上面相同,只不过是过程逆向

printf("\nThe length of the encoded message is %d.\n\n",
    cbEncodedBlob);

if(CryptMsgUpdate(
    hMsg,                 // Handle to the message
    pbEncodedBlob,        // Pointer to the encoded BLOB
    cbEncodedBlob,        // Size of the encoded BLOB
    TRUE))                // Last call
{
      printf("The encoded BLOB has been added to the message. \n");
}
else
{
    MyHandleError("Decode MsgUpdate failed");
}
if(CryptMsgGetParam(                            CryptMsgGetParam的调用和上面有所不同,这里一共是调用两次,第一次的作用主要是得到消息的大小,第二次是得到消息所在的内存地址
                  hMsg,                         消息句柄
                  CMSG_CONTENT_PARAM,    // Parameter type
                  0,                     
                  NULL,                  // Address for returned
                                         // information
                  &cbDecoded))           // Size of the returned
                                         // information
{
    printf("The decoded message size is %d. \n", cbDecoded);
}
else
{
    MyHandleError("Decode CMSG_CONTENT_PARAM failed");
}
if(pbDecoded = (BYTE *) malloc(cbDecoded))
{
     printf("Memory has been allocated for the decoded message.\n");
}
else
{
    MyHandleError("Decoding memory allocation failed.");
}
if(CryptMsgGetParam(
                  hMsg,                  // Handle to the message
                  CMSG_CONTENT_PARAM,    // Parameter type
                  0,                     // Index
                  pbDecoded,             // Address for returned
                                         // information
                  &cbDecoded))           // Size of the returned
                                         // information
{
     printf("The message is %s.\n",(LPSTR)pbDecoded);
}
else
{
     MyHandleError("Decode CMSG_CONTENT_PARAM #2 failed");
}
if(pbEncodedBlob)
   free(pbEncodedBlob);
if(pbDecoded)
   free(pbDecoded);
if(hMsg)
    CryptMsgClose(hMsg);

printf("This program ran to completion without error. \n");

} //  End of main

下面我们来看看如何哈希一个对话密钥,这个密钥可以用来对一个消息,文件进行加密。我们依旧从一个程序开始。
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);

void main()
{

//--------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Declare variables.

HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;

//--------------------------------------------------------------------
// Begin processing.

printf("Process beginning. Creating a session key. \n");

if(CryptAcquireContext(                           首先依旧是获取一个缺省的CSP句柄
   &hCryptProv,
   NULL,
   NULL,
   PROV_RSA_FULL,
   0))
{
    printf("CryptAcquireContext complete. \n");
}
else
{
     MyHandleError("Acquisition of context failed.");
}

if(CryptCreateHash(                                 创建一个CALG_MD5算法的HASH对象,这个hash对象用的是MD5算法
   hCryptProv,                                        指定一个CSP句柄
   CALG_MD5,                                      指定算法
   0,               
   0,
   &hHash))
{
    printf("An empty hash object has been created. \n");
}
else
{
    MyHandleError("Error during CryptBeginHash!\n");
}

if(CryptGenKey(                                        创建密钥
   hCryptProv,                                         传入一个CSP句柄
   CALG_RC2,                                        指明密钥身成所用算法
   CRYPT_EXPORTABLE,                              说明密钥是可以导出到CSP,用于这个应用程序外的
   &hKey))
{
     printf("A random session key has been created. \n");
}
else
{
    MyHandleError("Error during CryptGenKey!\n");
}
if(CryptHashSessionKey(                                   对生成的密钥进行hash
   hHash,
   hKey,
   0))
{
     printf("The session key has been hashed. \n");
}
else
{
    MyHandleError("Error during CryptHashSessionKey!\n");
}
在这里就可以添加代码,用生成的密钥进行加密

if(hHash)
{
   if(!(CryptDestroyHash(hHash)))
       MyHandleError("Error during CryptDestroyHash");
}

if(hKey)
{
   if(!(CryptDestroyKey(hKey)))
       MyHandleError("Error during CryptDestroyKey");
}

// Release the CSP.

if(hCryptProv)
{
   if(!(CryptReleaseContext(hCryptProv,0)))
       MyHandleError("Error during CryptReleaseContext");
}

printf("Create random session key completed without error. \n");
} // end main
附件是DOC文档,希望大家多提宝贵意见

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (13)
雪    币: 338
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
bfqyygy 1 2006-9-4 15:44
2
0
学习!好棒的文章!
雪    币: 115
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
无奈无赖 2006-9-4 20:59
3
0
本人愚昧,Crypto API是什么?
雪    币: 333
活跃值: (11)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
jdxyw 19 2006-9-4 23:10
4
0
Crypto API是微软提供的一套用于加密解密的API
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xoojo 2006-9-5 11:31
5
0
三篇文章都顶了!因为想参加DCG的crackme编写大赛,这个正好用得着!
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinawash 2006-9-5 12:05
6
0
好文章,已经到三了
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Goodmann 2006-9-5 12:16
7
0
请教一下楼主
我的一个程序 用CryptEnCrypt进行的加密 那我用CryptDeCrypt函数能不能解密呢? 如果可以的话 他们的Key是一样的吗? CryptEnCrypt加密的时候用的什么加密算法啊 可逆吗? 如果不可逆的话? 我怎样通过加密的Key 得到 解密的Key呢?
雪    币: 333
活跃值: (11)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
jdxyw 19 2006-9-5 12:52
8
0
最初由 Goodmann 发布
请教一下楼主
我的一个程序 用CryptEnCrypt进行的加密 那我用CryptDeCrypt函数能不能解密呢? 如果可以的话 他们的Key是一样的吗? CryptEnCrypt加密的时候用的什么加密算法啊 可逆吗? 如果不可逆的话? 我怎样通过加密的Key 得到 解密的Key呢?

Key可以一样,也可以不一样,这就看你用的是否是对称算法。加密的算法在你获得密钥句柄的时候需要指定。
雪    币: 236
活跃值: (326)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
gzgzlxg 11 2006-9-5 14:51
9
0
楼主的几篇文章写的非常好,请继续。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Goodmann 2006-9-5 21:46
10
0
谢谢楼主的回复 我又试了一下 还是有点小问题
我用CryptAcquireContext(&hCryptProv,NULL,(const char *)pProviderName,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)
创建了一个CSP,然后用CryptImportKey导入了一个密钥,然后用CryptEnCrypt加密一段数据是成功的.但是再用这些句柄CryptDeCrypt解密加密出来的数据失败
GetLastError返回8009000d错误
// MessageId: NTE_NO_KEY
// MessageText:
//  Key does not exist
#define NTE_NO_KEY   _HRESULT_TYPEDEF_(0x8009000DL)
怎摸会出现这个错误呢?我的密钥句柄创建是成功的啊
还有CRYPT_VERIFYCONTEXT标志是不是就可以说明这个加密可以是双向的啊?
雪    币: 225
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yalcm 2006-10-30 19:08
11
0
三顶
好文好文好文
雪    币: 398
活跃值: (29)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wzjok 1 2009-12-15 12:19
12
0
请问,这些函数,可以用在软件的序列号加密上吗?
比如说:
我在发行的软件里放了一段代码,也就是用Crypto API 来对该软件运行的电脑上,其原始机器码进行加密,软件会在“请注册”的对话框里显示加密后的“变形机器码”;
我则可以通过由用户提供的“用户名”+“变形机器码”,来生成注册号
然后,用户只有在软件的“请注册”对话框里输入我生成的注册号,才可完成注册!
-------
说明:由于,对该算法不太了解,说起话来有点乱,请谅解!
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
blzwowar 2010-8-4 18:01
13
0
这系列的文章只有3篇吗?很不错啊,不继续了??

时间允许的话,作者继续吧。
很感谢你~
雪    币: 416
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jingong 2010-8-10 15:54
14
0
楼主辛苦了。 。
游客
登录 | 注册 方可回帖
返回