This question already has answers here:
Java - Encrypt String with existing public key file
(3 answers)
Closed 5 years ago.
To my knowledge a x509 certificate is used to distribute the public key, which in my case is a RSA key, thus I can encrypt a message with it, but without knowing the private key I couldn't get the message back. I created the keys on my linux virtual machine and copied them over to windows to use in my project and I obtain them this way:
InputStream inputStream = new FileInputStream("./certificates/cert" + LoginController.getLoggedUser().getID() + ".crt");
CertificateFactory cf = CertificateFactory.getInstance("X509");
Certificate c = cf.generateCertificate(inputStream);
myCert = (X509Certificate) c;
Now I use the certificate for two things, first to validate if a user can login into the app, and secondly I have to encrypt/decrypt a message I hide inside a picute using steganography. So I'd like to know which file contains my private key and how to load it into my program possibly using the Java SE API? (P.S. I have the CA body and everything still on my virtual machine).
The private key should be in the keystore generated by keytool (and ideally nowhere else -- private keys are not meant to be distributed, hence the name).
Looks like you can access keystores via an instance of java.security.KeyStore. You'll need the password you used when generating the keystore; it's one of the parameters to the load method.
Related
In the windows personal certificate store, I am trying to programmatically install a certificate with the private key(using method setKeyEntry) using Java. But I get an exception when I do that.
Caused by: java.lang.UnsupportedOperationException: Cannot assign the key to the given alias.
at jdk.crypto.mscapi/sun.security.mscapi.CKeyStore.engineSetKeyEntry(CKeyStore.java:405)
at jdk.crypto.mscapi/sun.security.mscapi.CKeyStore$MY.engineSetKeyEntry(CKeyStore.java:57)
Code snippet:
KeyStore userCertStore = KeyStore.getInstance(getValue(CERTIFICATE_STORE_TYPE));
userCertStore.load(null,null);
for (iaik.x509.X509Certificate cert : user.getUserCertificates()) {
userCertStore.setCertificateEntry(cert.getSubjectDN().toString(), cert);
userCertStore.setKeyEntry(cert.getSubjectDN().toString(),user.getUserPrivateKey(cert),new
SecureStringBuffer(new StringBuffer(password)).toCharArray(),user.getUserCertificates());
}
The certificates are already set during setKeyEntry - do not store the certificate using setCertificateEntry.
setCertificateEntry is used to set trusted certificates (of the other party), the setKeyEntry is used to store private keys and the full certificate chain belonging to that private key.
So when you set the private key the alias is already taken by a "trusted certificate".
I am writing an Android application to connect a sensor to an AWS IoT service.
I have been provided with the X.509 certificate, a pair of public-private key, clientEndpoint, etc.
I am trying to follow the AWS's Sample code (see here).
The instructions are clear, but I don't want to generate the certificate and the keys (I already have them).
Below is the code snippet:
// Create a new private key and certificate. This call
// creates both on the server and returns them to the
// device.
CreateKeysAndCertificateRequest createKeysAndCertificateRequest = new CreateKeysAndCertificateRequest();
createKeysAndCertificateRequest.setSetAsActive(true);
final CreateKeysAndCertificateResult createKeysAndCertificateResult;
createKeysAndCertificateResult = mIotAndroidClient.createKeysAndCertificate(createKeysAndCertificateRequest);
Log.i(LOG_TAG,"Cert ID: " +createKeysAndCertificateResult.getCertificateId() +" created.");
// store in keystore for use in MQTT client
// saved as alias "default" so a new certificate isn't
// generated each run of this application
AWSIotKeystoreHelper.saveCertificateAndPrivateKey(certificateId,createKeysAndCertificateResult.getCertificatePem(),createKeysAndCertificateResult.getKeyPair().getPrivateKey(),
keystorePath, keystoreName, keystorePassword);
// load keystore from file into memory to pass on
// connection
clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,keystorePath, keystoreName, keystorePassword);
How can I use the existing certificates files instead of generating new certificate and keys?
Thank you
Here's a full snip that I've successfully used with some test code.
String tempFilePath = context.getFilesDir().getAbsolutePath();
if (!AWSIotKeystoreHelper.isKeystorePresent(tempFilePath, "iotkeystore")) {
Resources resources = context.getResources();
int certId = resources.getIdentifier("foo_device_cert", "raw", context.getPackageName());
int privkeyId = resources.getIdentifier("foo_device_private_key", "raw", context.getPackageName());
String cert = TestUtils.loadTestResource(context, certId);
String privKey = TestUtils.loadTestResource(context, privkeyId);
AWSIotKeystoreHelper.saveCertificateAndPrivateKey("iotcert", cert, privKey, tempFilePath, "iotkeystore", "iotpasswd");
}
KeyStore keystore = AWSIotKeystoreHelper.getIotKeystore("iotcert", tempFilePath, "iotkeystore", "iotpasswd");
AWSIotMqttManager mqttManager = new AWSIotMqttManager("sdk-java", "xxxxxxxxxxxx-ats.iot.us-east-2.amazonaws.com");
mqttManager.connect(keystore, new LocalMqttStatusCallback());
mqttManager.subscribeToTopic("sdk/test/java", AWSIotMqttQos.QOS0, new LocalMessageCallback());
logger.info("testLoadCertificate()...");
In this case, I simply saved the certificates in the res/raw folder and loaded them at run time as shown above. This prob. isn't the best from a security standpoint, but should help you get something working. I put this entire snip into a Robolectric test case and the keystore gets reloaded each time. It properly connects and receives messages though.
The AWS documentation is really poor here, I wasn't able to find any working sample code from them (bad links) and I'm not wanting to just turn over my entire project to Amplify and it's automatic reconfiguration.
Good luck.
Use
AWSIotKeystoreHelper.isKeystorePresent(mKeystorePath, mKeystoreName) to check if keystore is already on you device
Check Alias using AWSIotKeystoreHelper.keystoreContainsAlias(mCertificateId, mKeystorePath, mKeystorePassword)
Get keystore using keystore = AWSIotKeystoreHelper.getIotKeystore(mCertificateId, mKeystoreName, mKeystorePassword)
Use keystore on mqttManager to connect
I've been asked to create a jks keystore based on a certificate we had created. I've read a bit on the topic, but I'm still confused on a few items:
Is the private key of a certificate supposed to be stored in a .jks keystone?
If yes - where does this get entered in? Using the keytool, it doesn't require one for creating a jks file.
If no - what is the purpose of a jks file? Why would my application need it instead of just reading in a certificate directly? And why does the keytool require a password to create a jks if it just contains a public key?
The purpose of a key store is to protect the privacy and integrity of cryptographic keys using password-based algorithms. Privacy means that the keys are kept secret; they can only be used by someone who knows the password; this is useful for private keys and secret keys. Integrity means that alteration of the keys can be detected by someone who knows the password; this is useful for public keys and secret keys.
Whether you should include the private key or not depends on what you are trying to do. If you are creating a key store for your server so that it can authenticate itself to clients, for example, then it should contain the private key. If you created a self-signed certificate, and want to give clients a key store so that they can authenticate your service, then it should not contain the private key.
If you have a pre-existing key pair, and want to import it to a JKS format key store, the easiest way might be to use OpenSSL to create a PKCS #12 format key store, then use keytool to convert that to a JKS key store. Normally, keytool expects to do key pair generation itself, and so the private key will be stored there from the beginning.
You should verify the integrity of a public key or a certificate before you use it to encrypt a message or verify a signature. Otherwise, an attacker can replace the key with one he owns and act as a man in the middle. If you simply read a public key from a file, you don't know it really belongs to your intended recipient. But if you store a password-based message authentication code with the public key, you can ensure that it hasn't been tampered with.
Is the private key of a certificate supposed to be stored in a .jks keystone?
Yes, if you own the certificate and it is stored there.
If yes - where does this get entered in? Using the keytool, it doesn't require one for creating a jks file.
That's because you can also use it as a truststore, which only contains trusted certificates.
To get the private key in there you will need to first convert it and its certificate to a PKCS#12 file using openssl, as answered in numerous questions here such as this.
If no - what is the purpose of a jks file? Why would my application need it instead of just reading in a certificate directly?
Because your application also needs the private key of the certificate.
And why does the keytool require a password to create a jks if it just contains a public key?
A keystore has a password because it is a security-related entity.
I have Android application which using WebRTC. All works perfect. But now, main problem, with encryption.
For making call and transfer data, WebRTC creates and uses a single KeyPair for every call. But I want to use custom KeyPair from AndroidKeyStore. For this problem I need to send own KeyPair to OpenSSL shared object to work.
The fix will be in NATIVE OpenSSL code, where WebRTC is getting OpenSSL context for encryption data using this function (opensslidnetity.cc):
bool OpenSSLIdentity::ConfigureIdentity
{
...
}
How transfer PK from AndroidKeyStore to WebRTC native code? Another case, how set custom PK for WebRTC encryption work?
AndroidKeyStore
In Java I can open the KeyStore (AndroidKeyStore) and get the public key - which ready to transfer (has bytes of key with method - getEncoded()). Also I can get private Key for encryption data, but I can't send this key in bytes, because getEncoded() return null. In this case, I thought, I can get PublicKey and PrivateKey and save them in bytes array. And after, call prepared methods in native code.
UPDATE: There is something similar located in google.source.chromium. Where they get key from Android KeyStore and creating OpenSSL context in native code. Native class for getting and using AndroidKeyStore for TLS - Link 1 and Link 2.
Android Keystore does not expose the key material of private or secret keys, by design (see https://developer.android.com/training/articles/keystore.html). You options are:
Present Android Keystore PrivateKey + Signature or Cipher as OpenSSL EVP_PKEY.
Don't use Android Keystore. Perhaps you don't need the additional protections it offered compared to storing private keys inside your process?
I have a chain of certificates (X509Certificate []), but I have only one certificate in the chain. I need to get the complete chain.
I have tried the openssl command, but that is not useful here. Can someone please tell me how to:
Convert this X509Certificate to PEM or ASN.1/DER that I can save in my file storage?
Get the complete chain using this certificate?
Edit:
So, code-wise what I'm trying to achieve is something like:
protected static String convertToPem(X509Certificate cert) {
Base64 encoder = new Base64(64);
String cert_begin = "-----BEGIN CERTIFICATE-----\n";
String end_cert = "-----END CERTIFICATE-----";
byte[] derCert = cert.getEncoded();
String pemCertPre = new String(Base64.encodeBase64(derCert));
String pemCert = cert_begin + pemCertPre + end_cert;
return pemCert;
}
But, this is not working. Basically, I'm looking for a method that takes a X509Certificate object and then converts it to a .pem etc, that is saved on the device.
Convert this X509Certificate object to .cer/ .per/ .der that I can save in my file storage?
See, for example, the answer at OpenSSL's rsautl cannot load public key created with PEM_write_RSAPublicKey. It tells you how to convert keys to/from PEM and ASN.1/DER format, and includes a treatment of Traditional Format (a.k.a. SubjectPublicKeyInfo).
If you are not doing it programmatically, then you should search for the answer. There are plenty of off-topic question on how to use the openssl command to convert between ASN.1/DER and PEM. Or ask on Super User, where they specialize in commands and their use.
Get the complete chain using this certificate?
This is a well known problem in PKI called the Which Directory problem. The solution is to have the server or service provide the missing intermediate CA certificates. If you can't validate a web server or service's identity because you are missing intermediate CA certificates, then the server is misconfigured.
Once you have the intermediate CA certificates, you still have to root trust somewhere. You can use the self-signed CA, or one of the intermediates signed by the self-signed CA.
This answer is helpful in troubleshooting a misconfugred server using OpenSSL's s_client: SSL site and browser warning.
Related: if there was a global directory of certificates like the ITU envisioned in X.500, then you would not have the second problem. A relying party or user agent would just fetch the certificate it needed from the directory.
But we lack a central directory, so relying parties and user agents often use the CA Zoo (a.k.a., the local Trust Store or cacerts.pem). This has its own set of problems, like the wrong CA certifying a site or service.
One of the off-shoots is the CA Cartel, where browser are in partnership with the CAs at the CA/Browser Forum. Browser have requirements for inclusion, but they often can't punish a misbehaving CA like Trustwave.
And the browsers have managed to box themselves into a position where the Internet of Things (IoT) will not work because of the browser's reliance/requirements on server certificates signed by a CA.