package com.intrbiz.bergamot.crypto.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class KeyUtil
{
public static IvParameterSpec newAESIV()
{
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
public static SecretKey newAESKey() throws NoSuchAlgorithmException
{
KeyGenerator sKeyGen = KeyGenerator.getInstance("AES");
sKeyGen.init(128);
SecretKey sKey = sKeyGen.generateKey();
return sKey;
}
public static SecretKey openAESKey(byte[] encoded)
{
return new SecretKeySpec(encoded, "AES");
}
public static IvParameterSpec openAESIV(byte[] iv)
{
return new IvParameterSpec(iv);
}
public static KeyPair newRSAKeyPair() throws NoSuchAlgorithmException
{
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(4096);
KeyPair pair = keyGen.generateKeyPair();
return pair;
}
public static byte[] encryptSecretKey(SecretKey sKey, PublicKey key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, key);
byte[] esk = rsa.doFinal(sKey.getEncoded());
return esk;
}
public static SecretKey decryptSecretKey(byte[] encrypted, PrivateKey key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
Cipher rsad = Cipher.getInstance("RSA");
rsad.init(Cipher.DECRYPT_MODE, key);
byte[] dsk = rsad.doFinal(encrypted);
return openAESKey(dsk);
}
public static byte[] encryptIV(IvParameterSpec iv, PublicKey key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, key);
byte[] esk = rsa.doFinal(iv.getIV());
return esk;
}
public static IvParameterSpec decryptIV(byte[] encrypted, PrivateKey key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
Cipher rsad = Cipher.getInstance("RSA");
rsad.init(Cipher.DECRYPT_MODE, key);
byte[] dsk = rsad.doFinal(encrypted);
return openAESIV(dsk);
}
public static void savePublicKey(File file, PublicKey key) throws FileNotFoundException, IOException
{
try (FileOutputStream out = new FileOutputStream(file))
{
out.write(key.getEncoded());
}
}
public static PublicKey loadPublicKey(File file) throws FileNotFoundException, IOException, NoSuchAlgorithmException, InvalidKeySpecException
{
byte[] data = loadFile(file);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(new X509EncodedKeySpec(data));
}
public static void savePrivateKey(File file, KeyPair key) throws FileNotFoundException, IOException
{
// the data
byte[] pub = key.getPublic().getEncoded();
byte[] prv = key.getPrivate().getEncoded();
// pack the data
ByteBuffer buf = ByteBuffer.wrap(new byte[8 + pub.length + prv.length]);
buf.putInt(pub.length);
buf.put(pub);
buf.putInt(prv.length);
buf.put(prv);
// write
try (FileOutputStream out = new FileOutputStream(file))
{
out.write(buf.array());
}
}
public static KeyPair loadPrivateKey(File file) throws FileNotFoundException, IOException, NoSuchAlgorithmException, InvalidKeySpecException
{
byte[] data = loadFile(file);
// unpack
ByteBuffer buf = ByteBuffer.wrap(data);
int pubLen = buf.getInt();
if (pubLen < 16 || pubLen > 8192) throw new IOException("Bad key");
byte[] pub = new byte[pubLen];
buf.get(pub);
int prvLen = buf.getInt();
if (prvLen < 16 || prvLen > 8192) throw new IOException("Bad key");
byte[] prv = new byte[prvLen];
buf.get(prv);
// load
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey prvKey = kf.generatePrivate(new PKCS8EncodedKeySpec(prv));
PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(pub));
return new KeyPair(pubKey, prvKey);
}
private static byte[] loadFile(File file) throws FileNotFoundException, IOException
{
byte[] data = new byte[(int) file.length()];
try (FileInputStream in = new FileInputStream(file))
{
in.read(data);
}
return data;
}
}