CryptoNG: экспорт ключа RSA с помощью BCryptExportKey завершается неудачно с помощью STATUS_INVALID_HANDLE - PullRequest
0 голосов
/ 25 мая 2019

Используя API следующего поколения для криптографии (также известный как CryptoAPI следующего поколения, известный как 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);
        }
    }
}

1 Ответ

1 голос
/ 27 мая 2019

После BCryptGenerateKeyPair вам следует позвонить BCryptFinalizeKeyPair .До BCryptFinalizeKeyPair пара ключей фактически не существует.

После создания ключа с помощью этой функции [...] ключ нельзя использовать до тех пор, пока BCryptFinalizeKeyPair функция вызывается.

...