I have the following methods for generating keys and signing the password message.
public void generateKeys() {
try {
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
if (!keyStore.containsAlias(KEY_NAME)) {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, KEYSTORE_NAME);
keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
// Require the user to authenticate with a fingerprint to authorize
// every use of the private key
.setUserAuthenticationRequired(true)
.build());
keyPairGenerator.generateKeyPair();
}
loadKeys();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public BiometricPrompt.CryptoObject getCryptoObject() {
cryptoObject = new BiometricPrompt.CryptoObject(signature);
return cryptoObject;
}
private void loadKeys() {
try {
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
if (keyStore.containsAlias(KEY_NAME)) {
publicKey = keyStore.getCertificate(KEY_NAME).getPublicKey();
privateKey = (PrivateKey) keyStore.getKey(KEY_NAME, null);
signature = Signature.getInstance(Constants.SIGNATURE);
signature.initSign(privateKey);
}
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
}
public String sign(String inputStr) {
try {
Signature signature = cryptoObject.getSignature();
signature.update(inputStr.getBytes());
byte[] signedBytes = signature.sign();
String result = HexManager.bytesToHex(signedBytes);
Log.d("TAG", result);
return result;
} catch (SignatureException e) {
e.printStackTrace();
}
return null;
}
After that, I saved the signed password in Shared Preferences. Later, I want to verify the saved password with a new password that is verified with the fingerprint.
Here is my method to verify:
public boolean verify(String inputStr, String savedStr) {
try {
Signature signature = cryptoObject.getSignature();
signature.initVerify(publicKey);
signature.update(inputStr.getBytes());
boolean isVerified = signature.verify(savedStr.getBytes());
return isVerified;
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
return false;
}
But it always return false.
Does anybody knows why?
It looks like in your sign() method you're returning the Hex of the byte[] obtained from the signature.sign() method. If this is what you're saving as savedStr. Then the verification method should be changed to convert the Hex encoded string to a byte[]. You could use HexManager.hexToBytes() (or equivalent) if it exists to convert the savedStr to a byte[] savedStrBytes.
public boolean verify(String inputStr, String savedStr) {
try {
byte[] savedStrBytes = HexManager.hexToByes(savedStr);
Signature signature = cryptoObject.getSignature();
signature.initVerify(publicKey);
signature.update(inputStr.getBytes());
boolean isVerified = signature.verify(savedStrBytes);
return isVerified;
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
return false;
}
Related
I encrypted data successfully using the biometric manager flow as shown by google but on trying the decrypt the encrypted data, I keep hitting the IllegalBlockSizeException clause. I need help please.
This is my class that handles all the fingerprint encryption( which works well) but decryption doesn't work, since it keeps hitting the IllegalBlockSizeException clause
public class FingerPrintEncrypter {
private static FingerPrintEncrypter fingerPrintEncrypter;
private static final String ENCRYPTION_BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;
private static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;
private static final String ENCRYPTION_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
byte[] initVector;
private FingerPrintEncrypter(){
}
public static synchronized FingerPrintEncrypter getInstance(){
if(fingerPrintEncrypter == null){
fingerPrintEncrypter = new FingerPrintEncrypter();
}
return fingerPrintEncrypter;
}
/*
gets the Cipher obj in encryptionMode for encryption tasks.
*/
public Cipher getCipherForEncryption(String aliasKeyName){
try {
Cipher cipher = getCipher();
SecretKey secretKey = getOrCreateSecreteKey(aliasKeyName);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
initVector = cipher.getIV();
return cipher;
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
/*
gets the Cipher obj in decryptionMode for decryption tasks.
*/
public Cipher getCipherForDecryption(String aliasKeyName){
try{
Cipher cipher = getCipher();
SecretKey secretKey = getOrCreateSecreteKey(aliasKeyName);
IvParameterSpec decryptParamSpec = new IvParameterSpec(initVector);
cipher.init(Cipher.DECRYPT_MODE, secretKey, decryptParamSpec);
return cipher;
}catch (InvalidKeyException e){
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}
private SecretKey getOrCreateSecreteKey(String aliasKeyName) {
try {
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
keyStore.load(null);
SecretKey key = ((SecretKey)keyStore.getKey(aliasKeyName, null));
if(key == null){
// key previously create so just grab it
generateSecretKey(aliasKeyName);
}
return key;
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
return null;
}
private void generateSecretKey(String aliasKeyName){
try {
// key not create create a new one
KeyGenParameterSpec parameterSpec = new KeyGenParameterSpec.Builder(aliasKeyName,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(ENCRYPTION_BLOCK_MODE)
.setEncryptionPaddings(ENCRYPTION_PADDING)
.setUserAuthenticationRequired(true)
.build();
KeyGenerator keyGenerator = KeyGenerator.getInstance(ENCRYPTION_ALGORITHM, ANDROID_KEY_STORE);
keyGenerator.init(parameterSpec);
keyGenerator.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
}
private Cipher getCipher() {
try {
return Cipher.getInstance(ENCRYPTION_ALGORITHM + "/"
+ ENCRYPTION_BLOCK_MODE + "/"
+ ENCRYPTION_PADDING);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
return null;
}
public String encryptData(String info, Cipher cipher){
try {
byte[] encryptedData = cipher.doFinal(info.getBytes("UTF-8"));
return Base64.encodeToString(encryptedData, Base64.NO_WRAP);
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
public String decryptData(String stringToDecrypt, Cipher cipher){
try {
return new String(cipher.doFinal(Base64.decode(stringToDecrypt, Base64.NO_WRAP)));
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
}
Here is my encryption method also Decryption method its working fine with Tag Basically server need TAG is it possible server find Tag by my Hex String because every String i send Tag to the server and also with Hex, is it have any other optimal solution
aesKey=context.getString(R.string.aes_key).getBytes();
iv=context.getString(R.string.input_vector).getBytes();
public Map encrypt(String string){
byte[] plainText= new byte[0];
try {
plainText = string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/GCM/NoPadding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(aesKey, "AES"), new IvParameterSpec(iv));
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
byte[] cipherText = new byte[0];
byte[] tag = new byte[0];
try {
cipherText = cipher.doFinal(plainText);
tag= Arrays.copyOfRange(cipherText, cipherText.length -16, cipherText.length);
cipherText= Arrays.copyOfRange(cipherText, 0, cipherText.length -16);
Log.d("testing", "encrypt: "+byteArrayToHexString(tag));
Map<String, Object> map=new HashMap();
map.put("content",byteArrayToHexString(cipherText));
map.put("tag",tag);
Log.d("testing", "encrypt: "+new Gson().toJson(map));
return map;
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return new HashMap();
}
Server need Hex so i convert it into Hex
public String byteArrayToHexString(final byte[] bytes) {
StringBuilder sb = new StringBuilder();
for(byte b : bytes){
sb.append(String.format("%02x", b&0xff));
}
return sb.toString();
}
My Decryption Function is that return me the String i receive Tag and Hex String from the server
public String decrypt(String content,byte[] tag){
byte[] cipherText = hexStringToByteArray(content+byteArrayToHexString(tag));
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/GCM/NoPadding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(aesKey, "AES"), new IvParameterSpec(iv));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
byte[] plainText = new byte[0];
try {
plainText = cipher.doFinal(cipherText);
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
try {
Log.d("testing", "encrypt: plain text:"+new String(plainText,"UTF-8"));
return new String(plainText,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
I have some token and I need first to sign it with SHA256 and ECDSA based on private and public key from KeyStore.
Every time when I try to verify value I get false as result. I do not know why.
Does someone have any idea how to solve this?
Here are my functions to generate and load keys:
private void generateKeys(){
try {
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
if(!keyStore.containsAlias(KEY_NAME)) {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, KEYSTORE_NAME);
keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setUserAuthenticationRequired(false)
.build());
keyPairGenerator.generateKeyPair();
setRegistred(true);
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void loadKeys(){
try {
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
if(keyStore.containsAlias(KEY_NAME)) {
publicKey = keyStore.getCertificate(KEY_NAME).getPublicKey();
privateKey = (PrivateKey) keyStore.getKey(KEY_NAME, null);
}
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
}
This is how sign value:
public String sign(String inputStr, FingerprintManager.CryptoObject cryptoObject){
try {
Signature signature = Signature.getInstance(SecurityConstants.SIGNATURE);
signature.initSign(privateKey);
signature.update(inputStr.getBytes());
byte[] signedBytes = signature.sign();
String result = Base64.encodeToString(signedBytes, Base64.DEFAULT);
Log.d("TAG", result);
return result;
} catch (SignatureException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
Here is my try to verify with Public Key:
public boolean verifyWithPublicKey(String input, FingerprintManager.CryptoObject cryptoObject){
try {
Signature signature = Signature.getInstance(SecurityConstants.SIGNATURE);
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
PublicKey pk = getPublicKeyForVerification();
signature.initVerify(pk);
signature.update(input.getBytes());
boolean isVerifed = signature.verify(input.getBytes());
Log.d("TAG", String.valueOf(isVerifed));
return isVerifed;
} catch (SignatureException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
The error is here, when you write the following code to verify the signature:
signature.update(input.getBytes());
boolean isVerifed = signature.verify(input.getBytes());
With this code, you try to verify that the signature has been signed with itself!
You should have:
signature.update(MY_BYTES_ARRAY_OF_DATA);
boolean isVerifed = signature.verify(MY_SIGNATURE);
Do not forget that the signature does not encapsulate the signed data by default.
If you want to have a format that includes signed data and associated signature, use S/MIME, OpenPGP, etc.
My app have a database, and I need a password to encrypt it.
If I store the hardcode password in java or in JNI, it is easy to hack.
Is it safer using AndroidKeyStore to generate a password? (I will recreate a copied db when the password changed.) So the hacker cannot easily to get the password.
Here is my code. I use public key of a KayPair to be the password:
private String generateAcStr() {
String keyAlias = "DBAlias";
KeyStore keystore = null;
try {
keystore = KeyStore.getInstance(ANDROID_KEY_STORE);
keystore.load(null);
if(!keystore.containsAlias(keyAlias)) {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", ANDROID_KEY_STORE);
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.MONTH, 1);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(keyAlias)
.setSubject(new X500Principal("CN=Custer Name, O=Android Authority"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.setKeySize(1024)
.build();
generator.initialize(spec);
generator.generateKeyPair();
}
KeyStore.PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) keystore.getEntry(keyAlias, null);
// use the public key to be the password
return Base64.encodeToString(privateKeyEntry.getCertificate().getPublicKey().getEncoded(), Base64.DEFAULT);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (UnrecoverableEntryException e) {
e.printStackTrace();
}
return null;
}
Thanks for helping me.
I want to encode my Url-params with Base64 and crypt(AES with CFB Mode), but it will not working and I can't get the error. Can someone help me? Here is my code:
private String toBase64Crypt(String cryptString) {
try {
SecretKeySpec key = new SecretKeySpec(pwd.getBytes("UTF8"), "AES");
byte[] cryptByte = cryptString.getBytes("UTF8");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
cryptString = Base64.encodeToString(cipher.doFinal(cryptByte),Base64.DEFAULT);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return cryptString;
}