/**
*
*/
package org.commcare.android.crypt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.commcare.android.util.AndroidStreamUtil;
/**
* @author ctsims
*
*/
public class CryptUtil {
private static final String PBE_PROVIDER = "PBEWITHSHA-256AND256BITAES-CBC-BC";
private static Cipher encodingCipher(String password) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(password.toCharArray(), "SFDWFDCF".getBytes(), 10);
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_PROVIDER);
SecretKey key = factory.generateSecret(spec);
Cipher cipher = Cipher.getInstance(PBE_PROVIDER);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher;
}
private static Cipher decodingCipher(String password) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException {
KeySpec spec = new PBEKeySpec(password.toCharArray(), "SFDWFDCF".getBytes(), 10);
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_PROVIDER);
SecretKey key = factory.generateSecret(spec);
Cipher cipher = Cipher.getInstance(PBE_PROVIDER);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher;
}
public static byte[] encrypt(byte[] input, Cipher cipher) {
ByteArrayInputStream bis = new ByteArrayInputStream(input);
CipherInputStream cis = new CipherInputStream(bis, cipher);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
AndroidStreamUtil.writeFromInputToOutput(cis, bos);
} catch (IOException e) {
throw new RuntimeException(e);
}
return bos.toByteArray();
}
public static byte[] decrypt(byte[] input, Cipher cipher) {
try {
return cipher.doFinal(input);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
//
// ByteArrayInputStream bis = new ByteArrayInputStream(input);
// CipherInputStream cis = new CipherInputStream(bis, cipher);
//
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
//
// AndroidStreamUtil.writeFromInputToOutput(new BufferedInputStream(cis), bos);
//
// return bos.toByteArray();
}
public static byte[] wrapKey(SecretKey key, String password) {
return wrapKey(key.getEncoded(), password);
}
public static byte[] wrapKey(byte[] secretKey, String password) {
try{
//SecretKeySpec spec = (SecretKeySpec)SecretKeyFactory.getInstance("AES").getKeySpec(key, javax.crypto.spec.SecretKeySpec.class);
byte[] encrypted = encrypt(secretKey, encodingCipher(password));
return encrypted;
}catch (InvalidKeySpecException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
return null;
}
}
public static byte[] unWrapKey(byte[] wrapped, String password) {
try{
Cipher cipher = decodingCipher(password);
byte[] encoded = decrypt(wrapped, cipher);
return encoded;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
return null;
}
}
private static byte[] append(byte[] one, byte[] two) {
byte[] result = new byte[one.length + two.length];
for(int i = 0; i < result.length; ++i) {
if(i < one.length) {
result[i] = one[i];
} else {
int index = i - one.length;
result[i] = two[index];
}
}
return result;
}
public static byte[] uniqueSeedFromSecureStatic(byte[] secureStatic) {
long uniqueBase = new Date().getTime();
String baseString = Long.toHexString(uniqueBase);
try {
return append(baseString.getBytes(), MessageDigest.getInstance("SHA-1").digest(secureStatic));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static SecretKey generateSymetricKey(byte[] prngSeed) {
KeyGenerator generator;
try {
generator = KeyGenerator.getInstance("AES");
generator.init(256, new SecureRandom(prngSeed));
return generator.generateKey();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static SecretKey generateSemiRandomKey() {
KeyGenerator generator;
try {
generator = KeyGenerator.getInstance("AES");
generator.init(256, new SecureRandom());
return generator.generateKey();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Cipher getPrivateKeyCipher(byte[] privateKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(privateKey);
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.DECRYPT_MODE, privKey);
return c;
}
public static Cipher getAesKeyCipher(byte[] aesKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
return getAesKeyCipher(aesKey, Cipher.DECRYPT_MODE);
}
public static Cipher getAesKeyCipher(byte[] aesKey, int mode) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
SecretKeySpec spec = new SecretKeySpec(aesKey, "AES");
Cipher decrypter = Cipher.getInstance("AES");
decrypter.init(mode, spec);
return decrypter;
}
}