This is default featured slide 1 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

This is default featured slide 2 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

This is default featured slide 3 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

This is default featured slide 4 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

Wednesday 28 December 2011

As mentioned in a previous post, Android 4.0 (ICS) adds both a system UI and SDK API's that let you add certificates to the system trust store. On all previous version though, the system trust store is read-only and there is no way to add certificates on non-rooted devices. Therefore, if you want to connect to a server that is using a certificate not signed by one of the CA's included in the system trust store (including a self-signed one), you need to create and use a private trust store for the application. That is not particularly hard to do, but 'how to connect to a server with a self-signed certificate' is one of the most asked Android questions on StackOverflow, and the usual answer goes along the lines of 'simply trust all certificates and you are done'. While this will indeed let you connect, and might be OK for testing, it defeats the whole purpose of using HTTPS: your connection might be encrypted but you have no way of knowing who you are talking to. This opens the door to man-in-the-middle (MITM) attacks, and, needless to say, is bad practice. In this post we will explore how Android's HTTPS system works pre-ICS and show how to create and use a custom certificate trust store and a dynamically configurable TrustManager.

Some background: JSSE

Java, and by extension Android, implement SSL using a framework called Java Secure Socket Extension (JSSE). A discussion of how SSL and JSSE work is beyond the scope of this post, but you can find a shot introduction to SSL in the context of JSSE here. In brief, SSL provides both privacy and data integrity (i.e., an encrypted communications channel) and authentication of the parties involved. Authentication is implemented using public key cryptography and certificates. Each party presents their certificate, and if the other party trusts it, they negotiate a shared key to encrypt communications using the associated key pairs (public and private). JSSE delegates trust decisions to a TrustManager class, and authentication key selection to a KeyManager class. Each SSLSocket instance created via JSSE has access to those classes via the associated SSLContext (you can find a pretty picture here). Each TrustManager has a set of trusted CA certificates (trust anchors) and makes trust decisions based on those: if the target party's certificate is issued by one of the trusted CA's, it is considered trusted itself.

One way to specify the trust anchors is to add the CA certificates to a Java key store file, referred to as a 'trust store'. The default JSSE TrustManager is initialized using the system trust store which is generally a single key store file, saved to a system location and pre-populated with a set of major commercial and government CA certificates. If you want to change this, you need to create an appropriately configured TrustManager instance, either via a TrustManagerFactory, or by directly implementing the X509TrustManager interface. To make the general case where one just wants to use their own key store file to initialize the default TrustManager and/or KeyManager, JSSE provides a set of system properties to specify the files to use.

Android and javax.net.ssl.trustStore

If you want to specify your own system trust store file in desktop Java, it is just a matter of setting a value to the javax.net.ssl.trustStore system property when starting the program (usually using the -D JVM command line parameter). This property is also supported on Android, but things work a little differently. If you print the value of the property it will most likely be /system/etc/security/cacerts.bks, the system trust store file (pre-ICS; the property is not set on ICS). This value is used to intialize the default TrustManagerFactory, which in turn creates an X.509 certificate-based TrustManager. You can print the current trust anchors like this:

TrustManagerFactory 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(TAG, certStr);
}

If you now use System.setProperty() to point the property to your own trust store file, and run the above code again, you will see that it outputs the certificates in the specified file. Check the 'Set javax.net.ssl.trustStore' checkbox and use the 'Dump trusted certs' button of the sample app to try it.


If we can change the set of trusted certificates using this property, connecting to a server using a custom certificate should be easy, right? It turns out this is not the case. You can try it yourself using the sample app: pressing 'Default Connect' will result in a 'Trust anchor for certificate path not found' error regardless of the state of the 'Set javax.net.ssl.trustStore' checkbox. A little further investigation reveals that the default SSLContext is already initialized with the system trust anchors and setting the javax.net.ssl.trustStore property does not change this. Why? Because Android pre-loads system classes, and by the time your application starts, the default SSLContext is already initialized. Of course, any TrustManager's you create after setting the property will pick it up (see above).

Using your own trust store: HttpClient

Since we can't use the 'easy way' on Android, we need to specify the trust store to use programmatically. This is not hard either, but first we need to create a key store file with the certificates we need. The sample project contains a shell script that does this automatically. All you need is a recent Bouncy Castle jar file and the openssl command (usually available on Linux systems).  Drop the jar and a certificate (in PEM format) in the script's directory and run it like this:

$ ./importcert.sh cacert.pem

This will calculate the certificate subject's hash and use it as the alias in a Bouncy Castle key store file (BKS format) created in the application's raw/ resource directory. The script deletes the key store file if it already exists, but you can easily modify it to append certificates instead. If you are not the command-line type, you can use the Portecle GUI utility to create the key store file.

Apache's HttpClient provides a convenient SSLSocketFactory class that can be directly initialized with a trust store file (and a key store file if client authentication is needed). All you need to do is to register it in the scheme registry to handle the https scheme:

KeyStore localTrustStore = KeyStore.getInstance("BKS");
InputStream in = getResources().openRawResource(R.raw.mytruststore);
localTrustStore.load(in, TRUSTSTORE_PASSWORD.toCharArray());

SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(trustStore);
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
HttpParams params = new BasicHttpParams();
ClientConnectionManager cm =
new ThreadSafeClientConnManager(params, schemeRegistry);

HttpClient client = new DefaultHttpClient(cm, params);

Once initialized like this, the HttpClient instance will use our local trust store when verifying server certificates. If you need to use client authentication as well, just load and pass the key store containing the client's private key and certificate to the appropriate SSLSocketFactory constructor. See the sample project for details and use the 'HttpClient SSLSocketFactory Connect' button to test. Note that, when initialized like this, our HttpClient will use only the certificates in the specified file, completely ignoring the system trust store. Thus connections to say, https://google.com will fail. We will address this later.

Using your own trust store: HttpsURLConnection

Another popular HTTPS API on Android is HttpsURLConnection. Despite the not particularly flexible or expressive interface, apparently this is the preferred API from Android 2.3 (Gingerbread) and on. Whether to actually use is it is, of course, entirely up to you :) It uses JSSE to connect via HTTPS, so initializing it with our own trust and/or key store involves creating and initializing an SSLContext (HttpClient's SSLSocketFactory does this behind the scenes):

KeyStore trustStore = loadTrustStore();
KeyStore keyStore = loadKeyStore();

TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);

KeyManagerFactory kmf = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, KEYSTORE_PASSWORD.toCharArray());

SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

URL url = new URL("https://myserver.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url
urlConnection.setSSLSocketFactory(sslCtx.getSocketFactory());

In this example we are using both a trust store and a key store, but if you don't need client authentication, you can just pass null as the first parameter of SSLContext.init().

Creating a dynamic TrustManager

As mentioned above, a TrustManager initialized with a custom trust store will only use the certificates in that store as trust anchors: the system defaults will be completely ignored. Sometimes this is all that is needed, but if you need to connect to both your own server and other public servers that use HTTPS (such as Twitter, for example), you will need to create two separate instances of HttpClient or HttpsURLConnection and switch between the two. Additionally, since the trust store is stored as an application resource, there is no way to add trusted certificates dynamically, you need to repackage the application to update the trust anchors. Certainly we can do better than that. The first problem is easily addressed by creating a custom TrustManager that delegates certificate checks to the system default one and uses the local trust store if verification fails. Here's how this looks like:

public class MyTrustManager implements X509TrustManager {

private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;

private X509Certificate[] acceptedIssuers;

public MyTrustManager(KeyStore localKeyStore) {
// init defaultTrustManager using the system defaults
// init localTrustManager using localKeyStore
}

public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}

//...
}

To address the second problem, we simply copy the trust store to internal storage when we first start the application and use that file to initialize our TrustManager's. Since the file is owned by the application, you can easily add and remove trusted certificates. To test modifying the trust store works, copy a certificate file(s) in DER format to the SD card (external storage) root and use the sample application's 'Add certs' and 'Remove certs' menus to add or remove it to/from the local trust store file. You can then verify the contents of the file by using the 'Dump trusted certs' button (don't forget to check 'Set javax.net.ssl.trustStore'). To implement this the app simply uses the JCE KeyStore API to add or remove certificates and save the trust store file:

CertificateFactory cf = CertificateFactory.getInstance("X509");
InputStream is = new BufferedInputStream(new FileInputStream(certFile));
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
String alias = hashName(cert.getSubjectX500Principal());
localTrustStore.setCertificateEntry(alias, cert);

FileOutputStream out = new FileOutputStream(localTrustStoreFile);
localTrustStore.store(out, TRUSTSTORE_PASSWORD.toCharArray());

Using our MyTrustManager with HttpsURLConnection is not much different than using the default one:

MyTrustManager myTrustManager = new MyTrustManager(localTrustStore);
TrustManager[] tms = new TrustManager[] { myTrustManager };
SSLContext sslCtx = SSLContext.getInstance("TLS");
context.init(null, tms, null);

HttpsURLConnection urlConnection = (HttpsURLConnection) url
.openConnection();
urlConnection.setSSLSocketFactory(sslCtx.getSocketFactory());

HttpClient's SSLSocketFactory doesn't let us specify a custom TrustManager, so we need to create our own SocketFactory. To make initialization consistent with that of HttpsURLConnection, we have it take an already initialized SSLContext as a parameter and use it to get a factory that lets us create SSL sockets as needed:

public class MySSLSocketFactory implements LayeredSocketFactory {

private SSLSocketFactory socketFactory;
private X509HostnameVerifier hostnameVerifier;

public MySSLSocketFactory(SSLContext sslCtx,
X509HostnameVerifier hostnameVerifier) {
this.socketFactory = sslCtx.getSocketFactory();
this.hostnameVerifier = hostnameVerifier;
}

//..

@Override
public Socket createSocket() throws IOException {
return socketFactory.createSocket();
}
}

Initializing an HttpClient instance is now simply a matter of registering our socket factory for the https scheme:

SSLContext sslContext = createSslContext();
MySSLSocketFactory socketFactory = new MySSLSocketFactory(
sslContext, new BrowserCompatHostnameVerifier());
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));

You can check that this actually works with the 'HttpClient Connect' and 'HttpsURLConnection Connect' buttons of the sample application. Both clients are using our custom TrustManager outlined above and trust anchors are loaded dynamically: adding and removing certificates via the menu will directly influence whether you can connect to the target server.

Summary

We've shown how the default TrustManager on pre-ICS Android devices works and how to set up both HttpClient and HttpsURLConnection to use a local (application-scoped) trust and/or key store. In addition, the sample app provides a custom TrustManager implementation that both extends the system one, and supports dynamically adding and removing application-specified trust anchors. While this is not as flexible as the system-wide trust store introduced in ICS, it should be sufficient for most applications that need to manage their own SSL trust store. Do use those examples as a starting point and please do not use any of the trust-all 'solutions' that pop up on StackOverflow every other day.

Wednesday 21 December 2011

Elliptic curve cryptography (ECC) offers equivalent or higher levels of security than the currently widely deployed RSA and Diffie�Hellman (DH) algorithms using much shorter keys. For example, the computational effort  for cryptanalysis of a 160-bit ECC key is roughly equivalent to that of a 1024-bit key (NIST). The shift to ECC has however been fairly slow, mostly due to the added complexity, the need for standardization, and of course, patents. Standards are now available (more than a few, of course) and efficient implementations in both software and dedicated hardware have been developed. This,  along with the constant need for higher security, is pushing the wider adoption of ECC. Let's see if, and how we can use ECC on Android, specifically to perform key exchange using the ECDH (Elliptic Curve Diffie-Hellman) algorithm.

Android uses the Bouncy Castle Java libraries to implement some of its cryptographic functionality. It acts as the default JCE crypto provider, accessible through the java.security and related JCA API's. Bouncy Castle has supported EC for quite some time, and the most recent Android release, 4.0 (Ice Cream Sandwich, ICS), is based on the latest Bouncy Castle version (1.46), so this should be easy, right? Android, however, does not include the full Bouncy Castle library (some algorithms are omitted, presumably to save space), and the bundled version has some Android-specific modifications. Let's see what EC-related algorithms are supported on Android (output is from ICS, version 4.0.1):

BC/BouncyCastle Security Provider v1.46/1.460000
KeyAgreement/ECDH
KeyFactory/EC
KeyPairGenerator/EC
Signature/ECDSA
Signature/NONEwithECDSA
Signature/SHA256WITHECDSA
Signature/SHA384WITHECDSA
Signature/SHA512WITHECDSA

As seen above, it does support EC key generation, ECDH key exchange and ECDSA signatures. That is sufficient to generate EC keys and preform the exchange on the newest Android version, but as it turns out, currently more than 85% of devices are using 2.2 or 2.3. Android 4.0 doesn't even show up in the platform distribution graph. Let's check what is supported on a more mainstream version, such as 2.3 (Gingerbread). The output below is from stock 2.3.6:

BC/BouncyCastle Security Provider v1.45/1.450000

Which is exactly nothing: the JCE provider in Gingerbread is missing all EC-related mechanisms. The solution is, of course, to bundle the full Bouncy Castle library with our app, so that we have all algorithms available. It turns out that it is not that simple, though. Android preloads the framework libraries, including Bouncy Castle, and as a result, if you include the stock library in your project, it won't be properly loaded (you will most likely get a ClassCastException). This appears to have been fixed in 3.0 (Honeycomb) and later versions (they have changed the provider's package name), but not in our target platform (2.3). There are two main solutions to this:
  • use jarjar to rename the Bouncy Castle library package name we bundle
  • use the Spongy Castle library that already does this for us
We'll take the second option, because it's less work and the name sounds funny :) Using the library is pretty straightforward, but do check the Eclipse-specific instructions if you get stuck. Now that we have it set up, let's initialize the provider and see what algorithms it gives us. 

// add the provider
{
Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
}

SC/BouncyCastle Security Provider v1.46/1.460000
AlgorithmParameters/SHA1WITHECDSA
...
Cipher/BrokenECIES
Cipher/ECIES
KeyAgreement/ECDH
KeyAgreement/ECDHC
KeyAgreement/ECMQV
KeyFactory/EC
KeyFactory/ECDH
KeyFactory/ECDHC
KeyFactory/ECDSA
KeyFactory/ECGOST3410
KeyFactory/ECMQV
KeyPairGenerator/EC
KeyPairGenerator/ECDH
KeyPairGenerator/ECDHC
KeyPairGenerator/ECDSA
KeyPairGenerator/ECGOST3410
KeyPairGenerator/ECIES
KeyPairGenerator/ECMQV
Mac/DESEDECMAC
Signature/ECDSA
Signature/ECGOST3410
Signature/NONEwithECDSA
Signature/RIPEMD160WITHECDSA
Signature/SHA1WITHCVC-ECDSA
...

This is much, much better. As you have probably noticed, the provider name has also been changed from 'BC' to 'SC' in order not to clash with the platform default. We will use 'SC' in our code, to ensure we are calling the correct crypto provider.

Now that we have a working configuration, let's move on to the actual implementation. JCE makes DH key exchange pretty straightforward: you just need to initialize the KeyAgreement class with the current party's (Alice!) private key, pass the other party's public key (who else but Bob), and call generateSecret() to get the shared secret bytes. To make things a little bit more interesting, we'll try to stimulate a (fairly) realistic example where we use pre-generated keys serialized in the PKCS#8 (for the private key) and X.509 (for the public) formats. We'll also show two ways of initializing the EC crypto system: by using a standard named EC curve, and by initializing the curve using discrete EC domain parameters.

To generate EC keys we need to first specify the required EC domain parameters:
  • an elliptic curve, defined by an elliptic field and the coefficients a and b, 
  • the generator (base point) G and its order n, 
  • and the cofactor h.
Assuming we have the parameters (we use the recommended values from SEC 2) in an instance of a class ECParams called ecp (see sample code) the required code looks like this:

ECFieldFp fp = new ECFieldFp(ecp.getP());
EllipticCurve ec = EllipticCurve(fp, ecp.getA(), ecp.getB());
ECParameterSpec esSpec = new ECParameterSpec(curve, ecp.getG(),
ecp.getN(), ecp.h);
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH", "SC");
kpg.initialize(esSpec);

Of course, since we are using standard curves, we can make this much shorter:

ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("secp224k1");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH", "SC");
kpg.initialize(ecParamSpec);

Next, we generate Alice's and Bob's key pairs, and save them as Base64 encoded strings in the app's shared preferences (we show only Alice's part, Bob's is identical):

KeyPair kpA = kpg.generateKeyPair();

String pubStr = Crypto.base64Encode(kpA.getPublic().getEncoded());
String privStr = Crypto.base64Encode(kpA.getPrivate().getEncoded());

SharedPreferences.Editor prefsEditor = PreferenceManager
.getDefaultSharedPreferences(this).edit();

prefsEditor.putString("kpA_public", pubStr);
prefsEditor.putString("kpA_private", privStr);
prefsEditor.commit();

If we save the keys as files on external storage as well, it's easy to check the key format using OpenSSL:

$ openssl asn1parse -inform DER -in kpA_public.der
cons: SEQUENCE
cons: SEQUENCE
prim: OBJECT :id-ecPublicKey
cons: SEQUENCE
prim: INTEGER :01
cons: SEQUENCE
prim: OBJECT :prime-field
prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73
cons: SEQUENCE
prim: OCTET STRING [HEX DUMP]:0000000000000000000000000000000000000000
prim: OCTET STRING [HEX DUMP]:0000000000000000000000000000000000000007
prim: OCTET STRING [HEX DUMP]:043B4C382CE37AA192A4019E763036F4F5DD4...
prim: INTEGER :0100000000000000000001B8FA16DFAB9ACA16B6B3
prim: INTEGER :01
prim: BIT STRING

We see that it contains the EC domain parameters (G is in uncompressed form) and the public key itself as a bit string. The private key file contains the public key plus the private key as an octet string (not shown).

Now that we have the two sets of keys, let's perform the actual key exchange. First we read the keys from storage, and use a KeyFactory to decode them (only Alice's part is shown):

SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(this);
String pubKeyStr = prefs.getString("kpA_public", null);
String privKeyStr = prefs.getString("kpB_private", null);

KeyFactory kf = KeyFactory.getInstance("ECDH", "SC");

X509EncodedKeySpec x509ks = new X509EncodedKeySpec(
Base64.decode(pubKeyStr));
PublicKey pubKeyA = kf.generatePublic(x509ks);

PKCS8EncodedKeySpec p8ks = new PKCS8EncodedKeySpec(
Base64.decode(privKeyStr));
PrivateKey privKeyA = kf.generatePrivate(p8ks);

After all that work, the actual key exchange is pretty easy (again, only Alice's part):

KeyAgreement aKA = KeyAgreement.getInstance("ECDH", "SC");
aKeyAgreement.init(privKeyA);
aKeyAgreement.doPhase(pubKeyB, true);

byte[] sharedKeyA = aKA.generateSecret();

Finally, the all important screenshot:


As you can see, Alice's and Bob's shared keys are the same, so we can conclude the key agreement is successful. Of course, for a practically useful cryptographic protocol that is only part of the story: they would need to generate a session key based on the shared secret and use it to encrypt communications. It's not too hard to come up with one, but inventing a secure protocol is not a trivial task, so the usual advice applies: use TLS or another standard protocol that already supports ECC.

To sum things up: you can easily implement ECDH using the standard JCE interfaces available in Android. However, older version (2.x) don't include the necessary ECC implementation classes in the default JCE provider (based on Bouncy Castle). To add support for ECC, you need to bundle a JCE provider that does and is usable on Android (i.e., doesn't depend on JDK classes not available in Android and doesn't clash with the default provider), such as Spongy Castle. Of course, another way is to use a lightweight API not based on JCE. For this particular scenario, Bouncy/Spongy Castle provides ECDHBasicAgreement.

That concludes our discussion of ECDH on Android. As usual, the full source code of the example app is available on Github for your hacking pleasure.

Monday 12 December 2011

The latest version is now available in the Android Market. There are no new user visible features, but the  renewed UI and full support for tablets warrant the major version bump.

Hanzi Recognizer now has an app-wide action bar, available both on the newer Ice Cream Sandwich (4.0) and Honeycomb (3.x) Android versions, and on all mainstream Android 2.x versions. Functions previously only accessible via the overflow menu are now easier to use and discover courtesy of the action bar. Here's a screenshot of the app's main screen:


The two icons on the right kick off the keyword (reading or meaning) search and the favorites/history screen, respectively. All other screens have a home icon on the left as well, providing an easy way to get to the main screen from anywhere. Less frequently used activities such as Settings and About are available via the Menu key, as before.

The favorites and history tabbed screen now has a new look, consistent with the Honeycomb and ICS visual style. Changing tabs is also easier: just swipe left or right to switch from favorites to history and vice versa. In addition, the filter and import/export actions are now available on action bar.


On tablets the app uses the larger screen estate to show more information and make browsing characters and compounds easier. Search results or recognition candidates (when not using search on stroke) are displayed on the left, and tapping an item will update the details pane on the right. Here's how the compounds search result screens look on a Honeycomb tablet:


Version 2.0 now requires Android 2.1. Since less than 2% of all installs are on the Android 1.6,  most users won't be affected by this new requirement. Hanzi Recognizer v1.7.2 is still available on the Android Market  for devices running earlier Android versions, but no new features are planned.

Other changes and improvement in version 2.0:
  • Reduced startup time
  • Better error handling and reporting
  • Various optimizations and bug fixes
Finally, the app now has an official Google+ page. Add it to your circles to get the latest news and updates and don't forget to +1 and share.

Thursday 1 December 2011

In the previous two posts we looked at the internal implementation of the Android credential storage, and how it is linked to the new KeyChain API introduced in ICS. As briefly mentioned in the second post, there is also a new TrustedCertificateStore class that manages user installed CA certificates. In this entry we will examine how the new trust store is implemented and how it is integrated in the framework and system applications.

Storing user credentials such as passwords and private keys securely is of course essential, but why should we care about the trust store? As the name implies, the trust store determines who we trust when connecting to Internet servers or validating signed messages. While credentials are usually used proactively only when we authenticate to a particular service, the trust store is used every time we connect to a secure server. For example, each time you check GMail, Android connects to Google's severs using SSL and validates their certificates based on the device's trust store. Most users are unaware of this, unless some error occurs. Since the trust store is used practically all the time, and usually in the background, one could argue that it's even more important then credential storage. Up till Android 4.0, the OS trust store was hard wired into the firmware, and users had no control over it whatsoever. Certificates bundled in the store were chosen solely by the device manufacturer or carrier. The only way to make changes was to root your device, re-package the trusted certificates file and replace the original one (instructions from cacert.org here). That is obviously not too practical, and a major obstacle to using Android in enterprise PKI's. In the wake of major CA's being compromised practically each month this year, tools that make changing the default trusted certificates in place have been developed, but using them still requires a rooted phone. Fortunately, ICS has made managing the trust store much more flexible, and gives the much needed control over who to trust to the user. Let's see what has changed.

Pre-ICS, the trust store was a single file: /system/etc/security/cacerts.bks, a Bouncy Castle (one of the JCE cryptographic providers used in Android) native keystore file. It contains all the CA certificates Android trusts and is used both by system apps such as the email client and browser, and applications developed using the SDK. Since it resides on the read-only system partition, it cannot be changed even by system-level applications. The newly introduced in ICS TrustedCertificateStore class still reads system trusted certificates from /system/etc/security, but adds two new, mutable locations to store CA certificates in /data/misc/keychain: the cacerts-added and cacerts-removed directories. Let's see what's inside:

ls -l /data/misc/keychain
drwxr-xr-x system system 2011-11-30 12:56 cacerts-added
drwxr-xr-x system system 2011-12-02 15:21 cacerts-removed
# ls -l /data/misc/keychain/cacerts-added
ls -l /data/misc/keychain/cacerts-added
-rw-r--r-- system system 653 2011-11-29 18:34 30ef493b.0
-rw-r--r-- system system 815 2011-11-30 12:56 9a8df086.0
# ls -l /data/misc/keychain/cacerts-removed
ls -l /data/misc/keychain/cacerts-removed
-rw-r--r-- system system 1060 2011-12-02 15:21 00673b5b.0

Each file contains one CA certificate. The file names may look familiar: they are hashes of the CA subject names, as used in mod_ssl and other cryptographic software implemented using OpenSSL. This makes it easy to quickly find certificates without scanning the entire store. Also note the permissions of the directories: 0775 system system guarantees that only the system user is able to add or remove certificates, but anyone can read them. As can be expected, adding trusted CA certificates is implemented by storing the certificate in cacerts-added under the appropriate file name. The two files above, 30ef493b.0 and 9a8df086.0, correspond to the certificates displayed in the 'User' tab of the Trusted credential system application (Settings->Security->Trusted credentials). But how are OS-trusted certificates disabled? Since pre-installed CA certificates are still stored in /system/etc/security (read-only), a CA is marked as not trusted by placing a copy of its certificate in cacerts-removed. Re-enabling is performed by simply removing the file. In this particular case, 00673b5b.0 is the thawte Primary Root CA, shown as disabled in the 'System' tab:


TrustedCertificateStore is not available in the SDK, but it has a wrapper accessible via the standard JCE KeyStore API, TrustedCertificateKeyStoreSpi, that applications can use. Here's how we can use it to get the current list of trusted certificates::

KeyStore ks = KeyStore.getInstance("AndroidCAStore");
ks.load(null, null);
Enumeration aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
X09Certificate cert = (X509Certificate)
ks.getCertificate(alias);
Log.d(TAG, "Subject DN: " +
cert.getSubjectDN().getName());
Log.d(TAG, "Issuer DN: " +
cert.getIssuerDN().getName());
}

If you examine the output of this code, you would notice that certificate aliases start with either the user: (for user installed certificates) or system: (for pre-installed ones) prefix, followed by the subject's hash value. This lets us easily access the OS's trusted certificates, but a real word application would be more interested in whether it should trust a particular server certificate, not what the current trust anchors are. ICS makes this very easy by integrating the TrustedCertificateKeyStoreSpi with Android's JSSE (secure sockets) implementation. The default TrustManagerFactory uses it to get a list of trust anchors, thus automatically validating server certificates against the system's currently trusted certificates. Higher-level code that uses HttpsURLConnection or HttpClient (both built on top of JSSE) should thus just work without needing to worry about creating and initializing a custom SSLSocketFactory. Here's how we can use the TrustManager to validate a certificate issued by a private CA (the CA certificate is already installed in the user trust store).

X509Certificate[] chain = KeyChain.getCertificateChain(ctx,
"keystore-test-ee");
Log.d(TAG, "chain length: " + chain.length);
for (X509Certificate x : chain) {
Log.d(TAG, "Subject DN: "
+ x.getSubjectDN().getName());
Log.d(TAG, "Issuer DN: "
+ x.getIssuerDN().getName());
}

TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init((KeyStore) null);

TrustManager[] tms = tmf.getTrustManagers();
X509TrustManager xtm = (X509TrustManager) tms[0];
Log.d(TAG, "checking chain with " + xtm);
xtm.checkClientTrusted(chain, "RSA");
Log.d(TAG, "chain is valid");

Works pretty well, but there is one major problem with this code: it does not check revocation. Android's default TrustManager explicitly turns off revocation when validating the certificate chain. So even if the certificate had a valid CDP (CRL distribution point) extension, pointing to a valid CRL, and the certificate was actually revoked, it would still validate fine in Android. What's missing here is the ability to dynamically fetch, cache and update revocation information as needed, based on information available in certificate extensions. Hopefully future version of Android will add this functionality to make Android's PKI support complete.

Of course, system applications such as the browser, email and VPN clients are also taking advantage of the new trust store, so connecting to a corporate Exchange server or a secure Web application should be as easy as installing the appropriate certificates. We'll see how well that works out in practice once I get a real ICS device (shouldn't be too long now...).

That concludes our discussion of the new credential and trust stores introduced in Android 4.0. To sum things up: users can now freely install and remove private keys and trusted certificates, as well as disable pre-installed CA certificates via the Settings app. Third-party applications can also do this via the new KeyChain API, if the user grants the app the necessary permissions. The key and trust stores are fully integrated into the OS, so using standard secure communication and cryptographic Java API's should just work, without the need for applications-specific key stores. A key element required for full PKI support -- revocation checking, is still missing, but the key and trust store functionality added in ICS is a huge step in making Android more secure, flexible and enterprise-friendly.

Wednesday 30 November 2011

In the previous entry, we found how Android's keystore daemon manages keys and certificates, and how to connect to it using the provided keystore_cli utility. Now we will look at the intermediate layers between the OS daemon and the public KeyChain API introduced in ICS.

Browsing the android.security package, we find two AIDL files: IKeyChainService.aidl and IKeyChainAliasCallback.aidl. This is a hint that the actual key store functionality, like most Android OS services, is implemented as a remote service that the public API's bind to. IKeyChainAliasCallback is just the callback called when you select a key via KeyStore#choosePrivateKeyAlias(), so it's of little interest. IKeyChainService has the actual methods KeyChain uses to get a handle to a private key or a certificate, plus some internal API's used by the Settings and certificate installer applications. Naturally, the whole interface is marked as hidden, so SDK applications cannot directly bind to the service.

The IKeyChainService interface has one implementation, the KeyChainService in the KeyChain.apk system package. We find the source in packages/apps/KeyChain, so let's explore the app's configuration. Looking at the manifest reveals that it consists of three components: the KeyChainService, a KeyChainActivity, and a broadcast receiver, you guessed it, KeyChainBroadcastReceiver. The package is com.android.keychain and its sharedUserId is set to 'android.uid.system', which, as we saw in the previous article, is necessary to be able to send management commands to the native keystore daemon. Let's first examine the service.

As can be expected, the KeyChainService is a wrapper for the android.security.KeyStore class that directly communicates with the native keystore daemon. It provides 4 sets of functionality:
  • key store management: methods for getting private keys and certificates
  • trust store management: methods for installing and deleting CA certificates in the user trust store
  • key and trust store initialization: a reset() method that deletes all key store entries, including the master key, thus returning the key store to a 'not initialized' state; it also removes all user-installed trusted certificates
  • methods for querying and adding entries to the key access grant database (more on this later)
Since the KeyChain application is running as the system user, any process that binds to its remote interface would technically be able to perform all key and trust store operations. To prevent this, the KeyChainService imposes additional access control on its users. It employs two mechanisms to achieve this: controlling access based on the caller's UID and a key access grant database. Deleting a CA certificate and resetting the key and trust stores are only allowed to the system user (those operations are typically called via the Settings app's UI, which runs as system), and installing a trusted CA certificate is only allowed to the system user or the certificate installer application (com.android.certinstaller package). Controlling access to the key store is a little bit more interesting: KeyChainService maintains a grants database (in /data/data/com.android.keychain/databases/grants.db) that maps UID's to the key aliases they are allowed to use. Let's have a look inside:
# cd /data/data/com.android.keychain/databases
cd /data/data/com.android.keychain/databases
# ls
ls
grants.db
grants.db-journal
# sqlite3 grants.db
sqlite3 grants.db
sqlite> .schema
.schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE grants ( alias STRING NOT NULL, uid INTEGER NOT NULL, UNIQUE (al
ias,uid));
sqlite> select * from grants;
select * from grants;
test|10044
key1|10044

In this example, the application with UID 10044 (our test application) is granted access to the keys with the test and key1 aliases.

Each call to getPrivateKey() or getCertificate() is subject to a check against the grants database, and results in a exception if a grant for the required alias is not found. As stated before, KeyChainService has API's for adding and querying grants, and only the system user is allowed to call them. But who is responsible for actually granting and revoking access? Remember the private key selection dialog from the first article? When you call KeyChain#choosePrivateKeyAlias(), it will start the KeyChainActivity introduced above, which will check if the key store is unlocked, and if so, show they key selection dialog. Clicking the 'Allow' button will return to the KeyChainActivity, which will then call KeyChainService#setGrant() with the selected alias, adding it to the grants database. Thus, even if the activity requesting access to a private key has the needed permissions, the user has to unlock the key store and explicitly authorize access to each individual key.

Besides controlling private key storage, the KeyChainService also offers trust store management by using the newly added TrustedCertificateStore class (part of libcore). This class provides both the ability to add user-installed trusted CA certificates and remove (mark as not trusted) system (pre-installed) CA's. Since the implementation is fairly complex and rather interesting, it will be the topic of another post.

The last component of the KeyChain app is the KeyChainBroadcastReceiver. It listens for a android.intent.action.PACKAGE_REMOVED broadcast and simply forwards control to the KeyChainService. On receiving the PACKAGE_REMOVED action, the service does some grant database maintenance: it goes through all entries and deletes those referencing packages that are no longer available (i.e., uninstalled ones). With this we now have the (almost) complete picture (click to enlarge):


ICS introduces a new service that grants access to both the system key store (managed by the keystore daemon) and trust store (manged by the TrustedCertificateStore class) that backs the KeyChain API exposed in the public SDK. That makes it possible to control access to keys based on both the calling process's UID and the key access grant database, thus allowing for fine-grained, user-driven control over what keys each application can access. We've discussed most of the components this framework consists of in this and the previous entry. What remains is to look into the new trust store implementation introduced in Android 4.0. That will be the focus of the next post of this series.

Tuesday 29 November 2011

In the previous entry, we looked at how the new ICS KeyChain API is used and tried installing a user private key/certificate pair and a CA certificate. Now we'll will try to find out where  they are actually stored and how they are protected.

Looking at frameworks/base/keystore/java/android/security, we notice several interesting classes that are not mentioned in the SDK documentation. The most promising is the KeyStore class, so let's have a look. Sure enough, it is marked as hidden (using the dreaded @hide comment). It does have methods for interacting with the key store (get(), put(), delete(), reset(), etc.), but where is the actual key store? As it turns out, all methods send command to a local socket aptly named 'keystore'. With a little creative grepping, we find out that there is native daemon with the same name listening on that socket. The source is in frameworks/base/cmds/keystore/keystore.cpp, so let's have a look. The file has some helpful comments, and we learn that keys are encrypted, checksummed and saved as files (one key per file). But where are the actual files? Looking at /init.rc we find the keystore daemon startup command looks like this:

service keystore /system/bin/keystore /data/misc/keystore
class main
user keystore
group keystore
socket keystore stream 666

Next step is, of course, peeking into /data/misc/keystore

# ls -la /data/misc/keystore
-rw------- keystore keystore 84 2011-11-30 15:26 .masterkey
-rw------- keystore keystore 980 2011-11-30 15:56 1000_CACERT_testca
-rw------- keystore keystore 820 2011-11-30 15:55 1000_USRCERT_test
-rw------- keystore keystore 932 2011-11-30 15:55 1000_USRPKEY_test

Here each file name consists of the UID of the user that created it (1000 is system), the entry type (CA certificate, user certificate or private key), and the key name (alias) connected with underscores. And, of course, there is a .masterkey. Going back to the keystore daemon source, we find out that:
  • each key is encrypted with a 128-bit AES master key in CBC mode
  • each key blob contains an info header, the initial vector (IV) used for encryption, an MD5 hash value of the encrypted data and the encrypted data itself
  • the master key (in .masterkey) is itself encrypted with an AES key. The encryption key is derived from the password using the PBKDF2 key-derivation function with 8192 iterations (it may take a while...). The salt is randomly generated and is stored in the .masterkey file's info header.
What this means in practice is that the Android key store is pretty secure for a software solution: even if you had access to a rooted device and managed to extract the key blobs, you would still need the keystore password to derive the master key. Trying out different password to decrypt the master key would require at least 8192 iterations to derive a key, which is prohibitively expensive. In addition, the derivation function is seeded  with a 128-bit random number, so pre-calculated password tables cannot be used.

Key blobs are owned by the keystore user, so on a regular (not rooted) device, you need to go through the daemon to access the keys. As it turns out, there is a helpful command line utility that talks to the daemon and lets us manipulate the key store: keystore_cli. It has commands for initializing the key store, listing, getting and deleting keys, etc. Experimenting with it shows that the keystore daemon is additionally checking the calling process's UID to grant or deny access to each command:

# keystore_cli unlock
keystore_cli unlock
6 Permission denied
# keystore_cli get CACERT_testca
keystore_cli get CACERT_testca
1 No error
-----BEGIN CERTIFICATE-----
MIICiTCCAfKgAwI...

# su system
su system
$ keystore_cli insert foo bar
keystore_cli insert foo bar
1 No error
$ keystore_cli saw ""
keystore_cli saw ""
1 No error
foo
USRPKEY_test
USRCERT_test
CACERT_testca
$ keystore_cli get foo
keystore_cli get foo
1 No error
bar
$ exit

# su app_44
su app_44
$ keystore_cli saw ""
keystore_cli saw ""
1 No error
$ keystore_cli insert baz boo
keystore_cli insert baz boo
1 No error
$ keystore_cli get baz
keystore_cli get baz
1 No error
boo

This basically translates to:
  • root cannot lock/unlock the key store, but can access system keys
  • the system user can do pretty much anything (initialize or reset the key store, etc.)
  • regular users can insert, delete and access keys, but can only see their own keys

The android.security.KeyStore class we found while browsing the framework's source is almost a one-to-one port of the keystore_cli command's functionality to Java. By using it Java apps can get direct access to the keystore daemon, but as we said, that class is not part of the public API. There are a couple of reasons for this:

  • even if they had access to it, normal apps wouldn't have the needed permissions to initialize or unlock the key store
  • it's interface exposes the current implementation: keys are returned as raw blobs which wouldn't be possible if the key store and related cryptographic operations were implemented in hardware (such as in a TPM).

As mentioned in the previous article, most of the described credential storage functionality has been available in Android since at least Donut (1.5), but the key store was only accessible to system applications such as Settings, and the WiFi and VPN clients. What ICS adds are a few layers on top of this that make it possible to offer user applications access to the system key store and assert fine-grained control over what keys each app is allowed to use. In the next part of the series we will look at the implementation of the new credential storage functionality added in ICS.

Update: Sample app code is now available on github.

The recently released Android 4.0 (Ice Cream Sandwich, ICS) introduces a new, unified UI for both tablets and handsets, lots of 'people-centric' communication and sharing features and other convenient improvements such as a better camera app and the much-hyped face unlock. Since everyone is talking about those, we will have a look at some of the less-user visible, but nonetheless important security-related improvements.

Android is often said to be missing crucial security features to be seriously accepted in the corporate world, which has long been the  domain of RIM's BlackBerry. Two of those missing features were the ability to control the system's trusted CA certificates and offer a centralized secure credential storage. Since many companies use private PKI's, the ability to install trusted certificates system-wide is essential for using corporate services secured by those PKI's. Until now, the only way to use those was to embed the needed CA certificates in each application and create custom TrustStores to be able to connect using SSL. A system-wide credential storage has actually been available for a while, but it was only usable by the built-in VPN and WiFi (EAP) clients. One could install a private key/certificate pair using the Settings app, but there was no public API to access the installed keys from applications. ICS offers SDK API's for both trusted certificate management and the secure credential storage via the KeyChain class. We will have a look at how it is used in the following sections.

The KeyChain class is deceptively simple: it offers only 4 public static methods, but those are sufficient to do most certificate-related tasks. Let's first see how one would install a private key/certificate pair and use those to sign and verify some data. The KeyChain API lets you install a private key/certificate pair bundled in a PKCS#12 file. Instead of offering an API to directly install the key and certificate, KeyChain provides a factory method, createInstallIntent() that returns a system intent to parse and install keys/certificates (that is actually the same intent offered by the Settings app in previous versions). To install a PKCS#12 file, you have to read it to a binary array, store it under the EXTRA_PKCS12 key in the intent's extras, and start the associated activity:

Intent intent = KeyChain.createInstallIntent();
byte[] p12 = readFile("keystore-test.pfx");
intent.putExtra(KeyChain.EXTRA_PKCS12, p12);
startActivity(intent);

This will prompt you for the PKCS#12 password in order to extract and parse the key and certificate. If the password is correct, you will be prompted for a 'certificate name' as shown in the screenshot below. If the PKCS#12 has a friendly name attribute it will be shown as the default, if not you will just get a long hexadecimal hash string. The string you enter here is the key/certificate alias you will use to access those later via the KeyChain API. You will be prompted to set a lock screen PIN or password to protect the credential storage if you haven't already set one.


To use a private key stored in the system credential storage, you need to call KeyChain.choosePrivateKeyAlias() and provide a callback implementation that receives the selected alias:

public class KeystoreTest extends Activity implements OnClickListener,
KeyChainAliasCallback {

@Override
public void onClick(View v) {
KeyChain.choosePrivateKeyAlias(this, this,
new String[] { "RSA" }, null, null, -1, null);
}

@Override
public void alias(final String alias) {
Log.d(TAG, "Thread: " + Thread.currentThread().getName());
Log.d(TAG, "selected alias: " + alias);
}
}

The first parameter is the current context, the second -- the callback to invoke, and the third and forth specify the acceptable keys (RSA, DSA or null for any) and acceptable certificate issuers for the certificate matching the private key (Edit: it turns out both keyTypes and issuers are currently unused, so just pass null). The next two parameters are the host and port number of the server requesting a certificate, and the last one is the alias to preselect. We leave all but the key type as unspecified (null or -1) here to be able to select from all available certificates. One thing to note here is that the alias() callback will not be called on the main thread, so you shouldn't try to directly manipulate the UI (it is called on a binder thread).  Using the key requires user authorization, so Android will display a key selection dialog which also serves to allow access to the selected key.


In order to get a reference to a private key, you need to call the KeyChain.getPrivateKey() method passing the key alias name received in the previous step. This doesn't seem to be documented but if you try to call this method on the main thread you will get an exception saying that this may 'lead to a deadlock'. Here we call it on a background thread using AsyncTask (which is almost always the right thing to do when dealing with potentially time-consuming I/O operations).

new AsyncTask<Void, Void, Boolean>() {

private Exception error;

@Override
protected Boolean doInBackground(Void... arg) {
try {
PrivateKey pk = KeyChain.getPrivateKey(ctx,
alias);
X509Certificate[] chain = KeyChain.getCertificateChain(ctx,
alias);

byte[] data = "foobar".getBytes("ASCII");
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(pk);
sig.update(data);
byte[] signed = sig.sign();

PublicKey pubk = chain[0].getPublicKey();
sig.initVerify(pubk);
sig.update(data);
boolean valid = sig.verify(signed);
Log.d(TAG, "signature is valid: " + valid);

return valid;
} catch (Exception e) {
e.printStackTrace();
error = e;

return null;
}
}

@Override
protected void onPostExecute(Boolean valid) {
if (error != null) {
Toast.makeText(ctx, "Error: " + error.getMessage(),
Toast.LENGTH_LONG).show();

return;
}

Toast.makeText(ctx, "Signature is valid: " + valid,
Toast.LENGTH_SHORT).show();
}
}.execute();

We first get the private key and certificate chain using the key alias and then create and verify a signature to check if the key is actually usable. Since we are using a self-signed certificate the 'chain' consists of a single entry, but for a certificate signed by a CA you will need to find the actual end entity certificate in the returned array.

Installing a CA certificate is not very different from installing a PKCS#12 file: you load the certificate in a byte array and pass it as an extra to the install intent.

Intent intent = KeyChain.createInstallIntent();
intent.putExtra(KeyChain.EXTRA_CERTIFICATE, cert);
startActivity(intent);

Android will parse the certificate, and if it's Basic Constraints extension is set to CA:TRUE it will consider it a CA certificate and import it into the user trust store. You will need to authenticate to import the certificate, but the funny thing is that the import dialog does not show neither the certificate DN, nor its hash value. The user has no way of knowing what they are importing, until it's done. Very few people will bother to actually check, so this could be a potential security threat: malicious applications might trick people into installing rogue certificates. Here's how the import dialog looks:


After the certificate is imported, it will show up in the 'Trusted credentials' screen's 'User' tab (Settings->Security->Trusted credentials). Tapping the certificate entry displays a details dialog, where you can (finally!) check the subject, issuer, validity period, serial number and  SHA-1/SHA-256 fingerprints. You can also remove the certificate by pressing the 'Remove' button (scroll down to display it).


While you can delete individual CA certificates, there is no way to delete individual keys and user certificates. You can delete all by using the 'Clear credentials' option in the Credential storage section of the security settings. Another thing to note is that, as long as you have keys in the credential storage, you cannot remove the screen lock, since it is used to protect access to the keystore. In previous Android versions, there was a separate 'credential storage password', but it seems in ICS they decided to simplify things by using the screen lock password to protect credential storage as well.

The newly introduced KeyChain API lets you install and access private keys in a centralized and secure credential storage, as well as add system-wide trusted certificates. It doesn't provide low-level access to the underlying keystore, utilizing the Android intent dispatching mechanism instead to call a system activity that does the actual work. The CA certificate install dialog is missing a crucial feature (displaying details about the certificate), but all in all, providing the access to the system keystore service is a step in the right direction.

That wraps the first part of our Android keystore introduction. In the next part we will look into all that is hidden behind the KeyChain facade, and try to give some details about the underlying implementation.

Monday 28 November 2011


It's been a while since the last release, but the latest version is finally available. The focus of this release is an improved new UI and full support for tablets.

The app is now using an action bar for easier access to key functionality. This is a feature originally only available on the Honeycomb (3.x) and Ice Cream Sandwich (4.0) Android versions, but Kanji Recognizer uses the excellent ActionBarSherlock library to bring ot bar to previous versions as well. Functions that were previously only accessible via the overflow menu (displayed when you press the menu key), now have an icon on the action bar. That will hopefully make it easier for new users to find and try them. Here's how the main screen looks in version 2.0:

The three icons on the right side of the action bar start the quiz, character search and history/favorites screens, respectively. Less frequently used features, such as the Settings and About screens are still in the overflow menu, so you need to press the menu key to display those. All other screens also have a home icon on the left, providing an easy way to get to the main screen from anywhere (see the quiz details screenshot below). 

It is now  easier to add kanji for later review directly from the writing quiz. When reviewing the quiz answers, simply press the star icon to add the character to your favorites. You can later create a customized quiz containing the characters you starred, or export your favorites to a CSV file to create flashcards.


Offline access to kanji stroke order is another often-requested feature added in this release. If you have the premium version, you can enable it in Settings. Once you download and extract the stroke order database (4MB download, 9MB decompressed), all of the app's features will be available even when offline.

As mentioned in the introduction, the app now fully supports tablets. The UI is very similar on handsets and tablets, but on tablets the app takes advantage of the bigger screen to display more information where applicable. The most notable example of this is the kanji search result screen: search results and kanji details are displayed in a single window and tapping on a kanji in the list updates the details in place (screenshot below). Font sizes and layout have also been optimized for best viewing on tablet screens. 

Another thing worth nothing is that version 2.0 now requires Android 2.1. Most users shouldn't be affected by this, since almost 99% of installs are already on devices running Android 2.1 and later. Users of Android 1.6 and 2.0 can still get v1.7.2 from the Android Market, but no new features are planned for that version.

Other notable changes in this release:
  • Reduced startup time
  • Better error handling/reporting
  • Various optimizations and bug fixes
Last but not least: the app now has a Google+ page. Add it to your circles to get the latest updates and tips.

Sunday 6 November 2011

The newest release is now live in the Android Market. The highlights of this version are improved Japanese text-to-speech (TTS) and Android 4.0 (Ice Cream Sandwich, ICS) support.

Version 2.0 introduced Japanese TTS support using the free N2 TTS speech engine, but apparently (and unfortunately) it is not available from the Android Market outside of Japan. In 2.1 I've added support for two other major Japanese TTS engines: SVOX Japanese and AquesTalk TTS. You can now switch the Japanese TTS engine in the Settings screen, check out the screenshot below. The app doesn't check if the engine is actually installed, so you should install the relevant TTS package before changing the setting (if you select an engine that is not available, Japanese TTS support will be disabled throughout the app). Another improvement in this release: the settings screen is now using an action bar, courtesy of ActionBarSherlock v3.4.0.


Unfortunately, an API to list available TTS engines was only added in ICS, so currently there is no way to automatically find installed engines that support Japanese. If you think the engine you are using should be supported, drop me a line.

Another often requested feature is TTS support for example sentences. This is now available, just press the speaker button on the action bar:


The recently announced Android 4.0, a.k.a Ice Cream Sandwich (ICS), brings a lot of features previously available only on tablets to handsets as well. The most visible change is, of course, the redesigned UI, including native action bar support and slimmer tabs. WWWJDIC now follows the ICS display style of action bar on top of tabs in portrait mode, and has been optimized to look nice on ICS. More work on this will be done when I get an actual ICS device. Here's how the main screen looks when running on ICS:



And one last thing: not to blow my own horn, but WWWJDIC for Android 2.0 was voted best Honeycomb-compatible app on the recent Android Developers Lab follow-up event at Google Tokyo. Among other things, this means I get to go to Goole I/O next year :)

Friday 30 September 2011

More than a year and a half since the initial release to the Android Market, WWWJDIC for Android's second major version update is now live. It brings a refreshed UI for phones, a fully optimized and easier to use interface for tablets, and one of the most often requested features -- Japanese text-to-speech. Get it now from the Market and read about what's new and improved below.

First thing, first: tablets. The tablet-optimized version of Android, Honeycomb, was released early this year, but affordable Android tablets are just now getting mainstream. The biggest user visible changes are the introduction of the action bar on the top, and the fixed system bar with soft back and home buttons at the bottom of the screen. And, of course, the obviously larger screen. To take advantage of those, Honeycomb apps move previously hard to find option menus to the easily accessible action bar, and display more information when more screen real estate is available. Here's how the main screen of WWWJDIC for Android implements those patterns:

  • action items for accessing the frequently used handwriting and multi-radical kanji search, OCR, as well as the favorites and history screen are now on the action bar. The relatively rarely used Settings is available from the overflow menu, triggered by the button in the top right corner.
  • The most recent favorites and history items for each search category (dictionary, kanji and examples) are displayed inline below the search options area. You can now access recently looked up words and kanji with a single tap.
The new version keeps the familiar three-tab interface, and lets you change tabs by swiping left and right. No need to reach for the top of the screen! Swiping is also available on the history and favorites screen.

Search results also make use of the larger screen: the result list is displayed on the left, and details about the selected item are shown on the right. This design lets you quickly check the meaning of similar words or kanji without having to go back and forth between the list and details screens. Actions for each item are again show on the action bar. You can always go to the main screen by pressing the home icon on the left. Here's how example search result look on a tablet:


But not all improvements are for tablets alone. The phone UI has also been refreshed and follows similar patterns: an action bar with a home icon and the most widely used actions is displayed on all non-tabbed screens. Tabs are now Honeycomb-style and take less screen space than before. As on tablets, you can change tabs by swiping. Here's the main screen with the new tabs and action items for handwriting recognition and OCR at the top:


A free Japanese text-to-speech engine, N2 TTS, was recently released by KDDI R&D Labs to the Android Market and that made it possible to add Japanese pronunciation to WWWJDIC. After you install and enable N2 TTS, a speaker icon is displayed next to the reading section of dictionary and kanji entries. Pressing it will read out all available readings. You might want to turn up the volume a little, since speech generated by N2 TTS seems to be a little more silent than the default.

Details on how to enable Japanese pronunciation are available in the FAQ. Be aware that using two separate engines at the same time (one for Japanese and one for English, etc.) requires Android 2.2 (Froyo), so this feature is not available on 2.1 (Eclair). Below is the dictionary entry details view with Japanese text-to-speech enabled:


Multi-radical kanji search has also been made significantly easier to use in 2.0. Previous versions displayed kanji candidates as clickable links at the top, constrained by screen width. In 2.0, kanji are displayed in a horizontally scrollable list, letting you browse all candidates without changing screens (the same display pattern is used in Kanji Recognizer). Here's the obligatory screenshot:


Other less visible changes:

  • Google account permissions have been removed. Those were scaring off a lot of people, even though this is the preferred way to access user accounts, and the app never had access to you actual password. As a result of this, favorites export to Google Docs has also been removed. You can still export as CSV and import the file into Google Docs, if you want to take your kanji to the cloud.
  • The number of devices running Android 1.6 has been steadily decreasing, and is now less than 2%. Keeping up with the times, version 2.0 has dropped support for Android 1.6 and now requires Android 2.1 (Eclair) and above. Older versions that support 1.6 are available on the project's website, but will not be updated anymore. 
  • Various performance and error handling improvements, as well as bug fixes. 
This has been a major re-design of the app, and while it has been extensively tested, there may be bugs and problems not only on tablets, but on phones as well. Please report any problems you encounter by using the bugtracker or by email, and I will do my best to fix them. Feature requests are also welcome, but, as usual, no timeline or any guarantees. 

Enjoy and don't forget to rate, +1, share, tweet or otherwise spread the word!

Thursday 18 August 2011

The latest version is now available in the Android Market and soon in the Amazon Appstore.

Example search has been largely improved by using a feature recently added to WWWJDIC's API. While clicking on the 'Ex.' button next to a dictionary entry would only show you sentences containing the exact word before, searching for examples is a lot 'smarter' now. It now matches inflected words, alternative spellings and more. For example, searching for ?? will match ???, as well as ????; searching for ?? will match ???, ????, as well as the original ??, of course. Up to 100 sentences matching the query will be returned by default. For common words, you might want to turn the 'Random examples' option in Settings on. If you do, you will get 10 random examples containing the target word each time you search, giving you a much broader view of the word's usage.

Another new feature in this release is support for optical character recognition (OCR) of gallery images. In all previous versions, you needed to take a picture to start OCR, now you can use pictures you took previously too. Cropping and processing the image might be memory intensive, so it works best with lower resolution images (up to 2MB on a Nexus One). Your mileage might vary depending on the device you are using, but you might want to reduce your camera's resolution if you intend to use the images for OCR. Here's how the new OCR screen looks like. Notice the 'Gallery' button on the left:


That's it for now. Don't forget to rate if you like the app and stay tuned for version 2.0, featuring a revamped UI and full support for tablets.

Popular Posts

Visitors

Sample Text

About

Social Profiles

Featured Posts Coolbthemes