How to get a CNG key handle to a public certificate previously imported to windows Cert: store (in Delphi)? - signature

I need to use CNG to verify a message signature (RSA). The only problem is how to get the CNG key handle (NCRYPT_KEY_HANDLE or BCRYPT_KEY_HANDLE) if I have the public certificate stored in windows certs (Cert:\CurrentUser\My).
I am using a
NCryptOpenStorageProvider({out}hProv, MS_KEY_STORAGE_PROVIDER, 0)
and I tried to get the public key handle using
NCryptOpenKey(hProv, {out}hKey, PWideChar('my.test.com'), AT_KEYEXCHANGE, 0)
but it seems that NCryptOpenKey() can only open the certificates that also have private keys.
I was also looking at BCryptImportKeyPair() but this requires to have the public key in BCRYPT_RSAKEY_BLOB structure which I don't know how to achieve.
The last function I was looking at was NCryptImportKey() but this again only works with private keys.
Anyone knows how to get the public key handle using CNG?
I have the public key in a file (cer/pem) and I imported it to windows Cert: store but if you know how to load it directly from a file to CNG key handle I would be happy as well.

NCrypt* functions works with persisted key pairs which stored at Key Storage Provider. If you import certificate in certificate store and this certificate does not contain private key then public key will not save in KSP.
You can use function CryptImportPublicKeyInfoEx2 to acquire BCRYPT_KEY_HANDLE.
Sample code in C:
HCERTSTORE hStore = nullptr;
PCCERT_CONTEXT pCert = nullptr;
BCRYPT_KEY_HANDLE hKey = nullptr;
/* Open MY certificate store */
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if (!hStore) {
goto Exit;
}
/* Find your certificate in store. For example search by subject name */
pCert = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, L"subject name", nullptr);
if (!pCert) {
goto Exit;
}
/* Or if you want to load certificate from file (assuming you read file to cert_data):
pCert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_data, cert_size);
*/
/* Now you can create BCRYPTKEY_HANDLE from your public key */
if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &pCert->pCertInfo->SubjectPublicKeyInfo, 0, nullptr, &hKey)) {
goto Exit;
}
/* Now you can verify signature with BCryptVerifySignature(hKey...) */
Exit:
/* Don't forget to free handle after use */
if (hKey) {
BCryptDestroyKey(hKey);
}
if (pCert) {
CertFreeCertificateContext(pCert);
}
if (hStore) {
CertCloseStore(hStore, 0);
}
return 0;

Related

How to decrypt mp4 PKCS8 encoded file using private key in node js and crypto

I'm trying to decrypt a MP4 file that is encrypted using public key in pkcs8 format in Node JS and private key.
I tried this code:
var decrypted = crypto.privateDecrypt({ key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING }, buffer);
I'm getting the following error:
Error: error:0406506C:rsa routines:rsa_ossl_private_decrypt:data greater than mod len
I'm currently using this Java code that is working. I would like to swich to Node JS
final byte[] cekWrapped = Base64.getDecoder().decode(conn.getHeaderField("x-amz-meta-x-amz-key").getBytes());
final byte[] iv = Base64.getDecoder().decode(conn.getHeaderField("x-amz-meta-x-amz-iv").getBytes());
// Now we need to decrypt the envelope
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(DECRYPT_MODE, privateKey);
final byte[] decryptedSymmetricKeyBytes = cipher.doFinal(cekWrapped);
final SecretKeySpec cek = new SecretKeySpec(decryptedSymmetricKeyBytes, "AES");
// Once we have the symmetric master key, we can decrypt the contents
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try {
cipher.init(DECRYPT_MODE, cek, new IvParameterSpec(iv));
} catch (final InvalidKeyException e) {
System.out.println(
"Invalid key exception. Please make sure that Java Cryptography Extensions with unlimited " +
"jurisdiction are installed");
}
try (final InputStream in = conn.getInputStream()) {
try (final CipherInputStream cis = new CipherInputStream(in, cipher)) {
try (final FileOutputStream fos = new FileOutputStream(destination.toFile())) {
byte[] b = new byte[1024];
int bytesRead;
while ((bytesRead = cis.read(b)) >= 0) {
fos.write(b, 0, bytesRead);
}
}
}
}
RSA uses the difficulty of factoring large semi-primes as it's trap-door function.
As part of the RSA crypto-system two primes are generated during public/private key creation.
We call the two primes p and q. They multiply to form n, which is the modulus (a semi-prime).
Although RSA can be used to to encrypt data directly (via c=m^e mod{n}), you cannot encrypt data larger than the modulus directly.
Therefore if you are using 2048-bit primes to generate n, you can only encrypt 4096-bits of information directly with the keys (in practice even a little less).
Instead, for large data you need to generate a random symmetric key and send it to your counterpart encrypting it with their RSA public key, and then use the agreed key with a symmetric cipher like AES-GCM or xSalsa20.
Really though, you should move to using ECDH over elliptic curves.
tldr: If you encrypt some data with RSA, where data.length > modulus.length, you're gonna get nonsense when you decrypt it.

How to sign message with TPM2?

From MethodA() :
First I created template, then the signing key. Then saved context with ContextSave(); And Marshalled it to file.
From MethodB() :
I unmarshalled the file, And did the ContextLoad(); Here it fails with Integrity check. What did i do wrong?
I created signing key like this:
var keyTemplate = new TpmPublic(TpmAlgId.Sha1, // Name algorithm
ObjectAttr.UserWithAuth | ObjectAttr.Sign | // Signing key
ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-migratable
ObjectAttr.SensitiveDataOrigin,
null, // No policy
new RsaParms(new SymDefObject(),
new SchemeRsassa(TpmAlgId.Sha1), 2048, 0),
new Tpm2bPublicKeyRsa());
TpmHandle keyHandle = tpm[ownerAuth].CreatePrimary(
TpmRh.Owner, // In the owner-hierarchy
new SensitiveCreate(keyAuth, null), // With this auth-value
keyTemplate, // Describes key
null, // Extra data for creation ticket
new PcrSelection[0], // Non-PCR-bound
out keyPublic, // PubKey and attributes
out creationData, out creationHash, out creationTicket); // Not used here
EDIT 1:
MethodA();
public static void MethodA()
{
try
{
Tpm2Device tpmDevice = new TcpTpmDevice(tpm_host, tpm_port);
//Tpm2Device tpmDevice = new TbsDevice();
tpmDevice.Connect();
var tpm = new Tpm2(tpmDevice);
if (tpmDevice is TcpTpmDevice)
{
tpmDevice.PowerCycle();
tpm.Startup(Su.Clear);
}
//
// The TPM needs a template that describes the parameters of the key
// or other object to be created. The template below instructs the TPM
// to create a new 2048-bit non-migratable signing key.
//
var keyTemplate = new TpmPublic(TpmAlgId.Sha1, // Name algorithm
ObjectAttr.UserWithAuth | ObjectAttr.Sign | // Signing key
ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-migratable
ObjectAttr.SensitiveDataOrigin,
null, // No policy
new RsaParms(new SymDefObject(),
new SchemeRsassa(TpmAlgId.Sha1), 2048, 0),
new Tpm2bPublicKeyRsa());
//
// AuthValue encapsulates an authorization value: essentially a byte-array.
// OwnerAuth is the owner authorization value of the TPM-under-test. We
// assume that it (and other) auths are set to the default (null) value.
// If running on a real TPM, which has been provisioned by Windows, this
// value will be different. An administrator can retrieve the owner
// authorization value from the registry.
//
//var ownerAuth = new AuthValue();
//
// Authorization for the key we are about to create.
//
var keyAuth = new byte[] { 1, 2, 3 };
TpmPublic keyPublic;
CreationData creationData;
TkCreation creationTicket;
byte[] creationHash;
//
// Ask the TPM to create a new primary RSA signing key.
//
TpmHandle keyHandle = tpm[ownerAuth].CreatePrimary(
TpmRh.Owner, // In the owner-hierarchy
new SensitiveCreate(keyAuth, null), // With this auth-value
keyTemplate, // Describes key
null, // Extra data for creation ticket
new PcrSelection[0], // Non-PCR-bound
out keyPublic, // PubKey and attributes
out creationData, out creationHash, out creationTicket); // Not used here
//
// Print out text-versions of the public key just created
//
//Console.WriteLine("New public key\n" + keyPublic.ToString());
Context ctx = tpm.ContextSave(keyHandle);
File.WriteAllBytes("key.bin", Marshaller.GetTpmRepresentation(ctx));
// Clean up.
tpm.FlushContext(keyHandle);
tpm.Dispose();
}
catch (Exception e)
{
Console.WriteLine("Exception occurred: {0}", e.Message);
}
}
MethodB():
public static void MethodB()
{
try
{
Tpm2Device tpmDevice = new TcpTpmDevice(tpm_host, tpm_port);
//Tpm2Device tpmDevice = new TbsDevice();
tpmDevice.Connect();
var tpm = new Tpm2(tpmDevice);
if (tpmDevice is TcpTpmDevice)
{
tpmDevice.PowerCycle();
tpm.Startup(Su.Clear);
}
Context ctx2 = Marshaller.FromTpmRepresentation<Context>(File.ReadAllBytes("key.bin"));
TpmHandle keyHandle = tpm.ContextLoad(ctx2); //integrity check fail
This code is present in both MethodA() and MethodB():
if (tpmDevice is TcpTpmDevice)
{
tpmDevice.PowerCycle();
tpm.Startup(Su.Clear);
}
This is a common pattern in TSS MSR examples. It checks whether the TPM you're talking to is a simulated device, and if so executes the Clear command on it, making sure you're starting with a clean slate. Doing this in MethodA() is fine, but by doing it in MethodB() as well, you're basically undoing what you did in MethodA(): the key you just created is removed and the integrity check fails because of it.

Using same X509 certificate for multiple devices in Azure device provisioning service

I have to enroll multiple devices in Azure Device provisioning service and I am using group enrollment to achieve the same. I have created a self signed X509 certificate and enrollment group too. I registered a simulated device to the group using the sample code. I want to create another simulated device with same certificate and enroll in group. Is that possible? The input to the sample app is the Id scope of device provisioning service and the certificate. How can I add another device.
if (string.IsNullOrWhiteSpace(s_idScope))
{
Console.WriteLine("ProvisioningDeviceClientX509 <IDScope>");
return 1;
}
X509Certificate2 certificate = LoadProvisioningCertificate();
using (var security = new SecurityProviderX509Certificate(certificate))
{
ProvisioningDeviceClient provClient =
ProvisioningDeviceClient.Create(GlobalDeviceEndpoint, s_idScope, security, transport);
var sample = new ProvisioningDeviceClientSample(provClient, security);
sample.RunSampleAsync().GetAwaiter().GetResult();
}
return 0;
}
private static X509Certificate2 LoadProvisioningCertificate()
{
string certificatePassword = ReadCertificatePassword();
var certificateCollection = new X509Certificate2Collection();
certificateCollection.Import(s_certificateFileName, certificatePassword, X509KeyStorageFlags.UserKeySet);
X509Certificate2 certificate = null;
foreach (X509Certificate2 element in certificateCollection)
{
Console.WriteLine($"Found certificate: {element?.Thumbprint} {element?.Subject}; PrivateKey: {element?.HasPrivateKey}");
if (certificate == null && element.HasPrivateKey)
{
certificate = element;
}
else
{
element.Dispose();
}
}
if (certificate == null)
{
throw new FileNotFoundException($"{s_certificateFileName} did not contain any certificate with a private key.");
}
else
{
Console.WriteLine($"Using certificate {certificate.Thumbprint} {certificate.Subject}");
}
return certificate;
}
private static string ReadCertificatePassword()
{
var password = new StringBuilder();
Console.WriteLine($"Enter the PFX password for {s_certificateFileName}:");
while (true)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Backspace)
{
if (password.Length > 0)
{
password.Remove(password.Length - 1, 1);
Console.Write("\b \b");
}
}
else if (key.Key == ConsoleKey.Enter)
{
Console.WriteLine();
break;
}
else
{
Console.Write('*');
password.Append(key.KeyChar);
}
}
return password.ToString();
}
}
}
Client side authentication (X.509 for verifying the party) implemented in Azure needs each end node to have a unique leaf certificate and private key, kind of like a public/private key pair.
This key pair is used to verify that the party is who it is saying it is.
Each end node must possess unique key pair to do so. This key pair is generated from a trusted certificate chain and generated key pair is known as leafs.
Certificate chain can be either CA signed or self-signed (self-signed is only for development/testing purpose, not suitable for production).
In this chain you have a Root certificate from which you generate leafs. You can generate as many leaves as you want within a chain. Each unique leaf can be used as a key pair for each device.
For your case, you can use OpenSSL to generate self-signed root certificate, and then generate as many self-signed leafs for all your devices.

How to generate random bytes via Cryptographic Service Provider (CSP) without .NET/COM?

Is there a way to generate strong random bytes via Microsoft's Cryptographic Service Provider (CSP) without using .NET/COM? For example, using command line or some other way?
I'd like to use it in NodeJS to be more specific.
Refer to http://technet.microsoft.com/en-us/library/cc733055(v=ws.10).aspx
netsh nap client set csp name = <name> keylength = <keylength>
If this command works for you, just exec it through nodejs. (require('child_process').exec)
Yes, using the Windows API. Here is a sample C++ code:
#include "Wincrypt.h"
// ==========================================================================
HCRYPTPROV hCryptProv= NULL; // handle for a cryptographic provider context
// ==========================================================================
void DoneCrypt()
{
::CryptReleaseContext(hCryptProv, 0);
hCryptProv= NULL;
}
// --------------------------------------------------------------------------
// acquire crypto context and a key ccontainer
bool InitCrypt()
{
if (hCryptProv) // already initialized
return true;
if (::CryptAcquireContext(&hCryptProv , // handle to the CSP
NULL , // container name
NULL , // use the default provider
PROV_RSA_FULL , // provider type
CRYPT_VERIFYCONTEXT )) // flag values
{
atexit(DoneCrypt);
return true;
}
REPORT(REP_ERROR, _T("CryptAcquireContext failed"));
return false;
}
// --------------------------------------------------------------------------
// fill buffer with random data
bool RandomBuf(BYTE* pBuf, size_t nLen)
{
if (!hCryptProv)
if (!InitCrypt())
return false;
size_t nIndex= 0;
while (nLen-nIndex)
{
DWORD nCount= (nLen-nIndex > (DWORD)-1) ? (DWORD)-1 : (DWORD)(nLen-nIndex);
if (!::CryptGenRandom(hCryptProv, nCount, &pBuf[nIndex]))
{
REPORT(REP_ERROR, _T("CryptGenRandom failed"));
return false;
}
nIndex+= nCount;
}
return true;
}

AES Encryption/Decryption with Bouncycastle Example in J2ME

i want to Encrypt and Decrypt data in J2ME using AES Algorithm with bouncy castle
can any one give me sample code for that
i want to use ECB with PKCS5Padding
Thanks in Advance.
I'm sure there are examples out there but I haven't found them. Here are a few hints to help you get started. You need to learn how to connect the BC classes together. First, get the bouncycastle source code and be prepared to look at it when you have questions. It's actually very readable so don't be afraid to examine it when the documentation is poor. For example, many classes want an instance of a CipherParameters object, but it is rare for the documentation to specify any more detail. However, in the source code it will be obvious as to which implementing classes are expected.
Choose one of the AES engines, for example AESEngine, as the encryption engine. Next pick a mode; ECB is rarely correct, so for example if you pick CBC mode then create a CBCBlockCipher object from your AESEngine object. Next, use this object to create a PaddedBufferBlockCipher object. The default constructor uses PKCS7 padding which is identical to the PKCS5 padding you want. Now you need to create an object to hold the key and IV. This is the CipherParameters interface. You create the object in two steps. First, you create a KeyParameter object with your key. Next, you create a ParametersWithIV object with your KeyParameter object and your IV. This object is supplied to the init method of the PaddedBufferBlockCipher object and then your are ready to go.
EDIT
Here is small example:
private static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data)
throws Exception
{
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
return result;
}
private static byte[] decrypt(byte[] cipher, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(false, ivAndKey);
return cipherData(aes, cipher);
}
private static byte[] encrypt(byte[] plain, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(true, ivAndKey);
return cipherData(aes, plain);
}

Resources