EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Retrieve certificate private ke

Also by EldoS: Rethync
The cross-platform framework that simplifies synchronizing data between mobile and desktop applications and servers and cloud storages
#32897
Posted: 04/02/2015 06:40:40
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hello.

I'm using BouncyCastle to encrypt files with a generated key, and then encrypting this key with an X509Certificate.
To decrypt, the user selects this certificate from his keystore and I want to retrieve the private key to decrypt the encrypted key and then decrypt the files.
But, if the user didn't set the key as exportable when he installed the certificate, SBB can't get the certificate private key so I can't decrypt the key.

I did this simple test to verify it :
Code
System.out.println("Test using Java KeyStore object :");
         
         KeyStore ks               = KeyStore.getInstance("Windows-MY");
         ks.load(null, null);
         Enumeration<String> aliases   = ks.aliases();
         
         while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            
            System.out.println("\t- " + alias);
            
            PrivateKey pk = null;
            try {
               pk = (PrivateKey) ks.getKey(alias, "WESH".toCharArray());
            }
            catch (Exception e) {
               // Doing nothing.
               System.out.println("\t\t- " + e.getMessage());
            }
            
            if (pk != null) {
               final Signature signature   = Signature.getInstance("SHA256withRSA");
               signature.initSign(pk);
               signature.update(new byte[128]);
               
               System.out.println("\t\t- " + new BigInteger(1, signature.sign()).toString(16));
            }
         }
         
         TElWinCertStorage winMYCertStorage = new TElWinCertStorage();
         winMYCertStorage.GetSystemStores().Add("MY");
         
         System.out.println("\nTest using SBB TElWinCertStorage object :");
         
         for (int i = 0; i < winMYCertStorage.GetCount(); i++) {
            TElX509Certificate cert   = winMYCertStorage.GetCertificate(i);
            String certAlias      = cert.GetSubjectName().CommonName;
            
            System.out.println("\t- " + certAlias);
            System.out.println("\t\t- PK exists : " + cert.GetPrivateKeyExists());
            System.out.println("\t\t- PK extractable : " + cert.GetPrivateKeyExtractable());
            
            PrivateKey pk = null;
            try {
               pk = cert.GetPrivateKey();
            }
            catch (Exception e) {
               // Doing nothing.
               System.out.println("\t\t- " + e.getMessage());
            }
            
            if (pk != null) {
               final Signature signature = Signature.getInstance("SHA256withRSA");
               signature.initSign(pk);
               signature.update(new byte[128]);
               
               System.out.println("\t\t- " + new BigInteger(1, signature.sign()).toString(16));
            }
         }

It displays :
Quote
Test using Java KeyStore object :
- AWS - Formation_service
- 9794...89b0

Test using SBB TElWinCertStorage object :
- AWS - Formation_service
- PK exists : true
- PK extractable : true
- 9794...89b0

But, if I reinstall the certificate and set the key as not exportable, I got this with TElWinCertStorage (java KeyStore stays the same) :
Quote

- AWS - Formation_service
- PK exists : true
- PK extractable : false
- java.security.InvalidKeyException: Invalid RSA private key

Is there a way to retrieve the certificate private key ? Maybe with PKCS11. If so, could I have an example please ? I'm using SSB v11.0.250.

Thank you.

Mickaël Bénès
#32899
Posted: 04/02/2015 06:47:20
by Eugene Mayevski (EldoS Corp.)

Indeed you can't extract the private key when it's marked as non-exportable. You still can use it for operations that involve private keys. But you must perform those operations with SecureBlackbox methods. So your approach won't work as is.

You should be able to use your certificate with TElMessageSigner/TElMessageVerifier class (for PKCS#7 signing/verification) and TElMessageEncryptor/TElMessageDecryptor class (for PKCS#7 encryption/decryption).

We also have TElPublicKeyCrypto class and related classes for PKCS#1 signing/verification and encryption/decryption operations and they should work for you.


Sincerely yours
Eugene Mayevski
#32901
Posted: 04/02/2015 06:56:37
by Vsevolod Ievgiienko (EldoS Corp.)

Thank you for contacting us.

Indeed TElX509Certificate.GetPrivateKey method requires private key to be exportable. What you can do is to rewrite your code that requires PrivateKey to use SecureBlackbox and TElX509Certificate. In this case TElRSAPublicKeyCrypto can be used: https://www.eldos.com/documentation/sb...rypto.html

This was improved in the 12th version of SecureBlackbox where you can use TElJavaCertStorage class to access certificates in Windows store and TElX509Certificate.getPrivateKey method will return correct PrivateKey for such certificates.
#32915
Posted: 04/02/2015 10:05:25
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

OK thanks.

I tried it and successfully encrypted/decrypted a string. I just want to know if I did it correctly.

Code
TElWinCertStorage winMYCertStorage = new TElWinCertStorage();
winMYCertStorage.GetSystemStores().Add("MY");

String key               = "stringToCrypt";
byte[] toCrypt            = key.getBytes();
InputStream is            = new ByteArrayInputStream( toCrypt );
ByteArrayOutputStream os   = new ByteArrayOutputStream();

System.out.println( "Key : " + key + "\n" );

TElRSAPublicKeyCrypto crypto = new TElRSAPublicKeyCrypto();
crypto.SetHashAlgorithm( SBConstants.SB_ALGORITHM_CNT_AES256 );
crypto.SetHashFuncOID( SBConstants.SB_OID_AES256_CBC.Data );

TElX509Certificate cert   = winMYCertStorage.GetCertificate( 1 );
String certAlias      = cert.GetSubjectName().CommonName;

crypto.SetKeyMaterial( cert.GetKeyMaterial() );
crypto.Encrypt( is, os, 0 );

String encKey = new String ( Base64.encode(os.toByteArray()) );
System.out.println( "- encrypted key : " + encKey );

is   = new ByteArrayInputStream( os.toByteArray() );
os.reset();

crypto.Decrypt( is, os, 0 );

System.out.println( "- decrypted key : " + os.toString() );

It displays :
Quote
Key : stringToCrypt
- encrypted key : rk3n...F784/p3u9VnOjg
MqNBuQo6GNdXrjRAnoQbciwaKL4Vo+MUL5TMRdXcjSyfVOtmdE2f69QOY1Di/QUBTmGO1kOdC2nf
jX45aJ5nTQGHqz+leHc=
decrypted key : stringToCrypt
#32927
Posted: 04/03/2015 01:38:38
by Vsevolod Ievgiienko (EldoS Corp.)

In general your code is correct with a few remarks.

Quote
crypto.SetHashFuncOID( SBConstants.SB_OID_AES256_CBC.Data );

This should be changed to

Code
crypto.SetHashFuncOID( SBConstants.SB_OID_SHA256.Data );


Also I recommend you to use String.getBytes() with specified encoding like

Code
byte[] toCrypt = key.getBytes("utf-8");


as this may solve possible encoding compatibility problems in future.
#32933
Posted: 04/03/2015 07:48:36
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Alright thanks, I made the mofifications.

I've got a problem though. We are actually using asymetric cryptography in our application and would like to stick to it. But I guess that, if we can't retrieve a certificate private key if it wasn't set as exportable, we can't do that with SBB ?
#32934
Posted: 04/03/2015 07:57:52
by Vsevolod Ievgiienko (EldoS Corp.)

You can't extract non-exportable private key, but it can be used to perform cryptographic operations.
#32935
Posted: 04/03/2015 08:30:24
by Eugene Mayevski (EldoS Corp.)

Just a clarification - you can't extract the non-exportable private key, no matter with SecureBlackbox or by any other [legal and technically valid] means.

SecureBlackbox has methods to use such non-extractable keys for cryptographic operations. Other libraries can also have means for such operations, but there's no universal way to transfer identifiers of non-extractable keys between various libraries (be it Java internal API or SecureBlackbox or CryptoAPI or BouncyCastle).


Sincerely yours
Eugene Mayevski
#32936
Posted: 04/03/2015 08:46:36
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Quote
Eugene Mayevski wrote:
Just a clarification - you can't extract the non-exportable private key, no matter with SecureBlackbox or by any other [legal and technically valid] means.

SecureBlackbox has methods to use such non-extractable keys for cryptographic operations. Other libraries can also have means for such operations, but there's no universal way to transfer identifiers of non-extractable keys between various libraries (be it Java internal API or SecureBlackbox or CryptoAPI or BouncyCastle).
Yeah sure I'm just not explaining what I mean correctly. By exportable I mean just retrieving the private key in an object, not get it and save it somewhere.

It's just weird because I can get the private key to do what I need like this (whether or not the key was set as exportable during the certificate installation) :
Code
PrivateKey pk = (PrivateKey) myKeyStore.getKey( alias, "".toCharArray() );
But with SecureBlackbox, the TElX509Certificate.GetPrivateKey() only works when the key is set as exportable. That's what confused me.

But maybe it's juste that I'm not really understanding what KeyStore.getKey() does, or some other things.

Quote
Vsevolod Ievgiienko wrote:
You can't extract non-exportable private key, but it can be used to perform cryptographic operations.


OK so which class should I look into ? Is TElRSAPublicKeyCrypto doing asymetric ciphering ?

If so, then I have another question.
To do the encryption, we actually get the certificate and its public key (only) from an URL, then build an X509Certificate from the java.security.cer.CertificateFactory class. Is it possible to get the KeyMaterial needed to do the encryption ?

Some time ago, you gave me the following code to make a TElX509Certificate from a X509Certificate and a private key.
Code
TElJCECryptoProvider cp = (TElJCECryptoProvider) SBCryptoProvJCE.JCECryptoProvider();
      
      TElPublicKeyMaterial km = new TElRSAKeyMaterial(cp); // RSA an DSA are supported at the moment
      km.SetKeyPair(new KeyPair(x509Certificate.getPublicKey(), x509CertPrivateKey));
      
      TElX509Certificate telX509Certificate = new TElX509Certificate();
      telX509Certificate.FromX509Certificate(x509Certificate); // load public part of the certificate that is usually exportable
      telX509Certificate.SetKeyMaterial(km); // set key material that is initialized with non-exportable key

But since I don't have the private key, I don't know how to make the key material.
#32937
Posted: 04/03/2015 09:04:03
by Vsevolod Ievgiienko (EldoS Corp.)

This method can be used to make TElX509Certificate objects from native Java objects. Also it will produce an instance of TElX509Certificate that can be used for signing/decryption operations even if the private key is non-exportable.

However if the certificate is retrieved using TElWinCertStorage this additional code is not necessary - it will return ready to use TElX509Certificate objects.
Also by EldoS: Solid File System
A virtual file system that offers a feature-rich storage for application documents and data with built-in compression and encryption.

Reply

Statistics

Topic viewed 1865 times

none




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!