What is the mechanism of private key for decryption in PKCS11 - encryption

Here is some part of my code
I already encrypt some text from another app VB.net via RSACryptoProvider
But I stuck at the step to decrypt in C.
Here is my code.
static CK_RV usePrivateKeytoDecrypt(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) {
CK_RV rv = CKR_OK;
CK_MECHANISM mechanism = {
{CKM_RSA_PKCS_OAEP}
};
rv = C_DecryptInit(hSession, &mechanism, hObject);
return rv;
}
The code is not completed. I try to debug and got the error CKR_MECHANISM_PARAM_INVALID
Please help. Thanks

You are not correctly initializing your mechanism structure. The CK_MECHANISM is a structure that requires 3 parameters to be defined:
typedef struct CK_MECHANISM {
CK_MECHANISM_TYPE mechanism;
CK_VOID_PTR pParameter;
CK_ULONG ulParameterLen; /* in bytes */
} CK_MECHANISM;
You need to initialize your mechanism as follow:
CK_MECHANISM mechanism = { CKM_RSA_PKCS_OAEP, NULL_PTR, 0 };
If you generated your private-public key-pair as RSA key-pair (using CKM_RSA_PKCS_KEY_PAIR_GEN mechanism) e.g.
CK_MECHANISM GenMechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
Then you need to initialize your mechanism for decryption as follow:
CK_MECHANISM mechanism = { CKM_RSA_PKCS, NULL_PTR, 0};
I presume you are already logged in with your hsession and the hObject is the located private key to be used for decryption?

It depends on the algorithm of the Key Pair.
If the Key Pair's algorithm is RSA, it could be CKM_RSA_PKCS / CKM_RSA_PKCS_OAEP / CKM_RSA_X_509.
If the Key Pair's algorithm is EC, it could be CKM_ECDSA.
Provided, the Private Key has the attribute CKA_DECRYPT set to true.
You can refer to this documentation here.

You must set mechanism parameters:
CK_RSA_PKCS_OAEP_PARAMS oaepParams = {CKM_SHA_1, CKG_MGF1_SHA1, 1, NULL_PTR, 0};
CK_MECHANISM MechEncrypt = {CKM_RSA_PKCS_OAEP, &oaepParams, sizeof(oaepParams)};

Related

HSM decryption + encryption chaining

My application is acting as a switchboard to transfer very sensitive messages between two parties and I'm trying to figure out how I can do this without "looking" at the message they're trying to send.
I have a HSM, and I've generated a keypair for the sender - they're going to encrypt the message with their public key that I gave them, and I can decrypt the message using the private key I have in the HSM.
I'm going to then pass that message on by encrypting it with the public key of the ultimate receiver, which I have.
Is there any way to chain these two operations inside the HSM, without having the decrypted message anywhere near my application memory? I would like the plaintext content to never leave the boundaries of the HSM.
I know that some HSMs have a CodeSafe / SEE machine feature that lets me write embedded system code and run it inside the HSM, before I get into that I'd like to see if there's a way using the general PKCS / JCE / CNG APIs to do this safely.
If all you need is to re-encrypt the same secret under a different key, you can use C_Unwrap to create a temporal HSM object with value of the translated secret and then use C_Wrap to encrypt the value of this temporal HSM object for all the recipients.
This way the secret will never leave HSM.
Something like this (verified to be working on SafeNet Luna 7 with RSA-OAEP):
// Your private key for 'decrypting' secret. Must have key unwrapping allowed
CK_OBJECT_HANDLE hsmPrivateKey = ... ;
// Encrypted secret
byte[] wrappedKey = ... ; //
// Template for temporal generic secret key with value of the secret
CK_ATTRIBUTE[] tempTemplate = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA.CLASS, CKO.SECRET_KEY),
new CK_ATTRIBUTE(CKA.KEY_TYPE, CKK.GENERIC_SECRET),
new CK_ATTRIBUTE(CKA.TOKEN, false),
new CK_ATTRIBUTE(CKA.PRIVATE, true),
new CK_ATTRIBUTE(CKA.EXTRACTABLE, true),
new CK_ATTRIBUTE(CKA.SENSITIVE, true),
new CK_ATTRIBUTE(CKA.ENCRYPT, false),
new CK_ATTRIBUTE(CKA.DECRYPT, false),
new CK_ATTRIBUTE(CKA.WRAP, false),
new CK_ATTRIBUTE(CKA.UNWRAP, false),
new CK_ATTRIBUTE(CKA.SIGN, false),
new CK_ATTRIBUTE(CKA.VERIFY, false),
new CK_ATTRIBUTE(CKA.DERIVE, false)
};
// Unwrapping/decryption mechanism
CK_MECHANISM mechanism = ... ;
// Handle for temporal generic secret key with value of the secret
CK_OBJECT_HANDLE temporalValueHandle = new CK_OBJECT_HANDLE();
// Unwrap/decrypt the secret into temporal key
CryptokiEx.C_UnwrapKey(session, mechanism, hsmPrivateKey, wrappedKey, wrappedKey.length, tempTemplate, tempTemplate.length, temporalValueHandle);
// Wrap/encrypt the secret for recipients. Recipient public keys must have key wrapping allowed
for(CK_OBJECT_HANDLE recipientPublicKey : ... ) {
LongRef resSize = new LongRef(0);
CryptokiEx.C_WrapKey(session, mechanism, recipientPublicKey, temporalValueHandle, null, resSize);
byte[] rewrappedKey = new byte[CryptokiUtils.safeIntCast(resSize.value)];
CryptokiEx.C_WrapKey(session, mechanism, recipientPublicKey, temporalValueHandle, rewrappedKey, resSize);
System.out.println("Re-wrapped key: " + bytesToHexString(rewrappedKey));
}
// Delete temporal generic secret key
CryptokiEx.C_DestroyObject(session, temporalValueHandle);
Good luck!

How x509chain works in C#? What is purpose of using it?

I have implement client certificate based security in C#. Everything is clear and working good for me. I was finding perfect way to verify client certificate on server side, through which i came to x509Chain. But i am not clear about How it exactly works? How can we configure it? Is it secure way to verify certificate?
Any help will be Appreciated! Thanks!
Note: By theoretical point of view, i have read my documents on that but i am not sure for it's functionality. Please provide practical example and guide for that.
A bit of theory I wrote some time ago: http://social.technet.microsoft.com/wiki/contents/articles/3147.certificate-chaining-engine-cce.aspx
This article describes what is certificate chaining engine (CCE) and how it works in Windows in general. It is based on RFC5280 and Microsoft-specific implementation of certificate chaining engine. .NET uses native CryptoAPI functions, so X509Chain behaves in the same way as in native CryptoAPI.
The X509Chain does not work reliably for scenarios where you do not have the root certificate in the trusted CA store on the machine.
Others will advocate using bouncy castle. I wanted to avoid bringing in another library just for this task, so I wrote my own.
As see in RFC3280 Section 4.1 the certificate is a ASN1 encoded structure, and at it's base level is comprised of only 3 elements.
The "TBS" (to be signed) certificate
The signature algorithm
and the signature value
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING
}
C# actually has a handy tool for parsing ASN1, the System.Formats.Asn1.AsnDecoder.
Using this, we can extract these 3 elements from the certificate to verify the chain.
The first step was extracting the certificate signature, since the X509Certificate2 class does not expose this information and it is necessary for the purpose of certificate validation.
Example code to extract the signature value part:
public static byte[] Signature(
this X509Certificate2 certificate,
AsnEncodingRules encodingRules = AsnEncodingRules.BER)
{
var signedData = certificate.RawDataMemory;
AsnDecoder.ReadSequence(
signedData.Span,
encodingRules,
out var offset,
out var length,
out _
);
var certificateSpan = signedData.Span[offset..(offset + length)];
AsnDecoder.ReadSequence(
certificateSpan,
encodingRules,
out var tbsOffset,
out var tbsLength,
out _
);
var offsetSpan = certificateSpan[(tbsOffset + tbsLength)..];
AsnDecoder.ReadSequence(
offsetSpan,
encodingRules,
out var algOffset,
out var algLength,
out _
);
return AsnDecoder.ReadBitString(
offsetSpan[(algOffset + algLength)..],
encodingRules,
out _,
out _
);
}
The next step is to extract the TBS certificate. This is the original data which was signed.
example code to extract the TBS certificate data:
public static ReadOnlySpan<byte> TbsCertificate(
this X509Certificate2 certificate,
AsnEncodingRules encodingRules = AsnEncodingRules.BER)
{
var signedData = certificate.RawDataMemory;
AsnDecoder.ReadSequence(
signedData.Span,
encodingRules,
out var offset,
out var length,
out _
);
var certificateSpan = signedData.Span[offset..(offset + length)];
AsnDecoder.ReadSequence(
certificateSpan,
encodingRules,
out var tbsOffset,
out var tbsLength,
out _
);
// include ASN1 4 byte header to get WHOLE TBS Cert
return certificateSpan.Slice(tbsOffset - 4, tbsLength + 4);
}
You may notice that when extracting the TBS certiifcate I needed to include the ASN1 header in the data, this is because the signature of the TBS Certificate INCLUDES this data (this annoyed me for a while).
For the first time in history, the Microsoft does not impede us with their API design, and we are able to obtain the Signature Algorithm directly from the X509Certificate2 object. Then we just need to decide to what extend we are going to implement different hash algorithms.
var signature = signed.Signature();
var tbs = signed.TbsCertificate();
var alg = signed.SignatureAlgorithm;
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpnap/a48b02b2-2a10-4eb0-bed4-1807a6d2f5ad
switch (alg)
{
case { Value: var value } when value?.StartsWith("1.2.840.113549.1.1.") ?? false:
return signedBy.GetRSAPublicKey()?.VerifyData(
tbs,
signature,
value switch {
"1.2.840.113549.1.1.11" => HashAlgorithmName.SHA256,
"1.2.840.113549.1.1.12" => HashAlgorithmName.SHA384,
"1.2.840.113549.1.1.13" => HashAlgorithmName.SHA512,
_ => throw new UnsupportedSignatureAlgorithm(alg)
},
RSASignaturePadding.Pkcs1
) ?? false;
case { Value: var value } when value?.StartsWith("1.2.840.10045.4.3.") ?? false:
return signedBy.GetECDsaPublicKey()?.VerifyData(
tbs,
signature,
value switch
{
"1.2.840.10045.4.3.2" => HashAlgorithmName.SHA256,
"1.2.840.10045.4.3.3" => HashAlgorithmName.SHA384,
"1.2.840.10045.4.3.4" => HashAlgorithmName.SHA512,
_ => throw new UnsupportedSignatureAlgorithm(alg)
},
DSASignatureFormat.Rfc3279DerSequence
) ?? false;
default: throw new UnsupportedSignatureAlgorithm(alg);
}
As shown in the code above, https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpnap/a48b02b2-2a10-4eb0-bed4-1807a6d2f5ad is a good resource to see the mapping of algorithms and OIDs.
Another thing you should be aware of is that there are some articles out there that claim that for elliptical curve algorithms, microsoft expects a R,S formatted key instead of a DER formatted key. I tried to convert the key to this format but it ultimately didn't work. What I discovered was that it was necessary to use the DSASignatureFormat.Rfc3279DerSequence parameter.
Additional certificate checks, like "not before" and "not after", or CRL and OCSP checks can be done in addition to the chain verification.

Salted Password Hashing. Am I doing it right in ASP.NET environment?

I am developing a website by using ASP.NET. I want to implement login authentication for my users. I am using SALT HASH method to securely save users' passwords to the DB. By looking at various codes I wrote a code like below to generate the SALT and the Hashed passwords to store in Database.
private string hashedPassword;
private string Salt;
private string SaltPlusPassword;
private const byte saltSize = 24;
byte[] saltArray;
byte[] hashedPasswordArray;
byte[] bytes;
public void Save_Login(string passWord)
{
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
saltArray = new byte[saltSize];
rng.GetBytes(saltArray);
}
Salt = Convert.ToBase64String(saltArray);
SaltPlusPassword = String.Format("{0}{1}", Salt, passWord);
using (SHA256 sha = SHA256.Create())
{
bytes = Encoding.UTF8.GetBytes(SaltPlusPassword);
hashedPasswordArray = sha.ComputeHash(bytes);
}
hashedPassword = Convert.ToBase64String(hashedPasswordArray);
}
//Salt will be save to DB
//hashedPassword will be save to DB.
So I have few questions.
1) I read in an article that saying "make your salt is at least as long as the hash function's output" ok. What are the sizes for saltArray, hashedPasswordArray and bytes arrays which are declared in my code? I used saltArray size as 24. Is it ok?
2) What will happen if I use ?
bytes = Encoding.Unicode.GetBytes(SaltPlusPassword);
instead of
bytes = Encoding.UTF8.GetBytes(SaltPlusPassword);
3) What is the datatype should I use to store salt and the hashed password in the DB? ( My db is MYSQL )
4) Is there any performance difference if I use SHA256Managed instead of SHA256? Which is best?
5) Finally am I doing this in the right way? What are the weaknesses in above code? What are your suggestions?
Rather than deal with all these issues, why not use the built in identity management tools provided by ASP.NET. See here
http://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity
Much more common and robust.

Sign and decrypt data using private keys located on a HSM

I have a task to sign and decrypt data, but the private keys are located at a HSM ( Luna SA, / Safenet ). I installed all the client software and connected the Luna SA CSP to the test servers.
Using the PKCS#11 functions provided, I am able to list and export the public keys on the HSM as PCCERT_CONTEXT (CertCreateCertificateContext). When I try to acquire the private key (using CryptoAPI function CryptAcquireCertificatePrivateKey), I receive an error code CRYPT_E_NO_KEY_PROPERTY.
I am probably missing the link between the certificate data and the CSP/HSM. Has anybody done something similar and can give any hints?
EDIT
I sucessfully created CER files from all the keys located on the HSM.
When i know use signtool.exe (the one that ships with Microsoft Plattform SDK) i am able to sign a dll with a key on the HSM (the tool wizard lets me choose key container, key spec, ...). I tried to use the information the tool shows me and set the private key
bool LinkPrivateKey(PCCERT_CONTEXT cert)
{
CRYPT_KEY_PROV_INFO cryptKeyProvInfo;
memset(&cryptKeyProvInfo, 0, sizeof(cryptKeyProvInfo));
cryptKeyProvInfo.pwszContainerName = L"MSS";
cryptKeyProvInfo.pwszProvName = L"Luna Cryptographic Services for Microsoft Windows";
cryptKeyProvInfo.dwProvType = PROV_RSA_FULL;
cryptKeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET; // CERT_SET_KEY_CONTEXT_PROP_ID | CERT_SET_KEY_PROV_HANDLE_PROP_ID;
cryptKeyProvInfo.cProvParam = 0;
cryptKeyProvInfo.dwKeySpec = AT_SIGNATURE;
return CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &cryptKeyProvInfo) != FALSE;
}
but CryptAcquirePrivateKey still gives me the same error. I believe I am missing only a small bit here, since the signtool is able to access the private key
Edit2
The screnshot shows KEYEXCHANGE but I chose SIGNATURE
Edit3
I changed the LinkPrivateKeyfunction a little bit, now it works
bool LinkPrivateKey(PCCERT_CONTEXT cert)
{
CRYPT_KEY_PROV_INFO cryptKeyProvInfo;
memset(&cryptKeyProvInfo, 0, sizeof(cryptKeyProvInfo));
cryptKeyProvInfo.pwszContainerName = L"MSS";
cryptKeyProvInfo.pwszProvName = L"Luna Cryptographic Services for Microsoft Windows";
cryptKeyProvInfo.dwProvType = PROV_RSA_FULL;
cryptKeyProvInfo.dwFlags = 1; // CERT_SET_KEY_CONTEXT_PROP_ID | CERT_SET_KEY_PROV_HANDLE_PROP_ID;
cryptKeyProvInfo.dwKeySpec = AT_SIGNATURE;
return CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &cryptKeyProvInfo) != FALSE;
}
I don't have any experience with Luna but this worked well for nCiper HSM:
certutil -repairstore -csp "nCipher Enhanced Cryptographic Provider" My <serial number of certificate>
where "nCipher Enhanced Cryptographic Provider" is the name of CSP that comes with HSM.
Serial number of certificate can be obtained using this command:
certutil -store My
It will print all certificates in Local_Machine\My store. The serial number will be between bunch of ====== like ================ Certificate 5 ================. It will also parse information about the certificates like serial number, subject etc. and it will run encrypt/decrypt test to verify usability of the certificate.
After you repair the binding you can use this (second) command to verify that it went well. Don't be fooled by output of the first command, I have never seen it put out anything other than success.
You can find more information about usage of certutil here.
As stated in my post, I can link the private key using
I changed the LinkPrivateKeyfunction a little bit, now it works
bool LinkPrivateKey(PCCERT_CONTEXT cert)
{
CRYPT_KEY_PROV_INFO cryptKeyProvInfo;
memset(&cryptKeyProvInfo, 0, sizeof(cryptKeyProvInfo));
cryptKeyProvInfo.pwszContainerName = L"MSS";
cryptKeyProvInfo.pwszProvName = L"Luna Cryptographic Services for Microsoft Windows";
cryptKeyProvInfo.dwProvType = PROV_RSA_FULL;
cryptKeyProvInfo.dwFlags = 1; // CERT_SET_KEY_CONTEXT_PROP_ID | CERT_SET_KEY_PROV_HANDLE_PROP_ID;
cryptKeyProvInfo.dwKeySpec = AT_SIGNATURE;
return CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &cryptKeyProvInfo) != FALSE;
}
YOu have to replace L"MSS"with the key container defined on you server.
LunSA provides the tool keymap.exe that is insatlled along with the LunaCSP to get the container names.

How to generate and use public key cryptography in WinCrypt

I'm currently experimenting with the Windows Cryptography API and running into some problems with Public-Key-Cryptography. I can find lots of examples of how to encrypt items, but nothing directly addressing a start-to-finish public key model.
Here's a rough outline of how my current code looks to generate an encryption key pair, I've removed the error checking code for readability
// MAKE AN RSA PUBLIC/PRIVATE KEY:
CryptGenKey(hProv, CALG_RSA_KEYX, CRYPT_EXPORTABLE, &hKey);
// NOW LET'S EXPORT THE PUBLIC KEY:
DWORD keylen;
CryptExportKey(hKey,0,PUBLICKEYBLOB,0,NULL,&keylen);
LPBYTE KeyBlob;
KeyBlob = (LPBYTE)malloc(keylen);
CryptExportKey(hKey,NULL,PUBLICKEYBLOB,0,KeyBlob,&keylen);
ofstream outputkey;
outputkey.open("TestPublicKey.txt", ios_base::out | ios_base::binary);
for(size_t i=0; i &lt keylen; ++i)
outputkey&lt&ltKeyBlob[i];
outputkey.close();
free(KeyBlob);
// NOW LET'S EXPORT THE PRIVATE KEY:
CryptExportKey(hKey, 0, PRIVATEKEYBLOB,0,NULL,&keylen);
KeyBlob = (LPBYTE)malloc(keylen);
CryptExportKey(hKey,NULL,PRIVATEKEYBLOB,0,KeyBlob,&keylen)
outputkey.open("TestPrivateKey.txt", ios_base::out | ios_base::binary);
for(size_t i=0;i&ltkeylen;++i)
outputkey&lt&ltKeyBlob[i];
outputkey.close();
free(KeyBlob);
// ENCRYPT A (SHORT) TEST MESSAGE [SHOULD JUST BE ANOTHER ALG'S KEY LATER]:
DWORD encryptBufferLen=0;
CryptEncrypt(hKey, 0, true, 0, NULL, &encryptBufferLen, 0); // how much space?
BYTE* encryptionBuffer = (BYTE*)malloc(encryptBufferLen);
memcpy(encryptionBuffer, TestMessage, TestMessageLen); // move for in-place-encrypt
CryptEncrypt(hKey,0,true,0, encryptionBuffer, &bufferlen, encryptBufferLen );
ofstream message;
message.open("Message.txt", ios_base::out | ios_base::binary);
for(size_t i=0;i&ltencryptBufferLen;++i)
message&lt&ltencryptionBuffer[i];
message.close();
My two exported keys are different, but both are able to decrypt message without the other key being loaded. Additionally, if I encrypt a new message in a new session that loads the exported public key, I can still decrypt it with either key.
Can anyone advise me on what I might be doing wrong or missing? Am I on completely the wrong path?
I do not fully understand your query. But generally
You do not encrypt data directly using a public key.
During Encryption: You use a session/symmetric/private key to encrypt data. This session key is then being encrypted by the AT_EXCHANGE public key.
During Decryption: The AT_EXCHANGE private key will decrypt the session key. In turn this session key will be used to decrypt the actual data.
I am not an expert with this encryption stuff just yet! but I am working with this at the moment so can feel your pain...
Something looks amiss with the encrypt bit
// ENCRYPT A (SHORT) TEST MESSAGE [SHOULD JUST BE ANOTHER ALG'S KEY LATER]:
DWORD encryptBufferLen=0;
CryptEncrypt(hKey, 0, true, 0, NULL, &encryptBufferLen, 0); // how much space?
BYTE* encryptionBuffer = (BYTE*)malloc(encryptBufferLen);
memcpy(encryptionBuffer, TestMessage, TestMessageLen); // move for in-place-encrypt
CryptEncrypt(hKey,0,true,0, encryptionBuffer, &bufferlen, encryptBufferLen );
It appears that you are asking the function to give you the size of the encrypted message so that you can assign its memory i.e. size... BUT you are not passing anything in apart from the key itself so I dont think it would be able to give that information surely..
You have CryptEncrypt(hKey, 0, true, 0, NULL, &encryptBufferLen, 0); // but why "NULL" when you actually should pass in the buffer containing the string to be encrypted, so that it can work out the size and return it for you! Then you can move on with the rest.. I know thats how the export bit works (because your working with the keys in that context), whereas here you are dealing with the actual message. Try passing in the parameter and see how that goes?
I think you'll find that your not actually able to decrypt with both keys, as you haven't actually encrypted anything yet???? Your encrypting a message into a zero sized buffer I think.
As I said not an expert but it does look wrong to me... Strangest thing is I found your post the other day and harvested the working bits to help me understand it, so I really hope that this info helps you!
Go through the links below provided by microsoft
http://msdn.microsoft.com/en-us/library/windows/desktop/aa382358(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa382044(v=vs.85).aspx
Are you using CryptImportKey on both keys? It looks like your encrypt is just using the handle to thekey you generated. To do Public/Private pairs correctly you should export just the public key with CryptExportKey and give it to whomever needs it. Although this isn't true "encryption" its a way for that person to know it is from you.

Resources