AndroidCrypto / Ntag424SdmFeature

This is an accompanying application to an articles series about demystifying the Secure Dynamic Message feature of NTAG 424 DNA NFC tags.
MIT License
4 stars 4 forks source link

Problem with EncryptedFileSunCustomKeysActivity #2

Open AndroidCrypto opened 2 weeks ago

AndroidCrypto commented 2 weeks ago

This issue was reported by medium.com user Bryan Lee on Oct. 4th 2024:

Seeing the same issues as Unaibox. Could it be possible that EncryptedFileSunCustomKeysActivity code is incorrect? I don't see it using the Application key 1/2/3/4 anywhere, instead just using Ntag424.FACTORY_KEY for all the operations.

AndroidCrypto commented 2 weeks ago

Mhm, I can't follow your comment - are you in the right activity code ? In the following you find excerpts from the code:

Header:

import static net.bplearning.ntag424.constants.Permissions.ACCESS_KEY0;
import static net.bplearning.ntag424.constants.Permissions.ACCESS_KEY2;
import static net.bplearning.ntag424.constants.Permissions.ACCESS_KEY3;
import static net.bplearning.ntag424.constants.Permissions.ACCESS_KEY4;
import static net.bplearning.ntag424.constants.Permissions.ACCESS_NONE;

In private void runWorker() {:

// write URL template to file 02 depending on radio button                                                               
SDMSettings sdmSettings = new SDMSettings();                                                                             
sdmSettings.sdmEnabled = true; // at this point we are just preparing the templated but do not enable the SUN/SDM feature
sdmSettings.sdmMetaReadPerm = ACCESS_KEY3; // Set to a key to get encrypted PICC data                                    
sdmSettings.sdmFileReadPerm = ACCESS_KEY4; // Used to create the MAC and Encrypted File data                             
sdmSettings.sdmReadCounterRetrievalPerm = ACCESS_NONE; // Not sure what this is for           

The sdmMetaReadPerm key is set to Key_3 and the sdmFileReadPerm key is set to KEY_4. In the Constants.java they are defined as:

public static final byte[] APPLICATION_KEY_3 = Utils.hexStringToByteArray("A3000000000000000000000000000000");
public static final byte[] APPLICATION_KEY_4 = Utils.hexStringToByteArray("A4000000000000000000000000000000");

The keys itself are set in the PrepareActivity.java for the Main Application of the NTAG424 tag (the tag itself needs to know the key it should use for operation) in the private void runWorker() { method (the code is just the change key 3 code:

...
// change application key 3                                                                                    
success = false;                                                                                               
try {                                                                                                          
    ChangeKey.run(dnaC, ACCESS_KEY3, APPLICATION_KEY_DEFAULT , APPLICATION_KEY_3, APPLICATION_KEY_VERSION_NEW);
    success = true;                                                                                            
} catch (IOException e) {                                                                                      
    Log.e(TAG, "ChangeKey 3 IOException: " + e.getMessage());                                                  
}                                                                                                              
if (success) {                                                                                                 
    writeToUiAppend(output, "Change Application Key 3 SUCCESS");                                               
} else {                                                                                                       
    writeToUiAppend(output, "Change Application Key 3 FAILURE, Operation aborted");                            
    return;                                                                                                    
} 
...       

where ChangeKey.run is defined as:

public static void run(     @NonNull     DnaCommunicator communicator,
    int keyNum,
    byte[] oldKey,
    byte[] newKey,
    int keyVersion )

so I'm going the ACCESS_KEY3 from oldKey ("APPLICATION_KEY_DEFAULT") to newKey ("APPLICATION_KEY_3").

Please do not mix the keys for the (external used) SDM feature (KEY_3 and KEY_4) with the keys used internally to write the data like the URL_TEMPLATE to the tag or change the file settings for enabling the SDM feature (KEY_0, KEY_1 and KEY_2). Especially when I authenticate the NTAG424 I'm using the factory key:

success = AESEncryptionMode.authenticateEV2(dnaC, ACCESS_KEY0, Ntag424.FACTORY_KEY);

I left KEY_0 ("Master Application Key") unchanged because when changing this key (e.g. during testing with different data) to a unknown value ("unknown" = some times later when you forgot this key...) the key may get unusable as there is no way to recover this key.

A note on https://github.com/nfc-developer/sdm-backend: I never worked with the source code of this repository, I'm just using the backend server for an easy verification of the created NDEF messages. I do not know what keys need to set to decrypt and verify the data created with "Custom" keys.

I hope that helped. Michael

smblee commented 2 weeks ago

Hey @AndroidCrypto thanks for this detailed response. So i believe what the hosted sdm-backend is doing is its using the null master key to decrypt (0x16). So my expectation was for example, if i were to switch all the APPLICATION_KEY_X to say 123400000000000000000000000000AA (non-default), and try calling out to the sdm-backend again, i should be getting an error response (since the key should have changed), but was still working fine. I tried running my own instance of sdm-backend with the non-default master key (same key as the changed APPLICATION_KEY_X), which returned the decryption error.

My guess was that since the activity code is using FACTORY_KEY (0x16), and have no usage of APPLICATION_KEY_X, maybe it was a mistake. But it also could be my lack of understanding of how FACTORY_KEY is being used vs the roles of the APPLICATION_KEY

My end goal here is I want to be able to use my own self-hosted sdm-backend with non-null master key, and be able to authenticate the chips. Also prevent others from messing with the chip without knowing the master key.

Really appreciate your thorough post and respond around this and looking forward to your reply!

AndroidCrypto commented 2 weeks ago

You are right, the "key settings" part is the most tricky one when using this feature. Here are some hints to do it the right way during personalization of the tag.

A note at the beginning: "Master Key" is a not diversified key (before diversification). I don't know what another repository like SDM backend means for this term !

1) Use different "Master" key values for each application key (0 to 4 on an NTAG424) and not the same for each key.

2) write diversified keys to the tag. Please do NOT run this for the specified key that is used for "sdmMetaReadPermission" - because for decryption of the encrypted PICC-data (that gives you the UID) with a diversified key you need to know this UID...

In my sample app I'm using the application keys 0, 1 and 2 that are factory keys (unchanged, default / "nulled") except when running the "EncryptedFileSunCustomKeysActivity"; this is the only activity that uses CUSTOM or DIVERSIFIED keys for the SDM/SUN feature but NOT for application keys 0-2, they are left unchanged to fabric keys. I've done this as it has nothing to do with the SDM/SUN feature but of course the keys need to get changed as written above.

"My end goal here is I want to be able to use my own self-hosted sdm-backend with non-null master key, and be able to authenticate the chips. Also prevent others from messing with the chip without knowing the master key.": of course you can set your own backend server with custom and/or diversified keys. Simply change the applications keys on the tag and use your own keys. BUT you write as well: "authenticate the chips": I don't understand what you mean by this as the backend server just receives the NDEF message as part of the URL but has no further access to the tag and cannot "authenticate" the tag for whatever. The authentication is possible on a separate device only that works complete different to a backend server.

Hope that helps, Michael