Here I conclude the recent research and discussions with the storage of the seed/private key in parity-signer.
Currently, we require a user to input a pin code for encrypting the seed, and then put the encrypted seed together with other account data into a secure store. The secure store then uses the native KeysStore
or KeyChain
to store the encrypted account data.
After discussion with @kirushik and @geastwood, it has the following improvement potential to achieve a higher security level than industry standard.
Here the way we used to encrypt the pin data is from EthSign Rust library, I am not sure how it works, hope @maciejhirsz could give some hints on that. We could use Argon2 to create a hash of the pin, and use that hash to encrypt the seed. With Argon2, we can efficiently prevent brute force attack.
To store the encrypted account data into the keychain, we may add an extra biometric authentication layer. One thing needs to be noticed here is that apple use a so-called Local Authentication Framework to bridging the biometric data in Secure Enclave, but that does not mean that the encryption key is also kept there, it is stored in the Keychain. This is also the behavior what react-native-keychain library does.
iOS devices with A7 (first on iPhone6) or newer chips contain security chips but not all Android devices have the same thing. The good news is Google enforced new devices supporting Android 7 must have a hardware-backed security element.
The Secure Enclave is a hardware-based key manager that’s isolated from the main processor to provide an extra layer of security. When you store a private key in the Secure Enclave, you never actually handle the key, making it difficult for the key to becoming compromised.
AFAIK, these Secure Enclave is not implemented on any react-native keychain related libraries, I suggest we contribute to react-native-keychain.
The availability of a trusted execution environment in a system on a chip (SoC) offers an opportunity for Android devices to provide hardware-backed, strong security services to the Android OS, to platform services, and even to third-party apps
AFAIK, this Hardware backend Keystore is not implemented on any react-native keychain related libraries (Searched KeyInfo.isInsideSecurityHardware
in their repository). But the hardware implementation on the Android maybe variant according to the device provider. So our priority is to implement it on iOS.
Consider the user experience, that two authentication steps in the image2 maybe too much, And the high complexity may increase the risk at the same time,
So the proposal includes two parts as highlighted with the red rectangles:
We may rely on the hardware-backed Key store instead of Argon2 hash and encryption function. They provider similar brute force prevention whereas the secure enclave could prevent software-related risks. Besides, the TouchID / FaceID supposed to be more complicated to compromise than the Pincode, if related user data are exposed, plus the Biometric data's mathematical presentation is also stored in secure enclave according to here.
As we already have the authentication with biometric data before, here we may just rely on dependency's setItem
function to help us save the account data into Keychain. Which uses kSecClassGenericPassword
, the primary key is the combination of kSecAttrAccount
and kSecAttrService
.
Remarks:
- Consider the still the plain-text seed will be sent to Javascript runtime. We need to force run the garbage collection each time after the seed is present. According to some discussion on Stackoverflow, it seems uncertain that how the GC works, I suggest we use the current
delete account[key]
implementation. - Swift code will automatically release the memory if we use native code. While in Objective-C, we have to release it manually by
if (privateKey) { CFRelease(privateKey); }
if (access) { CFRelease(access); }
- In image2 we do not store the hash for comparison but rather throw an error on the decryption process, which could make the process longer to compromise the private key.