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
|
||||
/// </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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user