为什么 MS CryptoAPI 中的 CryptDecrpyt() 不能在远程系统上正确解密前 16 个字节?

如何解决为什么 MS CryptoAPI 中的 CryptDecrpyt() 不能在远程系统上正确解密前 16 个字节?

我试图想出如何使用 MS CryptoAPI 创建会话密钥并传输到远程,以便他们可以加密通过专用网络发送的数据(所以不用担心中间人,只是数据包嗅探器) .还需要支持Windows XP。我想我已经弄清楚了其中的大部分,并建立了一个类来做我需要的事情。但是,当我将 2604 字节的明文加密为 2608 的密文,然后在导入会话密钥的同一台机器(“机器 A”)上解密时,它工作正常,但是在另一台机器上(实际创建会话密钥的机器),"Machine B") 解密该数据不能正确解密前 16 个字节(第一个块)。

我所做的是让机器 A 将公钥发送给机器 B,机器 B 创建一个随机会话密钥,然后将其导出并发送给机器 A,机器 A 导入该密钥。

Machine A                                   Machine B
------------------------------------------  -------------------------------------------
Initialize();                               Initialize();
                                            CreateRandomSessionKey();
ExportPublicKey();
                                            ExportSessionKey();
ImportSessionKey();
CalcSizeForInPlaceEncryption(4604);
[create 4608 byte buffer with plaintext]
EncryptData(); *In Place*
DecryptData(); *New Buffer*                 
                                            DecryptData(); *In Place*
[Decrypted data matches.]                   [Decrypted data first 16 bytes invalid.]
                                            [Input of encrypted data matchines Machine A]

这是我曾经做过的课程:

头文件:

#include <wincrypt.h>

class CMSCryptoAPI
{
  protected:
    HCRYPTPROV m_hCryptProv=NULL;        // crypto provider
    HCRYPTKEY m_hSessionKey=NULL;        // the symmetric key (session key)
    DWORD m_dwSessionKeyBlockSize=0;     // block size for encryption
  
    HCRYPTKEY CreateExchangeKey();
    bool ExportKey(HCRYPTKEY hkey,HCRYPTKEY hexpkey,DWORD blobtype,BYTE** pblob,DWORD* blobsize);
    DWORD GetSessionKeyBlockSize();

  public:
    virtual ~CMSCryptoAPI();

    // initialize before using class object
    bool Initialize();
    // uninitialize the initialization
    bool Uninitialize();

    bool DestroySessionKey();
    bool CreateRandomSessionKey();
    bool ExportSessionKey(const BYTE* publickeyblob,DWORD publickeyblobsize,DWORD* blobsize);
    bool ImportSessionKey(const BYTE* pkeyblob,DWORD keyblobsize);
    bool ExportPublicKey(BYTE** pblob,DWORD* blobsize);
    bool EncryptData(BYTE* ppaintext,DWORD plaintextsize,BYTE** pciphertext,DWORD* ciphertextsize);
    bool DecryptData(BYTE* pciphertext,DWORD ciphertextsize,BYTE** ppaintext,DWORD *plaintextsize);
    bool SetIV(BYTE* pbiv=NULL);

    DWORD CalcSizeForInPlaceEncryption(DWORD plaintextsize);
};

源文件:

// Link with the Advapi32.lib file.
#pragma comment (lib,"advapi32")

#define KEYLENGTHSHIFT 16
#define KEYLENGTH      4096

//-------------------------------------------------------------------------
// Purpose: Destructor
//
// Input:   
//
// Output:    
//
// Notes:   
//
CMSCryptoAPI::~CMSCryptoAPI()
{
  Uninitialize();
}

//-------------------------------------------------------------------------
// Purpose: Initialize the object
//
// Input:   na
//
// Output:  true/false restult
//
// Notes:   must be called first before using any of the other functions
//
bool CMSCryptoAPI::Initialize()
{
  // acquire the provider to use
  if (!CryptAcquireContext(&m_hCryptProv,NULL,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,0)) {
    // user may not have key set like the local system account so try machine set
    if (GetLastError()==NTE_BAD_KEYSET) {
      if (!CryptAcquireContext(&m_hCryptProv,CRYPT_MACHINE_KEYSET)) {
        if (GetLastError()==NTE_BAD_KEYSET) {
          if (!CryptAcquireContext(&m_hCryptProv,CRYPT_NEWKEYSET)) {
            CDebugPrint::DebugPrint(_T("Error %u during CryptAcquireContext for new keyset!\n"),GetLastError());
            return false;
          }
          else CDebugPrint::DebugPrint(_T("Created new keyset for CryptAcquireContext!\n"));
        }
        else {
          CDebugPrint::DebugPrint(_T("Error %u during CryptAcquireContext for machine set!\n"),GetLastError());
          return false;
        }
      }
      else CDebugPrint::DebugPrint(_T("Using the Machine Key Set\n"));
    }
    else {
      CDebugPrint::DebugPrint(_T("Error %u during CryptAcquireContext for user!\n"),GetLastError());
      return false;
    }
  }
  return true;
}

//-------------------------------------------------------------------------
// Purpose: Clean up object to release resources
//
// Input:   na
//
// Output:  true/false result
//
// Notes:   
//
bool CMSCryptoAPI::Uninitialize()
{
  if (DestroySessionKey()) {
  // now release crypto context
    if (m_hCryptProv) {
      if (!CryptReleaseContext(m_hCryptProv,0)) {
        CDebugPrint::DebugPrint(_T("Error %u release context!\n"),GetLastError());
      }
      else m_hCryptProv=NULL;
    }
  }

  return m_hCryptProv==NULL;
}

//-------------------------------------------------------------------------
// Purpose: Destroy the session key if it exists
//
// Input:   na
//
// Output:  true / false result of it being destroyed
//
// Notes:   true is returned if it never existed
//
bool CMSCryptoAPI::DestroySessionKey()
{
  if (m_hSessionKey) {
    if (!CryptDestroyKey(m_hSessionKey)) {
      CDebugPrint::DebugPrint(_T("Error %u destroying session key!\n"),GetLastError());
    }
    else m_hSessionKey=NULL;
  }

  return m_hSessionKey==NULL;
}

//-------------------------------------------------------------------------
// Purpose: Create a session key using random data
//
// Input:   na
//
// Output:  true/false result
//
// Notes:   
//
bool CMSCryptoAPI::CreateRandomSessionKey()
{
  bool result=false;
  if (DestroySessionKey()) {
  // Create a random session key. 
    if (CryptGenKey(m_hCryptProv,CALG_AES_128,CRYPT_EXPORTABLE,&m_hSessionKey)) {
      // now populate IV
      result=SetIV();
    }
    else CDebugPrint::DebugPrint(_T("Error %u creating session key\n"),GetLastError());
  }

  return result;
}

//-------------------------------------------------------------------------
// Purpose: Import the session key from remote
//
// Input:   pkeyblob      - [i] the session key blob from remote
//          keyblobsize   - [i] size of the session key blob
//
// Output:  true/false result
//
// Notes:   
//
bool CMSCryptoAPI::ImportSessionKey(const BYTE* pkeyblob,DWORD keyblobsize)
{
  bool result=false;

  if (DestroySessionKey()) {
    // Get the handle to the exchange key. 
    HCRYPTKEY rsakeypair=CreateExchangeKey();
    if (rsakeypair) {
      // import the blob
      if (CryptImportKey(m_hCryptProv,pkeyblob,keyblobsize,rsakeypair,&m_hSessionKey)) {
        result=true;
      }
      else CDebugPrint::DebugPrint(_T("Error %u importing session key\n"),GetLastError());
      // clean up
      if (!CryptDestroyKey(rsakeypair)) {
        CDebugPrint::DebugPrint(_T("Error %u destroying exchange key for import\n"),GetLastError());
      }
    }
  }

  return result;
}

//-------------------------------------------------------------------------
// Purpose: Export the session key for a remote to use
//
// Input:   publickeyblob       - [i] remote systems public key
//          publickeyblobsize   - [i] size of the public key
//          pblob               - [o] the created session key blob
//          blobsize            - [o] size of the created session key blob
//
// Output:  true/false result
//
// Notes:   
//
bool CMSCryptoAPI::ExportSessionKey(const BYTE* publickeyblob,DWORD *blobsize)
{
  // init output variables
  *pblob=NULL;
  *blobsize=0;

  bool result=false;

  // import the public key
  HCRYPTKEY hremotepubickey;
  if (!CryptImportKey(m_hCryptProv,publickeyblob,publickeyblobsize,AT_KEYEXCHANGE,&hremotepubickey)) {
    CDebugPrint::DebugPrint(_T("Error %u importing public key blob for keyexchange\n"),GetLastError());
  }
  else {
    // use that key to export the session key
    result=ExportKey(m_hSessionKey,hremotepubickey,SIMPLEBLOB,pblob,blobsize);

    // clean up
    if (!CryptDestroyKey(hremotepubickey)) {
      CDebugPrint::DebugPrint(_T("Error %u destroying remote public key\n"),GetLastError());
    }
  }
  return result;
}


//-------------------------------------------------------------------------
// Purpose: Create the RSA exchange key pair
//
// Input:   na
//
// Output:  the key handle or NULL if problem
//
// Notes:   Use CryptDestroyKey() when done with key
//
HCRYPTKEY CMSCryptoAPI::CreateExchangeKey()
{
  HCRYPTKEY rsakeypair=NULL;
  if (!CryptGetUserKey(m_hCryptProv,&rsakeypair)) {
    if (GetLastError()==NTE_NO_KEY) {
      // create a RSA private/public key pair
      CDebugPrint::DebugPrint(_T("Create RSA Key\n"));
      if (!CryptGenKey(m_hCryptProv,(KEYLENGTH<<KEYLENGTHSHIFT)|CRYPT_EXPORTABLE,&rsakeypair)) {
        CDebugPrint::DebugPrint(_T("Error %u creating RSA Key\n"),GetLastError());
      }
    }
    else CDebugPrint::DebugPrint(_T("Error %u getting user RSA key\n"),GetLastError());
  }

  return rsakeypair;
}


//-------------------------------------------------------------------------
// Purpose: Export a public key to a blob
//
// Input:   pbolb     - [o] the exported key blob
//          blobsize  - [o] size of the blob
//
// Output:  true/false result
//
// Notes:   The requester of a session key sends this over in order to
//          receive a protected session key
//
bool CMSCryptoAPI::ExportPublicKey(BYTE** pblob,DWORD* blobsize)
{
  bool result=false;

  // Get the handle to the exchange key. 
  HCRYPTKEY rsakeypair=CreateExchangeKey();
  if (rsakeypair) {
    // now export the public key
    result=ExportKey(rsakeypair,PUBLICKEYBLOB,blobsize);
    // clean up
    if (!CryptDestroyKey(rsakeypair)) {
      CDebugPrint::DebugPrint(_T("Error %u destroying rsa key\n"),GetLastError());
    }
  }

  return result;
}

//-------------------------------------------------------------------------
// Purpose: generic routine to export a key to a blob
//
// Input:   hkey        - [i] key to export
//          hexpkey     - [i] export key (remote public key)
//          blobtype    - [i] type of blob to create
//          pblob       - [o] blob created
//          blobsize    - [i] size of blob created
//
// Output:  true/false result
//
// Notes:   
//
bool CMSCryptoAPI::ExportKey(HCRYPTKEY hkey,DWORD* blobsize)
{
  bool result=false;

  // get size of blob needed to export key
  if (!CryptExportKey(hkey,hexpkey,blobtype,blobsize)) {
    CDebugPrint::DebugPrint(_T("Error %u getting size to export key with blob type %u\n"),GetLastError(),blobtype);
    // ensure stays zero
    *blobsize=0;
  }
  else {
    CDebugPrint::DebugPrint(_T("Export Key blob size %u\n"),*blobsize);
    // we have the size - create buffer for the exported session key
    if ((*pblob=new BYTE[*blobsize])!=NULL) {
      // success - now actually get the exported session key
      if (!CryptExportKey(hkey,*pblob,blobsize)) {
        CDebugPrint::DebugPrint(_T("Error %u exporting key with blob type %u\n"),blobtype);
        // clean up
        delete[](*pblob);
        // return nothing
        *pblob=NULL;
        *blobsize=0;
      }
      else result=true;
    }
    else {
      CDebugPrint::DebugPrint(_T("Error allocating %u byte buffer to export key with blob type %u\n"),*blobsize,blobtype);
      *blobsize=0;
    }
  }
  return result;
}

//-------------------------------------------------------------------------
// Purpose: Encrypt a block of data
//
// Input:   pplaintext    - [i] plain text to encrypt
//          plaintextsize - [i] size of plain text
//          pciphertext   - [o][opt] buffer with cipher data
//          ciphertextsize- [io] size of cipher data
//
// Output:  true/false result
//
// Notes:   If pciphertext is NULL encryption is done in-place and the
//          ciphertextsize gives the total size of the input buffer
//
bool CMSCryptoAPI::EncryptData(BYTE* pplaintext,DWORD* ciphertextsize)
{
  bool result=false;

  if (pciphertext) {
    *ciphertextsize=0;
    *pciphertext=NULL;
    // Get the size of the output buffer needed
    if (CryptEncrypt(m_hSessionKey,TRUE,ciphertextsize,0)) {
      assert(*ciphertextsize>=plaintextsize);
      // create the output buffer
      if ((*pciphertext=new BYTE[*ciphertextsize])!=NULL) {
        // created buffer - copy over data
        memcpy(*pciphertext,pplaintext,plaintextsize);
      }
    }
  }
  else pciphertext=&pplaintext;

  if (*pciphertext!=NULL) {
    // do the encryption
    if (CryptEncrypt(m_hSessionKey,*pciphertext,&plaintextsize,*ciphertextsize)) {
      // ensure result of encryption matches size returned
      assert(plaintextsize==*ciphertextsize);
      result=true;
    }
    else CDebugPrint::DebugPrint(_T("Error %u encrypting data\n"),GetLastError());
  }
  else CDebugPrint::DebugPrint(_T("Unable to create buffer of %u bytes to encrypt data\n"),*ciphertextsize);
  
  return result;
}

//-------------------------------------------------------------------------
// Purpose: Decrypt a block of data
//
// Input:   pciphertext   - [i] buffer with cipher data
//          ciphertextsize- [i] size of cipher data
//          pplaintext    - [o][opt] plain text 
//          plaintextsize - [o] size of plain text
//
// Output:  true/false result
//
// Notes:   if plaintext is NULL the decryption occurs in-place
//
bool CMSCryptoAPI::DecryptData(BYTE* pciphertext,BYTE** pplaintext,DWORD* plaintextsize)
{
  bool result=false;

  *plaintextsize=0;
  if (pplaintext) {
    if ((*pplaintext=new BYTE[ciphertextsize])!=NULL) {
      // copy over data
      memcpy(*pplaintext,pciphertext,ciphertextsize);
    }
  }
  else pplaintext=&pciphertext;

  if (*pplaintext!=NULL) {
    // do the decryption
    *plaintextsize=ciphertextsize;
    if (CryptDecrypt(m_hSessionKey,*pplaintext,plaintextsize)) {
      result=true;
    }
    else CDebugPrint::DebugPrint(_T("Error %u decrypting data\n"),GetLastError());
  }
  else CDebugPrint::DebugPrint(_T("Unable to create buffer of %u bytes to decrypt data\n"),ciphertextsize);

  return result;
}

//-------------------------------------------------------------------------
// Purpose: Setup the IV of a key
//
// Input:   pbiv   - [i][opt] IV data to use
//
// Output:  true/false result
//
// Notes:   Random data is used if pbiv is not given
//
bool CMSCryptoAPI::SetIV(BYTE* pbiv)
{
  bool result=false;

  // check if we put in random data or use callers value
  if (pbiv==NULL) {
    // get block length
    DWORD dwblocklen=GetSessionKeyBlockSize();
    if (dwblocklen!=0) {
      // create buffer for random data
      BYTE* pbtemp;
      if ((pbtemp=new BYTE[dwblocklen])!=NULL) {
        // create random data
        if (CryptGenRandom(m_hCryptProv,dwblocklen,pbtemp)) {
          // set the IV data
          if (CryptSetKeyParam(m_hSessionKey,KP_IV,pbtemp,0)) {
            result=true;
          }
          else CDebugPrint::DebugPrint(_T("Error %u on CryptSetKeyParam KP_IV\n"),GetLastError());
        }
        else CDebugPrint::DebugPrint(_T("Error %u on CryptGenRandom\n"),GetLastError());

        // clean up
        delete[] pbtemp;
      }
      else CDebugPrint::DebugPrint(_T("Unable to create buffer of %u bytes for rng\n"),dwblocklen);
    }
  }
  else {
    if (CryptSetKeyParam(m_hSessionKey,pbiv,0)) {
      result=true;
    }
    else CDebugPrint::DebugPrint(_T("Error %u on CryptSetKeyParam KP_VI caller buffer\n"),GetLastError());
  }

  return result;
}

//-------------------------------------------------------------------------
// Purpose: Calculate size of buffer that can used for in place encryption
//
// Input:   plaintextsize  - [i] size of the plain text
//
// Output:  size of aligned buffer that can be used for in place encryption
//
// Notes:   
//
DWORD CMSCryptoAPI::CalcSizeForInPlaceEncryption(DWORD plaintextsize)
{
  // get the block size
  DWORD dwblocksize=GetSessionKeyBlockSize();
  // align up to it
  return (((plaintextsize+dwblocksize-1)/dwblocksize)*dwblocksize);
  // if always a factor of 2 then 
  // return ((plaintextsize+dwblocksize-1) & ~(dwblocksize-1));
}

//-------------------------------------------------------------------------
// Purpose: Get the block size for the session key
//
// Input:   na
//
// Output:  size of aligned buffer that can be used for in place encryption
//
// Notes:   
//
DWORD CMSCryptoAPI::GetSessionKeyBlockSize()
{
  // get block length
  DWORD dwblocklen=0;
  DWORD dwdatalen=sizeof(dwblocklen);
  if (CryptGetKeyParam(m_hSessionKey,KP_BLOCKLEN,(BYTE*) &dwblocklen,&dwdatalen,0)) {
    // convert bits to bytes
    dwblocklen/=8;
  }
  else CDebugPrint::DebugPrint(_T("Error %u on CryptGetKeyParam KP_BLOCKLEN\n"),GetLastError());

  return dwblocklen;
}

解决方法

好吧,我想知道它是否可能是 IV。我在创建会话密钥时改为不设置它,所以它看起来像:

bool CMSCryptoAPI::CreateRandomSessionKey()
{
  bool result=false;
  if (DestroySessionKey()) {
  // Create a random session key. 
    if (CryptGenKey(m_hCryptProv,CALG_AES_128,CRYPT_EXPORTABLE,&m_hSessionKey)) {
      // now populate IV
      //result=SetIV(); REMOVED
      result=true;
    }
    else CDebugPrint::DebugPrint(_T("Error %u creating session key\n"),GetLastError());
  }

  return result;
}

现在它适用于双方,但这让我想知道,我应该设置一些固定的 IV 还是 Windows 处理它,或者它总是 0 或类似的东西?

顺便说一句,为像我这样需要某些东西的人享受课程,其他人可能会帮助改进它。我倾向于使用 nothrownew.obj,但其他人可能使用异常处理(我不太了解)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res