This repository is used for class PV204 Security Technologies at Masaryk University. All meaningful improvements will be attempted to be pushed to upstream repository in June 2018.
KeePass Password Safe is an open source password manager that aims to store passwords securely.
KeepassNFC is an applet that can protect the secret key of the KeePass database.
This applet was based on the project smartcard_crypto_applet and can be run on javacard platform with JCRE version 2.2.x or above. It is meant to be used in a card supporting NFC (Near Field Communication) technology.
This project has two different build systems that can be used. JCIDE is the one originally used, while the Gradle integration has been added later using the template from @crocs-muni.
A project file (KeepassNFC.jcproj) has been created for the users of JCIDE. If you have already installed the JCIDE, only a simple double-clicking on this file is needed to start the development environment. You can view, edit, build or debug the code with JCIDE, a powerful Javacard Integrated Development Environment. You can use pyApdutool to download and install the applet, please reference the topic in the JavaCardOS for the operation detail.
Support for this configuration is guaranteed until commit 701cdfc.
This configuration gives the ability to easily compile and convert the applet to cap files, it has support for easy tests creation, including test coverage. Also, it provides integration with Travis CI platform (and easily with any other CI platform). It additionally provides the means to execute on both real cards and JCardSim.org simulator.
This build configuration can be used with all the IDEs that provide integration (native or by plugins) with Gradle (IntelliJ, NetBeans, Eclipse...).
After recursively cloning the repository (to gather all the JavaCard SKDs),
git clone --recurse-submodules git@github.com:JavaCardSpot-dev/KeepassNFCApplet.git
you can choose the desired JavaCard SDK to use by setting the JCSDK
environment variable (by default it is empty, and the minimum required SDK version will be used). Then simply run
./gradlew buildJavaCard --info
JCSDK=jc304 ./gradlew buildJavaCard --info
to get the .cap
file. It will be located under bin/net/lardcave/keepassnfcapplet/{JCSDK}/keepassnfcapplet.cap
Here, the user is intended as both you and the client application.
Also, when talking about APDU headers, the length will be always omitted, just like P1 and P2, except when needed.
Actually, the applet is able to decrypt the user-supplied database using AES-256. Future development will include also its encryption, and possibly support for more algorithms (Twofish/ChaCha20).
The applet uses three classes of commands:
0x90
: includes commands always accessible by any user0xA0
: includes all PIN-related commands. Some of them are freely accessible (PIN verifications), others require the Master PIN to have been previously verified.0xB0
: any command under this class needs the User PIN to have been previously verified. This class includes all actual implementation of the required functionality to decrypt the database.Authentication is provided by the means of two PIN verifications. Both PINs initial values are actually hardcoded.
123456
. For increased security its minimum length is 6.1234
, with a minimum required length of 4 characters.Both PINs are recommended to be changed by the final user using commands under the 0xA0
class.
Both PIN verifications are kept valid until the card is extracted (or the applet is deselected).
For applet configuration, all commands are of class 0xB0
, and as such require verify User PIN (A082) to have been called successfully.
After calling these commands, the applet is configured to actually decrypt the KeePass database.
For applet usage, all commands are of class 0xB0
, and as such require verify User PIN (A082) to have been called successfully. Also, the configuration is considered to be done.
Each usage is identified by a transaction, with related transaction key (AES-128). The user is required to:
The user can obtain two different information pieces about the status of the applet, without changing its state and without any authentication:
Header | Name | Payload (plaintext) | Functionality | Authenticated | Requirements | Response format |
---|---|---|---|---|---|---|
9072 | lock reason/PIN trials | empty | Return number of trials remaining for both PINs. In future can contain more information | mmuu , with mm remaining trials for Master PIN and uu for User PIN |
||
9074 |
get version | empty | Return applet version | 01vv , with vv the actual version. |
||
A080 | verify Master PIN | Master PIN | Verify given Master PIN against the stored one |
|
||
A081 | set Master PIN | New Master PIN | Set Master PIN to given data | Master (A080) | ||
A082 | verify User PIN | User PIN | Verify given User PIN against the stored one |
|
||
A083 | set User PIN | New User PIN | Set User PIN to given data | Master (A080) | ||
B070 | get public key | 010000 |
Get public key's exponent | User (A082) | B075 successfully called | 01ssssk... , with ssss a short for exponent length, and k... the actual exponent |
B070 | get public key | 02oooo |
Get public key's modulus from offset oooo |
User (A082) | B075 successfully called | 01ssssSSSSk... , with ssss a short for the bytes sent, SSSS a short for the missing bytes after the sent ones, and k... the actual modulus part |
B070 | get public key | xxoooo |
--- | User (A082) | 02 (failure) when xx different from 01 or 02 |
|
B071 | set password key | empty | Decrypt first bytes in scratch area as password key (AES-256, saved also after disconnection) | User (A082) | B075 successfully called and B076 used to store encrypted password key in scratch area | 01 if successful |
B072 | prepare decryption | password & transaction IVs (16+16 bytes) | Decrypt first bytes in scratch area as transaction key (AES-128, saved only for the session). Initialize password cipher for decryption and transaction cipher for encryption. | User (A082) | B076 used to store encrypted transaction key in scratch area | 01 if successful |
B073P1=80 |
decrypt block | encrypted block | Decrypts given data with password cipher expecting more data. Then encrypts the result with transaction cipher. | User (A082) | B072 successfully called | 01b... , with b... actual block |
B073P1!=80 |
decrypt block | encrypted block | Same as above, but as last block. This will also reset ciphers. | User (A082) | B072 successfully called | 01b... , with b... actual block |
B075 | generate key pair | empty | Generate card's key pair. | User (A082) | 01ssss , with ssss a short for key length. |
|
B076 | write to scratch | oodd... |
Store data (dd... ) in internal scratch area at offset oo |
User (A082) | 01ssss , with ssss a short for free space after saved data. |
B074 instruction to get version is maintained only for compatibility reasons, and it's deprecated. Nevertheless, since it's a B0
-class instruction, it still needs correct User PIN verification.
Apart from standard exception codes, the following specific SW codes are used:
SW | Meaning | ISO7816 equivalence |
---|---|---|
97nn | Action requires Master PIN verification, but A080 wasn't successfully called. nn contains remaining numebr of trials. |
|
98nn | Action requires User PIN verification, but A082 wasn't successfully called. nn contains remaining number of trials. |
|
99nn | The verification of Master/User PIN gone wrong. nn contains remaining number of trials. |
|
6700 | Input data has wrong length compared to expected one. | SW_WRONG_LENGTH |
6A80 | Input data has different values than expected. | SW_WRONG_DATA |
6982 | In case of error caused by supposed tampering. | SW_SECURITY_STATUS_NOT_SATISFIED |
F1tt | A crypto-related exception occurred. tt from 01 to 05 are standard CryptoException reasons, while 09 is used for rare situation when evaluating a number too big. This only happened if skipping some commands while setting password/trasaction keys. |
Help is always appreciated! Please read these suggestions for what to do, and always follow the contibution rules!
This applet can be improved in several ways:
01
/02
to show success/failure of commands, and just use SW
codesAlso the repository can be improved:
Until 701cdfc it should work on JC30M48, the downloading and installation have been tested on this card.
Until June 2018 it was successfully tested with NXP J2E 081 (NXP JCOP v2.4.x).
Some profiling has been performed for all the commands (timings are in ms, average over 20 trials, smartcard NXP J2E 081):
Header | Avg timing | Timing range | Notes |
---|---|---|---|
9072 | 7 | 7 - 8 | (get lock reason/remaining PINs), direct read |
9074 | 7 | 7 - 9 | (get version), direct read |
A080 | 37 | 37 - 39 | (verify Master PIN) |
A081 | 33 | 33 - 34 | (set Master PIN) |
A082 | 37 | 37 - 38 | (verify User PIN) |
A083 | 33 | 32 - 34 | (set User PIN) |
B070010000 |
13 | 13 - 14 | (get Card Key exponent) Supposed one execution every usage. |
B070020000 |
44 | 44 - 45 | (get Card Key modulus - first part) Supposed one execution every usage. |
B071 | 714 | 714 - 716 | (set password key) Supposed one execution every long time. |
B072 | 699 | 698 - 700 | (set transaction key) Supposed one execution every usage. |
B073P1!=80 |
96 | 95 - 97 | (decrypt one block) Decrypting 128 bytes unique block. |
B075 | 21660 | 5557 - 54592 | (generate card key) Supposed one execution every long time. |
B076 | 14 | 14 - 15 | (write to scratch) Writing 16 bytes to scratch ~encrypted transaction key. |
B076 | 18 | 18 | (write to scratch) Writing 32 bytes to scratch ~encrypted password key. |
B076 | 26 | 26 - 27 | (write to scratch) Writing 64 bytes to scratch, more than needed by keys. |
About the B073 command (block decryption): a fully populated KeePass database can be long around 200 KiB, that corresponds to 1600 executions of given command. These result in a total execution time of around 150 seconds, or 2.5 minutes. This should be improved.
The original creator of the project is the JavaCardOS community.
As the initial notice explains, this project will be maintained by students of the Masaryk University about until June 2018.