Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to change 2nd key in desfire application #99

Closed
AndrewLeiper opened this issue Nov 11, 2015 · 13 comments
Closed

Unable to change 2nd key in desfire application #99

AndrewLeiper opened this issue Nov 11, 2015 · 13 comments
Labels

Comments

@AndrewLeiper
Copy link

Hi there,

I'm using V1.80 via the com dll in delphi and an Omnikey 5321.

I have created an application on a DESfire EV1 card with 2 keys (KS_DEFAULT).
I can successfully authenticate both keys.
I can change key 0 on both the PICC master and the application.

But if I select the application, authenticate with key 0, and then try to change key 1, I get an exception:
'CRC or MAC does not match data / Padding bytes not valid'.

This happens on both DES and AES keys.

Hope you can help.

Andy Leiper

@Liryna
Copy link
Contributor

Liryna commented Nov 11, 2015

Hi,

Can you try again with one of the KS_CHANGE_* flags in addition to KS_DEFAULT ?

@AndrewLeiper
Copy link
Author

Hi,

To be a bit clearer:

  1. Create Application with 2 keys (KS_DEFAULT) - OK
  2. Authenticate App with key 0 (00 00 00 00 00 ...) - OK
  3. Change key 0 to "20 00 00 00 ..." - OK
  4. Authenticate App with key 0 (20 00 00 00 00 ...) - OK
  5. Change key 1 to "30 00 00 00 ..." - OK
  6. Authenticate App with key 1 (30 00 00 00 00 ...) - OK
    ...Now try to change key 1 a second time...
  7. Authenticate App with key 0 (20 00 00 00 00 ...) - OK
  8. Change key 1 to "40 00 00 00 ..."
    ERROR - 'CRC or MAC does not match data / Padding bytes not valid'
  9. Authenticate App with key 0 (20 00 00 00 00 ...) - OK
  10. Change key 0 to "22 00 00 00 ..." - OK

Using (KS_DEFAULT | KS_CHANGE_KEY_WITH_TARGETED_KEYNO) or (KS_DEFAULT | KS_CHANGE_KEY_FROZEN) as you suggested, I only get as far as step 5) where I get:
"Current authentication status does not allow the requested command"

So in other words:
With KS_DEFAULT, I can change Key 1 only once.
With (KS_DEFAULT | KS_CHANGE_KEY_...), I can't change Key 1 at all.

Thanks for your help,

Andy Leiper.

@xaqq
Copy link
Contributor

xaqq commented Nov 12, 2015

May be related to #97

@Liryna
Copy link
Contributor

Liryna commented Nov 12, 2015

@AndrewLeiper , can you try with KS_DEFAULT | KS_CHANGE_KEY_WITH_MK | KS_FREE_LISTING_WITHOUT_MK | KS_CONFIGURATION_CHANGEABLE | KS_CHANGE_KEY_WITH_MK (it is what I use)

@AndrewLeiper
Copy link
Author

@Liryna
That is the same thing as KS_DEFAULT (0x0B). You put KS_CHANGE_KEY_WITH_MK twice. Did you mean to put one of the other options ?

@xaqq
Regarding #97. The workaround for that was to authenticate with key 0 just before the changekey which is what I am doing.

Thanks for the suggestions,

Andy Leiper

@Liryna
Copy link
Contributor

Liryna commented Nov 12, 2015

Sorry I wanted to say KS_DEFAULT | KS_CHANGE_KEY_WITH_MK | KS_FREE_LISTING_WITHOUT_MK | KS_CONFIGURATION_CHANGEABLE | KS_ALLOW_CHANGE_MK.

But from what you say, I think @xaqq is right.

@AndrewLeiper
Copy link
Author

@Liryna
Thanks for the update. Those options are the same as KS_DEFAULT though.

@xaqq
#97 suggests that the operation completes despite the error message. In this case though, I just double checked and the key does not get changed.

Thanks,

Andy.

@Maxhy
Copy link
Member

Maxhy commented Jun 11, 2016

@AndrewLeiper I took the time to test your issue but I cannot reproduce it.
Could you copy/past code snippet you're using? Thanks.

@AndrewLeiper
Copy link
Author

@Maxhy
I don't have the hardware with me at the moment. I'll try and get you simplified test code later this week.
Thanks

@AndrewLeiper
Copy link
Author

AndrewLeiper commented Jun 14, 2016

@Maxhy
Here's the code (in Delphi) calling the V1.80.0.1106 com DLL. If you would like my test program as an EXE, please let me know. Hope it helps.

Andy.

procedure TForm1.GetDESFireCommands;
var
  cmd: ICommands;
begin
  Log('');
  FIDESFireEv1Cmd := nil;
  FIDESFireCmd := nil;

  Log('GetDESFireCommands');
  if Supports(FIChip, IID_IDESFireChip) then
  begin
    Log('Is IDESFireChip');
    cmd := FIChip.Commands;
    if Supports(cmd, IID_IDESFireCommands, FIDESFireCmd) then
    begin
      Log('Is IDESFireCommands');
      //FIDESFireCmd.CreateApplication($000521, KS_DEFAULT, 3);
      //Log('DESFireCmd.CreateApplication($000521, KS_DEFAULT, 3)');
    end;
    if Supports(cmd, IID_IDESFireEV1Commands, FIDESFireEv1Cmd) then
    begin
      Log('Is IDESFireEV1Commands');
      ListDESfireApps;
    end;
  end;
end;

procedure TForm1.ConnectCard;
begin
  DisconnectCard;
  Memo1.Lines.Clear;
  // Explicitly use the PC/SC Reader Provider.
  FIReaderProvider := CoPCSCReaderProvider.Create;
  Log('Got IReaderProvider');
  // Create the default reader unit. On PC/SC, we will listen on all readers.
  FIReaderUnit := FIReaderProvider.CreateReaderUnit();
  Log('Got IReaderUnit');

  if FIReaderUnit.ConnectToReader() then
  begin
    Log('Wait 15s for card>>>>>>>>');
    if FIReaderUnit.WaitInsertion(15000) then
    begin
      Log(Format('Card inserted on:', [FIReaderUnit.Get_ConnectedName]));
      if FIReaderUnit.Connect then
      begin
        Log('OK: readerUnit.Connect');

        Log('readerUnit.ConnectToReader()');
        Log(Format('   Reader name: %s', [FIReaderUnit.name])); //This returns ''
        Log(Format('   Reader connected name: %s', [FIReaderUnit.ConnectedName])); //This returns 'OMNIKEY CardMan 5x21-CL 0'

        FIChip := FIReaderUnit.GetSingleChip();
        Log('');
        Log(Format('Card type: %s', [FIChip.type_]));
        Log(Format('Card generic type: %s', [FIChip.GenericType]));
        Log(Format('Reception level: %d', [FIChip.Get_ReceptionLevel]));
        Log(Format('Chip identifier: %s', [FIChip.ChipIdentifier]));
        Log(Format('Card unique manufacturer number: %s', [FIReaderUnit.GetNumber(FIChip)]));

        GetDESFireCommands;
      end;
    end
    else
    begin
      Log('No card inserted');
    end;
  end;
end;

procedure TForm1.BugTestClick(Sender: TObject);
var
  MasterCardKey: IDESFireKey;
  KeyStr: string;
  KeyNo: Cardinal;

  AppID: Cardinal;
  KeySettings: DESFireKeySettings;
  maxNbKeys: Byte;
  useFid: WordBool;
  CryptoMethod: DESFireKeyType;
  isoFID: Word;
  isoDFName: OleVariant;

begin
  ConnectCard;

  Assert(FIDESFireCmd <> nil);

  //Select Application 0
  Log(Format('FIDESFireCmd.SelectApplication(%d)', [0]));
  FIDESFireCmd.SelectApplication(0);

  //Authenticate Application 0, key 0
  MasterCardKey := FIDESFireAccessInfo.MasterCardKey;
  MasterCardKey.keytype := DF_KEY_DES;
  KeyStr := '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00';
  MasterCardKey.Value := KeyStr;
  KeyNo := 0;
  MasterCardKey.KeyDiversification := nil;
  Log(FIDESFireAccessInfo.MasterCardKey.Value);
  Log(Format('FIDESFireCmd.Authenticate(%d, "%s")', [KeyNo, FIDESFireAccessInfo.MasterCardKey.Value]));
  FIDESFireCmd.Authenticate(KeyNo, FIDESFireAccessInfo.MasterCardKey);


  //Create Application with AppID1 and 2 keys
  Assert(FIDESFireEv1Cmd <> nil);
  AppID := 1;
  KeySettings := KS_DEFAULT;
  maxNbKeys := 2;
  useFid := False;
  CryptoMethod := DF_KEY_DES;
  isoFID := 0;
  isoDFName := 0;
  //Ev1
  Log(Format('FIDESFireCmd.CreateApplicationEV1: AppID=%d, KeySettings=$%2.2X, maxNbKeys=%d, CryptoMethod=%s',
    [AppID, KeySettings, maxNbKeys, DESFireKeyTypeToStr(CryptoMethod)]));
  FIDESFireEv1Cmd.CreateApplicationEV1(
    AppID, //aid: SYSUINT;
    KeySettings, //settings: DESFireKeySettings;
    maxNbKeys, //maxNbKeys: Byte
    useFid, //useFid: WordBool;
    CryptoMethod, //CryptoMethod: DESFireKeyType;
    isoFID, //isoFID: Word;
    isoDFName //isoDFName: OleVariant
    );

  //Select Application 1
  Log(Format('FIDESFireCmd.SelectApplication(%d)', [1]));
  FIDESFireCmd.SelectApplication(1);

  //Authenticate Application 1, key 0
  MasterCardKey := FIDESFireAccessInfo.MasterCardKey;
  MasterCardKey.keytype := DF_KEY_DES;
  KeyStr := '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00';
  MasterCardKey.Value := KeyStr;
  KeyNo := 0;
  MasterCardKey.KeyDiversification := nil;
  Log(FIDESFireAccessInfo.MasterCardKey.Value);
  Log(Format('FIDESFireCmd.Authenticate(%d, "%s")', [KeyNo, FIDESFireAccessInfo.MasterCardKey.Value]));
  FIDESFireCmd.Authenticate(KeyNo, FIDESFireAccessInfo.MasterCardKey);

  //Change Application 1 key 0 to '20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
  MasterCardKey := FIDESFireAccessInfo.MasterCardKey;
  MasterCardKey.keytype := DF_KEY_DES;
  KeyStr := '20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00';
  MasterCardKey.Value := KeyStr;
  KeyNo := 0;
  MasterCardKey.KeyDiversification := nil;
  Log(FIDESFireAccessInfo.MasterCardKey.Value);
  Log(Format('FIDESFireCmd.ChangeKey(%d, "%s")', [KeyNo, FIDESFireAccessInfo.MasterCardKey.Value]));
  FIDESFireCmd.ChangeKey(KeyNo, FIDESFireAccessInfo.MasterCardKey);

  //Authenticate Application 1, key 0
  MasterCardKey := FIDESFireAccessInfo.MasterCardKey;
  MasterCardKey.keytype := DF_KEY_DES;
  KeyStr := '20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00';
  MasterCardKey.Value := KeyStr;
  KeyNo := 0;
  MasterCardKey.KeyDiversification := nil;
  Log(FIDESFireAccessInfo.MasterCardKey.Value);
  Log(Format('FIDESFireCmd.Authenticate(%d, "%s")', [KeyNo, FIDESFireAccessInfo.MasterCardKey.Value]));
  FIDESFireCmd.Authenticate(KeyNo, FIDESFireAccessInfo.MasterCardKey);

  //Change Application 1 key 1 to '30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
  MasterCardKey := FIDESFireAccessInfo.MasterCardKey;
  MasterCardKey.keytype := DF_KEY_DES;
  KeyStr := '30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00';
  MasterCardKey.Value := KeyStr;
  KeyNo := 1;
  MasterCardKey.KeyDiversification := nil;
  Log(FIDESFireAccessInfo.MasterCardKey.Value);
  Log(Format('FIDESFireCmd.ChangeKey(%d, "%s")', [KeyNo, FIDESFireAccessInfo.MasterCardKey.Value]));
  FIDESFireCmd.ChangeKey(KeyNo, FIDESFireAccessInfo.MasterCardKey);

  //Authenticate Application 1, key 0
  MasterCardKey := FIDESFireAccessInfo.MasterCardKey;
  MasterCardKey.keytype := DF_KEY_DES;
  KeyStr := '20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00';
  MasterCardKey.Value := KeyStr;
  KeyNo := 0;
  MasterCardKey.KeyDiversification := nil;
  Log(FIDESFireAccessInfo.MasterCardKey.Value);
  Log(Format('FIDESFireCmd.Authenticate(%d, "%s")', [KeyNo, FIDESFireAccessInfo.MasterCardKey.Value]));
  FIDESFireCmd.Authenticate(KeyNo, FIDESFireAccessInfo.MasterCardKey);

  //Change Application 1 key 1 to '40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
  MasterCardKey := FIDESFireAccessInfo.MasterCardKey;
  MasterCardKey.keytype := DF_KEY_DES;
  KeyStr := '40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00';
  MasterCardKey.Value := KeyStr;
  KeyNo := 1;
  MasterCardKey.KeyDiversification := nil;
  Log(FIDESFireAccessInfo.MasterCardKey.Value);
  Log(Format('FIDESFireCmd.ChangeKey(%d, "%s")', [KeyNo, FIDESFireAccessInfo.MasterCardKey.Value]));
  //***************** FAILS HERE WITH 'CRC or MAC does not match data / Padding bytes not valid' ***********
  FIDESFireCmd.ChangeKey(KeyNo, FIDESFireAccessInfo.MasterCardKey);

end;

@Maxhy
Copy link
Member

Maxhy commented Jun 16, 2016

Indeed I can reproduce your issue when using DES encryption.
I wasn't able to fix it for now. C++ sample to reproduce it:

std::shared_ptr<logicalaccess::DESFireCommands> dcmd = std::dynamic_pointer_cast<logicalaccess::DESFireCommands>(chip->getCommands());
if (dcmd)
{
   dcmd->selectApplication(0);
   dcmd->authenticate(0);
   dcmd->erase();

   std::shared_ptr<logicalaccess::DESFireKey> key0(new logicalaccess::DESFireKey("20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
   std::shared_ptr<logicalaccess::DESFireKey> key1(new logicalaccess::DESFireKey("30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));

   dcmd->createApplication(0x521, logicalaccess::KS_DEFAULT, 3);
   std::cout << "createApplication passed " << std::endl;
   dcmd->selectApplication(0x521);
   std::cout << "selectApplication passed " << std::endl;
   dcmd->authenticate(0);
   std::cout << "auth0 passed " << std::endl;
   dcmd->changeKey(0, key0);
   std::cout << "changeKey0 passed " << std::endl;
   dcmd->authenticate(0, key0);
   std::cout << "auth0 passed " << std::endl;
   dcmd->changeKey(1, key1);
   std::cout << "changeKey1 passed " << std::endl;
   dcmd->authenticate(1, key1);
   std::cout << "auth1 passed " << std::endl;
   dcmd->authenticate(0, key0);
   std::cout << "auth0 passed " << std::endl;
   key1->fromString("40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
   dcmd->changeKey(1, key1); // Fail here
   std::cout << "changeKey1 passed " << std::endl;
}

@AndrewLeiper
Copy link
Author

@Maxhy
Excellent. Thanks, Maxime.

@Maxhy Maxhy added the bug label Jun 30, 2016
@Liryna
Copy link
Contributor

Liryna commented Jul 18, 2016

I have not been able to reproduce the issue BUT I have been able to get the SAME error message when I was authenticating with the correct key value and the wrong version (yes, this work) and this key will be used during changeKey and will fail because the correct version is mandatory here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants