Fingerprint API preview for Android N is found here with Sample App Sample App .As of this writing, createKey() in this method specify key_name,i don't know about key_name,Please anyone tell about key_name
/** Alias for our key in the Android Key Store */
private static final String KEY_NAME = "my_key";
public void createKey() {
// The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
// for your flow. Use of keys is necessary if you need to know if the set of
// enrolled fingerprints has changed.
try {
mKeyStore.load(null);
// Set the alias of the entry in Android KeyStore where the key will appear
// and the constrains (purposes) in the constructor of the Builder
mKeyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
// Require the user to authenticate with a fingerprint to authorize every use
// of the key
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
mKeyGenerator.generateKey();
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
| CertificateException | IOException e) {
throw new RuntimeException(e);
}
}
this my part of code,here what is KEY_NAME and key_name get from where
Just run this cmd on your terminal
/home/nn1android01user/Documents/Keystor_alicante/gerber_keystore.jks ->
this is your keystore file path
gerber -> alias name
keytool -exportcert -alias gerber -keystore /home/nn1android01user/Documents/Keystor_alicante/gerber_keystore.jks | openssl sha1 -binary | openssl base64
Related
This is the first time I am doing this SSL pinning on Android.
When creating OkHttp, I am adding this code:
certificatePinner(
CertificatePinner.Builder().add(
"url of the server",
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
).build()
)
the second parameter expects this:
SHA-256 or SHA-1 hashes. Each pin is a hash of a certificate's Subject Public Key Info, base64-encoded and prefixed with either sha256/ or sha1/.
I was given a certificate in a txt file that starts with --BEGIN CERTIFICATE-- and ends with --END CERTIFICATE--.
I am struggling to extract the hash of Public Key Info and convert it to base64.
So far I have tried these methods:
Method 1:
I put the certificate contents without BEGIN CERTIFICATE and END CERTIFICATE into some string variable. Tried to convert it into X509Certificate.
private fun certificateFromString(base64: String): X509Certificate? {
val decoded = Base64.decode(base64, Base64.NO_WRAP)
val inputStream = ByteArrayInputStream(decoded)
return CertificateFactory.getInstance("X.509").generateCertificate(inputStream) as? X509Certificate
}
Then I pass this certificate here to get Sha256 hash of the public key. Also, pay attention to c.encoded and c.publicKey.encoded. I am not sure if the method works correctly.
private fun getFingerprint(c: X509Certificate?): String {
var certificate = ""
try {
val md = MessageDigest.getInstance("SHA-256")
var publicKey = ByteArray(0)
if (c != null) {
publicKey = md.digest(c.encoded) // I tried both
publicKey = md.digest(c.publicKey.encoded) // I tried both
}
val hexString = StringBuilder()
for (aPublicKeyByte in publicKey) {
val appendString = Integer.toHexString(0xFF and aPublicKeyByte.toInt())
if (appendString.length == 1) hexString.append("0")
hexString.append(appendString)
}
certificate = hexString.toString()
} catch (e1: NoSuchAlgorithmException) {
e1.printStackTrace()
} catch (e1: CertificateEncodingException) {
e1.printStackTrace()
}
return certificate
}
then I am converting that string result to base64 like this:
private fun base64(openKey: String): String {
return Base64.encodeToString(openKey.toByteArray(), Base64.NO_WRAP).toString()
}
then I add the resulting String into the CertificatePinner class as sha256/resultingStringInBase64.
Method 2:
I changed the .txt into .pem in order to use openssl command line tools.
openssl rsa -in myCert.pem -pubout> myCert.pub
it returned writing RSA key
and when I open the generated myCert.pub, I see a text with ---BEGUN PUBLIC KEY--- and ---END PUBLIC KEY--- and a long list of letters between them.
Then I ran this to extract the sha256 hash:
openssl rsa -in myCert.pub -pubin -outform der | openssl dgst -sha256
this gave me a 64 character string 2c180286549...b1ba7.
Then I ran the command again but added base64 conversion.
openssl rsa -in myCert.pub -pubin -outform der | openssl dgst -sha256 | openssl enc -base64
The result is completely different than Method 1. Should it be the same? If so, could someone point me in the right direction? Or show how to properly get the SHA256 of Public Key.
My method I just used recently and worked succesfully:
In your Terminal, where the folder containing public key file is located, write the command:
openssl x509 -in yourFile.pem -pubkey -noout | open ssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
The result will be the your desired string (encoded in base64, which means that it'll have 44 characters, including an equal (=) symbol at the end), and must be placed in your Android code after sha256/....
Also, several methods could generate different hashes, so you can have multiple valid strings, meaning that both your generated hashes could be correct.
I'm building a simple app containing notes encrypted with the KeyStore key (for the purposes of security classes). To view the notes, the user must authenticate either with a fingerprint or a password set in the application. My problem is that when using password login I get "android.security.KeyStoreException: Key user not authenticated" error. I found that I can work around this problem by setting setUserAuthenticationRequired (false), but as far as I know it's not a good technique. I wonder if it is possible to set a password to access the key, which, if correct, authenticates our use of the key from the KeyStore. I have tried to achieve this by using the setKeyEntry() function, but I get the error "java.security.KeyStoreException: entries cannot be protected with passwords" . Can someone explain to me how to do it correctly (if of course it is possible?). Below is the code on how I'm generating and getting my key.
fun getOrCreateSecretKey(): SecretKey {
// if key already exists
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)
keyStore.load(null) // Keystore must be loaded before it can be accessed
keyStore.getKey(YOUR_SECRET_KEY_NAME, "testPassword".toCharArray())?.let { return it as SecretKey }
// if key doesn't exist
val paramsBuilder = KeyGenParameterSpec.Builder(
YOUR_SECRET_KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
paramsBuilder.apply {
setBlockModes(ENCRYPTION_BLOCK_MODE)
setEncryptionPaddings(ENCRYPTION_PADDING)
setKeySize(KEY_SIZE)
setUserAuthenticationRequired(false)
}
// generating key
val keyGenParams = paramsBuilder.build()
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
ANDROID_KEYSTORE
)
keyGenerator.init(keyGenParams)
val myKey = keyGenerator.generateKey()
// setting entry password
keyStore.setKeyEntry(YOUR_SECRET_KEY_NAME, myKey, "testPassword".toCharArray(), null)
return myKey
}
my apk is working fine in debug mode. but when I signed apk with release mode then
automatic sms retrivr is not working.
then I search I found I have to generate a hash key on official documentation
https://developers.google.com/identity/sms-retriever/verify#generating_a_one-time_code
where I found two methods
1> by signature helped class- I used but not working
2> second by following command
keytool -exportcert -alias MyAndroidKey -keystore MyProductionKeys.keystore | xxd -p | tr -d "[:space:]" | echo -n com.example.myapp cat | sha256sum | tr -d "[:space:]-" | xxd -r -p | base64 | cut -c1-11
but I got xxd command is not found
then I search on the stack then i run a command on git bash command runs but that hash key still not working
It would be easier to generate hash through this code.
Just call below line and print your signature.
ArrayList<String> sigList = (new AppSignatureHelper(this)).getAppSignatures()
Code Reference: https://github.com/googlesamples/android-credentials/blob/master/sms-verification/android/app/src/main/java/com/google/samples/smartlock/sms_verify/AppSignatureHelper.java
Update:
Hash code for debug and release version will be different.
Make sure you are using release specific app hash code for otp message with required format.
AppSignatureHelper will provide hash code using which apk is signed. Build release apk and print hash code in log to get release specific hash code.
Update:
Another approach of generating through command mentioned in : https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string
However if you are using windows, it may not work as you it dont have binary (command) like xxd or tr.
in that case, you have to download those exe from somewhere else.
If you are using git then you can find them at "C:\Program Files\Git\usr\bin\", in that case follow this steps.
Add path "C:\Program Files\Git\usr\bin\" in your environment variables.
Restart your command prompt. so xxd and tr starts working in prompt.
apply mentioned command in link.
keytool -exportcert -alias MY_ANDROID_KEY -keystore MY_PRODUCTION_KEY | xxd -p | tr -d "[:space:]" | echo -n MY_PACKAGE_NAMEcat| sha256sum | tr -d "[:space:]-" | xxd -r -p | base64 | cut -c1-11
Where in command
replace MY_ANDROID_KEY with your key alias
replace MY_PRODUCTION_KEY with your keystore path (some xyz.jks)
replace MY_PACKAGE_NAME with your package name
you will get 11 character long hash key. Hurray.
Here, if you are facing error like tr: write error: Illegal seek,
you can call cammand up to tr like ->
keytool -exportcert -alias MY_ANDROID_KEY -keystore MY_PRODUCTION_KEY | xxd -p | tr -d "[:space:]"
in this case you will get around 1800+ character long signature string.
pass package and signature string to hash method of AppSignatureHelper, it will return your key.
(Here, If at the end you are using AppSignatureHelper, i suggest to go for that first approach only)
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.util.Base64;
import android.util.Log;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
public class AppSignatureHelper extends ContextWrapper {
private static final String TAG = "AppSignatureHelper";
private static final String HASH_TYPE = "SHA-256";
public static final int NUM_HASHED_BYTES = 9;
public static final int NUM_BASE64_CHAR = 11;
public AppSignatureHelper(Context context) {
super(context);
}
/**
* Get all the app signatures for the current package
*/
public ArrayList<String> getAppSignatures() {
ArrayList<String> appCodes = new ArrayList<>();
try {
// Get all package signatures for the current package
String packageName = getPackageName();
PackageManager packageManager = getPackageManager();
Signature[] signatures = packageManager.getPackageInfo(packageName,
PackageManager.GET_SIGNATURES).signatures;
// For each signature create a compatible hash
for (Signature signature : signatures) {
String hash = hash(packageName, signature.toCharsString());
if (hash != null) {
appCodes.add(String.format("%s", hash));
}
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Unable to find package to obtain hash.", e);
}
return appCodes;
}
private static String hash(String packageName, String signature) {
String appInfo = packageName + " " + signature;
try {
MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE);
messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));
byte[] hashSignature = messageDigest.digest();
// truncated into NUM_HASHED_BYTES
hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
// encode into Base64
String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP);
base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR);
CommonUtils.base64Val = base64Hash;
Log.e("base64Val",base64Hash);
Log.d(TAG, String.format("pkg: %s -- hash: %s", packageName, base64Hash));
return base64Hash;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "hash:NoSuchAlgorithm", e);
}
return null;
}
}
You can use base64hash for debug build and if you are making app live, make signed APK and use the value generated from signed APK.
Don't forget to call this class from main application's oncreate()
AppSignatureHelper appSignatureHelper = new AppSignatureHelper(this);
appSignatureHelper.getAppSignatures();
I'm trying to use RSA encryption with KeyStore and I need to specify Parameters for KeyPairGenerator and I'm lost here. KeyPairGeneratorPair is kinda straightforward, but I don't understand KeyGenParameterSpec for API>=23
That's what I did, I think I got everything in else part, but now I'm confused about KeyGenParameterSpec
What exactly public exponent in RSAKeyGenParameterSpec is?
What Digests in .setDigests should i specify?
There's also .setBlockMode() method to call, and since I'm using RSA and RSA/None/OAEPWithSHA1AndMGF1Paddingwhich block mode to set? ECB, CBC?
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
generator.initialize(new KeyGenParameterSpec.Builder("PrivateKey", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
.setDigests(KeyProperties.DIGEST_SHA1,
KeyProperties.DIGEST_SHA256)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setCertificateSerialNumber(BigInteger.ONE)
.setCertificateSubject(new X500Principal("CN=" + "PrivateKey"))
.setCertificateNotBefore(calendar.getTime())
.setCertificateNotAfter(endCalendar.getTime())
.setKeySize(2048).build());
} else {
generator.initialize(new KeyPairGeneratorSpec.Builder(MainActivity.this)
.setAlias("PrivateKey")
.setSerialNumber(BigInteger.ONE)
.setSubject(new X500Principal("CN=" + "PrivateKey"))
.setStartDate(calendar.getTime())
.setEndDate(endCalendar.getTime())
.setKeySize(2048).build()
);
}
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding");
Method setDigests() sets digest method for your padding mode and setBlockMode() sets encryption mode which depends on your work.
I think you have set a lot of unnecessary field. For example I use this method to create my own RSA key:
public boolean createKey() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
);
mKeyStore.load(null);
KeyGenParameterSpec.Builder builder =
new KeyGenParameterSpec.Builder(
MY_KEY,
KeyProperties.PURPOSE_DECRYPT).
setKeySize(MY_KEYLEN).
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP).
setDigests(KeyProperties.DIGEST_SHA256);
keyPairGenerator.initialize(builder.build());
keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException | CertificateException | IOException |
InvalidAlgorithmParameterException | NoSuchProviderException e) {
return false;
}
return true;
}
I created this key to use with RSA/ECB/OAEPWithSHA-256AndMGF1Padding algorithm.
I am attempting to do the following,
Generate a secret key for sqlcipher.
Store the secret in android keystore.
Retrieve secret from keystore.
I've found nearly everything I need, but I'm having trouble getting the below pieces of code working together.
Pre: Setup keystore
private void InitialiseKeystore() throws ... {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
boolean containsAlias = keyStore.containsAlias("com.example.myapp");
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
if (!containsAlias) {
kpg.initialize(new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.build());
KeyPair kp = kpg.generateKeyPair();
}
Generating symmetric key
I found these good examples but they're creating public/private keys, as the same with many others, so a bit confused there, but I have the following.
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128); //<------------------------------------- [ERRORS HERE]
SecretKey secretKey = keyGen.generateKey();
Storing in keystore
Reviewing the documentation, it seems I should use KeyStore.SecretKeyEntry to store secrets, so this is what I currently have,
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
keyStore.setKeyEntry("key1", secretKeyEntry.getSecretKey().getEncoded(), null);
Retrieving from keystore
private static byte[] getRawSecret() throws Exception {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
byte[] raw = keyStore.getKey("key1", null).getEncoded();
return raw;
}
Here's where it goes wrong, in another function I'm trying to call getRawSecret().
SQLiteDatabase.openOrCreateDatabase(databaseFile, getRawSecret().toString(), null);
ERROR: Cannot initialize without a android.security.keystore.KeyGenParameterSpec parameter
So question, how do I create a symmetric key and store in keystore? As the error is telling me to use KeyGenParameterSpec but as in the examples linked above, this wants to create public/private keys. What am I doing wrong?
I used this to solve my issue,
Guide: https://medium.com/#josiassena/using-the-android-keystore-system-to-store-sensitive-information-3a56175a454b
Code: https://gist.github.com/JosiasSena/3bf4ca59777f7dedcaf41a495d96d984