Added: ChangeKey AES Same Key

This commit is contained in:
TheJoKlLa 2020-10-08 17:23:48 +02:00
parent 7381341d37
commit 307bd60925
3 changed files with 322 additions and 3 deletions

View File

@ -299,7 +299,7 @@ namespace NFC.Mifare_DESFire
/// Generates SessionKey for DES Authentification
/// </summary>
/// <returns>16Byte SessionKey</returns>
private byte[] GenerateSesionKey_DES(byte[] rndA, byte[] rndB)
public byte[] GenerateSesionKey_DES(byte[] rndA, byte[] rndB)
{
byte[] sesssionkey = new byte[8];
@ -319,6 +319,37 @@ namespace NFC.Mifare_DESFire
return Concatenate(sesssionkey, sesssionkey);
}
/// <summary>
/// Generates SessionKey for AES Authentification
/// </summary>
/// <returns>16Byte SessionKey</returns>
public byte[] GenerateSesionKey_AES(byte[] rndA, byte[] rndB)
{
byte[] sesssionkey = new byte[16];
for (int i = 0; i < sesssionkey.Length; i++)
{
if (i < 4)
{
sesssionkey[i] = rndA[i];
}
else if(i >= 4 && i < 8)
{
sesssionkey[i] = rndB[i - 4];
}
else if (i >= 8 && i < 12)
{
sesssionkey[i] = rndA[i + 4];
}
else
{
sesssionkey[i] = rndB[i];
}
}
return sesssionkey;
}
/// <summary>
/// Set KeyVersion in DES Key
/// KeyVersion is stored in LSB of the first 8 Bytes of the DES Key
@ -347,6 +378,30 @@ namespace NFC.Mifare_DESFire
return new_key;
}
/// <summary>
/// Expand Array to Block Size, fill with 0x00
/// </summary>
/// <param name="data"></param>
public byte[] ExpandToBlockSize(byte[] data, uint bocksize)
{
int diff = data.Length % (int)bocksize;
if (diff == 0)
{
return data;
}
byte[] expand = new byte[data.Length + bocksize - diff];
data.CopyTo(expand, 0);
for (int i = expand.Length - 1; i > data.Length - 1; i--)
{
expand[i] = 0x00;
}
return expand;
}
#endregion
#region DESFire Commands
@ -530,6 +585,147 @@ namespace NFC.Mifare_DESFire
_Log.Debug("End SelectApplication");
}
/// <summary>
/// Authenticate to PICC, with ISO Authenticate
/// </summary>
/// <param name="key_id">0x01 - 0x0D</param>
/// <param name="key"></param>
/// <param name="rndA">!!! WARNING For Testing only !!!</param>
/// <exception cref="AuthenticationDelayException">Retry after short Time</exception>
public void AuthenticateISO_AES(byte key_id, byte[] key, byte[] rndA = null)
{
_Log.Debug("Start AuthenticateISO_AES");
// Sepearte InitialisationVector for Authentication
byte[] iv = new byte[16];
APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short)
{
CLA = 0x90,
INS = 0xAA,
Data = new byte[]
{
key_id
}
};
_Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", ConvertToHexString(cmd_challange_request.ToArray()));
APDUResponse response = _Card.Transmit(cmd_challange_request);
_Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", ConvertToHexString(response.ToArray()));
CheckAPDUResponse(response);
byte[] rndB_enc = response.Body;
_Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_enc));
AES aes = new AES();
byte[] rndB = aes.Decrypt(rndB_enc, key, GenerateEmptyKey(16));
_Log.DebugFormat("rndB: {0}", ConvertToHexString(rndB));
rndB.CopyTo(iv, 0);
byte[] rndB_rl = RotateLeft(rndB);
_Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_rl));
if (rndA == null)
{
Random rnd = new Random();
rndA = new byte[16];
rnd.NextBytes(rndA);
}
_Log.DebugFormat("rndA: {0}", ConvertToHexString(rndA));
byte[] rndAB = Concatenate(rndA, rndB_rl);
_Log.DebugFormat("rndAB: {0}", ConvertToHexString(rndAB));
byte[] rndAB_enc = aes.Encrypt(rndAB, key, rndB_enc);
_Log.DebugFormat("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc));
iv = ExtractLastBlock(rndAB_enc, 16);
APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short)
{
CLA = 0x90,
INS = 0xAF,
Data = rndAB_enc
};
_Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray()));
response = _Card.Transmit(cmd_challange_response);
_Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray()));
CheckAPDUResponse(response);
byte[] encryptedRndAFromCard = response.Body;
_Log.DebugFormat("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard));
byte[] rotatedRndAFromCard = aes.Decrypt(encryptedRndAFromCard, key, iv);
_Log.DebugFormat("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard));
byte[] rndAFromCard = RotateRight(rotatedRndAFromCard);
_Log.DebugFormat("rndAFromCard: {0}", ConvertToHexString(rndAFromCard));
if (!rndA.SequenceEqual(rndAFromCard))
{
throw new Exception("Authentication failed, PICC Challenge is not corret");
}
_SessionKey = GenerateSesionKey_AES(rndA, rndB);
_Log.DebugFormat("_SessionKey: {0}", ConvertToHexString(_SessionKey));
_IV = GenerateEmptyKey(16);
_Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV));
_Log.Debug("End AuthenticateISO_DES");
}
public void ChangeKey_AES(byte key_id, byte[] new_key, byte key_version)
{
_Log.Debug("Start ChangeKey_AES");
byte[] header = new byte[]
{
0xC4, key_id
};
_Log.DebugFormat("header: {0}", ConvertToHexString(header));
// AES Key Version is Append to Key
byte[] key_and_version = Concatenate(new_key, new byte[] { key_version });
byte[] command = Concatenate(header, key_and_version);
_Log.DebugFormat("command: {0}", ConvertToHexString(command));
CRC32 crc32 = new CRC32();
byte[] crc = crc32.Calculate(command);
_Log.DebugFormat("crc: {0}", ConvertToHexString(crc));
byte[] cryptogram = Concatenate(key_and_version, crc);
_Log.DebugFormat("cryptogram: {0}", ConvertToHexString(cryptogram));
byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16);
_Log.DebugFormat("cryptogram_block: {0}", ConvertToHexString(cryptogram_block));
AES aes = new AES();
byte[] cryptogram_enc = aes.Encrypt(cryptogram_block, _SessionKey, _IV);
_Log.DebugFormat("cryptogram_enc: {0}", ConvertToHexString(cryptogram_enc));
byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc);
_Log.DebugFormat("data: {0}", ConvertToHexString(data));
APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short)
{
CLA = 0x90,
INS = 0xC4,
Data = data
};
_Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", ConvertToHexString(cmd_ChangeKey.ToArray()));
APDUResponse response = _Card.Transmit(cmd_ChangeKey);
_Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", ConvertToHexString(response.ToArray()));
CheckAPDUResponse(response);
_Log.Debug("End ChangeKey_AES");
}
#endregion
#region Configuration Generator

View File

@ -3,8 +3,11 @@ using NFC.ISO7816_4;
using NFC.Mifare_DESFire;
using NFC.NXP_MIFARE_DESFire.Exceptions;
using NSubstitute;
using NSubstitute.Core;
using NUnit.Framework;
using PCSC.Iso7816;
using System;
using System.Collections.Generic;
using System.Net;
namespace NFC_Test
@ -508,6 +511,24 @@ namespace NFC_Test
byte[] lastblock = desfire.XOR(null, null);
});
}
[Test]
public void GenerateSessionKey_AES()
{
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null);
byte[] rndA = desfire.ConvertFromHexString("bc14dfde20074617e45a8822f06fdd91");
Console.WriteLine(desfire.ConvertToHexString(rndA));
byte[] rndB = desfire.ConvertFromHexString("482ddc54426e6dee560413b8d95471f5");
Console.WriteLine(desfire.ConvertToHexString(rndB));
byte[] expected_sessionkey = desfire.ConvertFromHexString("bc14dfde482ddc54f06fdd91d95471f5");
Console.WriteLine(desfire.ConvertToHexString(expected_sessionkey));
byte[] sessionkey = desfire.GenerateSesionKey_AES(rndA, rndB);
Console.WriteLine(desfire.ConvertToHexString(sessionkey));
Assert.AreEqual(expected_sessionkey, sessionkey);
}
#endregion
#region DESFire Commands
@ -546,6 +567,68 @@ namespace NFC_Test
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
Assert.AreEqual(expected_iv, desfire._IV);
}
[Test]
public void AuthenticateISO_AES()
{
ICard card = Substitute.For<ICard>();
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
APDUResponse response_challenge_request = new APDUResponse()
{
SW1 = 0x91,
SW2 = 0xAF,
Body = desfire.ConvertFromHexString("43a28e28c653df83cd85039714bccb51")
};
APDUResponse response_challenge_response = new APDUResponse()
{
SW1 = 0x91,
SW2 = 0x00,
Body = desfire.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f")
};
byte[] rndA = desfire.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1");
byte[] key = desfire.ConvertFromHexString("00000000000000000000000000000000");
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAA)).Returns(response_challenge_request);
card.Transmit(Arg.Is<APDUCommand>(x => x.INS == 0xAF)).Returns(response_challenge_response);
desfire.AuthenticateISO_AES(0x00, key, rndA);
byte[] expected_sessionkey = desfire.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703");
byte[] expected_iv = desfire.GenerateEmptyKey(16);
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
Assert.AreEqual(expected_iv, desfire._IV);
}
[Test]
public void ChangeKey_AES()
{
ICard card = Substitute.For<ICard>();
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
APDUResponse response = new APDUResponse()
{
SW1 = 0x91,
SW2 = 0x00
};
byte[] new_key = desfire.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530");
byte[] sessionkey = desfire.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3");
byte[] iv = desfire.ConvertFromHexString("00000000000000000000000000000000");
desfire._SessionKey = sessionkey;
desfire._IV = iv;
card.Transmit(null).ReturnsForAnyArgs(response);
desfire.ChangeKey_AES(0x00, new_key, 0x10);
}
#endregion
}
}

View File

@ -39,9 +39,49 @@ namespace NFC_Test
byte keySetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
byte keySetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 0x03);
desfire.CreateApplication(0xAAFFEE, keySetting1, keySetting2);
desfire.CreateApplication(0xC0FFEE, keySetting1, keySetting2);
desfire.SelectApplication(0xAAFFEE);
desfire.SelectApplication(0xC0FFEE);
desfire.AuthenticateISO_AES(0x00, desfire.GenerateEmptyKey(16));
byte[] new_key = desfire.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530");
desfire.ChangeKey_AES(0x00, new_key, 0x10);
transmit_successfully = true;
card.Disconnect();
};
reader.CardDiscovered += handler;
reader.Start();
Assert.AreEqual(true, transmit_successfully);
reader.Stop();
reader.CardDiscovered -= handler;
}
[Test]
public void ChangeKey()
{
IHardware hardware = new Hardware();
IReader reader = hardware.OpenReader(_ReaderID);
bool transmit_successfully = false;
ReaderEventHandler handler = (sender, card) =>
{
card.Connect();
MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card);
desfire.SelectApplication(0xC0FFEE);
desfire.AuthenticateISO_AES(0x00, desfire.GenerateEmptyKey(16));
byte[] new_key = desfire.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530");
desfire.ChangeKey_AES(0x00, new_key, 0x10);
transmit_successfully = true;