mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-06-11 11:03:23 +02:00
Added: ChangeKey AES Same Key
This commit is contained in:
@ -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
|
||||
|
Reference in New Issue
Block a user