`
nwi887nj
  • 浏览: 15817 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

Crypto API 学习笔记

 
阅读更多

Crypto API 学习笔记
2011年07月02日
  微软公司在NT4.0以上版本中提供了一套完整的Crypto API的函数,支持密钥交换,数据加密解密,数字签名,给程序员带来了很大方便,用户在对软件进行保护的时候可以直接利用Crypto API来完成这些工作,比如计算注册码,检查程序的完整性等。
  我们在用这些的API进行加密解密的时候,只需要知道如何去应用它们,而不必知道它们的底层实现。如果想知道它们更为详尽的资料,可以查找相关的资料。
  对Crypto API只是业余型的感兴趣,想通过写学习笔记,一是让自己记的更牢固些,二是想把自己的学的跟大家探讨一下。写的不好,大家多多原谅。我主要通过MSDN来学习,例子也是完全取自MSDN。
  首先,是Crypto API运行的环境。
  首先需要Crypt32.lib,将它加到project->setting->link下面,当然你也可以在程序中用#pragma comment (lib, "crypt32.lib")加入。
  在程序开头,你要加入两个头文件 windows.h 和 Wincrypt.h,和一个#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  在正式应用API进行一系列的加密解密的时候,需要有一些准备工作,下面是介绍一些在正式开始时所需要了解和做的工作。
  生成密钥和密钥容器
  我们知道,在进行加密解密的时候,我们需要一个密钥进行加密,和一个密钥进行解密,加密密钥和解密密钥可能相同,也可能不同。于是在我们进行加密解密的开始时,我们首先需要有密钥。下面这个程序,完成了三个任务,并且介绍了一些函数的用法。
  任务一:获取一个指定的密钥容器,如果这个容器不存在,创建一个。
  任务二:如果容器中不存在一个签名密钥对,创建一个
  任务三:如果容器中不存在一个交换密钥对,创建一个
  //-------------------------------------------------------------------
  下面这段程序使用到了这几个函数
  CryptAcquireContext
  CryptDestroyKey
  CryptGenKey
  CryptGetUserKey
  // Copyright (c) Microsoft Corporation. All rights reserved.
  #include
  #include
  #include
  #include
  //-------------------------------------------------------------------
  void MyHandleError(LPTSTR psz)
  {
  _ftprintf(stderr, TEXT("An error occurred in the program. \n"));
  _ftprintf(stderr, TEXT("%s\n"), psz);
  _ftprintf(stderr, TEXT("Error number %x.\n"), GetLastError());
  _ftprintf(stderr, TEXT("Program terminating. \n"));
  exit(1);
  } // End of MyHandleError.
  上面这个函数是一个异常处理函数,当出现错误的时候,出现提示,并推出程序。以后的程序中都有这个函数,以后就会将这个函数的实现省去。现在这个函数的实现在后面。
  void main(void)
  {
  HCRYPTPROV hCryptProv; //定义一个CSP模块的句柄。“CSP模块,请查看《加密解密二》222页,那里有简单的说明,这里就不说了。
  LPCTSTR pszContainerName = TEXT("My Sample Key Container");//用一个TEXT宏定义一个容器的名字,
  if(CryptAcquireContext( //这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE。
  &hCryptProv, //指向一个CSP模块句柄指针,里面用指定的容器
  pszContainerName, //指定容器的名称
  NULL, //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块
  PROV_RSA_FULL, //确定密钥的类型
  0)) //常设为0,还有些其他的类型,请看MSDN
  {
  _tprintf(
  TEXT("A crypto context with the %s key container ")
  TEXT("has been acquired.\n"),
  pszContainerName);
  }
  else
  {
  //不成功的处理段
  if(GetLastError() == NTE_BAD_KEYSET) // NTE_BAD_KEYSET意味着密钥
  //容器不存在,下面就去创建一个
  //新的密钥容器
  {
  if(CryptAcquireContext(
  &hCryptProv,
  pszContainerName,
  NULL,
  PROV_RSA_FULL,
  CRYPT_NEWKEYSET)) // CRYPT_NEWKEYSET意味着当指定容器不存在的时候,去创建一个容器。
  {
  _tprintf(TEXT("A new key container has been ")
  TEXT("created.\n"));
  }
  else
  {
  MyHandleError(TEXT("Could not create a new key ")
  TEXT("container.\n"));
  }
  }
  else
  {
  MyHandleError(TEXT("CryptAcquireContext failed.\n"));
  }
  }
  HCRYPTKEY hKey; //创建一个密钥句柄
  if(CryptGetUserKey( // CryptGetUserKey是获取一个密钥//句柄的函数,成功返回TRUE
  hCryptProv, //指定容器的CSP模块句柄
  AT_SIGNATURE, //指定私钥的类型
  &hKey)) //原来接收获取的密钥句柄
  {
  _tprintf(TEXT("A signature key is available.\n"));
  }
  else
  {
  _tprintf(TEXT("No signature key is available.\n"));
  if(GetLastError() == NTE_NO_KEY) // NTE_NO_KEY意味着密钥不存在,下面就生成一个密钥
  {
  _tprintf(TEXT("The signature key does not exist.\n"));
  _tprintf(TEXT("Create a signature key pair.\n"));
  if(CryptGenKey( // CryptGenKey生成一个密钥
  hCryptProv, //指定CSP模块的句柄
  AT_SIGNATURE, //对于公钥密码系统,生成一个私钥和一个公钥,这个参数指定了这个密钥是公钥,于是生成了一个密码对。如果不是公钥系统,则指定了密码算法,具体看MSDN。
  0, //指定了生成密钥的类型,这个参数的说明挺多的,想获取更为详尽的资料请看MSDN。
  &hKey))
  {
  _tprintf(TEXT("Created a signature key pair.\n"));
  }
  else
  {
  MyHandleError(TEXT("Error occurred creating a ")
  TEXT("signature key.\n"));
  }
  }
  else
  {
  MyHandleError(TEXT("An error other than NTE_NO_KEY ")
  TEXT("getting a signature key.\n"));
  }
  } // End if.
  _tprintf(TEXT("A signature key pair existed, or one was ")
  TEXT("created.\n\n"));
  if(hKey) //将密钥句柄销毁
  {
  if(!(CryptDestroyKey(hKey)))
  {
  MyHandleError(TEXT("Error during CryptDestroyKey."));
  }
  hKey = NULL;
  }
  下面这部分和上面是类似的,只不过密钥类型不相同而已。
  if(CryptGetUserKey(
  hCryptProv,
  AT_KEYEXCHANGE,
  &hKey))
  {
  _tprintf(TEXT("An exchange key exists.\n"));
  }
  else
  {
  _tprintf(TEXT("No exchange key is available.\n"));
  // Check to determine whether an exchange key
  // needs to be created.
  if(GetLastError() == NTE_NO_KEY)
  {
  // Create a key exchange key pair.
  _tprintf(TEXT("The exchange key does not exist.\n"));
  _tprintf(TEXT("Attempting to create an exchange key ")
  TEXT("pair.\n"));
  if(CryptGenKey(
  hCryptProv,
  AT_KEYEXCHANGE,
  0,
  &hKey))
  {
  _tprintf(TEXT("Exchange key pair created.\n"));
  }
  else
  {
  MyHandleError(TEXT("Error occurred attempting to ")
  TEXT("create an exchange key.\n"));
  }
  }
  else
  {
  MyHandleError(TEXT("An error other than NTE_NO_KEY ")
  TEXT("occurred.\n"));
  }
  }
  // Destroy the exchange key.
  if(hKey)
  {
  if(!(CryptDestroyKey(hKey)))
  {
  MyHandleError(TEXT("Error during CryptDestroyKey."));
  }
  hKey = NULL;
  }
  // Release the CSP.
  if(hCryptProv)
  {
  if(!(CryptReleaseContext(hCryptProv, 0)))
  {
  MyHandleError(TEXT("Error during CryptReleaseContext."));
  }
  }
  _tprintf(TEXT("Everything is okay. A signature key "));
  _tprintf(TEXT("pair and an exchange key exist in "));
  _tprintf(TEXT("the %s key container.\n"), pszContainerName);
  } // End main.
  下面我们再通过一个程序,用几种不同的方法,将CryptAcquireContext和其他的API函数联系起来,看看它们是如何与一个CSP和容器工作的。这个程序演示了以下内容和几个函数。
  一. 用CryptAcquireContext获取一个缺省容器的缺省CSP的句柄。如果缺省容器不存在,用CryptAcquireContext创建一个。
  二. 用CryptGetProvParam获取CSP和容器的信息。
  三. 用CryptContextAddRef增加CSP的引用计数器的数值。
  四. 用CryptAcquireContext创建一个指定的容器
  五. 用CryptAcquireContext删除一个容器
  六. 用一个新创建的容器获取一个CSP的句柄。
  #include
  #include
  #include
  #include
  异常处理函数省略
  void main(void)
  {
  HCRYPTPROV hCryptProv; //定义CSP句柄
  if(CryptAcquireContext(
  &hCryptProv,
  NULL, //缺省容器
  NULL, //缺省CSP
  PROV_RSA_FULL,
  0))
  {
  _tprintf(TEXT("CryptAcquireContext succeeded.\n"));
  }
  else
  {
  if (GetLastError() == NTE_BAD_KEYSET) //同样,如果当不存在这样的容器的时候,创建一个
  {
  if(CryptAcquireContext(
  &hCryptProv,
  NULL,
  NULL,
  PROV_RSA_FULL,
  CRYPT_NEWKEYSET))
  {
  _tprintf(TEXT("CryptAcquireContext succeeded.\n"));
  }
  else
  {
  MyHandleError(TEXT("Could not create the default ")
  TEXT("key container.\n"));
  }
  }
  else
  {
  MyHandleError(TEXT("A general error running ")
  TEXT("CryptAcquireContext."));
  }
  }
  CHAR pszName[1000];
  DWORD cbName;
  cbName = 1000;
  if(CryptGetProvParam(
  hCryptProv, //CSP模块句柄
  PP_NAME, //指定获取哪些信息,这里是指定获取CSP名字的信息
  (BYTE*)pszName, //缓冲区接受信息返回值
  &cbName,
  0))
  {
  _tprintf(TEXT("CryptGetProvParam succeeded.\n"));
  printf("Provider name: %s\n", pszName);
  }
  else
  {
  MyHandleError(TEXT("Error reading CSP name.\n"));
  }
  //---------------------------------------------------------------
  // Read the name of the key container.
  cbName = 1000;
  if(CryptGetProvParam(
  hCryptProv,
  PP_CONTAINER, //获取容器名字
  (BYTE*)pszName,
  &cbName,
  0))
  {
  _tprintf(TEXT("CryptGetProvParam succeeded.\n"));
  printf("Key Container name: %s\n", pszName);
  }
  else
  {
  MyHandleError(TEXT("Error reading key container name.\n"));
  }
  if(CryptContextAddRef( // CryptContextAddRef是向一个CSP的引用计数器增加一个值的函数
  hCryptProv,
  NULL, //保留值,必须为NULL
  0)) //保留值,必须为0
  {
  _tprintf(TEXT("CryptcontextAddRef succeeded.\n"));
  }
  else
  {
  MyHandleError(TEXT("Error during CryptContextAddRef!\n"));
  }
  //---------------------------------------------------------------
  // The reference count on hCryptProv is now greater than one.
  // The first call to CryptReleaseContext will not release the
  // provider handle.
  //---------------------------------------------------------------
  // Release the context once.
  if (CryptReleaseContext(hCryptProv, 0)) // CryptReleaseContext是用来释放CSP句柄的,当这个函数调用一次的时候,CSP里面的引用计数就减少一,当引用计数减少的0的时候。CSP将不能再被这个程序中的任何函数调用了。
  {
  _tprintf(TEXT("The first call to CryptReleaseContext ")
  TEXT("succeeded.\n"));
  }
  else
  {
  MyHandleError(TEXT("Error during ")
  TEXT("CryptReleaseContext #1!\n"));
  }
  if (CryptReleaseContext(hCryptProv, 0)) //再次释放CSP模块
  {
  _tprintf(TEXT("The second call to CryptReleaseContext ")
  TEXT("succeeded.\n"));
  }
  else
  {
  MyHandleError(TEXT("Error during ")
  TEXT("CryptReleaseContext #2!\n"));
  }
  下面是从PROV_RSA_FULL的CSP模块中创建一个自己的容器
  LPCTSTR pszContainerName = TEXT("My Sample Key Container");
  hCryptProv = NULL;
  if(CryptAcquireContext(
  &hCryptProv,
  pszContainerName,
  NULL,
  PROV_RSA_FULL,
  CRYPT_NEWKEYSET))
  {
  _tprintf(TEXT("CryptAcquireContext succeeded. \n"));
  _tprintf(TEXT("New key set created. \n"));
  //-----------------------------------------------------------
  // Release the provider handle and the key container.
  if(hCryptProv)
  {
  if(CryptReleaseContext(hCryptProv, 0))
  {
  hCryptProv = NULL;
  _tprintf(TEXT("CryptReleaseContext succeeded. \n"));
  }
  else
  {
  MyHandleError(TEXT("Error during ")
  TEXT("CryptReleaseContext!\n"));
  }
  }
  }
  else
  {
  if(GetLastError() == NTE_EXISTS)
  {
  _tprintf(TEXT("The named key container could not be ")
  TEXT("created because it already exists.\n"));
  }
  else
  {
  MyHandleError(TEXT("Error during CryptAcquireContext ")
  TEXT("for a new key container."));
  }
  }
  if(CryptAcquireContext(
  &hCryptProv,
  pszContainerName,
  NULL,
  PROV_RSA_FULL,
  0))
  {
  _tprintf(TEXT("Acquired the key set just created. \n"));
  }
  else
  {
  MyHandleError(TEXT("Error during CryptAcquireContext!\n"));
  }
  //---------------------------------------------------------------
  // Perform cryptographic operations.
  //---------------------------------------------------------------
  if(CryptReleaseContext(
  hCryptProv,
  0))
  {
  _tprintf(TEXT("CryptReleaseContext succeeded. \n"));
  }
  else
  {
  MyHandleError(TEXT("Error during CryptReleaseContext!\n"));
  }
  if(CryptAcquireContext(
  &hCryptProv,
  pszContainerName,
  NULL,
  PROV_RSA_FULL,
  CRYPT_DELETEKEYSET)) //CRYPT_DELETEKEYSET意味着CryptAcquireContex删除一个指定的容器
  {
  _tprintf(TEXT("Deleted the key container just created. \n"));
  }
  else
  {
  MyHandleError(TEXT("Error during CryptAcquireContext!\n"));
  }
  }
  前面学习了密钥容器的建立的一些知识,现在我们接下来自然是学习如何获取一个密钥,首先是获取一个session key,即对话密钥,是对称密钥。
  这些学习笔记主要是从MSDN中的例子中,学习基本的Cryptography API的用法,了解一些用法的过程。欢迎大家多提宝贵意见。
  下面依旧是从一个小程序开始。这个程序的学习任务有以下几个:
  任务一:调用CryptAcquireContext,获取一个缺省CSP和缺省密钥容器的句柄
  任务二:用CryptCreateHash去创建一个空的哈希对象
  任务三:用CryptHashData.哈希密码
  任务四:调用CryptDeriveKey获取一个对话密钥
  任务五:销毁密码和哈希后的数据
  任务六:释放CSP
  #include
  #include
  #include
  #include
  #include
  #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  void MyHandleError(char *s);
  void GetConsoleInput(char*, int);
  void main()
  {
  HCRYPTPROV hCryptProv; 定义CSP句柄
  HCRYPTKEY hKey; 定义密钥句柄
  HCRYPTHASH hHash; 定义一个HASH对象的句柄
  CHAR szPassword[512] = ""; 定义512大小的字符数组,用来保存密码
  DWORD dwLength; 保存密码长度
  fprintf(stderr,"Enter a password to be used to create a key:");
  GetConsoleInput(szPassword, 512); 获取密码,这个是自己写的函数,目的是在屏幕上显示的是*。
  printf("The password has been stored.\n");
  dwLength = strlen(szPassword);
  if(CryptAcquireContext( 以下是获取一个缺省的PROV_RSA_FULL CSP 句柄
  &hCryptProv,
  NULL,
  NULL,
  PROV_RSA_FULL,
  0))
  {
  printf("A context has been acquired. \n");
  }
  else
  {
  MyHandleError("Error during CryptAcquireContext!");
  }
  //--------------------------------------------------------------------
  if(CryptCreateHash( 调用CryptCreateHash创建一个HASH对象
  hCryptProv, 一个CSP句柄
  CALG_MD5, 确定哈希算法
  0, 对于非密钥算法,这个参数一定是0,如果是密钥算法,那么这个参数就是密钥
  0, 保留参数,为0
  &hHash)) 一个哈希对象的指针
  {
  printf("An empty hash object has been created. \n");
  }
  else
  {
  MyHandleError("Error during CryptCreateHash!");
  }
  //--------------------------------------------------------------------
  if(CryptHashData( 调用CryptHashData哈希密码
  hHash, 哈希对象
  (BYTE *)szPassword, 指向缓冲区的地址
  dwLength, 密码长度
  0))
  {
  printf("The password has been hashed. \n");
  }
  else
  {
  MyHandleError("Error during CryptHashData!");
  }
  //--------------------------------------------------------------------
  if(CryptDeriveKey( 调用CryptDeriveKey获取对话密码
  hCryptProv, CSP句柄
  CALG_RC2, 一个ALG_ID结构,用来指定对称密钥生成的算法
  hHash, 哈希对象
  CRYPT_EXPORTABLE, 指定生成密钥的类型,CRYPT_EXPORTABLE意味着这个程序生成的密钥可以被其它程序调用,而不是仅仅限于这个程序当中。但是它不能用于非对称密码中。
  &hKey))
  {
  printf("The key has been derived. \n");
  }
  else
  {
  MyHandleError("Error during CryptDeriveKey!");
  }
  if(hHash) 销毁哈希对象
  {
  if(!(CryptDestroyHash(hHash)))
  MyHandleError("Error during CryptDestroyHash");
  }
  if(hKey) 销毁密钥句柄
  {
  if(!(CryptDestroyKey(hKey)))
  MyHandleError("Error during CryptDestroyKey");
  }
  if(hCryptProv) 销毁CSP句柄
  {
  if(!(CryptReleaseContext(hCryptProv, 0)))
  MyHandleError("Error during CryptReleaseContext");
  }
  printf("The program to derive a key completed without error. \n");
  } // end main
  void MyHandleError函数的实现省略,在上一篇中有
  void GetConsoleInput(char* strInput,
  int intMaxChars)
  {
  char ch;
  char minChar = ' ';
  minChar++;
  ch = getch();
  while (ch != '\r')
  {
  if (ch == '\b' && strlen(strInput) > 0)
  {
  strInput[strlen(strInput)-1] = '\0';
  printf("\b \b");
  }
  else if (ch >= minChar && strlen(strInput)
  #include
  #include
  #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  void MyHandleError(char *s);
  void main()
  {
  //-------------------------------------------------------------------
  // Declare and initialize variables.
  HCRYPTPROV hCryptProv; CSP句柄
  HCRYPTKEY hOriginalKey; 源密钥句柄
  HCRYPTKEY hDuplicateKey; 复制后的密钥句柄
  DWORD dwMode;
  BYTE pbData[16];
  printf("This program creates a session key and duplicates \n");
  printf("that key. Next, parameters are added to the original \n");
  printf("key. Finally, both keys are destroyed. \n\n");
  if(CryptAcquireContext( 获取CSP句柄,前面叙述过了,这里就不叙述了
  &hCryptProv,
  NULL,
  NULL,
  PROV_RSA_FULL,
  0))
  {
  printf("CryptAcquireContext succeeded. \n");
  }
  else
  {
  MyHandleError("Error during CryptAcquireContext!\n");
  }
  //-------------------------------------------------------------------
  if (CryptGenKey( 生成一个CALG_RC4算法生成的密钥,保存在hOriginalKey中
  hCryptProv,
  CALG_RC4, ALG_ID结构,指定生成这个密钥使用的算法
  0,
  &hOriginalKey))
  {
  printf("Original session key is created. \n");
  }
  else
  {
  MyHandleError("ERROR - CryptGenKey.");
  }
  if (CryptDuplicateKey( 复制密钥
  hOriginalKey, 源密钥
  NULL, 保留参数,必须为NULL
  0, 保留参数,必须为0
  &hDuplicateKey)) 副本密钥
  {
  printf("The session key has been duplicated. \n");
  }
  else
  {
  MyHandleError("ERROR - CryptDuplicateKey");
  }
  给源密钥设置附加参数
  dwMode = CRYPT_MODE_ECB; CRYPT_MODE_ECB是一个没有反馈的块加密模式
  if(CryptSetKeyParam(
  hOriginalKey,
  KP_MODE, 指定密钥的某种属性被改变,
  KP_MODE意味着改变的是加密模式
  (BYTE*)&dwMode, 指向一个已经被初始化的缓冲区
  0))
  {
  printf("Key Parameters set. \n");
  }
  else
  {
  MyHandleError("Error during CryptSetKeyParam.");
  }
  if(CryptGenRandom( 随机填充一块缓冲区
  hCryptProv, CSP句柄
  8, 缓冲区大小
  pbData)) 缓冲区地址
  {
  printf("Random sequence generated. \n");
  }
  else
  {
  MyHandleError("Error during CryptGenRandom.");
  }
  if(CryptSetKeyParam( 再次给密钥设置属性
  hOriginalKey,
  KP_IV, KP_IV意味着,这个函数的第三个参数指向一个BYTE数组,数组大小为块大小/8。
  pbData,
  0))
  {
  printf("Parameter set with random sequence as "
  "initialization vector. \n");
  }
  else
  {
  MyHandleError("Error during CryptSetKeyParam.");
  }
  //-------------------------------------------------------------------
  if (hOriginalKey) 以下依次销毁,释放源密钥句柄,副本句柄,CSP句柄,
  if (!CryptDestroyKey(hOriginalKey))
  MyHandleError("Failed CryptDestroyKey\n");
  if (hDuplicateKey)
  if (!CryptDestroyKey(hDuplicateKey))
  MyHandleError("Failed CryptDestroyKey\n");
  if(hCryptProv)
  if (!CryptReleaseContext(hCryptProv, 0))
  MyHandleError("Failed CryptReleaseContext\n");
  printf("\nThe program ran to completion without error. \n");
  } // End of main.
  当我们已经生成了一个密钥,我们下面要做的是如何保存,导出,导入一个对话密钥。将一个密钥保存起来,导出,保存到硬盘上。这样,这个密钥就可以在其它应用程序上使用,而不会随着生成密钥程序的关闭而丢失了。
  下面这段程序就是用来演示如何保存,导出一个对话密钥的。
  #include
  #include
  #include
  #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  void MyHandleError(char *s);
  void main(void)
  {
  //--------------------------------------------------------------------
  // Declare and initialize variables.
  HCRYPTPROV hProv; // CSP handle
  HCRYPTKEY hSignKey; // Signature key pair handle
  HCRYPTKEY hXchgKey; // Exchange key pair handle
  HCRYPTKEY hKey; // Session key handle
  BYTE *pbKeyBlob; // Pointer to a simple key BLOB
  DWORD dwBlobLen; // The length of the key BLOB
  //--------------------------------------------------------------------
  // Acquire a cryptographic provider context handle.
  if(CryptAcquireContext( 获取一个缺省容器的CSP句柄
  &hProv,
  NULL,
  NULL,
  PROV_RSA_FULL,
  0))
  {
  printf("The CSP has been acquired. \n");
  }
  else
  {
  MyHandleError("Error during CryptAcquireContext.");
  }
  if(CryptGetUserKey( 获取一个AT_SIGNATURE类型的密钥句柄
  hProv,
  AT_SIGNATURE,
  &hSignKey))
  {
  printf("The signature key has been acquired. \n");
  }
  else
  {
  MyHandleError("Error during CryptGetUserKey for signkey.");
  }
  //--------------------------------------------------------------------
  if(CryptGetUserKey( 获取一个AT_KEYEXCHANGE,类型的密钥句柄,保存在hXchgKey中
  hProv,
  AT_KEYEXCHANGE,
  &hXchgKey))
  {
  printf("The key exchange key has been acquired. \n");
  }
  else
  {
  printf("Error during CryptGetUserKey exchange key.");
  }
  // Generate a session key.
  if (CryptGenKey( 生成一个CRYPT_EXPORTABLE(可导出的),CALG_RC4(指定算法)的密钥,保存在hKey
  hProv,
  CALG_RC4,
  CRYPT_EXPORTABLE,
  &hKey))
  {
  printf("Original session key is created. \n");
  }
  else
  {
  MyHandleError("ERROR -- CryptGenKey.");
  }
  if(CryptExportKey( CryptExportKey导出一个密钥
  hKey, 将要导出的密钥的句柄
  hXchgKey, 用户最终使用到的密钥的句柄
  SIMPLEBLOB, 指定BLOB的类型,SIMPLEBLOB说明是 用来导出对话密钥的
  0, 指定密钥的附加属性
  NULL,
  &dwBlobLen)) 当时这个函数在这里的主要
  目的是得到这个BLOB的长度
  {
  printf("Size of the BLOB for the session key determined. \n");
  }
  else
  {
  MyHandleError("Error computing BLOB length.");
  }
  if(pbKeyBlob = (BYTE*)malloc(dwBlobLen))
  {
  printf("Memory has been allocated for the BLOB. \n");
  }
  else
  {
  MyHandleError("Out of memory. \n");
  }
  if(CryptExportKey( 这是这个函数才是真正的导出密钥
  hKey,
  hXchgKey,
  SIMPLEBLOB,
  0,
  pbKeyBlob,
  &dwBlobLen))
  {
  printf("Contents have been written to the BLOB. \n");
  }
  else
  {
  MyHandleError("Error during CryptExportKey.");
  }
  free(pbKeyBlob); 释放内存
  // Destroy the session key.
  if(hKey)
  CryptDestroyKey(hKey);
  // Destroy the signature key handle.
  if(hSignKey)
  CryptDestroyKey(hSignKey);
  // Destroy the key exchange key handle.
  if(hXchgKey)
  CryptDestroyKey(hXchgKey);
  // Release the provider handle.
  if(hProv)
  CryptReleaseContext(hProv, 0);
  printf("The program ran to completion without error. \n");
  }
  Encoding and Decoding Data
  下面逐渐进入主题了,现在来讲讲是如何对数据进行Encoding and Decoding的。依旧是从一段程序中开始。
  #include
  #include
  #include
  #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
  #include
  #include
  #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
分享到:
评论

相关推荐

    学习cryptoapi的笔记

    这里介绍一些CryptoAPI的知识,也是让自己对CryptoAPI做一个系统的总结(针对证书操作这块)。 微软加密服务体系 微软加密服务体系CryptoAPI的结构如下图所示,微软加密服务体系包含三层结构和两个接口,分别为应用...

    Delphi使用CryptoAPI生成证书及PHP(openssl)端签名验签

    Delphi使用CryptoAPI生成自签名证书,PHP端使用该证书进行签名,Delphi作为客户端使用公钥进行验签。

    CryptoAPI ukey获取证书以及签名流程

    本文整理了如何使用CryptoAPI 操作ukey进行数字签名。附上流程和部分代码,讲解cryptoapi实际应用以及应用中关键问题的解决方法,在这里,仅介绍数字签名(加密流程类似,但是,操作略有不同,所需要的函数也不同),...

    CryptoAPI培训教程

    CryptoAPI培训教程,包含了所有CryptoAPI函数介绍、CryptoAPI编程实例等等。

    用 Microsoft CryptoAPI对数据进行加解密

    用 Microsoft CryptoAPI对数据进行加解密.pdf

    基于CryptoAPI 的数据加解密文件.rar

    *CryptoAPI数据加解密,它的流程为: *(加密模块)1.创建会话密钥 2.加密数据 3.安全保存或交换会话密钥 *(解密模块)1.获取会话密钥 2.解密数据 *它的加密是基于对称加密算法的(对称算法加密解密速度快),对...

    CryptoAPI实例源码

    CryptoAPI实例源码,学CryptoAPI看看吧,有帮助

    MicroSoft CSP CryptoAPI教程

    CryptoAPI(一个应用程序编程接口)目的就是提供开发者在Windows下使用PKI的编程接口。CryptoAPI提供了很多函数,包括编码、解码、加密、解密、哈希、数字证书、证书管理和证书存储等功能。对于加密和解密,Crypto...

    windows的cryptoapi接口

    CryptoAPI培训教程.pdf 在VC中用CryptoAPI保证安全数据通信.pdf

    CryptoAPI例子

    这里介绍一些CryptoAPI的知识,也是让自己对CryptoAPI做一个系统的总结(针对证书操作这块)。 (1) 微软加密服务体系 微软加密服务体系CryptoAPI的结构如下图所示,微软加密服务体系包含三层结构和两个接口,分别...

    Microsoft CryptoAPI加密技术 源代码.zip

    Microsoft CryptoAPI加密技术 源代码.zip

    CryptoAPI例子代码

    CryptoAPI加密解密代码,vc6.0工程源代码,可以正常加密解密

    C语言下CryptoAPI加密系统

    C语言编写的,利用下CryptoAPI加密系统,代码有详细注释。

    crypto_cryptoapi.rar_CRYPTO_Crypto++_cryptoAPI

    Crypto wrapper for Microsoft CryptoAPI.

    用CryptoAPI生成密钥的方法

    用CryptoAPI生成密钥的方法.pdf

    CryptoAPI证书操作函数

    利用CryptoAPI函数产生根证书,证书请求,由根证书对证书请求签发证书,并提供下载。编译环境为VS2008。VC++6.0编译不过。

    CryptoApi封装库

    根据相关资料和示例,总结的基于微软CryptoApi封装的库。包含创建根证书、用户证书、安装根证书、创建私钥公钥、微缩图算法、证书保存到文件、导入证书库、显示证书信息,创建证书请求、查找证书...... 压缩中,还...

    信息安全实验:利用Windows CryptoAPI开发加解密工具软件

    这是一次大三的信息安全的实验,利用CryptoAPI 实现对称密钥加密、公钥密钥加密和数字签名,还有良好的界面,使用VS2008开发的,里面包含全部的源代码。希望能和大家相互交流学习。

    在VC++中用CryptoAPI保证安全数据通信

    在VC++中用CryptoAPI保证安全数据通信.pdf,论文

Global site tag (gtag.js) - Google Analytics