locked
How to Sign with RSA private key by CNG RRS feed

  • Question

  • 1. How to sign with RSA private key?

    I followed this sample to sign data with private key. I only reserve hash and sign functions, and use ECDSA P-256 private key like the sample.

    Here are my steps and the program work fine:

    • BCryptOpenAlgorithmProvider()
    • Hash some data
    • NCryptOpenStorageProvider()
    • NCryptCreatePersistedKey()
    • NCryptFinalizeKey()
    • NCryptSignHash()
    • NCryptSignHash()

    I tried to sign with RSA private key, replace NCRYPT_ECDSA_P256_ALGORITHM with NCRYPT_RSA_ALGORITHM and NCRYPT_RSA_SIGN_ALGORITHM, but it failed in second NCryptSignHash() with NTE_INVALID_PARAMETER.

        //create a persisted key
        if (FAILED(secStatus = NCryptCreatePersistedKey(
            hProv,
            &hKey,
            NCRYPT_RSA_ALGORITHM,
            L"my RSA key",
            0,
            0)))
        {
            wprintf(L"**** Error 0x%x returned by NCryptCreatePersistedKey\n", secStatus);
            goto Cleanup;
        }

    2. Why the program can't find the private key after first run?

    The private key in sample is created in the program, I tried to sign with X509 certificate which has private key(ECDSA P-256) in My certifacate store.

    Here are my steps and the program only work in the first run. It failed in CryptAcquireCertificatePrivateKey() with NTE_BAD_KEYSET error

    • BCryptOpenAlgorithmProvider()
    • Hash some data
    • CertOpenStore()
    • CertFindCertificateInStore()
    • CryptAcquireCertificatePrivateKey()
    • NCryptSignHash()
    • NCryptSignHash()
    // Open the certificate store.
       if (!(hCertStore = CertOpenStore(
           CERT_STORE_PROV_SYSTEM,
           0,
           NULL,
           CERT_SYSTEM_STORE_CURRENT_USER,
           CERT_STORE_NAME)))
       {
           MyHandleError(const_cast<LPTSTR>("The MY store could not be opened."));
       }
       swprintf(wMY_SIGNER_NAME, 100, L"%hs", MY_SIGNER_NAME);
       if (pSignerCert = CertFindCertificateInStore(
           hCertStore,
           MY_ENCODING_TYPE,
           0,
           CERT_FIND_SUBJECT_STR,
           wMY_SIGNER_NAME,
           NULL))
       {
           //_tprintf(TEXT("The signer's certificate was found.\n"));
       }
       else
       {
           MyHandleError(const_cast<LPTSTR>("Signer certificate not found."));
       }
    
       if (CryptAcquireCertificatePrivateKey(
           pSignerCert, 
           CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG, NULL, 
           &hKey,
           &dwKeySpec, 
           false))
       {
           printf("Get Priv OK\n");
       }
       else
       {
           if (GetLastError() == NTE_BAD_KEYSET)
               printf("NTE_BAD_KEYSET\n");
       }


    Wednesday, February 26, 2020 5:31 AM

Answers

  • Hi Rita, 

    For #1 question 

    The code worked after adding NCryptSetProperty() to set RSA key length and changing parameter in NCryptSignHash():

    	DWORD keyLength = 2048;
    	BCRYPT_PKCS1_PADDING_INFO padding_PKCS1 = BCRYPT_PKCS1_PADDING_INFO();

    	if (FAILED(NCryptSetProperty(
    		hKey, 
    		NCRYPT_LENGTH_PROPERTY, 
    		(PBYTE)(&keyLength), 
    		sizeof(keyLength), 
    		NCRYPT_PERSIST_FLAG)))
    	{
    		wprintf(L"**** Error 0x%x returned by NCryptSetProperty\n", secStatus);
    		goto Cleanup;
    	}


    	if (FAILED(secStatus = NCryptSignHash(
    		hKey,
    		&padding_PKCS1,
    		pbHash,
    		cbHash,
    		NULL,
    		0,
    		&cbSignature,
    		BCRYPT_PAD_PKCS1)))
    	{
    		wprintf(L"**** Error 0x%x returned by NCryptSignHash1\n", secStatus);
    		goto Cleanup;
    	}

    but it can't work with BCRYPT_PAD_PSS, do you have any idea?

    For #2 question

    Here is my code, the EC Key can only use one time. The RSA private key could reuse many times. I don't have any idea about this.

    Don't forget add BCRYPT_PAD_PKCS1 like above to use RSA key

    	NCRYPT_PROV_HANDLE      hProv = NULL;
    	NCRYPT_KEY_HANDLE       hKey = NULL;
    	BCRYPT_KEY_HANDLE       hTmpKey = NULL;
    	SECURITY_STATUS         secStatus = ERROR_SUCCESS;
    	BCRYPT_ALG_HANDLE       hHashAlg = NULL, hSignAlg = NULL;
    	BCRYPT_HASH_HANDLE      hHash = NULL;
    	NTSTATUS                status = STATUS_UNSUCCESSFUL;
    	DWORD                   cbData = 0, cbHash = 0, cbBlob = 0, cbSignature = 0, cbHashObject = 0;
    	PBYTE                   pbHashObject = NULL;
    	PBYTE                   pbHash = NULL, pbBlob = NULL, pbSignature = NULL;
    	HCERTSTORE hCertStore = NULL;
    	wchar_t wMY_SIGNER_NAME[100];
    	PCCERT_CONTEXT pSignerCert = NULL;
    	DWORD dwKeySpec;
    	DWORD keyLength = 2048;
    	BCRYPT_PKCS1_PADDING_INFO padding_PKCS1 = BCRYPT_PKCS1_PADDING_INFO();
    	BCRYPT_PSS_PADDING_INFO padding_PSS = BCRYPT_PSS_PADDING_INFO();
    // Hash data here


    if (!(hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"))) { printf("The MY store could not be opened."); } swprintf(wMY_SIGNER_NAME, 100, L"%hs", MY_SIGNER_NAME); if (pSignerCert = CertFindCertificateInStore( hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, wMY_SIGNER_NAME, NULL)) { printf("The signer's certificate was found.\n")l } else { printf("Signer certificate not found."); } if (CryptAcquireCertificatePrivateKey( pSignerCert, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, NULL, &hKey, &dwKeySpec, NULL)) { printf("Get Private Key\n"); } else { printf("Error code %x \n", GetLastError()); if (GetLastError() == NTE_BAD_KEYSET) printf("NTE_BAD_KEYSET\n"); goto Cleanup; } //sign the hash if (FAILED(secStatus = NCryptSignHash( hKey, 0, pbHash, cbHash, NULL, 0, &cbSignature, 0))) { wprintf(L"**** Error 0x%x returned by NCryptSignHash1\n", secStatus); goto Cleanup; } //allocate the signature buffer pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature); if (NULL == pbSignature) { wprintf(L"**** memory allocation failed\n"); goto Cleanup; } if (FAILED(secStatus = NCryptSignHash( hKey, 0, pbHash, cbHash, pbSignature, cbSignature, &cbSignature, 0))) { if (GetLastError() == NTE_BAD_KEYSET) printf("NTE_BAD_KEYSET\n"); wprintf(L"**** Error 0x%x returned by NCryptSignHash2\n", secStatus); goto Cleanup; } else { printf("Sign OK\n"); }

    Thanks.




    Wednesday, February 26, 2020 10:37 AM
  • UPDATE:

    PKCS#1 and PSS pading method could work after add these code before NCryptSignHash():

    padding_PKCS1.pszAlgId = BCRYPT_SHA256_ALGORITHM; padding_PSS.pszAlgId = BCRYPT_SHA256_ALGORITHM; padding_PSS.cbSalt = 32;

    //NCryptSignHash()...

    There is only one question remain, EC private key can only use one time.

    Thanks

    • Marked as answer by _Wayne56 Monday, March 2, 2020 12:55 AM
    Wednesday, February 26, 2020 11:32 AM
  • HI Rita,

    I think i found the problem!

    After every run, I delete and free objects like official sample. I tried to remove this part:

    	if (hKey)
    	{
    		NCryptDeleteKey(hKey, 0);
    	}

    The code run very well, EC key could reuse! But there is another question, why X509 certificate which has private key(RSA) not deleted by NCryptDeleteKey()?




    • Edited by _Wayne56 Thursday, February 27, 2020 5:51 AM
    • Marked as answer by _Wayne56 Monday, March 2, 2020 12:55 AM
    Thursday, February 27, 2020 5:42 AM

All replies

  • Hello 頑張る,

    For #1 question:

    The following code works for me. Can you have a try?

    	NCRYPT_PROV_HANDLE          hProv = 0;
    	NCRYPT_KEY_HANDLE           hKey = 0;
    	SECURITY_STATUS             secStatus = S_OK;
    
    	secStatus = NCryptOpenStorageProvider(
    		&hProv,
    		MS_KEY_STORAGE_PROVIDER,
    		0);
    	if (FAILED(secStatus))
    	{
    		printf("error: %d \n", secStatus);
    	}
    
    
    	if (FAILED(secStatus = NCryptCreatePersistedKey(
    		hProv,
    		&hKey,
    		NCRYPT_RSA_ALGORITHM,
    		L"my RSA key",
    		0,
    		0)))
    	{
    		printf("error: %d \n", secStatus);
    	}

    For #2 question:

    I can't reproduce this issue with the following code. You can have a try to see if it helps. And could you show a mini, complete and reproducible sample code for your parameter settings so I can do a further investigation. 

    void FindKey()
    {
    	HCERTSTORE hCertStore = NULL;
    	PCCERT_CONTEXT pSignerCert = NULL;
    	WCHAR wMY_SIGNER_NAME[] = L"mydevice";
    	HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hKey = NULL;
    	DWORD dwKeySpec = 0;
    
    	// Open the certificate store.
    	if (!(hCertStore = CertOpenStore(
    		CERT_STORE_PROV_SYSTEM,
    		0,
    		NULL,
    		CERT_SYSTEM_STORE_CURRENT_USER,
    		L"MY")))
    	{
    		printf("The MY store could not be opened. error: %x \n", GetLastError());
    	}
    
    	if (pSignerCert = CertFindCertificateInStore(
    		hCertStore,
    		X509_ASN_ENCODING,
    		0,
    		CERT_FIND_SUBJECT_STR,
    		wMY_SIGNER_NAME,
    		NULL))
    	{
    		//_tprintf(TEXT("The signer's certificate was found.\n"));
    	}
    	else
    	{
    		printf("Signer certificate not found.\n");
    	}
    
    	if (CryptAcquireCertificatePrivateKey(
    		pSignerCert,
    		CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG, NULL,
    		&hKey,
    		&dwKeySpec,
    		false))
    	{
    		printf("Get Priv OK\n");
    	}
    	else
    	{
    		if (GetLastError() == NTE_BAD_KEYSET)
    			printf("NTE_BAD_KEYSET\n");
    	}
    }

    Please let me know if it helps.

    Best regards,

    Rita


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, February 26, 2020 10:08 AM
  • Hi Rita, 

    For #1 question 

    The code worked after adding NCryptSetProperty() to set RSA key length and changing parameter in NCryptSignHash():

    	DWORD keyLength = 2048;
    	BCRYPT_PKCS1_PADDING_INFO padding_PKCS1 = BCRYPT_PKCS1_PADDING_INFO();

    	if (FAILED(NCryptSetProperty(
    		hKey, 
    		NCRYPT_LENGTH_PROPERTY, 
    		(PBYTE)(&keyLength), 
    		sizeof(keyLength), 
    		NCRYPT_PERSIST_FLAG)))
    	{
    		wprintf(L"**** Error 0x%x returned by NCryptSetProperty\n", secStatus);
    		goto Cleanup;
    	}


    	if (FAILED(secStatus = NCryptSignHash(
    		hKey,
    		&padding_PKCS1,
    		pbHash,
    		cbHash,
    		NULL,
    		0,
    		&cbSignature,
    		BCRYPT_PAD_PKCS1)))
    	{
    		wprintf(L"**** Error 0x%x returned by NCryptSignHash1\n", secStatus);
    		goto Cleanup;
    	}

    but it can't work with BCRYPT_PAD_PSS, do you have any idea?

    For #2 question

    Here is my code, the EC Key can only use one time. The RSA private key could reuse many times. I don't have any idea about this.

    Don't forget add BCRYPT_PAD_PKCS1 like above to use RSA key

    	NCRYPT_PROV_HANDLE      hProv = NULL;
    	NCRYPT_KEY_HANDLE       hKey = NULL;
    	BCRYPT_KEY_HANDLE       hTmpKey = NULL;
    	SECURITY_STATUS         secStatus = ERROR_SUCCESS;
    	BCRYPT_ALG_HANDLE       hHashAlg = NULL, hSignAlg = NULL;
    	BCRYPT_HASH_HANDLE      hHash = NULL;
    	NTSTATUS                status = STATUS_UNSUCCESSFUL;
    	DWORD                   cbData = 0, cbHash = 0, cbBlob = 0, cbSignature = 0, cbHashObject = 0;
    	PBYTE                   pbHashObject = NULL;
    	PBYTE                   pbHash = NULL, pbBlob = NULL, pbSignature = NULL;
    	HCERTSTORE hCertStore = NULL;
    	wchar_t wMY_SIGNER_NAME[100];
    	PCCERT_CONTEXT pSignerCert = NULL;
    	DWORD dwKeySpec;
    	DWORD keyLength = 2048;
    	BCRYPT_PKCS1_PADDING_INFO padding_PKCS1 = BCRYPT_PKCS1_PADDING_INFO();
    	BCRYPT_PSS_PADDING_INFO padding_PSS = BCRYPT_PSS_PADDING_INFO();
    // Hash data here


    if (!(hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"))) { printf("The MY store could not be opened."); } swprintf(wMY_SIGNER_NAME, 100, L"%hs", MY_SIGNER_NAME); if (pSignerCert = CertFindCertificateInStore( hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, wMY_SIGNER_NAME, NULL)) { printf("The signer's certificate was found.\n")l } else { printf("Signer certificate not found."); } if (CryptAcquireCertificatePrivateKey( pSignerCert, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, NULL, &hKey, &dwKeySpec, NULL)) { printf("Get Private Key\n"); } else { printf("Error code %x \n", GetLastError()); if (GetLastError() == NTE_BAD_KEYSET) printf("NTE_BAD_KEYSET\n"); goto Cleanup; } //sign the hash if (FAILED(secStatus = NCryptSignHash( hKey, 0, pbHash, cbHash, NULL, 0, &cbSignature, 0))) { wprintf(L"**** Error 0x%x returned by NCryptSignHash1\n", secStatus); goto Cleanup; } //allocate the signature buffer pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature); if (NULL == pbSignature) { wprintf(L"**** memory allocation failed\n"); goto Cleanup; } if (FAILED(secStatus = NCryptSignHash( hKey, 0, pbHash, cbHash, pbSignature, cbSignature, &cbSignature, 0))) { if (GetLastError() == NTE_BAD_KEYSET) printf("NTE_BAD_KEYSET\n"); wprintf(L"**** Error 0x%x returned by NCryptSignHash2\n", secStatus); goto Cleanup; } else { printf("Sign OK\n"); }

    Thanks.




    Wednesday, February 26, 2020 10:37 AM
  • UPDATE:

    PKCS#1 and PSS pading method could work after add these code before NCryptSignHash():

    padding_PKCS1.pszAlgId = BCRYPT_SHA256_ALGORITHM; padding_PSS.pszAlgId = BCRYPT_SHA256_ALGORITHM; padding_PSS.cbSalt = 32;

    //NCryptSignHash()...

    There is only one question remain, EC private key can only use one time.

    Thanks

    • Marked as answer by _Wayne56 Monday, March 2, 2020 12:55 AM
    Wednesday, February 26, 2020 11:32 AM
  • Hello 頑張る,

    I make some edit and get your code works for me. The following is complete code:

    	NCRYPT_PROV_HANDLE      hProv = NULL;
    	NCRYPT_KEY_HANDLE       hKey = NULL;
    	BCRYPT_KEY_HANDLE       hTmpKey = NULL;
    	SECURITY_STATUS         secStatus = ERROR_SUCCESS;
    	BCRYPT_ALG_HANDLE       hHashAlg = NULL, hSignAlg = NULL;
    	BCRYPT_HASH_HANDLE      hHash = NULL;
    	NTSTATUS                status = 0;
    	DWORD                   cbData = 0, cbHash = 0, cbBlob = 0, cbSignature = 0, cbHashObject = 0;
    	PBYTE                   pbHashObject = NULL;
    	PBYTE                   pbHash = NULL, pbBlob = NULL, pbSignature = NULL;
    	HCERTSTORE hCertStore = NULL;
    	WCHAR wMY_SIGNER_NAME[] = L"mydevice";
    	PCCERT_CONTEXT pSignerCert = NULL;
    	DWORD dwKeySpec;
    	DWORD keyLength = 2048;
    	BCRYPT_PKCS1_PADDING_INFO padding_PKCS1 = BCRYPT_PKCS1_PADDING_INFO();
    	BCRYPT_PSS_PADDING_INFO padding_PSS = BCRYPT_PSS_PADDING_INFO();
    
    	if (!(hCertStore = CertOpenStore(
    		CERT_STORE_PROV_SYSTEM,
    		0,
    		NULL,
    		CERT_SYSTEM_STORE_CURRENT_USER,
    		L"MY")))
    	{
    		printf("The MY store could not be opened.");
    	}
    
    	if (pSignerCert = CertFindCertificateInStore(
    		hCertStore,
    		X509_ASN_ENCODING,
    		0,
    		CERT_FIND_SUBJECT_STR,
    		wMY_SIGNER_NAME,
    		NULL))
    	{
    		printf("The signer's certificate was found.\n");
    	}
    	else
    	{
    		printf("Signer certificate not found.");
    	}
    
    	if (CryptAcquireCertificatePrivateKey(
    		pSignerCert,
    		CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG,
    		NULL,
    		&hKey,
    		&dwKeySpec,
    		NULL))
    	{
    		printf("Get Private Key\n");
    	}
    	else
    	{
    		printf("Error code %x \n", GetLastError());
    		if (GetLastError() == NTE_BAD_KEYSET)
    			printf("NTE_BAD_KEYSET\n");
    	}
    
    	padding_PKCS1.pszAlgId = BCRYPT_SHA256_ALGORITHM;
    	padding_PSS.pszAlgId = BCRYPT_SHA256_ALGORITHM;
    	padding_PSS.cbSalt = 32;
    	BYTE testData[10] = {0}; // For testing purpose
    	pbHash = testData;
    	cbHash = sizeof(testData);
    	//sign the hash
    	if (FAILED(secStatus = NCryptSignHash(
    		hKey,
    		&padding_PSS,
    		pbHash,
    		cbHash,
    		NULL,
    		0,
    		&cbSignature,
    		BCRYPT_PAD_PSS)))
    	{
    		wprintf(L"**** Error 0x%x returned by NCryptSignHash1\n", secStatus);
    	}
    	NTE_BAD_ALGID;
    	//allocate the signature buffer
    	pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature);
    	if (NULL == pbSignature)
    	{
    		wprintf(L"**** memory allocation failed\n");
    	}
    	DWORD cbResult = 0;
    	secStatus = NCryptSignHash(
    		hKey,
    		&padding_PSS,
    		pbHash,
    		cbHash,
    		pbSignature,
    		cbSignature,
    		&cbResult,
    		BCRYPT_PAD_PSS);
    	if (FAILED(secStatus))
    	{
    		if (GetLastError() == NTE_BAD_KEYSET)
    			printf("NTE_BAD_KEYSET\n");
    		wprintf(L"**** Error 0x%x returned by NCryptSignHash2\n", secStatus);
    	}
    	else {
    		printf("Sign OK\n");
    	}

    >>>There is only one question remain, EC private key can only use one time.

    If you mean EC private key is NCRYPT_ECDSA_P256_ALGORITHM/BCRYPT_ECDSA_P256_ALGORITHM, the official sample you referred to is an example of using NCRYPT_ECDSA_P256_ALGORITHM.

    First run will success. And second run result in NTE_EXISTS error at NCryptCreatePersistedKey function call. This because "A key with the specified name already exists and the NCRYPT_OVERWRITE_KEY_FLAG was not specified.". To solve this issue, either change the key name, for example, from "my ecc key" to "my ecc 1 key", or set NCRYPT_OVERWRITE_KEY_FLAG value to dwFlags parameter.

    If this is not your case, show a complete sample code can reproduce this issue that "EC private key can only use one time" and reproducible steps. So I can do a further investigation.

    Please let me know if it helps.

    Best regards,

    Rita


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, February 27, 2020 4:17 AM
  • Hi Rita, 

    Let me clarify my case, I tried to sign with X509 certificate which has private key(ECDSA P-256) in MY certificate store.

    The private key in official sample is generated by code. It's not my need now.

    The code you post almost is my sample. Just change the parameters in NCryptSignHash()

    	//sign the hash
    	if (FAILED(secStatus = NCryptSignHash(
    		hKey,
    		0,
    		pbHash,
    		cbHash,
    		NULL,
    		0,
    		&cbSignature,
    		0)))
    	{
    		wprintf(L"**** Error 0x%x returned by NCryptSignHash1\n", secStatus);
    		goto Cleanup;
    	}
    
    	//allocate the signature buffer
    	pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature);
    	if (NULL == pbSignature)
    	{
    		wprintf(L"**** memory allocation failed\n");
    		goto Cleanup;
    	}
    
    	if (FAILED(secStatus = NCryptSignHash(
    		hKey,
    		0,
    		pbHash,
    		cbHash,
    		pbSignature,
    		cbSignature,
    		&cbSignature,
    		0)))
    	{
    		wprintf(L"**** Error 0x%x returned by NCryptSignHash2\n", secStatus);
    		goto Cleanup;
    	}

    It sign the data success in the first run. Failed in CryptAcquireCertificatePrivateKey() with NTE_BAD_KEYSET after first run.

    Thanks for you help.

    Thursday, February 27, 2020 5:27 AM
  • HI Rita,

    I think i found the problem!

    After every run, I delete and free objects like official sample. I tried to remove this part:

    	if (hKey)
    	{
    		NCryptDeleteKey(hKey, 0);
    	}

    The code run very well, EC key could reuse! But there is another question, why X509 certificate which has private key(RSA) not deleted by NCryptDeleteKey()?




    • Edited by _Wayne56 Thursday, February 27, 2020 5:51 AM
    • Marked as answer by _Wayne56 Monday, March 2, 2020 12:55 AM
    Thursday, February 27, 2020 5:42 AM
  • Hello 頑張る,

    After call NCryptDeleteKey function, x509 certificate private key also result in NTE_BAD_KEYSET for me. Can you have a double check?

    Best regards,

    Rita


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, February 27, 2020 9:45 AM
  • Do you remove certificate and import again?
    Thursday, February 27, 2020 11:33 AM
  • You need to add NCryptSetProperty() to set key length.

    That will solve your problem.

    Regards.

    Abigail | Apps4Rent

    Thursday, February 27, 2020 11:53 AM
  • Yes, I solved that. Thanks😀
    Thursday, February 27, 2020 12:01 PM