How to retrieve installed X509 certificate from Android keychain? - android

I installed a X509 certificate into andorid keychain using following code:
Intent installIntent = KeyChain.createInstallIntent();
installIntent.putExtra(KeyChain.EXTRA_NAME, "My certificate");
installIntent.putExtra(KeyChain.EXTRA_CERTIFICATE, certificate.getEncoded());
startActivityForResult(installIntent, 2);
I get an toast mentioning "My Certificate is installed". Now when I am trying to fetch it back using following code:
try {
KeyStore ks = KeyStore.getInstance("AndroidCAStore");
if (ks != null) {
ks.load(null, null);
Enumeration aliases = ks.aliases();
List<String> alliasesNames = Collections.list(aliases);
for (String name : alliasesNames) {
if (ks.getCertificate(name) instanceof X509Certificate) {
X509Certificate certificate = (X509Certificate) ks.getCertificate(name);
if (certificate.getIssuerDN().getName().contains("My Certificate")) {
Log.d("CERTEXIST", "**********User Cert " + certificate.getIssuerDN().getName());
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (java.security.cert.CertificateException e) {
e.printStackTrace();
}
I am not able to find that installed x509 in this. Also I could see the installed x509 cert in User certificate in security settings of the device.
Also when I prompt user to choose a cert for server communication using:
KeyChain.choosePrivateKeyAlias(loginActivity, this,
new String[]{}, null, null, -1, null);
}
The prompt doesn't show my certificate. I am new to this certificates and key chain in Android.
I would like to know how to retrive the saved x509 cert and prompt that to user to select that certificate.
Any help is appreciated.

KeyChain.choosePrivateKeyAlias launches an antivity to prompt user to select the alias for a private key, but you have installed a certificate, not a private key, so your certificate will not be there.
KeyChain.createInstallIntent() can be used to install X509 certificates or PKCS#12 files, containing both private key and certificates. If you need to install a private key+certificate for authentication you need to provide a p12 file.
byte pkcs12Data[] = ...
installIntent.putExtra(KeyChain._PKCS12, pkcs12Data);

Related

ECIES (Elliptic Curve Cryptography) with pre-exist Certificate using python

I have a code in android to:
Generate ECDSA key-pair (Public Key and Private Key)
Generate Certificate Signing Request (CSR) from public key
Store Private Key
Then I send CSR to CA server. The CA server generate X.509 certificate.
Now I want to encrypt a string with public key from that X.509 certificate above. And then I will write android code to decrypt encrypted string using stored Private Key.
I have code to encrypt/ decrypt ECIES in android:
Here is my code:
///Gen Key
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1");
try {
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA","SC");
g.initialize(spec, new SecureRandom());
KeyPair keyPair = g.generateKeyPair();
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
Toast.makeText(MainActivity.this, "GEN KEY SUCCESS!!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
/////Encrypt
String origin = txtOrigin.getText().toString();
try {
Cipher c = Cipher.getInstance("ECIES","SC");
c.init(Cipher.ENCRYPT_MODE,publicKey);
encodeBytes = c.doFinal(origin.getBytes());
txtEncrypt.setText(Base64.encodeToString(encodeBytes,Base64.DEFAULT));
Toast.makeText(MainActivity.this, "ENCRYPT SUCCESS!!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
////Decrypt
byte[] decodeBytes = null;
try
{
Cipher c = Cipher.getInstance("ECIES","SC");
c.init(Cipher.DECRYPT_MODE,privateKey);
decodeBytes = c.doFinal(encodeBytes);
String deCrypt = new String(decodeBytes,"UTF-8");
txtDecrypt.setText(deCrypt);
Toast.makeText(MainActivity.this, "DECRYPT SUCCESS!!", Toast.LENGTH_SHORT).show();
}
catch (Exception ex)
{
ex.printStackTrace();
}
But I want to encrypt string using python with public key from X.509 certificate on my CA server and decrypt using my code above in android.

Unable to overwrite files in Google Drive AppData folder INTERNAL_ERROR

I am using GDAA in my application for managing my application files in google drive. All the below listed operations work fine like
google sign-in (scope is added for AppData Folder)
download file from AppData Folder
upload file to AppData Folder
delete file from AppData Folder
but when I try to overwrite a file in AppData Folder i am getting the following error in the onResult() callback.
Status Message : Failed to commit changes.
Status Code : INTERNAL_ERROR (8)
I am unable to understand why this is happening. Please find below my code for reference
public void overwrite(String strLocalFilePath, String strDriveId, String strGoogleDriveFileMimeType, String strGoogleDriveFileTitle){
final DriveId driveId = DriveId.decodeFromString(strDriveId);
DriveFile file = driveId.asDriveFile();
file.open(mGoogleApiClient, DriveFile.MODE_WRITE_ONLY, null).setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() {
#Override
public void onResult(DriveApi.DriveContentsResult result) {
if (!result.getStatus().isSuccess()) {
Log.e(TAG,"Error");
return;
}
DriveContents driveContents = result.getDriveContents();
OutputStream outputStream = driveContents.getOutputStream();
boolean isSuccess = writeFileToStream(outputStream, strLocalFilePath);
if (isSuccess) {
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle(strGoogleDriveFileTitle)
.setMimeType(strGoogleDriveFileMimeType)
.build();
ExecutionOptions executionOptions = new ExecutionOptions.Builder()
.setNotifyOnCompletion(true)
.setTrackingTag("SAMPLE_TRACKING_TAG")
.build();
driveContents.commit(mGoogleApiClient, changeSet, executionOptions).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// Handle the response status
if (!status.getStatus().isSuccess()) {
Log.e(TAG, "Error while trying to overwrite file. Message : "+status.getStatus().getStatusMessage() + " Status code : "+status.getStatus().getStatusCode());
return;
}else{
Log.d(TAG,"File overwritten successfully!!");
}
}
});
} else {
Log.e(TAG, "File I/O Error occurred : "+ strGoogleDriveFileTitle);
}
}
});
}
private boolean writeFileToStream (OutputStream oos, String filePath){
if (oos != null) {
InputStream is = null;
try {
Log.d(TAG, "Started writing file : "+filePath);
is = new FileInputStream(filePath);
byte[] buf = new byte[4096];
int c;
while ((c = is.read(buf, 0, buf.length)) > 0) {
oos.write(buf, 0, c);
oos.flush();
}
Log.d(TAG, "Finished writing file : "+filePath);
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
try {
if(oos != null) {
oos.close();
}
if(is != null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
return false;
}
According to this thread, if you get error code 8 (INTERNAL_ERROR), please double check your app registration in dev console. Note that every registered Android client is uniquely identified by the (package name, Android Signing Certificate SHA-1) pair. If you have multiple package names / signing certificate for your debug and production environments, make sure to register every pair of them.
To verify:
Open the Credentials page and select your project
Make sure every pair has an Android typed OAuth 2.0 client IDs.
To create a new OAuth 2.0 client ID for your Android client, select New Credentials->OAuth2 Client ID from the dropdown, select Android and input your Package name / Signing-certificate fingerprint there.
To get your signing key certificate SHA-1:
Standard Debug Key
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
Other (Custom) Key
keytool -list -v -keystore $YOUR_KEYSTORE_LOCATION
Here's a reference which might also help:
Error : ConnectionResult{statusCode=INTERNAL_ERROR, resolution=null}
If you are getting this bug even after 1) making sure that you have registered the package name with its corresponding certificate fingerprint, and 2) are (re)using an already existing project, then you should check that this project has an product name and an email address (double check that one specially) associated with it, both to be found in the "consent screen" section.

Validate android app certificate

I want to check if installed android application has self signed or trusted certificate. The problem is that my code listed below raises CertificateException for all installed (including Google made) apps. Could you help me to find a problem why it doesn't work correctly?
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
List<ResolveInfo> runningServices = getPackageManager().queryIntentActivities(intent, 0);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("AndroidCaStore");
ks.load(null, null);
tmf.init(ks);
X509TrustManager trustManager = (X509TrustManager)tmf.getTrustManagers()[0];
PackageManager manager = getPackageManager();
try {
for (ResolveInfo runningService : runningServices) {
PackageInfo info = manager.getPackageInfo(runningService.activityInfo.packageName,
PackageManager.GET_SIGNATURES);
Signature signature = info.signatures[0];
Signature[] arrSignatures = info.signatures;
for (Signature sig : arrSignatures) {
byte[] rawCert = sig.toByteArray();
InputStream certStream = new ByteArrayInputStream(rawCert);
CertificateFactory certFactory;
X509Certificate x509Cert;
try {
certFactory = CertificateFactory.getInstance("X509");
x509Cert = (X509Certificate) certFactory.generateCertificate(certStream);
trustManager.checkServerTrusted(new X509Certificate[] { x509Cert }, "RSA");
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
The answer is pretty obvious: we can't validate android app certificate using trusted certificates chain (what normally do ssl guts to check web resource certificate), because they are self-signed. That is why checkServerTrusted function raises CertificateException during such check. This book gives following information:
Because a process is tied to a package name, and a package name is
tied to its signature, signatures play a role in securing the data
belonging to a package. A package is typically signed with a
self-signed PKI (Public Key Infrastructure) certificate. A certificate
identifies who the author of the package is. These certificates need
not be issued by a certificate authority. This means the information
in the certificate is not approved or validated by any authority. This
means one can create a certificate that says that their name is
Google. The only assurance is that this package name is reserved to
that user if no one had claimed it in the marketplace before, and any
subsequent updates to that package are given only to that user
(identified by that certificate).

Android - Encode & Decode RSA with Private Key?

I am trying to encode and decode Strings on Android using a Private Key generated and stored using the Android Key Store Provider that was introduced in Android 4.3
I can successfully generate and get the private key using the following code:
private void generatePrivateKey(Activity context, String alias){
/** Generate a new entry in the KeyStore by using the * KeyPairGenerator API. We have to specify the attributes for a * self-signed X.509 certificate here so the KeyStore can attach * the public key part to it. It can be replaced later with a * certificate signed by a Certificate Authority (CA) if needed. */
Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
cal.add(Calendar.YEAR, 1);
Date end = cal.getTime();
KeyPairGenerator kpg = null;
try {
kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
try {
kpg.initialize(new KeyPairGeneratorSpec.Builder(context)
.setAlias(alias)
.setStartDate(now)
.setEndDate(end)
.setSerialNumber(BigInteger.valueOf(1))
.setSubject(new X500Principal("CN=" + alias))
.build());
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
KeyPair kp = kpg.generateKeyPair();
/*
* Load the Android KeyStore instance using the the
* "AndroidKeyStore" provider to list out what entries are
* currently stored.
*/
KeyStore ks = null;
try {
ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
/*
* Use a PrivateKey in the KeyStore to create a signature over
* some data.
*/
KeyStore.Entry entry = null;
try {
entry = ks.getEntry(alias, null);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableEntryException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
Log.w("E", "Not an instance of a PrivateKeyEntry");
}
else{
Log.w("E", "Got Key!");
privateKeyEntry = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
}
}
And here is the code I am using for encrypt (encode) and decrypt (decode):
private String encryptString(String value){
byte[] encodedBytes = null;
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
cipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry );
encodedBytes = cipher.doFinal(value.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return Base64.encodeToString(encodedBytes, Base64.DEFAULT);
}
private String decryptString(String value){
byte[] decodedBytes = null;
try {
Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
c.init(Cipher.DECRYPT_MODE, privateKeyEntry );
decodedBytes = c.doFinal(Base64.decode(value, Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
return new String(decodedBytes);
}
The Encryption appears to work fine but when I try to decrypt it I get the following error:
javax.crypto.BadPaddingException: error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
Googling this seems to suggest that the private key used for decryption is different to the one used for decryption but in my code I use the exact same private key for both. I have also seen it suggested to set the key size manually but doing this in the KeyPairGenerator builder like this:
.setKeySize(1024);
Did not work and seems to be only available on API 19, I need to target API 18.
Can anyone help point me in the right direction as to a solution?
You are not using the public key for encryption.
When you are using asymmetric encryption algorithms, you need to use the public key to encrypt your data, and the private key only to decrypt it again.
Besides encryption, you can also use the private key for signing, but that's not what you want here, so let's forget about that for the moment.
If you take the public key from the generated pair, when you encrypt your string, and the private key when decrypting, you should get the desired result. The public key you can extract by accessing the certificate from the keystore-object that holds your private key.
Alternatively you could also use a symmetric algorithm like AES and by that make your work a lot easier. Plus, symmetric algorithms are usually much faster, which is why asymmetric algorithms are never used purely, but in conjunction with symmetric algorithms, building so-called hybrid algorithms.
Signature generation is not the same thing as encryption. You need to encrypt with the public key and decrypt with the private key if you want encryption. If you want signature generation, you need to sign with the private key and verify with the public key. This order cannot be reversed nor can it be mixed (securely).

How to view the contents cacerts.bks (Certificate file /system/etc/security/cacerts.bks)

Does anybody know how to view the list of root certificates that an Android device supports?
I would like to see that information.
I found that /system/etc/security/cacerts.bks contains the root certificates information,
but I am not able to decode the contents using any available editors.
I have also tried KeyTool but couldn't succeed with that.
Please suggest how to decode this file's content.
Regards,
Durga
keytool -list -v -keystore "cacerts.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-146.jar" -storetype BKS -storepass ""
If you do not want to be an expert who always write scripts/codes to do what he want.
This is a recommended GUI keystore tool for you: http://www.keystore-explorer.org/downloads.html
You can get the list of installed certificates in an Android device from code: In your onCreate() method, include this code:
For devices pre IceCream Sandwich (API < 14):
TrustManagerFactory tmf;
try {
tmf = TrustManagerFactory.getInstance(TrustManagerFactory
.getDefaultAlgorithm());
tmf.init((KeyStore) null);
X509TrustManager xtm = (X509TrustManager) tmf.getTrustManagers()[0];
for (X509Certificate cert : xtm.getAcceptedIssuers()) {
String certStr = "S:" + cert.getSubjectDN().getName() + "\nI:"
+ cert.getIssuerDN().getName();
Log.d(LOG_TAG, certStr);
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
For devices with Android 4.0 and upwards (API >= 14):
try
{
KeyStore ks = KeyStore.getInstance("AndroidCAStore");
if (ks != null)
{
ks.load(null, null);
Enumeration aliases = ks.aliases();
while (aliases.hasMoreElements())
{
String alias = (String) aliases.nextElement();
java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) ks.getCertificate(alias);
Log.d(LOG_TAG, cert.getIssuerDN().getName());
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (java.security.cert.CertificateException e) {
e.printStackTrace();
}

Categories

Resources