Ephemeral RSA key vs Ephemeral DH key? - java

I try to design system that encrypts files(audio) and store them in disc in order that only my clients(applet) decrypt and play them. So I decided to use AES cipher for bulk encryption and store keys in database. My problem is transferring secret key securely.
In modern systems use SSL for transferring keys and data which are not stored cryptically. In SSL/TLS design, session key is generated two ways;
First way client creates key and encrypt it server's public key(certificate).
Second option is more secure and becomes more important after detecting heartbleed security bug. In this option key is created by client and server with (EC)DHE key agreement for every sessions.
When it comes to my case, there are two options as well.
First case;
Client(applet) can create ephemeral RSA key pair and sends public key to server.
Server encrypts secret key with client's public key and sends to client.
Client(applet) decrypt secret key with private key.
Client(applet) can decrypt audio files streamly and play.
Second case;
Client(applet) and server agrees on session key using (EC)DHE.
Server encrypts secret key symmetrically with session key and sends to client.
Client(applet) decrypt secret key with session key.
Client(applet) can decrypt audio files streamlly and play.
Which option is suits my scenario? What is pros and cons each case?
Thanks for answers.

Both solutions are vulnerable to an active attacker, in position of man-in-the-middle, because the key exchange is not authenticated. This issue is solved in SSL/TLS by the use of the X.509 PKI. It could also be solved by giving your client prior knowledge of the server's public key, for example.
That being said, between your two options, go with the (EC)DHE one, because generating a new DH key from pre-computed DH group (also known as DH parameters) is fast, whereas generating a new RSA key is very slow.

Related

Java, Android Keystore - supply unencrypted API key or secret for encrypting

As i am new to Android, i am working on hiding my API keys and found Android keystore the way to go. But when i see examples of how to use Android Keystore, one thing i am not understanding is how to supply the unencrypted original key for encryption? if i am storing in the code, wouldn't that beat the purpose of using Android Keystore?
from an article on storing secrets:
https://medium.com/#ericfu/securely-storing-secrets-in-an-android-application-501f030ae5a3
Generate a random key when the app runs the first time;
When you want to store a secret, retrieve the key from KeyStore, encrypt the data with it, and then store the encrypted data in
Preferences.
When you want to read a secret, read the encrypted data from Preferences, get the key from KeyStore and then use the key to decrypt
the data
In second point, it says encrypt the data with it. How to supply the data without exposing to the code/application?
I apologize if this has been answered.
Thanks
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
private static final String AES_MODE = "AES/GCM/NoPadding";
private static final String KEY_ALIAS = "MyNiceKey";
Load the default AndroidKeyStore:
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
keyStore.load(null);
Generate AES key inside the KeyStore which in the latest verision of android, it is hardware-backed keystore; it means that it is very hard to extract the bytes of the key from it:
if (!keyStore.containsAlias(KEY_ALIAS)) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(false)
.build());
keyGenerator.generateKey();
}
Anyway you should use .setRandomizedEncryptionRequired(true). There is no point to set up a faulty protocol. Otherwise, if you have to encrypt only few bytes(your API key) you could create an asymmetric public/private key and encrypt it with RSA so that you don't even need to provide the IV.
Haing said that, when you get the secret key from the KeyStore:
public static SecretKey getKeyStoreSecretKeyEntry(final String entryAlias)
throws GeneralSecurityException, IOException {
return ((KeyStore.SecretKeyEntry) getKeyStore().getEntry(entryAlias, null)).getSecretKey();
}
the returned SecretKey does not containt the Key Material (the real bytes of the key) but only its reference. So you can use it freely iside the Cipher to encrypt and decrypt what you want. In any case, you API key will be exposed enyway if you use it to make http request directly to you service. The best way to go in your case is to use a server like Google Firebase
P.s. there is very a simple library from google that will save you time and headache:
https://developer.android.com/jetpack/androidx/releases/security
https://developer.android.com/topic/security/data
Conclusion: The key you generate within the android Key Store is property of the user and it should be used to protect the user's private data. So it is not a good practice to encrypt an API Key, wich is the developer's private data, with the user key. Use a server to protect the API key.

Java (Android): Diffie-Hellman key exchange process according to JWA (RFC 7518)

I need to use ECDH key exchange process in order to encrypt/decrypt messages between the client and the server.
I use jose4j library for cryptographic functionality.
I have the local key pair (private dC and public QC), I have the remote public key QT and I have transactionID and referenceNumber.
Now, I need to generate a content encryption key (CEK) from all these details and use it for decrypting messages received from server and for encrypting messages sent to server.
I can't find how it should be done.
The spec:
Diffie-Hellman key exchange process according to JWA (RFC 7518) in Direct Key Agreement mode using curve P-256, dC and QT to produce a pair of
CEKs (one for each direction), which are identified to the transactionID. In order to obtain 256 bits of keying material from the included Concat KDF function assume an "enc" parameter of ECDH-ES+A256KW and assume the algorithmID to be null for the KDF (Note this is using RFC 7518 only for key derivation). The parameter values supported in this version of the specification are:
"alg": ECDH-ES
"apv": referenceNumber
"epk": QТ
{"kty":"EC" "crv":"P-256"}
All other parameters: not present
CEK: "kty": oct-256 bits extracted as:
CEK(a->s): 256 bits
CEK(s->a): 256 bits
Thank you!

What is the purpose of a .jks keystore?

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.

Two-way SSL without access to client private key (but able to sign)

Summary
I need to establish a two-way SSL connection (with client certificate) in Android, preferrably using Apache HttpClient. I have access to the client's certificate, but no direct access to the clients private key. I can, however sign data with the client's private key.
Since I can't create a normal keystore without the private key, is there some way to override the SSL handshake and manually sign the challenge sent by the server?
What? You have no key, but you can still use it to sign?
The user's private key is stored on a dedicated hardware device. It will present the user's public certificate, and it allows me to pass in data that it will then sign/encrypt with the private key. But it will not give me the key itself.

What is the proper way to perform authenticated encryption in Java?

Authenticated encryption requires that we use some accepted standard for encrypting and authenticating a message. So we both encrypt the message and compute a MAC on the message to verify it has not been tampered with.
This question outlines a way to perform password based key strengthening and encryption:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
But as far as I can tell, this does not compute any MAC on the ciphertext and so would be insecure. What is the accepted standard for performing authenticated encryption in Java?
I would recommend using GCM mode encryption. It is included in the latest JDK (1.7) by default. It uses a counter mode encryption (a stream cipher, no padding required) and adds an authentication tag. One big advantage is that it requires only a single key, whereas HMAC adds another key to the mix. Bouncy Castle has an implementation as well, which is moslty compatible with one provided by Oracle.
GCM mode encryption is also features in a TLS RFC, and in XML encrypt 1.1 (both not final). GCM mode provides all three security features: confidentiality, integrity and authenticity of the data send. The String would be "AES/GCM/NoPadding" instead of the CBC one you are now deploying. As said, make sure you have the latest JDK from Oracle, or have Bouncy Castle provider installed.
Also check out my answer here, which is mostly about String encoding, but I've succesfully tried GCM mode too - see the comment.
When transferring files from one server to another through secure ftp, I use private/public key pairs with the private key residing on the "from" server and the public key residing on the "to" server.
Using private/public key pairs is a secure standard when transferring files.
I believe it would also be a secure means in the context of a Java application.
Check out Generating and Verifying Signatures and Generate Public and Private Keys
for more details on using a private/public key pair setup for digital signatures in Java.

Categories