2009-08-05 5 views
11

Je suis nouveau à l'ensemble de la chose Crypto, donc je demande quelques pointeurs de base.Charger un fichier PEM X509 dans Windows CryptoApi

J'ai besoin de charger .PEM (X509) "----- BEGIN RSA XXX KEY ----- ----- FIN RSA XXX KEY -----" dans un contexte Windows Crypto Api à utiliser avec C++ (j'ai trouvé des exemples pour Python et .NET mais ils utilisent des fonctions spécifiques que je ne peux pas associer au crypto Api de Windows)

Je comprends comment crypter/décrypter une fois que j'ai un HCRYPTKEY. MAIS, je ne comprends pas comment importer le BLOB Base64 dans le (s) fichier (s) .PEM et obtenir un HCRYPTKEY que je peux utiliser hors de celui-ci. J'ai le sentiment étrange qu'il y a plus que simplement appeler CryptDecodeObject().

Des pointeurs qui peuvent me mettre sur la bonne voie? J'ai déjà perdu 2 jours en faisant "erreur de procès &" de programmation et d'obtenir nulle part.

Répondre

19

KJKHyperion a dit dans son 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

Cette séquence m'a vraiment aidé à comprendre ce qui se passe , mais ça n'a pas marché pour moi tel quel. Le deuxième appel à CryptDecodeObjectEx m'a donné une erreur: "ASN.1 bad tag value met". Après de nombreuses tentatives de compréhension de la documentation de Microsoft, j'ai finalement réalisé que la sortie du premier décodage ne peut plus être décodée en ASN et qu'elle est prête à être importée. Avec cette compréhension, j'ai trouvé la réponse dans le lien suivant:

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

Ce qui suit est mon propre programme qui importe une clé publique d'un.fichier pem dans un contexte de 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

pourriez-vous fournir la clé publique WORKING? Votre programme ne fonctionne toujours pas pour moi .. mais ma clé est vraiment valide. – socketpair

+0

Autre implémentation: http://idrix.fr/Root/Samples/capi_pem.cpp – socketpair

+1

@socketpair en fonction de l'implémentation, la signature numérique devra peut-être être complètement inversée par octet avant d'être vérifiée – moala

2

Je suis actuellement confronté à la même difficulté. Je n'ai pas fini de coder une solution, mais si je comprends bien, vous devez enlever le ----- BEGIN etc ----- et ----- END etc ------ tags et décoder le Base64 . Cela vous laisse avec une chaîne codée DER, que vous devez analyser pour obtenir le module et l'exposant public. Parmi ceux-ci, vous pouvez remplir les structures PUBLICKEYSTRUC et RSAPUBKEY. Bonne chance ;-)

+0

Regardez dans CryptDecodeObjectEx avec des options de X509_ASN_ENCODING et RSA_CSP_PUBLICKEYBLOB. Semble décoder et remplir la structure correctement, mais vous devrez peut-être encore échanger l'ordre des octets de certaines parties. – jarmond

9

J'ai découvert la séquence "magique" d'appels pour importer une clé publique RSA au format PEM. Ici, vous allez:

  1. decode la clé dans un blob binaire avec CryptStringToBinary; passer CRYPT_STRING_BASE64HEADER dans dwFlags
  2. décoder la clé blob binaire en un CERT_PUBLIC_KEY_INFO avec CryptDecodeObjectEx; passer X509_ASN_ENCODING dans dwCertEncodingType et X509_PUBLIC_KEY_INFO dans lpszStructType
  3. décoder le blob PublicKey du CERT_PUBLIC_KEY_INFO dans une goutte de clé RSA avec CryptDecodeObjectEx; passer X509_ASN_ENCODING dans dwCertEncodingType et RSA_CSP_PUBLICKEYBLOB dans lpszStructType
  4. importer le blob clé RSA avec CryptImportKey
+1

Une autre implémentation: http://www.idrix.fr/Root/Samples/capi_pem.cpp – socketpair

Questions connexes