【问题标题】:CryptoNG: Exporting RSA key with BCryptExportKey fails with STATUS_INVALID_HANDLECryptoNG:使用 BCryptExportKey 导出 RSA 密钥失败并出现 STATUS_INVALID_HANDLE
【发布时间】:2019-05-25 18:37:41
【问题描述】:

使用 Cryptography Next Generation API(又名 CryptoAPI Next Generation,又名 CryptoNG,又名 Cng,又名 BestCrypt,又名 bcrypt),我正在尝试导出新生成的 RSA 私钥对:

编辑:更短的代码版本:

BCRYPT_ALG_HANDLE alg;
BCryptOpenAlgorithmProvider(out alg, BCRYPT_RSA_ALGORITHM, null, 0);

BCRYPT_KEY_HANDLE key;
BCryptGenerateKeyPair(alg, out key, 4096, 0);

DWORD cbResult;
BCryptExportKey(key, 0, BCRYPT_RSAFULLPRIVATE_BLOB, null, 0, out cbResult, 0);

更长的代码版本

NTSTATUS nt;

// Open the RSA algorithm provider
BCRYPT_ALG_HANDLE alg;
nt = BCryptOpenAlgorithmProvider(out alg, BCRYPT_RSA_ALGORITHM, null, 0);
NTStatusCheck(nt);
      // Successfully opened the RSA algorithm provider

// Generate a 4096 bit RSA public-private key pair
BCRYPT_KEY_HANDLE key;
nt = BCryptGenerateKeyPair(alg, out key, 4096, 0);
NTStatusCheck(nt);
      // Successfully generates a key pair (key <-- $4E737A0)

// Ask for the buffer size required to export the key pair
DWORD cbResult;
nt = BCryptExportKey(key, 0, BCRYPT_RSAFULLPRIVATE_BLOB, null, 0, out cbResult, 0);
NTStatusCheck(nt);
      // Fails with 0xC0000008 (STATUS_INVALID_HANDLE)

我做错了什么?

阅读奖励

完整的最小示例(Delphi)

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows, ComObj, ActiveX;

type
  NTSTATUS = Cardinal;
const
    BCRYPT_RSA_ALGORITHM:       WideString = 'RSA';
  BCRYPT_RSAFULLPRIVATE_BLOB: WideString = 'RSAFULLPRIVATEBLOB';
  BCRYPT_RSAPRIVATE_BLOB:     WideString = 'RSAPRIVATEBLOB';
  BCRYPT_RSAPUBLIC_BLOB:      WideString = 'RSAPUBLICBLOB';
  LEGACY_RSAPRIVATE_BLOB:     WideString = 'CAPIPRIVATEBLOB';
  LEGACY_RSAPUBLIC_BLOB:      WideString = 'CAPIPUBLICBLOB';

function BCryptOpenAlgorithmProvider(out hAlgorithm: THandle; pszAlgId, pszImplementation: PWideChar; dwFlags: Cardinal): NTSTATUS; stdcall; external 'bcrypt.dll';
function BCryptGenerateKeyPair(hAlgorithm: THandle; out phKey: THandle; dwLength: Cardinal; dwFlags: Cardinal): NTSTATUS; stdcall; external 'bcrypt.dll';
function BCryptExportKey(hKey: THandle; hExportKey: THandle; pszBlobType: PWideChar; pbOutput: Pointer; cbOutput: Cardinal; out pcbResult: Cardinal; dwFlags: Cardinal): NTSTATUS; stdcall; external 'bcrypt.dll';


procedure Main;
var
  nt: Cardinal;
  alg: THandle;
  key: THandle;
  cbResult: Cardinal;
begin
  // Open the RSA algorithm provider
  WriteLn('Opening algorithm provider');
  nt := BCryptOpenAlgorithmProvider({out} alg, PWideChar(BCRYPT_RSA_ALGORITHM), nil, 0);
  OleCheck(HRESULT(nt));

  // Generate a RSA public-private key pair
  WriteLn('Generating key pair');
  key := 0;
  nt := BCryptGenerateKeyPair(alg, {out} key, 1024, 0);
  OleCheck(HRESULT(nt));

  // Ask for the buffer size required to export the key pair
  WriteLn('Exporting full private blob');
  cbResult := 0;
  nt := BCryptExportKey(key, 0, PWideChar(BCRYPT_RSAFULLPRIVATE_BLOB), nil, 0, {out} cbResult, 0);
  OleCheck(HRESULT(nt));

  WriteLn('Success');
end;

begin
    Main;
  WriteLn('Press enter to close...');
  ReadLn;
end.

完整的最小示例(C#)

using System;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    class Program
    {
        [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)]
        internal static extern Int32 BCryptOpenAlgorithmProvider(out IntPtr phAlgorithm, [In] string pszAlgId, [In] string pszImplementation, [In] int dwFlags);

        [DllImport("bcrypt.dll")]
        internal static extern Int32 BCryptGenerateKeyPair([In] IntPtr hAlgorithm, out IntPtr phKey, [In] UInt32 dwLength, [In] UInt32 dwFlags);

        [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)]
        internal static extern Int32 BCryptExportKey([In] IntPtr hKey, [In] IntPtr hExportKey, [MarshalAs(UnmanagedType.LPWStr)] [In] string pszBlobType, [MarshalAs(UnmanagedType.LPArray)] [Out] byte[] pbOutput, [In] int cbOutput, [In] ref UInt32 cbResult, [In] int dwFlags);

        static void Main(string[] args)
        {
            Int32 nt;

            IntPtr alg;
            nt = BCryptOpenAlgorithmProvider(out alg, "RSA", null, 0);
            if (nt < 0)
                throw new COMException("Open algorithm", (int)nt);

            IntPtr key;
            nt = BCryptGenerateKeyPair(alg, out key, 1024, 0);
            if (nt < 0)
                throw new COMException("Generate key", nt);

            UInt32 cbResult = 0;
            nt = BCryptExportKey(key, IntPtr.Zero, "RSAPRIVATEBLOB", null, 0, ref cbResult, 0);
            if (nt < 0)
                throw new COMException("Export", nt);
        }
    }
}

【问题讨论】:

    标签: windows cryptography cng


    【解决方案1】:

    BCryptGenerateKeyPair 之后,您应该调用 BCryptFinalizeKeyPair。在 BCryptFinalizeKeyPair 之前实际上并不存在密钥对。

    使用此函数创建密钥后,[...] 在调用 BCryptFinalizeKeyPair 函数之前无法使用该密钥。

    所以:

    BCRYPT_ALG_HANDLE alg;
    BCryptOpenAlgorithmProvider(out alg, BCRYPT_RSA_ALGORITHM, null, 0);
    
    BCRYPT_KEY_HANDLE key;
    BCryptGenerateKeyPair(alg, out key, 4096, 0);
    
    BCryptFinalizeKeyPair(key, 0); //finalize the key so we can use it
    
    DWORD cbResult;
    BCryptExportKey(key, 0, BCRYPT_RSAFULLPRIVATE_BLOB, null, 0, out cbResult, 0);
    

    【讨论】:

      猜你喜欢
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多