clausecker / freefare

Go bindings for the libfreefare
GNU Lesser General Public License v3.0
18 stars 3 forks source link

DESFireTag ReadData returning all zeros #2

Open stevenmirabito opened 5 years ago

stevenmirabito commented 5 years ago

I'm going to do some more debugging, but I figured I would throw this up here in case anyone can quickly point out something I'm doing wrong.

I am using this library to write a standard data file with 32 bytes of data to a newly created application on a DESFire target:

// Ensure we're on the master application
log.Infof("Switching to the master application...")
if err = target.SelectApplication(mAppId); err != nil {
    return err
}

// Authenticate to the target
log.Infof("Authenticating to tag...")
if err = target.Authenticate(0, *defaultDESFireDESKey); err != nil {
    return err
}

// Create the application
log.Infof("Creating application in slot %d...", realm.Slot)
if err = target.CreateApplication(appId, initialApplicationSettings, 4|freefare.CryptoAES); err != nil {
    return err
}

// Select the newly created application
log.Infof("Selecting application...")
if err = target.SelectApplication(appId); err != nil {
    return err
}

// Authenticate to the application
log.Infof("Authenticating to application...")
if err = target.Authenticate(0, *defaultDESFireAESKey); err != nil {
    return err
}

// Change the application transport keys
log.Infof("Changing application transport keys...")
if err = target.ChangeKey(1, *appReadKey, *defaultDESFireAESKey); err != nil {
    return err
}

if err = target.ChangeKey(2, *appAuthKey, *defaultDESFireAESKey); err != nil {
    return err
}

if err = target.ChangeKey(3, *appUpdateKey, *defaultDESFireAESKey); err != nil {
    return err
}

// Create the UUID data file
log.Infof("Writing UUID data file...")
if err = target.CreateDataFile(1, freefare.Enciphered, initialFileSettings, mangledUUIDLength, false); err != nil {
    return err
}

dataLen, err := target.WriteData(1, 0, []byte(mangledUUID))
if err != nil {
    return err
}

if dataLen != mangledUUIDLength {
    return errors.New("failed to write UUID to target")
}

The context surrounding this can be found here (subject to change, active development branch): https://github.com/ComputerScienceHouse/gatekeeper/blob/master/device/nfc.go#L231

This all works and dataLen reports that 32 bytes were written. However, when I go back and read the same file:

appId := freefare.NewDESFireAid(baseAppId + realm.Slot)
appReadKey := keys.GenDESFireKey(realm.ReadKey)

// Select the realm's application
if err := target.SelectApplication(appId); err != nil {
    return nil, err
}

// Authenticate to the application
if err := target.Authenticate(1, *appReadKey); err != nil {
    return nil, err
}

// Read the UUID from the application
mangledUUID := make([]byte, mangledUUIDLength)
dataLen, err := target.ReadData(1, 0, mangledUUID)
if err != nil {
    return nil, err
}

if dataLen != mangledUUIDLength {
    return nil, errors.New("failed to read UUID from target")
}

This runs successfully and dataLen reports that 32 bytes were read, but mangledUUID (the buffer passed to the read function) is all zeros.

I've tried different communication modes (Plain, Enciphered), different data, and attempted to read immediately after writing before any access rights were applied, to no avail. The logic around all of this is based on this project, which uses libfreefare directly: https://github.com/henryk/libopenkey/blob/master/libopenkey/libopenkey.c

Am I doing something incorrectly, or does this have something to do with the read_data buffer overrun bug in libfreefare <= 0.4.0?

Thanks for any insight you may be able to provide!

clausecker commented 4 years ago

Unfortunately, I have no idea what the problem is. There is going to be a new libfreefare release soonish which is going to fix many of these issues. I hope this may fix your problem as well.