none
[CryptoAPI]Get Modulus and exponent the public key RRS feed

  • Question

  • Hi guys,

    I would like know as i can get the modulus and exponent of the public key.

    The key was generated with success.

    // Public/private key handle.
        HCRYPTKEY hKey;
    
      if(CryptGenKey(
                            hCryptProv,
                            AT_SIGNATURE,
                            0,
                            &hKey))
                {
                    qDebug("Created a signature key pair.\n");
                }
                else
                {
    
                    qDebug()<<"Error occurred creating a signature key.";
                }

    Now I get the public key and construct

    DWORD dwPublicKeyLen = 0;
        BYTE* pbPublicKey = NULL;
    
        // Get public key size
        qDebug("CryptExportKey...\n");
        if (!CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwPublicKeyLen))
        {
            // Error
            qDebug()<< "CryptExportKey error 0x" <<GetLastError();
    
        }
    
        // Create a buffer for the public key
        qDebug("malloc...\n");
        if (!(pbPublicKey = (BYTE *)malloc(dwPublicKeyLen)))
        {
            // Error
            qDebug()<<"malloc error 0x%x\n"<<GetLastError();
        }
    
        // Get public key
        qDebug("CryptExportKey...\n");
        if (!CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, pbPublicKey, &dwPublicKeyLen))
        {
            // Error
            qDebug()<<"CryptExportKey error 0x"<< GetLastError();
        }

    Now I dont know as I can obtain the modulus and the exponent.

    Help me please

    Regards,

    Pedro Lopes


    • Edited by lopesaeteurope Friday, November 16, 2012 12:06 PM Change title
    Friday, November 16, 2012 11:35 AM

Answers

  • If you use CryptExportKey with PUBLICKEYBLOB then according to: http://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx

    The output will be:

    PUBLICKEYSTRUC  publickeystruc;
    RSAPUBKEY rsapubkey;
    BYTE modulus[rsapubkey.bitlen/8];

    You can get the exponent from the RSAPUBKEY.

    Andrew

    • Marked as answer by lopesaeteurope Monday, November 19, 2012 11:39 AM
    • Unmarked as answer by lopesaeteurope Monday, November 19, 2012 11:39 AM
    • Marked as answer by lopesaeteurope Monday, November 19, 2012 11:39 AM
    Monday, November 19, 2012 6:02 AM
  • If you call:

    CryptExportKey(PUBLICKEYBLOB, ... &pPublicKeyBlob);

    Then you can get the modulus by looking at:

    pbModulus = (PBYTE) pPublicKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY);

    The modulus will be a big number starting at pbModulus and it is rsapubkey.bitlength/8 bytes long.

    Andrew

    • Marked as answer by lopesaeteurope Wednesday, November 21, 2012 12:11 PM
    Wednesday, November 21, 2012 5:18 AM

All replies

  • If you use CryptExportKey with PUBLICKEYBLOB then according to: http://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx

    The output will be:

    PUBLICKEYSTRUC  publickeystruc;
    RSAPUBKEY rsapubkey;
    BYTE modulus[rsapubkey.bitlen/8];

    You can get the exponent from the RSAPUBKEY.

    Andrew

    • Marked as answer by lopesaeteurope Monday, November 19, 2012 11:39 AM
    • Unmarked as answer by lopesaeteurope Monday, November 19, 2012 11:39 AM
    • Marked as answer by lopesaeteurope Monday, November 19, 2012 11:39 AM
    Monday, November 19, 2012 6:02 AM
  • But how I can get the value of the modulus? Only modulus.

    Thanks for your answer!

    Regards, 

    Pedro Lopes

    Tuesday, November 20, 2012 9:56 AM
  • If you call:

    CryptExportKey(PUBLICKEYBLOB, ... &pPublicKeyBlob);

    Then you can get the modulus by looking at:

    pbModulus = (PBYTE) pPublicKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY);

    The modulus will be a big number starting at pbModulus and it is rsapubkey.bitlength/8 bytes long.

    Andrew

    • Marked as answer by lopesaeteurope Wednesday, November 21, 2012 12:11 PM
    Wednesday, November 21, 2012 5:18 AM
  • Thanks Andrew, you are helping me a lot.

     

    RSAPUBKEY *rsaPubKey;

    rsaPubKey = (RSAPUBKEY*)(pbPublicKey + sizeof(PUBLICKEYSTRUC));

    int two_sizes= (sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); int three_sizes= (sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + bitLen / 8); PBYTE pbModulus = (PBYTE) pbPublicKey + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY); std::string stringModulusAux(pbModulus,pbModulus+bitLen/8); std::string stringModulus(stringModulusAux,two_sizes,three_sizes);


    Seems good...right?

    To get exponent I have this 

    std::string stringExponent(rsaPubKey->pubexp,sizeof(rsaPubKey->pubexp));

    But doesn't work. What I do Andrew? 

    Also I have another problem with generation key pair.

    My code:

    if(CryptGenKey(
                            hCryptProv,
                            AT_SIGNATURE ,
                            RSA1024BIT_KEY,
                            &hKey))
                {

    Sometimes it´s generated key pairs size 512BIT and not 1024 as I have in code. Do you know what it happens?

    Thanks a lot, best regards for you !!



    Wednesday, November 21, 2012 11:07 AM
  • I'm not sure what std::stringModulusAux or std::stringModuls does. I searched and did not find info about them. Are you sure you are using it correctly?

    With respect to CryptGenKey, you should be getting a 1024 bit key. How do you know your key is not 1024? And what CSP are you using?

    Andrew

    Saturday, November 24, 2012 6:28 AM
  • I'm assuming you are trying to make text out of the exponent and modulus to send them somewhere else.

    If so, you want to convert the binary data to base64 using CryptBinaryToString()

       See http://technet.microsoft.com/en-us/library/aa379887.aspx

    You can't construct a std:string and assume that all the characters will be printable, as these multi-bytes numbers may contain the zero byte.

    Andrew B; Those are two and three parameter std::string constructors.

    For example:    std::string ( const string& str, size_t pos, size_t n = npos );

    Content is initialized to a copy of a substring of str. The substring is the portion of str that begins at the character position pos and takes up to n characters (it takes less than n if the end of str is reached before).

    NOTE: The third parameter of a std::string constructor is a length, not a position.

    Saturday, November 24, 2012 12:53 PM
  • I didn't read the code very carefully. You are right that using the std::string constructor is not appropriate since embedded "\00 \00" strings are possible and characters are likely non-printable. Using CryptBinaryToString to convert to hex or base64 is a good choice.

    Monday, November 26, 2012 2:35 AM
  • Hi thank you for your responses...

    I have other problem here now.

    I generate key pair and I got the modulus and exponent.

    Then so, i construct P10 (my code) and send it to CA. CA approve it and give me Certificate.

    Now I want put my certificate in store L"MY" and link key pair (container) with certificate.

    How I do this?

    I have this piece of code.

     //Find the certificate context
            if(pCertContext = CertCreateCertificateContext(
                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,// Encoding type
                        (BYTE*)certificate->constData(),
                        certificate->length()))
            {
                qDebug("A new certificate has been created.\n");
            }
            else
            {
                qDebug("A new certificate could not be created.");
            }
    
           
    
            // Declare and initialize variables.for CRYPT_KEY_PROV_INFO
            PCRYPT_KEY_PROV_INFO pData;
    
            if(!(pData= (CRYPT_KEY_PROV_INFO*) malloc
                 (sizeof(CRYPT_KEY_PROV_INFO))))
                qDebug("Memory allocation failed.");
    
            pData->pwszContainerName= (LPWSTR) CN.unicode();
            pData->pwszProvName= MS_DEF_PROV;
            pData->dwProvType= PROV_RSA_FULL;
            pData->dwFlags=CERT_SET_KEY_CONTEXT_PROP_ID;
            pData->cProvParam=0;
            pData->rgProvParam= NULL;
            pData->dwKeySpec= AT_SIGNATURE;
    
            //Associate key pair in one certificate
    
            if((CertSetCertificateContextProperty(pCertContext,               //pointer to the certificate context
                                                  CERT_KEY_PROV_INFO_PROP_ID,   //get the private key from file
                                                  NULL,
                                                  pData))){
                qDebug("The key was associated of the certificate.");
                free(pData);
    
            }else{
                qDebug("The key wasn't associated of the certificate.");
    
            }
    
    
            //-------------------------------------------------------------------
            // Add the certificate from the My store to the new memory store.
    
    
            if(CertAddCertificateContextToStore(
                        hMemoryStore,                // Store handle
                        pCertContext,
                        CERT_STORE_ADD_REPLACE_EXISTING,
                        NULL))
            {
                qDebug("Certificate added to the memory store. \n");
    
                CertFreeCertificateContext(pCertContext);

    The certificate appears in store L"MY" with image of the key but when I go sign a document not work. Error is : Set of Key pair doesnt exist!!

    Thanks for all

    Best regards!

    Wednesday, December 12, 2012 7:05 PM
  • First, check that the key containers are the same:

    #1) Parameter for CryptAcquireContext when you created the key pair.

    #2) pData->pwszContainerName= (LPWSTR) CN.unicode();
     

    Second try a GetUserKey with the parameters you set.

    Also which API did you use to sign something?

    p.s. Congrat on getting the .p10 and certificate.


    • Edited by Andrew7Webb Wednesday, December 12, 2012 7:53 PM .
    Wednesday, December 12, 2012 7:51 PM
  • Hello, thanks for your quick reply.

    My container is always the same. 

    I sign data as you can see below in the code.

     if(CryptAcquireContext(
                    &hCryptProv,
                    pszContainerName,
                    MS_DEF_PROV,
                    PROV_RSA_FULL,
                    0))
        {
            qDebug("CryptAcquireContext succeeded, signData().\n");
        }
    
        //-------------------------------------------------------------------
        // Create the hash object.
    
        if(CryptCreateHash(
                    hCryptProv,
                    CALG_SHA1,
                    0,
                    0,
                    &hHash))
        {
            qDebug("Hash object created. \n");
        }
        else
        {
            MyHandleError("Error during CryptCreateHash.");
        }
        //-------------------------------------------------------------------
        // Compute the cryptographic hash of the buffer.
    
        if(CryptHashData(
                    hHash,
                    pbBuffer,
                    dwBufferLen,
                    0))
        {
            qDebug("The data buffer has been hashed.\n");
        }
        else
        {
            MyHandleError("Error during CryptHashData.");
        }
        //-------------------------------------------------------------------
        // Determine the size of the signature and allocate memory.
    
        dwSigLen= 0;
        if(CryptSignHash(
                    hHash,
                    AT_SIGNATURE,
                    NULL,
                    0,
                    NULL,
                    &dwSigLen))
        {
            qDebug("Signature length %d found.\n",dwSigLen);
        }
        else
        {
            MyHandleError("Error during CryptSignHash.");
        }
        //-------------------------------------------------------------------
        // Allocate memory for the signature buffer.
    
        if(pbSignature = (BYTE *)malloc(dwSigLen))
        {
            qDebug("Memory allocated for the signature.\n");
        }
        else
        {
            MyHandleError("Out of memory.");
        }
        //-------------------------------------------------------------------
        // Sign the hash object.
    
        if(CryptSignHash(
                    hHash,
                    AT_SIGNATURE,
                    NULL,
                    0,
                    pbSignature,
                    &dwSigLen))
        {
            qDebug("pbSignature is the hash signature.\n");
        }
        else
        {
            MyHandleError("Error during CryptSignHash.");
        }

    it works fine, and then of this code, I check the signature (also good).

    I really dont understand this!!!

    Thursday, December 13, 2012 7:19 PM
  • So now you can produce and verify a signature with the public key. 

    So what remains to be explained is why you received a NTE_NO_KEY from CryptSignHash on Wednesday, but not Thursday.

    Perhaps there was some glitch associated with the creation of the key container.  Maybe you were debugging once and did not do the CryptReleaseContext() after the key creation?   That would be a possible explanation of a problem that goes away after you run the code again.

    There are two test cases to consider: 1) Does the code work before the key container is created, and 2) Does it work if the container is already created.

    Friday, December 14, 2012 2:25 PM
  • I've finally managed to sign a document. Thanks a lot andrew!!

    The problem was name container. Has be NULL.

    Thanks guys!!

    Wednesday, December 19, 2012 4:00 PM
  • Could you explain a bit more? In which API did you need a NULL ?
    Wednesday, December 19, 2012 4:05 PM
  • For example, I had this

     if(CryptAcquireContext(
                    &hCryptProv,
                    pszContainerName,
                    MS_DEF_PROV,
                    PROV_RSA_FULL,
                    0))
    {}

    The container name was a name eg "john-lopes21" as could be "andrew21". But when I would sign not existed key pair because I wasnt authenticated (user account windows) by that name. So, I put the name of the container to NULL. If container name is NULL the user account is default, (i´m using in this moment).

    I don't know if I properly explained myself. (my english yet is poor, sorry)

    Thanks for all!!

    Best regards!

    Thursday, December 20, 2012 9:59 AM
  • Using different accounts for the key generation and signing could also cause missing keys.
    Thursday, December 20, 2012 3:15 PM