mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-04-20 18:36:31 +02:00
Added: ChangeKey AES Same Key
This commit is contained in:
parent
7381341d37
commit
307bd60925
@ -299,7 +299,7 @@ namespace NFC.Mifare_DESFire
|
|||||||
/// Generates SessionKey for DES Authentification
|
/// Generates SessionKey for DES Authentification
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>16Byte SessionKey</returns>
|
/// <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];
|
byte[] sesssionkey = new byte[8];
|
||||||
|
|
||||||
@ -319,6 +319,37 @@ namespace NFC.Mifare_DESFire
|
|||||||
return Concatenate(sesssionkey, sesssionkey);
|
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>
|
/// <summary>
|
||||||
/// Set KeyVersion in DES Key
|
/// Set KeyVersion in DES Key
|
||||||
/// KeyVersion is stored in LSB of the first 8 Bytes of the 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;
|
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
|
#endregion
|
||||||
|
|
||||||
#region DESFire Commands
|
#region DESFire Commands
|
||||||
@ -530,6 +585,147 @@ namespace NFC.Mifare_DESFire
|
|||||||
|
|
||||||
_Log.Debug("End SelectApplication");
|
_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
|
#endregion
|
||||||
|
|
||||||
#region Configuration Generator
|
#region Configuration Generator
|
||||||
|
@ -3,8 +3,11 @@ using NFC.ISO7816_4;
|
|||||||
using NFC.Mifare_DESFire;
|
using NFC.Mifare_DESFire;
|
||||||
using NFC.NXP_MIFARE_DESFire.Exceptions;
|
using NFC.NXP_MIFARE_DESFire.Exceptions;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
|
using NSubstitute.Core;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using PCSC.Iso7816;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace NFC_Test
|
namespace NFC_Test
|
||||||
@ -508,6 +511,24 @@ namespace NFC_Test
|
|||||||
byte[] lastblock = desfire.XOR(null, null);
|
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
|
#endregion
|
||||||
|
|
||||||
#region DESFire Commands
|
#region DESFire Commands
|
||||||
@ -546,6 +567,68 @@ namespace NFC_Test
|
|||||||
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
Assert.AreEqual(expected_sessionkey, desfire._SessionKey);
|
||||||
Assert.AreEqual(expected_iv, desfire._IV);
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,49 @@ namespace NFC_Test
|
|||||||
|
|
||||||
byte keySetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
|
byte keySetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
|
||||||
byte keySetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 0x03);
|
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;
|
transmit_successfully = true;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user