The security of the KeepassNFC applet is insufficient for NFC application and I would probably recommend that only standard ISO7816 contact channel be used and even if contact channels are used, it is still vastly insufficient in terms of security.
The reasons:
* Lack of PIN access
* Sloppy use of RSA to wrap keys instead of implementing a full secure channel protocol.
* Sloppy allocation and use of memory (not critical)
* No zeroizing of memory for critical memory areas that may hold cryptographic material (aes_key_temporary).
Possible security attacks:
* MiTM interception and spoofing when transferring public key from card
* MiTM interception and modifying of public key wrapped cryptographic materials
* Abuse of no secure and authenticated channel feature turning the card into an "Oracle" where a malicious attackers can spam the NFC channel in a bid to further attacks.
Security mitigations:
* Introduce asymmetric secure channel especially the A02 Secure Channel Protocol (
viewtopic.php?f=12&t=983#p3004) I have created and used successfully on actual cards. The benefits and cons are written inside.
* Over the A02 Secure Channel, attempt a login with a PIN code. If the login succeed, the channel is not only secure but also authenticated.
* Using a secure and authenticated channel, transfer key materials as needed.
* Zeroize buffer memory after decryption or encryption have taken place.
Efficiency and Improvements:
* aes_key_temporary is not needed at all and one can save 260 bytes of RAM space immediately. The rationale is aes_key_temporary is exclusively used in the context of:
Code: Select all
private boolean decryptWithCardKey(byte[] input, short offset, byte[] output)
{
if(!card_cipher_initialised) {
RSAPrivateCrtKey private_key = (RSAPrivateCrtKey)card_key.getPrivate();
card_cipher.init(private_key, Cipher.MODE_DECRYPT);
card_cipher_initialised = true;
}
card_cipher.doFinal(input, offset, (short)(RSA_KEYLENGTH / 8), output, (short)0);
return true;
}
It is used in the
cipher.doFinal portion and as we know the input and the output can be the same byte array especially suitable for the circumstances for KeepassNFC where after the input is loaded to be decrypted into the output, it is not used anymore in the function and thus can be reused in such an efficient manner.
The better code would be:
Code: Select all
decryptWithCardKey(scratch_area, (short)0, scratch_area);
Util.arrayFillNonAtomic(scratch_area, (short) 0, (short)(RSA_KEYLENGTH / 8), (short) 0); // Zeroize memory
These are my personal opinions on the insufficiencies of the security measures that KeepassNFC and the inefficient and insecure use of resources by the applet which can be improved on.