2009-08-05 6 views
11

Sono nuovo per l'intera cosa Crypto, quindi supplico alcune indicazioni di base.Carica un file PEM X509 in Windows CryptoApi

Ho bisogno di caricare .PEM (X509) "----- INIZIA A RSA XXX KEY ----- ----- END RSA XXX KEY -----" in un contesto Windows Crypto Api per uso con C++ (ho trovato esempi per Python e .NET ma usano funzioni specifiche che non posso riferire al semplice Windows Crypto Api)

Capisco come crittografare/decifrare una volta che ho un HCRYPTKEY. MA, proprio non capisco come importare il BLOB Base64 nei file .PEM e ottenere un HCRYPTKEY che posso usare al di fuori di esso.

Ho la sensazione che ci sia qualcosa di più che semplicemente chiamando CryptDecodeObject().

Eventuali puntatori che possono mettermi in pista? Ho già perso 2 giorni facendo "programmazione & errore" di programmazione e senza ottenere nulla.

risposta

19

KJKHyperion ha detto nel suo answer:

I discovered the "magic" sequence of calls to import a RSA public key in PEM format. Here you go:

  1. decode the key into a binary blob with CryptStringToBinary; pass CRYPT_STRING_BASE64HEADER in dwFlags
  2. decode the binary key blob into a CERT_PUBLIC_KEY_INFO with CryptDecodeObjectEx; pass X509_ASN_ENCODING in dwCertEncodingType and X509_PUBLIC_KEY_INFO in lpszStructType
  3. decode the PublicKey blob from the CERT_PUBLIC_KEY_INFO into a RSA key blob with CryptDecodeObjectEx; pass X509_ASN_ENCODING in dwCertEncodingType and RSA_CSP_PUBLICKEYBLOB in lpszStructType
  4. import the RSA key blob with CryptImportKey

Questa sequenza mi ha aiutato a capire cosa sta succedendo , ma non ha funzionato per me così com'è. La seconda chiamata a CryptDecodeObjectEx mi ha restituito un errore: "Valore tag non valido ASN.1 soddisfatto". Dopo molti tentativi di comprensione della documentazione Microsoft, ho finalmente realizzato che l'output della decodifica del pugno non può essere decodificato come ASN e che è effettivamente pronto per l'importazione. Con questa comprensione ho trovato la risposta al seguente link:

http://www.ms-news.net/f2748/problem-importing-public-key-4052577.html

seguito è il mio programma che importa una chiave pubblica da un.file PEM ad un contesto CryptApi:

int main() 
{ 
    char   pemPubKey[2048]; 
    int   readLen; 
    char   derPubKey[2048]; 
    size_t   derPubKeyLen = 2048; 
    CERT_PUBLIC_KEY_INFO *publicKeyInfo; 
    int   publicKeyInfoLen; 
    HANDLE   hFile; 
    HCRYPTPROV  hProv = 0; 
    HCRYPTKEY  hKey = 0; 

    /* 
    * Read the public key cert from the file 
    */ 
    hFile = CreateFileA("c:\\pub.pem", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
    if (hFile == INVALID_HANDLE_VALUE) 
    { 
     fprintf(stderr, "Failed to open file. error: %d\n", GetLastError()); 
    } 

    if (!ReadFile(hFile, pemPubKey, 2048, &readLen, NULL)) 
    { 
     fprintf(stderr, "Failed to read file. error: %d\n", GetLastError()); 
    } 

    /* 
    * Convert from PEM format to DER format - removes header and footer and decodes from base64 
    */ 
    if (!CryptStringToBinaryA(pemPubKey, 0, CRYPT_STRING_BASE64HEADER, derPubKey, &derPubKeyLen, NULL, NULL)) 
    { 
     fprintf(stderr, "CryptStringToBinary failed. Err: %d\n", GetLastError()); 
    } 

    /* 
    * Decode from DER format to CERT_PUBLIC_KEY_INFO 
    */ 
    if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, derPubKey, derPubKeyLen, 
           CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen)) 
    { 
     fprintf(stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError()); 
     return -1; 
    } 

    /* 
    * Acquire context 
    */ 
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 
    { 
     { 
      printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError()); 
      return -1; 
     } 
    } 

    /* 
    * Import the public key using the context 
    */ 
    if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey)) 
    { 
     fprintf(stderr, "CryptImportPublicKeyInfo failed. error: %d\n", GetLastError()); 
     return -1; 
    } 
    LocalFree(publicKeyInfo); 

    /* 
    * Now use hKey to encrypt whatever you need. 
    */ 

    return 0; 
} 
+0

potresti fornire la chiave pubblica di LAVORO? Il tuo programma non funziona ancora per me ... ma la mia chiave è davvero valida. – socketpair

+0

Un'altra implementazione: http://idrix.fr/Root/Samples/capi_pem.cpp – socketpair

+1

@socketpair a seconda dell'implementazione, potrebbe essere necessario che la firma digitale sia completamente invertita in byte prima di essere verificata – moala

2

Attualmente sto affrontando la stessa difficoltà. Non ho ancora finito di scrivere una soluzione, ma a quanto ho capito è necessario rimuovere il ----- BEGIN etc ----- e ----- END ecc. ------ tag e decodificare Base64 .

Questo lascia una stringa codificata DER, che è necessario analizzare per ottenere il modulo e l'esponente pubblico. Da quelli puoi popolare le strutture PUBLICKEYSTRUC e RSAPUBKEY. Buona fortuna ;-)

+0

Guardare in CryptDecodeObjectEx con le opzioni X509_ASN_ENCODING e RSA_CSP_PUBLICKEYBLOB. Sembra decodificare e riempire correttamente la struttura, ma potrebbe essere comunque necessario scambiare l'ordine dei byte di alcune parti. – jarmond

9

Ho scoperto la sequenza "magica" di chiamate per importare una chiave pubblica RSA in formato PEM. Qui si va:

  1. decodificare la chiave in un blob binario con CryptStringToBinary; passare CRYPT_STRING_BASE64HEADER in dwFlags
  2. decodifica blob chiave binario in una CERT_PUBLIC_KEY_INFO con CryptDecodeObjectEx; passare X509_ASN_ENCODING in dwCertEncodingType e X509_PUBLIC_KEY_INFO in lpszStructType
  3. decodificare il blob PublicKey dal CERT_PUBLIC_KEY_INFO in un blob chiave RSA con CryptDecodeObjectEx; passare X509_ASN_ENCODING in dwCertEncodingType e RSA_CSP_PUBLICKEYBLOB in lpszStructType
  4. importare la chiave blob RSA con CryptImportKey
+1

Un'altra implementazione: http://www.idrix.fr/Root/Samples/capi_pem.cpp – socketpair