I am using NSS as my keystore. I have generated a secret key which i use for encrypting/decrypting sensitive data (using AES) and all works fine.
For portability, is there a way in which this secret key can be extracted and inserted back to a different NSS DB?
I am using jre6 with SunPKCS11 provider. I am generating key as follows
KeyStore ks = //get NSS keystore
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey skey = kg.generateKey();
ks.setEntry(SECREY_KEY, new KeyStore.SecretKeyEntry(skey),
new KeyStore.PasswordProtection(pw.toCharArray()));
Try the NSS toolkit, it has a utility to extract PKCS#12 keys from NSS keystores:
http://www.mozilla.org/projects/security/pki/nss/tools/
Related
I am trying to store my own secret key in PKCS12 keystore. I tried by using below code:
char[] passArray = "password".toCharArray();// this is key store pass
String key = "test123"; // this is my own secret key
// Loading a Keystore
KeyStore p12KeyStore = KeyStore.getInstance("PKCS12");
p12KeyStore.load(new FileInputStream("testKeyStore.p12"), passArray);
Storing my own secret key like as shown below:
byte [] byteKey = key.getBytes();
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "DSA");
KeyStore.SecretKeyEntry secret = new KeyStore.SecretKeyEntry(keySpec);
KeyStore.ProtectionParameter password = new KeyStore.PasswordProtection(passArray);
p12KeyStore.setEntry("secret-key", secret, password);
but i am not sure whether storing the my own secret key as per best practice or not. and also when trying to get my own key from keystore as it is not getting like as my original secret key.
Key eKey = p12KeyStore.getKey("secret-key", passArray);
Can anyone please help me on this to store & get my own secret in PKCS12 keystore?
Are you sure the code you have above worked? Because DSA is a asymmetric algorithm, not a symmetric algorithm. If you are sure it is a secret key, it has to be AES or DES or DESede (Triple DES). Your above code should have failed.
And answers to your questions:
Just like databases stores data, keys (secret keys and key pairs) and certificates are meant to be stored in a keystore, that's where they should residing in your application. You should be referring/retrieving them from the keystore.
And from what you said in one of the statements, that the key is different from what you had originally when you stored and then retrieved, judging by this, I think the key you have is a Triple DES or a DES key. DES/TripleDES uses parity bits, and the parity bits are corrected by the Java API SecretKeySpec. This causes the key to look different from the original, but it is actually the same. You can read more about the parity bits here.
And as a best practice you shouldn't be storing the secret keys in a PKCS12 Keystore. The internet standard defines that the PKCS12 keystore should contain only one KeyPair entry associated with its certificate chain. Even though it can contain more than one entry, it is ideal to have only one entry, with the key password same as the keystore password. They can store secret keys too, but it is best if you store them in a JCEKS keystore format.
I am provided two files encrypted_key.enc and encrypted_data.csv.enc. I need to use my private key to decrypt the encrypted_key.enc to get a symmetric key and then use that symmetric key to decrypt the encrypted_data.csv.enc file.
On the terminal, the following commands get the job done:
openssl rsautl -decrypt -ssl -inkey my_private_key -in encrypted_key.enc -out key
openssl aes-256-cbc -d -in encrypted_data.csv.enc -out secret.txt -pass file:key
My goal is to perform the java equivalent of the two commands. I was able to successfully decrypt the first file and retrieve the symmetric key.
Now I'm unable to use that symmetric key to decrypt the csv file. My issue arises in the decipher.init(Cipher.DECRYPT_MODE, keySpec); I receive the following stacktrace
Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters
I'm unclear on what exactly I'm missing from the decryption process. I've tried changing the cipher provider but that didn't help. Other posts have posted solutions using an IVParameterSpec but my decryption case doesn't seem to need it or I'm confused on where to put it.
File file = new File("my_private_key");
PrivateKey pk = getPrivateKey(file);
// Decrypt secret key
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pk);
File skFile = new File("encrypted_key.enc");
FileInputStream fileInputStream = new FileInputStream(skFile);
byte[] decodedBytes = IOUtils.toByteArray(fileInputStream);
byte[] original = cipher.doFinal(decodedBytes);
String decodedOriginal = new String(Base64.encodeBase64(original));
System.out.println(decodedOriginal);
// Use the secret key for decrypting file
File csvFile =
new File(
"encrypted_data.csv.enc");
FileInputStream csvIS = new FileInputStream(csvFile);
Cipher decipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(original, "AES");
decipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] csvOriginal = decipher.doFinal(IOUtils.toByteArray(csvIS));
String csvContents = new String(csvOriginal);
System.out.println(csvContents);
Before Java 1.8 (I think, somewhere around there) you are limited by the Java Unlimited Strength Policy for key sizes above 128-bits. This is the most likely cause of the exception you are getting.
Unfortunately this won't fix your code. openssl with the pass flag uses an insecure KDF named EVP_BytesToKey(). Java doesn't natively support this KDF. You don't want to use it anyway since it is insecure. Update the upstream code to use a better KDF like PBKDF2. There is native support for this in Java.
Further, you're using CBC mode in openssl and ECB mode in Java. And you aren't specifying an IV in openssl. I get the impression you didn't write the Java code yourself. You might benefit from taking the time to learn and research what is actually happening in your code and in the commands you are executing and you might be better equipped to solve the problem.
I am trying to do the AES encryption/decryption in java
I generated the secretkey using KeyGenerator. I stored the key using java keystore.
Key myKey = KeyGenerator.getInstance("AES").generateKey();
KeyStore.ProtectionParameter protParam =
new KeyStore.PasswordProtection("secretpass".toCharArray());
//For writing the secret Key
KeyStore.SecretKeyEntry skEntry =
new KeyStore.SecretKeyEntry((SecretKey)myKey);
FileOutputStream fout = new FileOutputStream("test.ks");
KeyStore ksout = KeyStore.getInstance("JCEKS");
ksout.load(null,"changeit".toCharArray());
ksout.setEntry("secretalias", skEntry, protParam);
I wanted to get this secretkey from this file using openssl programatically. Is it possible? If so, please give me some suggestions on how do I proceed.
Thank you in advance.
This is not possible as the default keystore (jks) is a proprietary format used by Java.
To exchange the key you would need something portable like PKCS#11 (which is a supported KeyStore format at least in Java 8).
I obtain a randomly generated RSA certificate and private key as strings from another service, and I would like to use those strings to create a Java KeyStore. All of the examples I see involve saving these strings to files, using the openssl and keytool command line tools to create the keystore on disk, and then loading the resulting KeyStore into memory (like here). However, it makes more sense for my purposes to create the KeyStore entirely in memory.
To that end, I am trying to use the Java Security API. I am able to convert the certificate string into an instance of the java.security.cert.Certificate class, but I am unable to convert the private key into an instance of java.security.PrivateKey. Here's method I am trying to create:
private PrivateKey generatePrivateKey (String newKey)
throws NoSuchAlgorithmException,
InvalidKeySpecException, IOException {
//Configuring the KeyFactory to use RSA
KeyFactory kf = KeyFactory.getInstance("RSA");
//Convert the key string to a byte array
byte[] keyBytes = newKey.getBytes();
KeySpec ks = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey key = kf.generatePrivate(ks);
return key;
}
Where the value of newKey is something like "-----BEGIN RSA PRIVATE KEY-----\nMIIEow...gNK3x\n-----END RSA PRIVATE KEY-----".
When I run the code, I receive the following exception:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
... 30 more
Caused by: java.security.InvalidKeyException: invalid key format
at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:341)
at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:367)
at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
... 32 more
This particular error is very similar to this stackoverflow question, and I would be grateful if that question were resolved, but I also want to know if my higher level goal (creating a JKS programmatically and solely in memory using Java) is feasible, and if so, whether I am on the right path.
you need to decode base64 if your key is in the base64 representation:
KeySpec ks = new PKCS8EncodedKeySpec(Base64.decodeBase64(newKey));
you can use org.apache.commons.codec.binary.Base64 to do this.
if you want to generate keyPair you can you this code:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// extract the encoded private key, this is an unencrypted PKCS#8 private key
byte[] encodedprivkey = keyPair.getPrivate().getEncoded();
System.out.println(Base64.encodeBase64String(encodedprivkey));
I have a bash script which uses openssl to encrypt data, and Java code which decrypts the result. Based on my earlier post, I'm now able to enter a password in openssl, and copy the resulting key/iv into Java. This relies on using the -nosalt option in openssl. I'd like to remove that option, and take password/salt/iv from openssl and pass it into a JDK key derivation function.
Here's the openssl script I'm using:
#!/bin/bash
openssl enc -aes-128-cbc -in test -out test.enc -p
When I run this, and enter a password, it prints out the following for example.
salt=820E005048F1DF74
key=16023FBEB58DF4EB36229286419F4589
iv=DE46F8904224A0E86E8F8F08F03BCC1A
When I try the same password/salt/iv in Java, I'm not able to decrypt test.enc. I tried Java code based on the answer by #erickson in this post. Here's the snippet.
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 1024, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
If I print the "secret" that's generated, it's not the same as the "key" that openssl printed. Do I need to change one of the Java parameters to match how openssl is deriving its key?