DetailPage-MSS-KB

Microsoft Knowledge Base

Identificativo articolo: 228786 - Ultima modifica: martedì 21 novembre 2006 - Revisione: 4.3

 

Sommario

A volte è utile esportare e importare chiavi di sessione come testo normale. Tuttavia, i provider di crittografia Microsoft (base e avanzata) non supportano questa funzionalità. Sia in CryptExportKey() e in CryptImportKey() richiedono un handle di chiave valido per crittografare e decrittografare la chiave di sessione, rispettivamente. Ma, utilizzando a una chiave privata di "esponente di uno" lo stesso effetto è possibile ottenere per crittografare e decrittografare la chiave di sessione.

Informazioni

Poiché l'esponente chiave è una, crittografia e decrittografia non eseguire alcuna operazione al testo normale e quindi lasciare essenzialmente la chiave di sessione in formato testo normale.

Nel codice di esempio riportato di seguito viene illustrato come implementare questa funzionalità:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>

BOOL CreatePrivateExponentOneKey(LPTSTR szProvider, 
                                 DWORD dwProvType, 
                                 LPTSTR szContainer,
                                 DWORD dwKeySpec,
                                 HCRYPTPROV *hProv, 
                                 HCRYPTKEY *hPrivateKey);

BOOL GenerateSessionKeyWithAlgorithm(HCRYPTPROV hProv, 
                                     ALG_ID Alg,
                                     HCRYPTKEY *hSessionKey);

BOOL DeriveSessionKeyWithAlgorithm(HCRYPTPROV hProv, 
                                   ALG_ID Alg,
                                   LPBYTE lpHashingData,
                                   DWORD dwHashingData,
                                   HCRYPTKEY *hSessionKey);

BOOL ExportPlainSessionBlob(HCRYPTKEY hPublicKey,
                            HCRYPTKEY hSessionKey,
                            LPBYTE *pbKeyMaterial,
                            DWORD *dwKeyMaterial);

BOOL ImportPlainSessionBlob(HCRYPTPROV hProv,
                            HCRYPTKEY hPrivateKey,
                            ALG_ID dwAlgId,
                            LPBYTE pbKeyMaterial,
                            DWORD dwKeyMaterial,
                            HCRYPTKEY *hSessionKey);

void main()
{
   HCRYPTPROV hProv = 0;
   HCRYPTKEY hPubPrivKey = 0;
   HCRYPTKEY hSessionKey = 0;
   BOOL fResult;
   LPBYTE pbKeyMaterial  = NULL;
   DWORD dwKeyMaterial ;   
   int n;

   __try
   {
      printf("Creating Exponent of One Private Key.\n\n");

      // Create Exponent of One private key
      fResult = CreatePrivateExponentOneKey(MS_ENHANCED_PROV, PROV_RSA_FULL,
                                            "TestContainer", AT_KEYEXCHANGE, 
                                            &hProv, &hPubPrivKey);
      if (!fResult)
      {
         printf("CreatePrivateExponentOneKey failed with %x\n", GetLastError());
         __leave;
      }

      // Allocate memory for 3DES key and 
      // Fill key with data 1,2,3,... in this case
      pbKeyMaterial = (LPBYTE)LocalAlloc(LPTR, 192/8);
      for (n = 0; n < 192/8; n++) pbKeyMaterial[n] = n+1;
      dwKeyMaterial = 192/8;

      printf("\nImporting 3DES key with key material 1,2,3,...\n");

      // Import this key and get an HCRYPTKEY handle
      if (!ImportPlainSessionBlob(hProv, hPubPrivKey, CALG_3DES, pbKeyMaterial, dwKeyMaterial, &hSessionKey))
      {
         printf("ImportPlainSessionBlob failed with %x\n", GetLastError());
         __leave;
      }

      LocalFree(pbKeyMaterial);
      pbKeyMaterial = NULL;

      printf("Exporting 3DES key.  We should get back 1,2,3,...\n");
      // Export it and get the key material back
      // It should be 1,2,3, ...
      fResult = ExportPlainSessionBlob(hPubPrivKey, hSessionKey, 
                                       &pbKeyMaterial , &dwKeyMaterial );
      if (!fResult)
      {
         printf("ExportPlainSessionBlob failed with %x\n", GetLastError());
         __leave;
      }
     
      // Print Key material
      printf("3DES session key:\n");
      for (n = 0; n < dwKeyMaterial; n++)      
      {
         if (n%8 == 0) printf(" ");
         printf("%02x", pbKeyMaterial[n]);
      }
      printf("\n");
   }
   __finally
   {
      if (pbKeyMaterial ) LocalFree(pbKeyMaterial );
      if (hSessionKey) CryptDestroyKey(hSessionKey);
      if (hPubPrivKey) CryptDestroyKey(hPubPrivKey);
      if (hProv) 
      {  
         CryptReleaseContext(hProv, 0);
         CryptAcquireContext(&hProv, "TestContainer", MS_ENHANCED_PROV, 
                                    PROV_RSA_FULL, CRYPT_DELETEKEYSET);
      }
   }
}

BOOL CreatePrivateExponentOneKey(LPTSTR szProvider, 
                                 DWORD dwProvType,
                                 LPTSTR szContainer,
                                 DWORD dwKeySpec,
                                 HCRYPTPROV *hProv, 
                                 HCRYPTKEY *hPrivateKey)
{
   BOOL fReturn = FALSE;
   BOOL fResult;
   int n;
   LPBYTE keyblob = NULL;
   DWORD dwkeyblob;
   DWORD dwBitLen;
   BYTE *ptr;

   __try
   {
      *hProv = 0;
      *hPrivateKey = 0;

      if ((dwKeySpec != AT_KEYEXCHANGE) && (dwKeySpec != AT_SIGNATURE))  __leave;

      // Try to create new container
      fResult = CryptAcquireContext(hProv, szContainer, szProvider, 
                                    dwProvType, CRYPT_NEWKEYSET);
      if (!fResult)
      {
         // If the container exists, open it
         if (GetLastError() == NTE_EXISTS)
         {
            fResult = CryptAcquireContext(hProv, szContainer, szProvider, dwProvType, 0);
            if (!fResult)
            {
               // No good, leave
               __leave;
            }
         }
         else
         {
            // No good, leave
            __leave;
         }
      }

      // Generate the private key
      fResult = CryptGenKey(*hProv, dwKeySpec, CRYPT_EXPORTABLE, hPrivateKey);
      if (!fResult) __leave;

      // Export the private key, we'll convert it to a private
      // exponent of one key
      fResult = CryptExportKey(*hPrivateKey, 0, PRIVATEKEYBLOB, 0, NULL, &dwkeyblob);
      if (!fResult) __leave;      

      keyblob = (LPBYTE)LocalAlloc(LPTR, dwkeyblob);
      if (!keyblob) __leave;

      fResult = CryptExportKey(*hPrivateKey, 0, PRIVATEKEYBLOB, 0, keyblob, &dwkeyblob);
      if (!fResult) __leave;


      CryptDestroyKey(*hPrivateKey);
      *hPrivateKey = 0;

      // Get the bit length of the key
      memcpy(&dwBitLen, &keyblob[12], 4);      

      // Modify the Exponent in Key BLOB format
      // Key BLOB format is documented in SDK

      // Convert pubexp in rsapubkey to 1
      ptr = &keyblob[16];
      for (n = 0; n < 4; n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }

      // Skip pubexp
      ptr += 4;
      // Skip modulus, prime1, prime2
      ptr += (dwBitLen/8);
      ptr += (dwBitLen/16);
      ptr += (dwBitLen/16);

      // Convert exponent1 to 1
      for (n = 0; n < (dwBitLen/16); n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }

      // Skip exponent1
      ptr += (dwBitLen/16);

      // Convert exponent2 to 1
      for (n = 0; n < (dwBitLen/16); n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }

      // Skip exponent2, coefficient
      ptr += (dwBitLen/16);
      ptr += (dwBitLen/16);

      // Convert privateExponent to 1
      for (n = 0; n < (dwBitLen/8); n++)
      {
         if (n == 0) ptr[n] = 1;
         else ptr[n] = 0;
      }
      
      // Import the exponent-of-one private key.      
      if (!CryptImportKey(*hProv, keyblob, dwkeyblob, 0, 0, hPrivateKey))
      {                 
         __leave;
      }

      fReturn = TRUE;
   }
   __finally
   {
      if (keyblob) LocalFree(keyblob);

      if (!fReturn)
      {
         if (*hPrivateKey) CryptDestroyKey(*hPrivateKey);
         if (*hProv) CryptReleaseContext(*hProv, 0);
      }
   }

   return fReturn;
}

BOOL GenerateSessionKeyWithAlgorithm(HCRYPTPROV hProv, 
                                     ALG_ID Alg,
                                     HCRYPTKEY *hSessionKey)
{   
   BOOL fResult;

   *hSessionKey = 0;

   fResult = CryptGenKey(hProv, Alg, CRYPT_EXPORTABLE, hSessionKey);
   if (!fResult)
   {
      return FALSE;
   }
   
   return TRUE;   
}

BOOL DeriveSessionKeyWithAlgorithm(HCRYPTPROV hProv, 
                                   ALG_ID Alg,
                                   LPBYTE lpHashingData,
                                   DWORD dwHashingData,
                                   HCRYPTKEY *hSessionKey)
{
   BOOL fResult;
   BOOL fReturn = FALSE;
   HCRYPTHASH hHash = 0;

   __try
   {
      *hSessionKey = 0;

      fResult = CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash);
      if (!fResult) __leave;

      fResult = CryptHashData(hHash, lpHashingData, dwHashingData, 0);
      if (!fResult) __leave;

      fResult = CryptDeriveKey(hProv, Alg, hHash, CRYPT_EXPORTABLE, hSessionKey);
      if (!fResult) __leave;

      fReturn = TRUE;
   }
   __finally
   {      
      if (hHash) CryptDestroyHash(hHash);
   }

   return fReturn;
}

BOOL ExportPlainSessionBlob(HCRYPTKEY hPublicKey,
                            HCRYPTKEY hSessionKey,
                            LPBYTE *pbKeyMaterial ,
                            DWORD *dwKeyMaterial )
{
   BOOL fReturn = FALSE;
   BOOL fResult;
   DWORD dwSize, n;
   LPBYTE pbSessionBlob = NULL;
   DWORD dwSessionBlob;
   LPBYTE pbPtr;

   __try
   {
      *pbKeyMaterial  = NULL;
      *dwKeyMaterial  = 0;

      fResult = CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB,
                               0, NULL, &dwSessionBlob );
      if (!fResult) __leave;

      pbSessionBlob  = (LPBYTE)LocalAlloc(LPTR, dwSessionBlob );
      if (!pbSessionBlob) __leave;

      fResult = CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB,
                               0, pbSessionBlob , &dwSessionBlob );
      if (!fResult) __leave;

      // Get session key size in bits
      dwSize = sizeof(DWORD);
      fResult = CryptGetKeyParam(hSessionKey, KP_KEYLEN, (LPBYTE)dwKeyMaterial, &dwSize, 0);
      if (!fResult) __leave;

      // Get the number of bytes and allocate buffer
      *dwKeyMaterial /= 8;
      *pbKeyMaterial = (LPBYTE)LocalAlloc(LPTR, *dwKeyMaterial);
      if (!*pbKeyMaterial) __leave;

      // Skip the header
      pbPtr = pbSessionBlob;
      pbPtr += sizeof(BLOBHEADER);
      pbPtr += sizeof(ALG_ID);

      // We are at the beginning of the key
      // but we need to start at the end since 
      // it's reversed
      pbPtr += (*dwKeyMaterial - 1);
      
      // Copy the raw key into our return buffer      
      for (n = 0; n < *dwKeyMaterial; n++)
      {
         (*pbKeyMaterial)[n] = *pbPtr;
         pbPtr--;
      }      
      
      fReturn = TRUE;
   }
   __finally
   {
      if (pbSessionBlob) LocalFree(pbSessionBlob);

      if ((!fReturn) && (*pbKeyMaterial ))
      {
         LocalFree(*pbKeyMaterial );
         *pbKeyMaterial  = NULL;
         *dwKeyMaterial  = 0;
      }
   }

   return fReturn;
}


BOOL ImportPlainSessionBlob(HCRYPTPROV hProv,
                            HCRYPTKEY hPrivateKey,
                            ALG_ID dwAlgId,
                            LPBYTE pbKeyMaterial ,
                            DWORD dwKeyMaterial ,
                            HCRYPTKEY *hSessionKey)
{
   BOOL fResult;   
   BOOL fReturn = FALSE;
   BOOL fFound = FALSE;
   LPBYTE pbSessionBlob = NULL;
   DWORD dwSessionBlob, dwSize, n;
   DWORD dwPublicKeySize;
   DWORD dwProvSessionKeySize;
   ALG_ID dwPrivKeyAlg;
   LPBYTE pbPtr; 
   DWORD dwFlags = CRYPT_FIRST;
   PROV_ENUMALGS_EX ProvEnum;
   HCRYPTKEY hTempKey = 0;

   __try
   {
      // Double check to see if this provider supports this algorithm
      // and key size
      do
      {        
         dwSize = sizeof(ProvEnum);
         fResult = CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum,
                                     &dwSize, dwFlags);
         if (!fResult) break;

         dwFlags = 0;

         if (ProvEnum.aiAlgid == dwAlgId) fFound = TRUE;
                                     
      } while (!fFound);

      if (!fFound) __leave;

      // We have to get the key size(including padding)
      // from an HCRYPTKEY handle.  PP_ENUMALGS_EX contains
      // the key size without the padding so we can't use it.
      fResult = CryptGenKey(hProv, dwAlgId, 0, &hTempKey);
      if (!fResult) __leave;
      
      dwSize = sizeof(DWORD);
      fResult = CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize,
                                 &dwSize, 0);
      if (!fResult) __leave;      
      CryptDestroyKey(hTempKey);
      hTempKey = 0;

      // Our key is too big, leave
      if ((dwKeyMaterial * 8) > dwProvSessionKeySize) __leave;

      // Get private key's algorithm
      dwSize = sizeof(ALG_ID);
      fResult = CryptGetKeyParam(hPrivateKey, KP_ALGID, (LPBYTE)&dwPrivKeyAlg, &dwSize, 0);
      if (!fResult) __leave;

      // Get private key's length in bits
      dwSize = sizeof(DWORD);
      fResult = CryptGetKeyParam(hPrivateKey, KP_KEYLEN, (LPBYTE)&dwPublicKeySize, &dwSize, 0);
      if (!fResult) __leave;

      // calculate Simple blob's length
      dwSessionBlob = (dwPublicKeySize/8) + sizeof(ALG_ID) + sizeof(BLOBHEADER);

      // allocate simple blob buffer
      pbSessionBlob = (LPBYTE)LocalAlloc(LPTR, dwSessionBlob);
      if (!pbSessionBlob) __leave;

      pbPtr = pbSessionBlob;

      // SIMPLEBLOB Format is documented in SDK
      // Copy header to buffer
      ((BLOBHEADER *)pbPtr)->bType = SIMPLEBLOB;
      ((BLOBHEADER *)pbPtr)->bVersion = 2;
      ((BLOBHEADER *)pbPtr)->reserved = 0;
      ((BLOBHEADER *)pbPtr)->aiKeyAlg = dwAlgId;
      pbPtr += sizeof(BLOBHEADER);

      // Copy private key algorithm to buffer
      *((DWORD *)pbPtr) = dwPrivKeyAlg;
      pbPtr += sizeof(ALG_ID);

      // Place the key material in reverse order
      for (n = 0; n < dwKeyMaterial; n++)
      {
         pbPtr[n] = pbKeyMaterial[dwKeyMaterial-n-1];
      }
     
      // 3 is for the first reserved byte after the key material + the 2 reserved bytes at the end.
      dwSize = dwSessionBlob - (sizeof(ALG_ID) + sizeof(BLOBHEADER) + dwKeyMaterial + 3);
      pbPtr += (dwKeyMaterial+1);

      // Generate random data for the rest of the buffer
      // (except that last two bytes)
      fResult = CryptGenRandom(hProv, dwSize, pbPtr);
      if (!fResult) __leave;

      for (n = 0; n < dwSize; n++)
      {
         if (pbPtr[n] == 0) pbPtr[n] = 1;
      }

      pbSessionBlob[dwSessionBlob - 2] = 2;

      fResult = CryptImportKey(hProv, pbSessionBlob , dwSessionBlob, 
                               hPrivateKey, CRYPT_EXPORTABLE, hSessionKey);
      if (!fResult) __leave;

      fReturn = TRUE;           
   }
   __finally
   {
      if (hTempKey) CryptDestroyKey(hTempKey);
      if (pbSessionBlob) LocalFree(pbSessionBlob);
   }
   
   return fReturn;
}
				

Riferimenti

Per ulteriori informazioni sulle API utilizzate in questo esempio, vedere MSDN Online.

I formati del BLOB di chiave sono documentati nella seguente pagina Web MSDN:
http://msdn.microsoft.com/en-us/library/aa386962.aspx (http://msdn.microsoft.com/en-us/library/aa386962.aspx)

Le informazioni in questo articolo si applicano a:
  • Microsoft Win32 Application Programming Interface alle seguenti piattaforme
    • Microsoft Windows 95
    • Microsoft Windows 98 Standard Edition
    • Microsoft Windows Millennium Edition
    • Microsoft Windows NT 4.0
    • the operating system: Microsoft Windows 2000
    • the operating system: Microsoft Windows XP
Chiavi: 
kbmt kbapi kbcrypt kbfaq kbhowto kbkernbase kbsecurity KB228786 KbMtit
Traduzione automatica articoliTraduzione automatica articoli
Il presente articolo è stato tradotto tramite il software di traduzione automatica di Microsoft e non da una persona. Microsoft offre sia articoli tradotti da persone fisiche sia articoli tradotti automaticamente da un software, in modo da rendere disponibili tutti gli articoli presenti nella nostra Knowledge Base nella lingua madre dell’utente. Tuttavia, un articolo tradotto in modo automatico non è sempre perfetto. Potrebbe contenere errori di sintassi, di grammatica o di utilizzo dei vocaboli, più o meno allo stesso modo di come una persona straniera potrebbe commettere degli errori parlando una lingua che non è la sua. Microsoft non è responsabile di alcuna imprecisione, errore o danno cagionato da qualsiasi traduzione non corretta dei contenuti o dell’utilizzo degli stessi fatto dai propri clienti. Microsoft, inoltre, aggiorna frequentemente il software di traduzione automatica.
Clicca qui per visualizzare la versione originale in inglese dell’articolo: 228786  (http://support.microsoft.com/kb/228786/en-us/ )
LE INFORMAZIONI CONTENUTE NELLA MICROSOFT KNOWLEDGE BASE SONO FORNITE SENZA GARANZIA DI ALCUN TIPO, IMPLICITA OD ESPLICITA, COMPRESA QUELLA RIGUARDO ALLA COMMERCIALIZZAZIONE E/O COMPATIBILITA' IN IMPIEGHI PARTICOLARI. L'UTENTE SI ASSUME L'INTERA RESPONSABILITA' PER L'UTILIZZO DI QUESTE INFORMAZIONI. IN NESSUN CASO MICROSOFT CORPORATION E I SUOI FORNITORI SI RENDONO RESPONSABILI PER DANNI DIRETTI, INDIRETTI O ACCIDENTALI CHE POSSANO PROVOCARE PERDITA DI DENARO O DI DATI, ANCHE SE MICROSOFT O I SUOI FORNITORI FOSSERO STATI AVVISATI. IL DOCUMENTO PUO' ESSERE COPIATO E DISTRIBUITO ALLE SEGUENTI CONDIZIONI: 1) IL TESTO DEVE ESSERE COPIATO INTEGRALMENTE E TUTTE LE PAGINE DEVONO ESSERE INCLUSE. 2) I PROGRAMMI SE PRESENTI, DEVONO ESSERE COPIATI SENZA MODIFICHE, 3) IL DOCUMENTO DEVE ESSERE DISTRIBUITO INTERAMENTE IN OGNI SUA PARTE. 4) IL DOCUMENTO NON PUO' ESSERE DISTRIBUITO A SCOPO DI LUCRO.
Condividi
Altre opzioni per il supporto
Forum del supporto di Microsoft Community
Contattaci direttamente
Ricerca di un partner certificato Microsoft
Microsoft Store