Differences Between RSA Key Generation on Android and iOS

First in a series comparing the cryptographic programming interfaces of Android and iOS.

Jim Hawkins
VMware 360
8 min readNov 16, 2020

--

The Android and iOS programming interfaces both support generation and storage of asymmetric key pairs for RSA (Rivest–Shamir–Adleman) cryptography. The programming interfaces can be utilized in Kotlin on Android, or in Swift on iOS. This post includes sample code and discussion of the platforms’ programming interfaces, separately and comparatively.

Illustration with a person, circles, and a padlock

Disclaimer: IANAC

Before you copy and paste the code into your banking app, be warned that I Am Not A Cryptographer (IANAC).

My understanding of cryptography is based on some reading, some coding, and on years of standing next to security engineers who themselves stand next to cryptographers.

In case you understand even less than me about cryptography, a few terms and definitions are included after the code and discussions.

Generate an RSA Key Pair on Android

Kotlin code for Android to generate a random asymmetric key pair for RSA cryptography in the Android key store could look like this:

The above snippet is based on the code here:
github.com/vmware/captivewebview/…/captivecrypto/StoredKey.kt#L308
The code is compatible with Android version 6, aka Marshmallow, which corresponds to a minimum API level of 23.

Line notes:

  • Line 5
    The constant “AndroidKeyStore” specifies that the key is to be generated in the hardware-backed key store on the device.
  • Lines 6 and 10
    For details of .apply(), .run(), and other Kotlin scope functions, see kotlinlang.org/…/scope-functions
  • Line 7
    The KeyGenParameterSpec class must be used to specify keys generated in the Android key store. The class is part of the Android Key Store package. It is a specific subclass of a base class in the Java Security package. This is a common pattern in the Android cryptography programming interface.
  • Line 9
    The KeyProperties constants here form a bit mask.
  • Lines 11 to 14
    The block mode, padding mode, and digests are part of the key specification. Cipher specification will come later, when the key is used to encrypt and decrypt data. However, only modes that were in the key specification can be used in the cipher specification. The particular combination here may not be suitable for your application IANAC but this code works and can be adapted to your needs. If you want to try different combinations of modes, it’s a good idea to check what combination Android supports first. A method for doing that will be covered later in this series.
  • Line 18
    This is the actual generation and storage of the key.

The stored key can now be used for other tasks like encryption and decryption.

Generate an RSA Key Pair on iOS

Swift code for iOS to generate a random asymmetric key pair for RSA cryptography in the iOS keychain could look like this:

The above snippet is based on the code here:
https://github.com/vmware/captivewebview/.../CaptiveCrypto/StoredKey.swift#L504
The code is compatible with version 10.0+ of iOS.

Line notes:

  • Lines 4 and 17
    The attributes declaration results in a Swift Dictionary object. This is toll-free bridged to CFDictionary at the point of usage.
  • Lines 5 to 10
    For reference documentation, see: Key Generation Attributes.
  • Line 11
    Use of UTF-8 is an assumption.
  • Line 16
    This is the actual generation and storage of the key. The key is returned as a SecKey instance, but it isn't used here.

The stored key can now be used for other tasks like encryption and decryption.

Comparison of RSA Key Pair Generation Programming Interfaces

The above Android and iOS code snippets for RSA key pair generation are quite different to each other, because the native programming interfaces that they utilize are quite different.

Java Security System

The Android cryptography programming interface is based on the Java Security system. The Java Security system has a broad scope.

A smart card that can respond to challenges can be coded in the Java Security system. So can a derived credentials system. So can a hardware security module in an Android smartphone. So can a certification authority service. The Java Security programming interface has to be quite extensive in order to model all the applications that it supports.

Two significant pieces are the concepts of the key store and the security provider. The Android KeyStore counts as both a store and a provider.

Pitfalls for Android

Although the Android RSA key generation code looks quite simple and robust, many pitfalls had to be fallen into, and climbed out of, in the process of writing it. For example:

  • You have to know that “AndroidKeyStore” is the magic value that selects the on-device hardware-backed storage of an Android device. Specifying the store explicitly is optional. If you don’t specify it, the Java Security system will select a store based on the key specification. It won’t necessarily select the Android KeyStore because an Android device can have several stores, including stores that only exist in-memory at run time.
  • You have to know to use the KeyGenParameterSpec class. The KeyPairGenerator will accept any parameter that implements the AlgorithmParameterSpec interface, of which there are quite a few. The generator can also be initialized directly just by specifying a key length, without a specification object. However, you must use KeyGenParameterSpec or else your key won’t be stored in the Android KeyStore.
  • Even though it’s a dedicated subclass for specifying keys in the Android KeyStore, the KeyGenParameterSpec class doesn’t prevent you from making mistakes. For example, it’s quite possible to specify a combination of modes that aren’t supported by any security provider on the device. Sometimes you won’t find out about that until the key generation code runs and throws an exception. Sometimes you won’t find out until later, like cipher preparation time when you try to attach the key. Or even later, after you’ve encrypted some data and then can’t decrypt it.

The Android code is at least object oriented, and works well with Kotlin scope functions and other modern concepts.

iOS Keychain Programming Interface

The RSA key generation programming interface of iOS isn’t modern. Old-time Objective-C coders will be familiar with the kSec constants and the rest of the SecKey family. The programming interface doesn’t seem to have been updated to make use of new Swift syntax.

The shorter dot notation for Swift enum constants can’t be used in a SecKey attributes dictionary, for example. The SecKey interface isn’t really based on objects and classes. Basically, it’s C code and a module map. Where Android has a class the represents the key specification, iOS uses a generic dictionary object that happens to have some particular values in the keys.

Narrow Range

The Swift keychain programming interface need support only iOS, macOS and other Apple operating systems. This is a much narrower range than Java and Android. Consequently, the model does not need to be multipurpose. For example, the key generation function can throw an error immediately if incompatible or unsupported options are specified.

On balance, if you can get past ye olde coding style, the iOS keychain programming interface seems less prone to coder error than the equivalent for Android. However, key identification should also be considered.

Key Identification

Key identification is simple in the Android programming interface. Each stored key has a textual name, referred to as its alias. You must include an alias in the key specification. If you generate a first key with an alias, A, and then generate a second key with the same alias, the second key will replace the first in the store. So, every key in the Android KeyStore must have a name, and uniqueness is enforced by the programming interface.

Key identification in the iOS keychain programming interface isn’t simple. It’s based on multiple attributes in the specification dictionary. Also, those attributes are optional. This means that you can create nameless keys, and keys with duplicate names. Those will be difficult to retrieve later, when you want to use them.

Conclusion: Difficult

In conclusion, both interfaces for RSA key generation seem more difficult to use than they need to be. They either offer too wide an array of options, and don’t trap errors at build time, or they use old-fashioned coding styles, and again don’t trap errors at build time.

Some Cryptographic Terms

You can make better use of the interfaces on either platform if you know a few cryptographic terms. The following definitions are a start but don’t claim to be rigorous IANAC.

Symmetric and Asymmetric Encryption

Symmetric encryption utilizes the same key to encrypt and decrypt data. The key can be referred to as a symmetric key.

Asymmetric encryption utilizes two dependent keys, sometimes referred to as a key pair. The two keys in a key pair can be referred to as the private key and the public key. If data is encrypted by the private key it can be decrypted by the public key, for example.

Cipher

A cipher is a process for a cryptographic operation, such as encrypting data.

Ciphers don’t feature as principals in the RSA key generation code snippets, above, but will make an appearance in a future post in this series. However, cipher specifications are mentioned, because there is a need for compatibility with key specifications. A cipher specification can include an algorithm, a block mode, and a padding mode, for example.

Key Store

Any persistent location for cryptographic keys on a mobile device can be referred to as a key store. Persistence here means through termination of the app or power cycling of the mobile device, for example.

Stored keys each have a key identification. Depending on the capabilities of the store, the identification will be used:

  • To retrieve the key from the store.
  • To request cryptographic processing involving the key and taking place inside the store.

Key stores that support processing requests typically also support generation of new keys inside the store. A key generated inside a store that supports processing requests never has to leave the store, which is a desirable security characteristic.

The RSA key generation snippets cover the following key stores.

Android KeyStore:

  • Supports processing requests.
  • Identifies each key by a simple name, referred to as its alias.

iOS keychain:

  • Doesn’t support processing requests.
  • Identifies each key by a set of attributes.

A future post could also cover the iOS Secure Enclave Processor (SEP), which does support processing requests.

Sample Code Locations

Many individually useful code samples can be found here on Medium, on Stack Overflow, and in GitHub Gists.

For the sample code that appears above, see the following.

For Android:

For iOS:

Use the sample code with care. It is working code but might require modification in order to represent the best cryptography for your application.

The above applications each use an embedded web view for their user interface (UI). The actions that the user can take in the UI correspond fairly closely to low-level cryptographic tasks. Commands are sent from the web view through a bridging layer to the native Kotlin or Swift code. The native code then utilizes the device’s cryptographic programming interface.

For official samples, see the following.

Next: AES Key Generation

The next post in this series will cover key generation for AES (Advanced Encryption Standard) cryptography.

Thank you for reading and happy coding.

--

--

Jim Hawkins
VMware 360

Software developer working on secure mobilisation of enterprise data to Android and iOS devices.