2009-08-05 12 views
11

Jestem nowy w całej sprawie Crypto, więc proszę o kilka podstawowych wskazówek.Załaduj plik PEM X509 do systemu Windows CryptoApi

Muszę załadować .PEM (X509) "----- BEGIN RSA XXX KEY ----- ----- END RSA XXX KEY -----" do kontekstu Windows Crypto Api, aby użyj z C++ (znalazłem przykłady dla Pythona i .NET, ale używają specyficznych funkcji, których nie mogę odnieść do zwykłego Windows Crypto Api)

Rozumiem, jak szyfrować/odszyfrowywać, gdy mam HCRYPTKEY. ALE, po prostu nie rozumiem, jak zaimportować blob Base64 w pliku .PEM i uzyskać HCRYPTKEY, z którego mogę go użyć.

Mam przeczucie, że chodzi o coś więcej niż po prostu wywołanie CryptDecodeObject().

Jakieś wskazówki, które mogą mi pomóc? Przegrałem już 2 dni, wykonując "próbny błąd &" programując i kończąc.

Odpowiedz

19

KJKHyperion powiedział w swoim 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

Ta sekwencja naprawdę pomógł mi zrozumieć, co się dzieje , ale to nie zadziałało jak na mnie. Drugie połączenie z numerem CryptDecodeObjectEx spowodowało błąd: "Zidentyfikowano nieprawidłową wartość tagu ASN.1". Po wielu próbach zrozumienia dokumentacji Microsoftu, w końcu zdałem sobie sprawę, że dane wyjściowe dekodowania pięści nie mogą być ponownie zdekodowane jako ASN, i że jest on faktycznie gotowy do importu. Z tego zrozumienia Znalazłem odpowiedź w poniższy link:

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

Po to mój własny program, który importuje klucz publiczny z a.plik PEM do kontekstu 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

Czy możesz podać WORKING public key? Twój program nadal nie działa dla mnie .. ale mój klucz jest naprawdę ważny. – socketpair

+0

Kolejna implementacja: http://idrix.fr/Root/Samples/capi_pem.cpp – socketpair

+1

@socketpair w zależności od implementacji, podpis cyfrowy może wymagać pełnego odwrócenia bajtu przed zweryfikowaniem – moala

2

Obecnie mam ten sam problem. Nie skończyłem kodowania rozwiązania, ale jak rozumiem, musisz rozebrać się na ----- BEGIN itd. ----- i ----- END etc ------ i zdekodować Base64 .

To pozostawia ci zakodowany ciąg DER, który musisz przeanalizować, aby uzyskać moduł i publiczny wykładnik. Z tych można wypełnić struktury PUBLICKEYSTRUC i RSAPUBKEY. Powodzenia ;-)

+0

Look w CryptDecodeObjectEx z opcji X509_ASN_ENCODING i RSA_CSP_PUBLICKEYBLOB. Wydaje się, że poprawnie dekoduje i wypełnia strukturę, ale nadal może być konieczna zamiana kolejności bajtów niektórych części. – jarmond

9

Odkryłem "magiczną" sekwencję wywołań do zaimportowania klucza publicznego RSA w formacie PEM. Proszę bardzo:

  1. dekodowania klucz do binarnego blob z CryptStringToBinary; przechodzą CRYPT_STRING_BASE64HEADER w dwFlags
  2. dekodować binarny blob klucz do CERT_PUBLIC_KEY_INFO z CryptDecodeObjectEx; przechodzą X509_ASN_ENCODING w dwCertEncodingType i X509_PUBLIC_KEY_INFO w lpszStructType
  3. dekodować blob PublicKey z CERT_PUBLIC_KEY_INFO pod klucz RSA blob z CryptDecodeObjectEx; przechodzą X509_ASN_ENCODING w dwCertEncodingType i RSA_CSP_PUBLICKEYBLOB w lpszStructType
  4. zaimportować klucz blob RSA z CryptImportKey
+1

Inna realizacja: http://www.idrix.fr/Root/Samples/capi_pem.cpp – socketpair

Powiązane problemy