How to convert pkcs8 to pkcs12 in Java - java

I know this is possible with openssl.
But I wonder if there are PKCS converting possibilities(pkcs8 to 12) in Java using any library.

First you read PKCS#8 encoded key as a file and create PrivateKey object
public PrivateKey loadPrivateKey(String keyFile)
throws Exception {
File f = new File(keyFile);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
Then this key is being saved into PKCS#12 key store
public void createKeyStore(String keyStorePwd, String keyStoreFile,
PrivateKey privateKey, X509Certificate certificate)
throws Exception {
char[] pwd = keyStorePwd.toCharArray();
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null, pwd);
KeyStore.ProtectionParameter protParam =
new KeyStore.PasswordProtection(pwd);
Certificate[] certChain =
new Certificate[]{ certificate };
KeyStore.PrivateKeyEntry pkEntry =
new KeyStore.PrivateKeyEntry(privateKey, certChain);
ks.setEntry("keypair", pkEntry, protParam);
FileOutputStream fos = new FileOutputStream(keyStoreFile);
ks.store(fos, pwd);
fos.close();
}

Related

The system cannot find the file specified trying to create .jks file

I'm currently learning encryption/decryption techniques in Java and one major problem I have come across is storing the key in a .jks file and being able to load it in during different launches. In my calling class it calls the constructor and this is the code for it:
public Encrypt_Decrypt() throws NoSuchAlgorithmException, NoSuchPaddingException
{
Cipher cipher = Cipher.getInstance("AES");
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
ivSpec = ivParams;
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
byte[] keyBytes = secretKey.getEncoded();
SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
key = sks;
KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(key);
KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection("password".toCharArray());
try
{
File f = new File("keystore.jks");
KeyStore keyStore = KeyStore.getInstance("JKS");
java.io.FileInputStream fis = null;
try
{
fis = new java.io.FileInputStream("keystore");
}
finally
{
if (fis != null)
{
fis.close();
}
}
keyStore.load(fis, "password".toCharArray());
keyStore.setEntry("key", entry, protParam);
try (FileOutputStream fout = new FileOutputStream(f))
{
keyStore.store(fout, "password".toCharArray());
;
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
After launching this code in the calling class, this is the error it returns:
keystore (The system cannot find the file specified)
In my code I create the file so why is it having an issue? I looked in my project folder and it is not being saved there so what do I have to do to be able to create, store and use this file without issues?
The keystore (The system cannot find the file specified) message relates to this line:
new java.io.FileInputStream("keystore");
It looks like that should have been using the File f? Something similar to how the FileOutputStream is handled just below works well:
try (FileInputStream fis = new FileInputStream(f)) {
keyStore.load(fis, "password".toCharArray());
}
For reference, there's another error waiting there. Trying to store the AES symmetric key in the JKS keystore results in this error:
java.security.KeyStoreException: Cannot store non-PrivateKeys
at sun.security.provider.JavaKeyStore.engineSetKeyEntry(JavaKeyStore.java:258)
at sun.security.provider.JavaKeyStore$JKS.engineSetKeyEntry(JavaKeyStore.java:56)
at java.security.KeyStoreSpi.engineSetEntry(KeyStoreSpi.java:550)
at sun.security.provider.KeyStoreDelegator.engineSetEntry(KeyStoreDelegator.java:179)
at sun.security.provider.JavaKeyStore$DualFormatJKS.engineSetEntry(JavaKeyStore.java:70)
at java.security.KeyStore.setEntry(KeyStore.java:1557)
at KeystoreTest.main(KeystoreTest.java:44)
This is because the JKS storetype only supports public/private keys - also here.
With a new JCEKS keystore instead, your example code then worked fine:
File f = new File("keystore.jceks");
KeyStore keyStore = KeyStore.getInstance("JCEKS");

InvalidKeySpecException while trying to generate public key from pem file

I am trying to generate a RSAPublicKey from the publickey.pem file but it is throwing me exception .
https://github.com/cerner/cds-hooks-sandbox/blob/master/ecpublickey.pem
Invalid token :::java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
KeyFactory factory = KeyFactory.getInstance("RSA");
PemReader pemReader = new PemReader(new InputStreamReader(new
FileInputStream(filename)));
PemObject pemObject = pemReader.readPemObject();
byte[] content = pemObject.getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
RSAPublicKey publicKey = factory.generatePublic(pubKeySpec);
It works fine if I generate and save my own pem file.

RSA encryption in Android

I am writing a program which employs RSA in Android. I have the following problem:
I am getting the RSA keys:
KeyPair kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
Using the encryption function to encrypt a test string:
String test ="test";
byte[] testbytes = test.getBytes();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherData = cipher.doFinal(testbytes);
String s = new String(cipherData);
Log.d("testbytes after encryption",s);
In the decryption function i am decrypting the data back to get the original string
Cipher cipher2 = Cipher.getInstance("RSA");
cipher2.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plainData = cipher.doFinal(cipherData);
String p = new String(plainData);
Log.d("decrypted data is:",p);
The data in 'p' printed out in the log does not match the original string "test" . Where am I going wrong in this?
Here an example on how to do it, BUT in practice,
You can't really encrypt and decrypt whole files with just RSA. The
RSA algorithm can only encrypt a single block, and it is rather slow
for doing a whole file.
You can encrypt the file using
3DES or AES, and then encrypt the AES key using intended recipient's
RSA public key.
Some code:
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
kpg.initialize(1024);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
PublicKey pubKey = keyPair.getPublic();
// Encrypt
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String test = "My test string";
String ciphertextFile = "ciphertextRSA.txt";
InputStream fis = new ByteArrayInputStream(test.getBytes("UTF-8"));
FileOutputStream fos = new FileOutputStream(ciphertextFile);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
byte[] block = new byte[32];
int i;
while ((i = fis.read(block)) != -1) {
cos.write(block, 0, i);
}
cos.close();
// Decrypt
String cleartextAgainFile = "cleartextAgainRSA.txt";
cipher.init(Cipher.DECRYPT_MODE, privKey);
fis = new FileInputStream(ciphertextFile);
CipherInputStream cis = new CipherInputStream(fis, cipher);
fos = new FileOutputStream(cleartextAgainFile);
while ((i = cis.read(block)) != -1) {
fos.write(block, 0, i);
}
fos.close();
}

RSA keypair generation and storing to keystore

I am tryng to generate RSA keypair and to store it on the HSM keystore. The code i have right now looks like this:
String configName = "C:\\eTokenConfig.cfg";
Provider p = new sun.security.pkcs11.SunPKCS11(configName);
Security.addProvider(p);
// Read the keystore form the smart card
char[] pin = { 'p', '4', 's', 's', 'w', '0', 'r', 'd' };
KeyStore keyStore = KeyStore.getInstance("PKCS11",p);
keyStore.load(null, pin);
//generate keys
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA",p);
kpg.initialize(512);
KeyPair pair = kpg.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
// Save Keys How ???
I tried to use the keyStore.setEntry method but the problem is it requires a Certificate chain and I don't know how to get this certificate ??
See http://docs.oracle.com/javase/tutorial/security/apisign/vstep2.html
Save Public Key:
X509EncodedKeySpec x509ks = new X509EncodedKeySpec(
publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream(strPathFilePubKey);
fos.write(x509ks.getEncoded());
Load Public Key:
byte[] encodedKey = IOUtils.toByteArray(new FileInputStream(strPathFilePubKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA", p);
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(
encodedKey);
PublicKey publicKey = keyFactory.generatePublic(pkSpec);
Save Private Key:
PKCS8EncodedKeySpec pkcsKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
FileOutputStream fos = new FileOutputStream(strPathFilePrivbKey);
fos.write(pkcsKeySpec.getEncoded());
Load Private Key:
byte[] encodedKey = IOUtils.toByteArray(new FileInputStream(strPathFilePrivKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA", p);
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
encodedKey);
PrivateKey privateKey = keyFactory.generatePrivate(privKeySpec);
You should not be able to read the private key if you generate the key inside the token.
you'll need to create a dummy certificate (for example self-signed) and store it with an alias, the keystore model depends on certificates to be usable.

RSA encryption :InvalidKeyException: invalid key format

I have to read pem key files to get RSA Public key,and then use them to encrypt.
I can do this using openssl and convert pem file to der file.
and then load my key using X509EncodedKeySpec and PKCS8EncodedKeySpec.
But I don't want to do this because pem is the user key exchange format.
user can register it's own key can like this :
--BEGIN PUBLIC KEY-- MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGi0/vKrSIIQMOm4atiw+2s8tSojOKHsWJU3oPTm
b1a5UQIH7CM3NgtLvUF5DqhsP2jTqgYSsZSl+W2RtqCFTavZTWvmc0UsuK8tTzvnCXETsnpjeL13
Hul9JIpxZVej7b6KxgyxFAhuz2AGscvCXnepElkVh7oGOqkUKL7gZSD7AgMBAAE=
--END PUBLIC KEY--
and this key is store in a database in this format...
Here is the code I have tried..
File pubKeyFile=new File("D:/public_key.pem");
DataInputStream dis = new DataInputStream(new FileInputStream(pubKeyFile));
byte[] pubKeyBytes = new byte[(int)pubKeyFile.length()];
dis.readFully(pubKeyBytes);
dis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubKeyBytes);
RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(pubSpec);
I am getting exception as
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
As I am completely new to encryption concepts can anyone please help me to solve this exception?
Many thanks.
With bouncycastle, it would be done this way:
CertificateFactory cf = CertificateFactory.getInstance("X509", "BC");
InputStream is = new FileInputStream("D:/public_key.pem");
X509Certificate certificate = (X509Certificate) cf.generateCertificate(is);
is.close();
RSAPublicKey pubKey = (RSAPublicKey)certificate.getPublicKey();
You were almost there, with the standard provider. You just need to strip the header and footer lines:
List<String> lines = Files.readAllLines(Paths.get(path), StandardCharsets.US_ASCII);
if (lines.size() < 2)
throw new IllegalArgumentException("Insufficient input");
if (!lines.remove(0).startsWith("--"))
throw new IllegalArgumentException("Expected header");
if (!lines.remove(lines.size() - 1).startsWith("--"))
throw new IllegalArgumentException("Expected footer");
byte[] raw = Base64.getDecoder().decode(String.join("", lines));
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey pub = factory.generatePublic(new X509EncodedKeySpec(raw));
try using bouncycastele's PemReader .
PublicKey getPublicKey(String pubKeyStr) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
PemObject pem = new PemReader(new StringReader(pubKeyStr)).readPemObject();
byte[] pubKeyBytes = pem.getContent();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubKeyBytes);
RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(pubSpec);
return pubKey;
}

Categories

Resources