I read that there is problem method KeyChain.getPrivateKey(Context,String) on Android 4.1 although on older versions it works. Does anybody has solution how to get private key on JellyBean?
Code that does not work on 4.1, but works great on older versions.
On Thu, Sep 20, 2012 at 4:24 PM, Meidey <toms.med...@gmail.com> wrote:
> I read that there is problem method KeyChain.getPrivateKey(Context,String)
> on Android 4.1 although on older versions it works. Does anybody has
> solution how to get private key on JellyBean?
Not sure what you read, but there were (fixed in AOSP master) some bugs
affecting keys with particular characters in the key name.
There is a problem in 4.1 with apps that need to create a signature using a private key in the keychain. In particular, apps that establish SSL client sessions (such as OpenVPN) would use code such as this to allow an SSL negotiation to use a client cert/key from the keychain:
This code now fails badly on 4.1 (testing on Nexus 7) even though KeyChain.getPrivateKey returns a non-null value for privateKey. It not only fails to work, but causes a segfault later when privateKey is garbage collected.
I understand that on 4.1, private keys might be offloaded to hardware, but still the code above should work because it's not accessing the key directly -- it is only performing an encrypt operation using the key.
On Fri, Oct 5, 2012 at 2:40 PM, James Yonan <caprifin...@gmail.com> wrote:
> PrivateKey privateKey = KeyChain.getPrivateKey(context, alias);
> if (privateKey) {
> byte[] data;
> Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
> cipher.init(Cipher.ENCRYPT_MODE, privateKey);
> byte[] signed_bytes = cipher.doFinal(data);
> }
> This code now fails badly on 4.1 (testing on Nexus 7) even though
> KeyChain.getPrivateKey returns a non-null value for privateKey. It not only
> fails to work, but causes a segfault later when privateKey is garbage
> collected.
> I understand that on 4.1, private keys might be offloaded to hardware, but
> still the code above should work because it's not accessing the key directly
> -- it is only performing an encrypt operation using the key.
Not quite. You are feeding it to the Bouncy Castle provider, which knows
nothing about native keys and thus cannot use your key. I agree that it
should be better documented, but the new OpenSSL engine supports
only signing, verifying and key import. It should work if you use the
Signature class. The segfault sounds bad though, can you reproduce
it consistently? You might want to post this on android-security as well,
a lot of the Google people responsible for this seem to monitor it.
> > I understand that on 4.1, private keys might be offloaded to hardware, > but > > still the code above should work because it's not accessing the key > directly > > -- it is only performing an encrypt operation using the key.
> Not quite. You are feeding it to the Bouncy Castle provider, which knows > nothing about native keys and thus cannot use your key. I agree that it > should be better documented, but the new OpenSSL engine supports > only signing, verifying and key import. It should work if you use the > Signature class. The segfault sounds bad though, can you reproduce > it consistently? You might want to post this on android-security as well, > a lot of the Google people responsible for this seem to monitor it.
Well, there's essentially two problems here...
1. KeyChain.getPrivateKey(this, alias) returns an object that segfaults when collected by the GC. The segfault occurs in RSA_free in libcrypto. This is 100% reproducible for me on Nexus 7. This behavior has been documented in other posts, e.g. http://code.google.com/p/android/issues/detail?id=36545
2. You say that the new OpenSSL engine supports only signing, verifying and key import. That's fine, but keep in mind that the RSA signature used for verification of an SSL session is typically generated by the cipher object javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1PADDING") acting as an encryptor. Can java.security.Signature replicate this behavior? This issue is also documented here: http://stackoverflow.com/questions/11261774/using-android-4-1-keychain
On Sat, Oct 6, 2012 at 5:40 AM, James Yonan <caprifin...@gmail.com> wrote:
> Well, there's essentially two problems here...
> 1. KeyChain.getPrivateKey(this, alias) returns an object that segfaults when
> collected by the GC. The segfault occurs in RSA_free in libcrypto. This is
> 100% reproducible for me on Nexus 7. This behavior has been documented in
> other posts, e.g. http://code.google.com/p/android/issues/detail?id=36545
If it is indeed reproducible, it should be easy to fix. Have you tried building
latest AOSP source, there have been a number of fixes/changes in this
area? I fail to see how this is documented in the bug report though (no
steps to reproduce).
> 2. You say that the new OpenSSL engine supports only signing, verifying and
> key import. That's fine, but keep in mind that the RSA signature used for
> verification of an SSL session is typically generated by the cipher object
> javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1PADDING") acting as an
> encryptor. Can java.security.Signature replicate this behavior? This issue
> is also documented here:
> http://stackoverflow.com/questions/11261774/using-android-4-1-keychain
Again, are there any reasons you are using the Cipher class for signing?
I don't think this is typical at all, but if you have a particular reason
for wanting to use 'raw' RSA encryption, please say why. And, again,
this is probably more suitable for andorid-security.
> If it is indeed reproducible, it should be easy to fix. Have you tried > building > latest AOSP source, there have been a number of fixes/changes in this > area? I fail to see how this is documented in the bug report though (no > steps to reproduce).
> > 2. You say that the new OpenSSL engine supports only signing, verifying > and > > key import. That's fine, but keep in mind that the RSA signature used > for > > verification of an SSL session is typically generated by the cipher > object > > javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1PADDING") acting as an > > encryptor. Can java.security.Signature replicate this behavior? This > issue > > is also documented here: > > http://stackoverflow.com/questions/11261774/using-android-4-1-keychain
> Again, are there any reasons you are using the Cipher class for signing? > I don't think this is typical at all, but if you have a particular reason > for wanting to use 'raw' RSA encryption, please say why. And, again, > this is probably more suitable for andorid-security.
Raw RSA encryption is necessary as part of the challenge/response handshake of an SSL/TLS negotiation, if your side of the connection is using a cert as an authentication factor. It's essential for VPN implementations that layer on top of SSL/TLS transport and need to interoperate with an external key store. I enumerated the signature algs provided by the AndroidOpenSSL 1.0 provider and I don't see any implementation for raw RSA. Some Java implementations include it as "NONEwithRSA", but I don't see it here.
Yes, I'll try to move this over to android-security. Thanks for your time.
On Sun, Oct 7, 2012 at 2:56 AM, James Yonan <caprifin...@gmail.com> wrote:
> Raw RSA encryption is necessary as part of the challenge/response handshake
> of an SSL/TLS negotiation, if your side of the connection is using a cert as
> an authentication factor. It's essential for VPN implementations that layer
> on top of SSL/TLS transport and need to interoperate with an external key
> store. I enumerated the signature algs provided by the AndroidOpenSSL 1.0
> provider and I don't see any implementation for raw RSA. Some Java
> implementations include it as "NONEwithRSA", but I don't see it here.
OK, that makes sense. The current version indeed doesn't provide this, but it
looks like it has been added in AOSP master: