@ -1,5 +1,4 @@
using log4net.Repository.Hierarchy ;
using NFC.Crypto ;
using NFC.Crypto ;
using NFC.ISO7816_4 ;
using NFC.Mifare_DESFire.Enums ;
using NFC.NXP_MIFARE_DESFire.Exceptions ;
@ -7,7 +6,6 @@ using PCSC.Iso7816;
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Reflection ;
namespace NFC.Mifare_DESFire
{
@ -54,7 +52,7 @@ namespace NFC.Mifare_DESFire
/// Generate Byte Array filled with 0
/// </summary>
/// <param name="size">Size of Array</param>
public byte [ ] GenerateEmptyKe y ( uint size )
public byte [ ] GenerateEmptyArra y ( uint size )
{
byte [ ] key = new byte [ size ] ;
for ( int i = 0 ; i < size ; i + + )
@ -66,42 +64,12 @@ namespace NFC.Mifare_DESFire
}
/// <summary>
/// Converts byte[] to string with HEX Code
/// No 0x is created
/// Get Range of Array Elements
/// </summary>
/// <param name="data">Data </param>
public string ConvertToHexString ( byte [ ] data )
{
return BitConverter . ToString ( data ) . Replace ( "-" , "" ) . ToLower ( ) ;
}
/// <summary>
/// Converts string with HEX Code to byte[]
/// No 0x is requiered
/// </summary>
/// <param name="data">Data</param>
public byte [ ] ConvertFromHexString ( string data )
{
if ( data . Length % 2 = = 1 )
throw new Exception ( "Data Length is uneven." ) ;
byte [ ] arr = new byte [ data . Length > > 1 ] ;
for ( int i = 0 ; i < data . Length > > 1 ; + + i )
{
arr [ i ] = ( byte ) ( ( GetHexVal ( data [ i < < 1 ] ) < < 4 ) + ( GetHexVal ( data [ ( i < < 1 ) + 1 ] ) ) ) ;
}
return arr ;
}
/// <summary>
/// Get Range of Array
/// </summary>
/// <param name="array"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
/// <returns></returns>
/// <param name="array">Array </param>
/// <param name="offset">Offset in Byte</param>
/// <param name="length">Lenght to read in Byte</param>
/// <returns>new Array with Range of Array Elements</returns>
public byte [ ] GetSubArray ( byte [ ] array , long offset , long length )
{
byte [ ] subarray = new byte [ length ] ;
@ -112,17 +80,6 @@ namespace NFC.Mifare_DESFire
return subarray ;
}
private int GetHexVal ( char hex )
{
int val = ( int ) hex ;
//For uppercase A-F letters:
//return val - (val < 58 ? 48 : 55);
//For lowercase a-f letters:
//return val - (val < 58 ? 48 : 87);
//Or the two combined, but a bit slower:
return val - ( val < 58 ? 48 : ( val < 97 ? 55 : 87 ) ) ;
}
/// <summary>
/// Check APDU Response for DESFire Error Codes
/// https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf
@ -206,6 +163,35 @@ namespace NFC.Mifare_DESFire
return lastblock ;
}
/// <summary>
/// Expand Array to Block Size, fill with 0x00
/// </summary>
/// <param name="data"></param>
public byte [ ] ExpandToBlockSize ( byte [ ] data , uint bocksize )
{
if ( data = = null )
{
throw new ArgumentNullException ( "Data cannot be null." ) ;
}
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 ;
}
/// <summary>
/// Rotates Array to the left
/// </summary>
@ -310,6 +296,7 @@ namespace NFC.Mifare_DESFire
return c ;
}
/// <summary>
/// Generates SessionKey for DES Authentification
/// </summary>
@ -364,62 +351,89 @@ namespace NFC.Mifare_DESFire
return sesssionkey ;
}
#endregion
#region Configuration Generator
/// <summary>
/// Set KeyVersion in DES Key
/// KeyVersion is stored in LSB of the first 8 Bytes of the DES Key
/// Genearte KeySetting1 for Application Settings or PICC Setting
/// </summary>
public byte [ ] SetKeyVersion ( byte [ ] key , byte keyversion )
public byte GenerateKeySetting1 ( ChangeApplicationKey changeKey , ChangeMasterKeySettings changeMasterKeySettings , CreateDeleteFile createDeleteFile , FileDirectoryAccess fileDirectoryAccess , ChangeMasterKey changeMasterKey )
{
byte [ ] pow2 = new byte [ ]
{
0x01 , 0x02 , 0x04 , 0x08 , 0x10 , 0x20 , 0x40 , 0x80
} ;
byte [ ] new_key = new byte [ key . Length ] ;
key . CopyTo ( new_key , 0 ) ;
for ( int i = 0 ; i < 8 ; i + + )
{
if ( ( keyversion & pow2 [ i ] ) > 0 )
{
new_key [ i ] = ( byte ) ( new_key [ 5 ] | 0x01 ) ;
}
else
{
new_key [ i ] = ( byte ) ( new_key [ 5 ] & 0x7F ) ;
}
}
return new_key ;
return ( byte ) ( ( ( byte ) changeKey < < 4 ) | ( byte ) changeMasterKeySettings | ( byte ) createDeleteFile | ( byte ) fileDirectoryAccess | ( byte ) changeMasterKey ) ;
}
/// <summary>
/// Expand Array to Block Size, fill with 0x00
/// Genearte KeySetting1 for Application Settings or PICC Setting
/// </summary>
/// <param name="data"> </param>
public byte [ ] ExpandToBlockSize ( byte [ ] data , uint bocksize )
/// <param name="changeKey">ID of Key for changing Application Keys </param>
/// <returns></returns>
public byte GenerateKeySetting1 ( byte changeKey , ChangeMasterKeySettings changeMasterKeySettings , CreateDeleteFile createDeleteFile , FileDirectoryAccess fileDirectoryAccess , ChangeMasterKey changeMasterKey )
{
int diff = data . Length % ( int ) bocksize ;
if ( diff = = 0 )
if ( changeKey < 0x01 | | changeKey > = 0x0E )
{
return data ;
throw new ArgumentOutOfRangeException ( ) ;
}
return GenerateKeySetting1 ( ( ChangeApplicationKey ) changeKey , changeMasterKeySettings , createDeleteFile , fileDirectoryAccess , changeMasterKey ) ;
}
/// <summary>
/// Genearte KeySetting2 for Application Creation
/// </summary>
/// <param name="numberOfKeys">Number of keys that can be stored within the application (0x01-0x0D)</param>
/// <returns></returns>
public byte GenerateKeySetting2 ( CryptoOperationsType cryptoOperations , FileIdentifies fileIdentifies , byte numberOfKeys )
{
if ( numberOfKeys < 0x01 | | numberOfKeys > = 0x0D )
{
throw new ArgumentOutOfRangeException ( ) ;
}
byte [ ] expand = new byte [ data . Length + bocksize - diff ] ;
return ( byte ) ( ( byte ) cryptoOperations | ( byte ) fileIdentifies | numberOfKeys ) ;
}
data . CopyTo ( expand , 0 ) ;
for ( int i = expand . Length - 1 ; i > data . Length - 1 ; i - - )
/// <summary>
/// Generate FileAccess Rights for File Settings
/// Use enum AccesRights for Free or Never Option
/// </summary>
/// <param name="read">KeyID for Read Access</param>
/// <param name="write">KeyID for Write Access</param>
/// <param name="read_write">KeyID for Read and Write Access</param>
/// <param name="configure">KeyID for Configuration Access</param>
public UInt16 GenerateFileAccessRights ( byte read , byte write , byte read_write , byte configure )
{
if ( read > 0x0F | | write > 0x0F | | read_write > 0x0F | | configure > 0x0F )
{
expand [ i ] = 0x00 ;
throw new ArgumentOutOfRangeException ( "One KeyID is not valid" ) ;
}
return expand ;
return ( UInt16 ) ( ( read < < 12 ) | ( write < < 8 ) | ( read_write < < 4 ) | configure ) ;
}
#endregion
#region DESFire Commands
/// <summary>
/// Format PICC
/// Works after PICC Authentication
/// </summary>
public void Format ( )
{
_Log . Debug ( "Start Format" ) ;
APDUCommand cmd_format = new APDUCommand ( IsoCase . Case2Short )
{
CLA = 0x90 ,
INS = 0xFC ,
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_format): {0}" , HexConverter . ConvertToHexString ( cmd_format . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_format ) ;
_Log . DebugFormat ( "APDU_RES(cmd_format): {0}" , HexConverter . ConvertToHexString ( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
_Log . Debug ( "End Format" ) ;
}
/// <summary>
/// Authenticate to PICC, with ISO Authenticate
/// </summary>
@ -443,24 +457,24 @@ namespace NFC.Mifare_DESFire
key_id
}
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_request): {0}" , ConvertToHexString ( cmd_challange_request . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_request): {0}" , HexConverter . ConvertToHexString( cmd_challange_request . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_challange_request ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_request): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_request): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
byte [ ] rndB_enc = response . Body ;
_Log . DebugFormat ( "rndB_enc: {0}" , ConvertToHexString ( rndB_enc ) ) ;
_Log . DebugFormat ( "rndB_enc: {0}" , HexConverter . ConvertToHexString( rndB_enc ) ) ;
TDES des = new TDES ( ) ;
byte [ ] rndB = des . Decrypt ( rndB_enc , key , GenerateEmptyKe y ( 8 ) ) ;
_Log . DebugFormat ( "rndB: {0}" , ConvertToHexString ( rndB ) ) ;
byte [ ] rndB = des . Decrypt ( rndB_enc , key , GenerateEmptyArra y ( 8 ) ) ;
_Log . DebugFormat ( "rndB: {0}" , HexConverter . ConvertToHexString( rndB ) ) ;
rndB . CopyTo ( iv , 0 ) ;
byte [ ] rndB_rl = RotateLeft ( rndB ) ;
_Log . DebugFormat ( "rndB_enc: {0}" , ConvertToHexString ( rndB_rl ) ) ;
_Log . DebugFormat ( "rndB_enc: {0}" , HexConverter . ConvertToHexString( rndB_rl ) ) ;
if ( rndA = = null )
{
@ -468,13 +482,13 @@ namespace NFC.Mifare_DESFire
rndA = new byte [ 8 ] ;
rnd . NextBytes ( rndA ) ;
}
_Log . DebugFormat ( "rndA: {0}" , ConvertToHexString ( rndA ) ) ;
_Log . DebugFormat ( "rndA: {0}" , HexConverter . ConvertToHexString( rndA ) ) ;
byte [ ] rndAB = Concatenate ( rndA , rndB_rl ) ;
_Log . DebugFormat ( "rndAB: {0}" , ConvertToHexString ( rndAB ) ) ;
_Log . DebugFormat ( "rndAB: {0}" , HexConverter . ConvertToHexString( rndAB ) ) ;
byte [ ] rndAB_enc = des . Encrypt ( rndAB , key , rndB_enc ) ;
_Log . DebugFormat ( "rndA_rndB_enc: {0}" , ConvertToHexString ( rndAB_enc ) ) ;
_Log . DebugFormat ( "rndA_rndB_enc: {0}" , HexConverter . ConvertToHexString( rndAB_enc ) ) ;
iv = ExtractLastBlock ( rndAB_enc , 8 ) ;
APDUCommand cmd_challange_response = new APDUCommand ( IsoCase . Case4Short )
@ -483,21 +497,21 @@ namespace NFC.Mifare_DESFire
INS = 0xAF ,
Data = rndAB_enc
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_response): {0}" , ConvertToHexString ( cmd_challange_response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_response): {0}" , HexConverter . ConvertToHexString( cmd_challange_response . ToArray ( ) ) ) ;
response = _Card . Transmit ( cmd_challange_response ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_response): {0}" , ConvertToHexString ( cmd_challange_response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_response): {0}" , HexConverter . ConvertToHexString( cmd_challange_response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
byte [ ] encryptedRndAFromCard = response . Body ;
_Log . DebugFormat ( "encryptedRndAFromCard: {0}" , ConvertToHexString ( encryptedRndAFromCard ) ) ;
_Log . DebugFormat ( "encryptedRndAFromCard: {0}" , HexConverter . ConvertToHexString( encryptedRndAFromCard ) ) ;
byte [ ] rotatedRndAFromCard = des . Decrypt ( encryptedRndAFromCard , key , iv ) ;
_Log . DebugFormat ( "rotatedRndAFromCard: {0}" , ConvertToHexString ( rotatedRndAFromCard ) ) ;
_Log . DebugFormat ( "rotatedRndAFromCard: {0}" , HexConverter . ConvertToHexString( rotatedRndAFromCard ) ) ;
byte [ ] rndAFromCard = RotateRight ( rotatedRndAFromCard ) ;
_Log . DebugFormat ( "rndAFromCard: {0}" , ConvertToHexString ( rndAFromCard ) ) ;
_Log . DebugFormat ( "rndAFromCard: {0}" , HexConverter . ConvertToHexString( rndAFromCard ) ) ;
if ( ! rndA . SequenceEqual ( rndAFromCard ) )
{
@ -505,36 +519,14 @@ namespace NFC.Mifare_DESFire
}
_SessionKey = GenerateSesionKey_DES ( rndA , rndB ) ;
_Log . DebugFormat ( "_SessionKey: {0}" , ConvertToHexString ( _SessionKey ) ) ;
_Log . DebugFormat ( "_SessionKey: {0}" , HexConverter . ConvertToHexString( _SessionKey ) ) ;
_IV = GenerateEmptyKe y ( 8 ) ;
_Log . DebugFormat ( "_IV: {0}" , ConvertToHexString ( _IV ) ) ;
_IV = GenerateEmptyArra y ( 8 ) ;
_Log . DebugFormat ( "_IV: {0}" , HexConverter . ConvertToHexString( _IV ) ) ;
_Log . Debug ( "End AuthenticateISO_DES" ) ;
}
/// <summary>
/// Format PICC
/// </summary>
public void Format ( )
{
_Log . Debug ( "Start Format" ) ;
APDUCommand cmd_format = new APDUCommand ( IsoCase . Case2Short )
{
CLA = 0x90 ,
INS = 0xFC ,
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_format): {0}" , ConvertToHexString ( cmd_format . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_format ) ;
_Log . DebugFormat ( "APDU_RES(cmd_format): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
_Log . Debug ( "End Format" ) ;
}
/// <summary>
/// Create Application for ID
/// </summary>
@ -544,7 +536,7 @@ namespace NFC.Mifare_DESFire
_Log . Debug ( "Start CreateApplication" ) ;
byte [ ] id_byte = BitConverter . GetBytes ( aid ) ;
_Log . DebugFormat ( "AID: {0}" , ConvertToHexString ( id_byte . ToArray ( ) ) ) ;
_Log . DebugFormat ( "AID: {0}" , HexConverter . ConvertToHexString( id_byte . ToArray ( ) ) ) ;
APDUCommand cmd_CreateApplication = new APDUCommand ( IsoCase . Case4Short )
{
@ -559,10 +551,10 @@ namespace NFC.Mifare_DESFire
keysetting2
}
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_CreateApplication): {0}" , ConvertToHexString ( cmd_CreateApplication . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_CreateApplication): {0}" , HexConverter . ConvertToHexString( cmd_CreateApplication . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_CreateApplication ) ;
_Log . DebugFormat ( "APDU_RES(cmd_CreateApplication): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_CreateApplication): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
@ -578,7 +570,7 @@ namespace NFC.Mifare_DESFire
_Log . Debug ( "Start SelectApplication" ) ;
byte [ ] id_byte = BitConverter . GetBytes ( aid ) ;
_Log . DebugFormat ( "AID: {0}" , ConvertToHexString ( id_byte . ToArray ( ) ) ) ;
_Log . DebugFormat ( "AID: {0}" , HexConverter . ConvertToHexString( id_byte . ToArray ( ) ) ) ;
APDUCommand cmd_SelectApplication = new APDUCommand ( IsoCase . Case4Short )
{
@ -591,10 +583,10 @@ namespace NFC.Mifare_DESFire
id_byte [ 2 ]
}
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_SelectApplication): {0}" , ConvertToHexString ( cmd_SelectApplication . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_SelectApplication): {0}" , HexConverter . ConvertToHexString( cmd_SelectApplication . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_SelectApplication ) ;
_Log . DebugFormat ( "APDU_RES(cmd_SelectApplication): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_SelectApplication): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
@ -624,24 +616,24 @@ namespace NFC.Mifare_DESFire
key_id
}
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_request): {0}" , ConvertToHexString ( cmd_challange_request . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_request): {0}" , HexConverter . ConvertToHexString( cmd_challange_request . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_challange_request ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_request): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_request): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
byte [ ] rndB_enc = response . Body ;
_Log . DebugFormat ( "rndB_enc: {0}" , ConvertToHexString ( rndB_enc ) ) ;
_Log . DebugFormat ( "rndB_enc: {0}" , HexConverter . ConvertToHexString( rndB_enc ) ) ;
AES aes = new AES ( ) ;
byte [ ] rndB = aes . Decrypt ( rndB_enc , key , GenerateEmptyKe y ( 16 ) ) ;
_Log . DebugFormat ( "rndB: {0}" , ConvertToHexString ( rndB ) ) ;
byte [ ] rndB = aes . Decrypt ( rndB_enc , key , GenerateEmptyArra y ( 16 ) ) ;
_Log . DebugFormat ( "rndB: {0}" , HexConverter . ConvertToHexString( rndB ) ) ;
rndB . CopyTo ( iv , 0 ) ;
byte [ ] rndB_rl = RotateLeft ( rndB ) ;
_Log . DebugFormat ( "rndB_enc: {0}" , ConvertToHexString ( rndB_rl ) ) ;
_Log . DebugFormat ( "rndB_enc: {0}" , HexConverter . ConvertToHexString( rndB_rl ) ) ;
if ( rndA = = null )
{
@ -649,13 +641,13 @@ namespace NFC.Mifare_DESFire
rndA = new byte [ 16 ] ;
rnd . NextBytes ( rndA ) ;
}
_Log . DebugFormat ( "rndA: {0}" , ConvertToHexString ( rndA ) ) ;
_Log . DebugFormat ( "rndA: {0}" , HexConverter . ConvertToHexString( rndA ) ) ;
byte [ ] rndAB = Concatenate ( rndA , rndB_rl ) ;
_Log . DebugFormat ( "rndAB: {0}" , ConvertToHexString ( rndAB ) ) ;
_Log . DebugFormat ( "rndAB: {0}" , HexConverter . ConvertToHexString( rndAB ) ) ;
byte [ ] rndAB_enc = aes . Encrypt ( rndAB , key , rndB_enc ) ;
_Log . DebugFormat ( "rndA_rndB_enc: {0}" , ConvertToHexString ( rndAB_enc ) ) ;
_Log . DebugFormat ( "rndA_rndB_enc: {0}" , HexConverter . ConvertToHexString( rndAB_enc ) ) ;
iv = ExtractLastBlock ( rndAB_enc , 16 ) ;
APDUCommand cmd_challange_response = new APDUCommand ( IsoCase . Case4Short )
@ -664,21 +656,21 @@ namespace NFC.Mifare_DESFire
INS = 0xAF ,
Data = rndAB_enc
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_response): {0}" , ConvertToHexString ( cmd_challange_response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_challange_response): {0}" , HexConverter . ConvertToHexString( cmd_challange_response . ToArray ( ) ) ) ;
response = _Card . Transmit ( cmd_challange_response ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_response): {0}" , ConvertToHexString ( cmd_challange_response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_challange_response): {0}" , HexConverter . ConvertToHexString( cmd_challange_response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
byte [ ] encryptedRndAFromCard = response . Body ;
_Log . DebugFormat ( "encryptedRndAFromCard: {0}" , ConvertToHexString ( encryptedRndAFromCard ) ) ;
_Log . DebugFormat ( "encryptedRndAFromCard: {0}" , HexConverter . ConvertToHexString( encryptedRndAFromCard ) ) ;
byte [ ] rotatedRndAFromCard = aes . Decrypt ( encryptedRndAFromCard , key , iv ) ;
_Log . DebugFormat ( "rotatedRndAFromCard: {0}" , ConvertToHexString ( rotatedRndAFromCard ) ) ;
_Log . DebugFormat ( "rotatedRndAFromCard: {0}" , HexConverter . ConvertToHexString( rotatedRndAFromCard ) ) ;
byte [ ] rndAFromCard = RotateRight ( rotatedRndAFromCard ) ;
_Log . DebugFormat ( "rndAFromCard: {0}" , ConvertToHexString ( rndAFromCard ) ) ;
_Log . DebugFormat ( "rndAFromCard: {0}" , HexConverter . ConvertToHexString( rndAFromCard ) ) ;
if ( ! rndA . SequenceEqual ( rndAFromCard ) )
{
@ -686,10 +678,10 @@ namespace NFC.Mifare_DESFire
}
_SessionKey = GenerateSesionKey_AES ( rndA , rndB ) ;
_Log . DebugFormat ( "_SessionKey: {0}" , ConvertToHexString ( _SessionKey ) ) ;
_Log . DebugFormat ( "_SessionKey: {0}" , HexConverter . ConvertToHexString( _SessionKey ) ) ;
_IV = GenerateEmptyKe y ( 16 ) ;
_Log . DebugFormat ( "_IV: {0}" , ConvertToHexString ( _IV ) ) ;
_IV = GenerateEmptyArra y ( 16 ) ;
_Log . DebugFormat ( "_IV: {0}" , HexConverter . ConvertToHexString( _IV ) ) ;
_Log . Debug ( "End AuthenticateISO_DES" ) ;
}
@ -708,31 +700,31 @@ namespace NFC.Mifare_DESFire
{
0xC4 , key_id
} ;
_Log . DebugFormat ( "header: {0}" , ConvertToHexString ( header ) ) ;
_Log . DebugFormat ( "header: {0}" , HexConverter . ConvertToHexString( header ) ) ;
byte [ ] key_and_version = new_key ;
byte [ ] command = Concatenate ( header , key_and_version ) ;
_Log . DebugFormat ( "command: {0}" , ConvertToHexString ( command ) ) ;
_Log . DebugFormat ( "command: {0}" , HexConverter . ConvertToHexString( command ) ) ;
CRC32 crc32 = new CRC32 ( ) ;
byte [ ] crc = crc32 . Calculate ( command ) ;
_Log . DebugFormat ( "crc: {0}" , ConvertToHexString ( crc ) ) ;
_Log . DebugFormat ( "crc: {0}" , HexConverter . ConvertToHexString( crc ) ) ;
byte [ ] cryptogram = Concatenate ( key_and_version , crc ) ;
_Log . DebugFormat ( "cryptogram: {0}" , ConvertToHexString ( cryptogram ) ) ;
_Log . DebugFormat ( "cryptogram: {0}" , HexConverter . ConvertToHexString( cryptogram ) ) ;
byte [ ] cryptogram_block = ExpandToBlockSize ( cryptogram , 16 ) ;
_Log . DebugFormat ( "cryptogram_block: {0}" , ConvertToHexString ( cryptogram_block ) ) ;
_Log . DebugFormat ( "cryptogram_block: {0}" , HexConverter . ConvertToHexString( cryptogram_block ) ) ;
TDES des = new TDES ( ) ;
byte [ ] cryptogram_enc = des . Encrypt ( cryptogram_block , _SessionKey , _IV ) ;
_Log . DebugFormat ( "cryptogram_enc: {0}" , ConvertToHexString ( cryptogram_enc ) ) ;
_Log . DebugFormat ( "cryptogram_enc: {0}" , HexConverter . ConvertToHexString( cryptogram_enc ) ) ;
_IV = ExtractLastBlock ( cryptogram_enc , 8 ) ;
_Log . DebugFormat ( "_IV: {0}" , ConvertToHexString ( _IV ) ) ;
_Log . DebugFormat ( "_IV: {0}" , HexConverter . ConvertToHexString( _IV ) ) ;
byte [ ] data = Concatenate ( new byte [ ] { key_id } , cryptogram_enc ) ;
_Log . DebugFormat ( "data: {0}" , ConvertToHexString ( data ) ) ;
_Log . DebugFormat ( "data: {0}" , HexConverter . ConvertToHexString( data ) ) ;
APDUCommand cmd_ChangeKey = new APDUCommand ( IsoCase . Case4Short )
{
@ -740,10 +732,10 @@ namespace NFC.Mifare_DESFire
INS = 0xC4 ,
Data = data
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_ChangeKey): {0}" , ConvertToHexString ( cmd_ChangeKey . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_ChangeKey): {0}" , HexConverter . ConvertToHexString( cmd_ChangeKey . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_ChangeKey ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ChangeKey): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ChangeKey): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
@ -764,32 +756,32 @@ namespace NFC.Mifare_DESFire
{
0xC4 , key_id
} ;
_Log . DebugFormat ( "header: {0}" , ConvertToHexString ( header ) ) ;
_Log . DebugFormat ( "header: {0}" , HexConverter . 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 ) ) ;
_Log . DebugFormat ( "command: {0}" , HexConverter . ConvertToHexString( command ) ) ;
CRC32 crc32 = new CRC32 ( ) ;
byte [ ] crc = crc32 . Calculate ( command ) ;
_Log . DebugFormat ( "crc: {0}" , ConvertToHexString ( crc ) ) ;
_Log . DebugFormat ( "crc: {0}" , HexConverter . ConvertToHexString( crc ) ) ;
byte [ ] cryptogram = Concatenate ( key_and_version , crc ) ;
_Log . DebugFormat ( "cryptogram: {0}" , ConvertToHexString ( cryptogram ) ) ;
_Log . DebugFormat ( "cryptogram: {0}" , HexConverter . ConvertToHexString( cryptogram ) ) ;
byte [ ] cryptogram_block = ExpandToBlockSize ( cryptogram , 16 ) ;
_Log . DebugFormat ( "cryptogram_block: {0}" , ConvertToHexString ( cryptogram_block ) ) ;
_Log . DebugFormat ( "cryptogram_block: {0}" , HexConverter . ConvertToHexString( cryptogram_block ) ) ;
AES aes = new AES ( ) ;
byte [ ] cryptogram_enc = aes . Encrypt ( cryptogram_block , _SessionKey , _IV ) ;
_Log . DebugFormat ( "cryptogram_enc: {0}" , ConvertToHexString ( cryptogram_enc ) ) ;
_Log . DebugFormat ( "cryptogram_enc: {0}" , HexConverter . ConvertToHexString( cryptogram_enc ) ) ;
_IV = ExtractLastBlock ( cryptogram_enc , 16 ) ;
_Log . DebugFormat ( "_IV: {0}" , ConvertToHexString ( _IV ) ) ;
_Log . DebugFormat ( "_IV: {0}" , HexConverter . ConvertToHexString( _IV ) ) ;
byte [ ] data = Concatenate ( new byte [ ] { key_id } , cryptogram_enc ) ;
_Log . DebugFormat ( "data: {0}" , ConvertToHexString ( data ) ) ;
_Log . DebugFormat ( "data: {0}" , HexConverter . ConvertToHexString( data ) ) ;
APDUCommand cmd_ChangeKey = new APDUCommand ( IsoCase . Case4Short )
{
@ -797,10 +789,10 @@ namespace NFC.Mifare_DESFire
INS = 0xC4 ,
Data = data
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_ChangeKey): {0}" , ConvertToHexString ( cmd_ChangeKey . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_ChangeKey): {0}" , HexConverter . ConvertToHexString( cmd_ChangeKey . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_ChangeKey ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ChangeKey): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ChangeKey): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
@ -821,37 +813,37 @@ namespace NFC.Mifare_DESFire
{
0xC4 , key_id
} ;
_Log . DebugFormat ( "header: {0}" , ConvertToHexString ( header ) ) ;
_Log . DebugFormat ( "header: {0}" , HexConverter . ConvertToHexString( header ) ) ;
byte [ ] key_xor = XOR ( new_key , old_key ) ;
// AES Key Version is Append to Key
byte [ ] key_and_version = Concatenate ( key_xor , new byte [ ] { key_version } ) ;
byte [ ] command = Concatenate ( header , key_and_version ) ;
_Log . DebugFormat ( "command: {0}" , ConvertToHexString ( command ) ) ;
_Log . DebugFormat ( "command: {0}" , HexConverter . ConvertToHexString( command ) ) ;
CRC32 crc32 = new CRC32 ( ) ;
byte [ ] crc_cmd = crc32 . Calculate ( command ) ;
_Log . DebugFormat ( "crc_cmd: {0}" , ConvertToHexString ( crc_cmd ) ) ;
_Log . DebugFormat ( "crc_cmd: {0}" , HexConverter . ConvertToHexString( crc_cmd ) ) ;
byte [ ] crc_key = crc32 . Calculate ( new_key ) ;
_Log . DebugFormat ( "crc_key: {0}" , ConvertToHexString ( crc_key ) ) ;
_Log . DebugFormat ( "crc_key: {0}" , HexConverter . ConvertToHexString( crc_key ) ) ;
byte [ ] cryptogram = Concatenate ( key_and_version , crc_cmd ) ;
cryptogram = Concatenate ( cryptogram , crc_key ) ;
_Log . DebugFormat ( "cryptogram: {0}" , ConvertToHexString ( cryptogram ) ) ;
_Log . DebugFormat ( "cryptogram: {0}" , HexConverter . ConvertToHexString( cryptogram ) ) ;
byte [ ] cryptogram_block = ExpandToBlockSize ( cryptogram , 16 ) ;
_Log . DebugFormat ( "cryptogram_block: {0}" , ConvertToHexString ( cryptogram_block ) ) ;
_Log . DebugFormat ( "cryptogram_block: {0}" , HexConverter . ConvertToHexString( cryptogram_block ) ) ;
AES aes = new AES ( ) ;
byte [ ] cryptogram_enc = aes . Encrypt ( cryptogram_block , _SessionKey , _IV ) ;
_Log . DebugFormat ( "cryptogram_enc: {0}" , ConvertToHexString ( cryptogram_enc ) ) ;
_Log . DebugFormat ( "cryptogram_enc: {0}" , HexConverter . ConvertToHexString( cryptogram_enc ) ) ;
_IV = ExtractLastBlock ( cryptogram_enc , 16 ) ;
_Log . DebugFormat ( "_IV: {0}" , ConvertToHexString ( _IV ) ) ;
_Log . DebugFormat ( "_IV: {0}" , HexConverter . ConvertToHexString( _IV ) ) ;
byte [ ] data = Concatenate ( new byte [ ] { key_id } , cryptogram_enc ) ;
_Log . DebugFormat ( "data: {0}" , ConvertToHexString ( data ) ) ;
_Log . DebugFormat ( "data: {0}" , HexConverter . ConvertToHexString( data ) ) ;
APDUCommand cmd_ChangeKey = new APDUCommand ( IsoCase . Case4Short )
{
@ -859,10 +851,10 @@ namespace NFC.Mifare_DESFire
INS = 0xC4 ,
Data = data
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_ChangeKey): {0}" , ConvertToHexString ( cmd_ChangeKey . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_ChangeKey): {0}" , HexConverter . ConvertToHexString( cmd_ChangeKey . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_ChangeKey ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ChangeKey): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ChangeKey): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
@ -904,10 +896,10 @@ namespace NFC.Mifare_DESFire
INS = ( byte ) APDUInstructions . CREATE_STDDATAFILE ,
Data = Concatenate ( data , accessRights_byte , size_byte )
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_CreateFile_Standard): {0}" , ConvertToHexString ( cmd_CreateFile_Standard . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_CreateFile_Standard): {0}" , HexConverter . ConvertToHexString( cmd_CreateFile_Standard . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_CreateFile_Standard ) ;
_Log . DebugFormat ( "APDU_RES(cmd_CreateFile_Standard): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_CreateFile_Standard): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
@ -924,7 +916,7 @@ namespace NFC.Mifare_DESFire
{
_Log . Debug ( "Start ReadData" ) ;
int max_read_bytes_pre_transaction = 58 ;
int max_read_bytes_pre_transaction = 47 ;
long bytes_readed = 0 ;
List < byte > read_data = new List < byte > ( ) ;
@ -973,10 +965,10 @@ namespace NFC.Mifare_DESFire
INS = ( byte ) APDUInstructions . READ_DATA ,
Data = Concatenate ( data , offset_byte , length_byte )
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_ReadData): {0}" , ConvertToHexString ( cmd_ReadData . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_CMD(cmd_ReadData): {0}" , HexConverter . ConvertToHexString( cmd_ReadData . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_ReadData ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ReadData): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
_Log . DebugFormat ( "APDU_RES(cmd_ReadData): {0}" , HexConverter . ConvertToHexString( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
read_data . AddRange ( response . Body ) ;
@ -996,119 +988,69 @@ namespace NFC.Mifare_DESFire
{
_Log . Debug ( "Start WriteData" ) ;
byte [ ] file_id_array = new byte [ ]
{
file_id
} ;
int max_write_bytes_pre_transaction = 47 ;
byte [ ] write_buffer ;
byte [ ] offset_byte_tolong = BitConverter . GetBytes ( offset ) ;
// Use only 3 Bytes
byte [ ] offset_byte = new byte [ ]
long bytes_writed = 0 ;
long length = data . Length ;
while ( bytes_writed ! = data . Length )
{
byte [ ] file_id_array = new byte [ ]
{
file_id
} ;
byte [ ] offset_byte_tolong = BitConverter . GetBytes ( offset + bytes_writed ) ;
// Use only 3 Bytes
byte [ ] offset_byte = new byte [ ]
{
offset_byte_tolong [ 0 ] ,
offset_byte_tolong [ 1 ] ,
offset_byte_tolong [ 2 ] ,
} ;
} ;
byte [ ] lenght_byte_tolong = BitConverter . GetBytes ( data . Length ) ;
// Use only 3 Bytes
byte [ ] lenght_byte = new byte [ ]
{
lenght_byte_tolong [ 0 ] ,
lenght_byte_tolong [ 1 ] ,
lenght_byte_tolong [ 2 ] ,
} ;
long bytes_towrite = 0 ;
APDUCommand cmd_WriteData = new APDUCommand ( IsoCase . Case4Short )
{
CLA = 0x90 ,
INS = ( byte ) APDUInstructions . WRITE_DATA ,
Data = Concatenate ( file_id_array , offset_byte , lenght_byte , data )
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_WriteData): {0}" , ConvertToHexString ( cmd_WriteData . ToArray ( ) ) ) ;
if ( length - bytes_writed < max_write_bytes_pre_transaction )
{
bytes_towrite = length - bytes_writed ;
}
else
{
bytes_towrite = max_write_bytes_pre_transaction ;
}
APDUResponse response = _Card . Transmit ( cmd_WriteData ) ;
_Log . DebugFormat ( "APDU_RES(cmd_WriteData): {0}" , ConvertToHexString ( response . ToArray ( ) ) ) ;
byte [ ] length_byte_tolong = BitConverter . GetBytes ( bytes_towrite ) ;
CheckAPDUResponse ( respons e) ;
write_buffer = GetSubArray ( data , bytes_writed , bytes_towrit e ) ;
bytes_writed + = bytes_towrite ;
// Use only 3 Bytes
byte [ ] length_byte = new byte [ ]
{
length_byte_tolong [ 0 ] ,
length_byte_tolong [ 1 ] ,
length_byte_tolong [ 2 ] ,
} ;
APDUCommand cmd_WriteData = new APDUCommand ( IsoCase . Case4Short )
{
CLA = 0x90 ,
INS = ( byte ) APDUInstructions . WRITE_DATA ,
Data = Concatenate ( file_id_array , offset_byte , length_byte , write_buffer )
} ;
_Log . DebugFormat ( "APDU_CMD(cmd_WriteData): {0}" , HexConverter . ConvertToHexString ( cmd_WriteData . ToArray ( ) ) ) ;
APDUResponse response = _Card . Transmit ( cmd_WriteData ) ;
_Log . DebugFormat ( "APDU_RES(cmd_WriteData): {0}" , HexConverter . ConvertToHexString ( response . ToArray ( ) ) ) ;
CheckAPDUResponse ( response ) ;
}
_Log . Debug ( "End WriteData" ) ;
}
///// <summary>
///// Write Data to File
///// </summary>
///// <param name="file_id">ID of File (0x01 - 0x10)</param>
///// <param name="offset">Offset for File</param>
///// <param name="data">Data to write</param>
//public void WriteData(byte file_id, UInt32 offset, byte[] data)
//{
// _Log.Debug("Start WriteData");
// int max_write_bytes_pre_transaction = 8;
// byte[] write_buffer;
// long bytes_writed = 0;
// long length = data.Length;
// while (bytes_writed != data.Length)
// {
// byte[] file_id_array = new byte[]
// {
// file_id
// };
// byte[] offset_byte_tolong = BitConverter.GetBytes(offset + bytes_writed);
// // Use only 3 Bytes
// byte[] offset_byte = new byte[]
// {
// offset_byte_tolong[0],
// offset_byte_tolong[1],
// offset_byte_tolong[2],
// };
// long bytes_towrite = 0;
// if (length - bytes_writed < max_write_bytes_pre_transaction)
// {
// bytes_towrite = length - bytes_writed;
// }
// else
// {
// bytes_towrite = max_write_bytes_pre_transaction;
// }
// byte[] length_byte_tolong = BitConverter.GetBytes(bytes_towrite);
// write_buffer = GetSubArray(data, bytes_writed, bytes_towrite);
// bytes_writed += bytes_towrite;
// // Use only 3 Bytes
// byte[] length_byte = new byte[]
// {
// length_byte_tolong[0],
// length_byte_tolong[1],
// length_byte_tolong[2],
// };
// APDUCommand cmd_WriteData = new APDUCommand(IsoCase.Case4Short)
// {
// CLA = 0x90,
// INS = (byte)APDUInstructions.WRITE_DATA,
// Data = Concatenate(file_id_array, offset_byte, length_byte, write_buffer)
// };
// _Log.DebugFormat("APDU_CMD(cmd_WriteData): {0}", ConvertToHexString(cmd_WriteData.ToArray()));
// APDUResponse response = _Card.Transmit(cmd_WriteData);
// _Log.DebugFormat("APDU_RES(cmd_WriteData): {0}", ConvertToHexString(response.ToArray()));
// CheckAPDUResponse(response);
// }
// _Log.Debug("End WriteData");
//}
/// <summary>
/// Get all ApplicationIDS from PICC
/// </summary>
@ -1176,63 +1118,6 @@ namespace NFC.Mifare_DESFire
// CheckAPDUResponse(response);
//}
#endregion
#region Configuration Generator
/// <summary>
/// Genearte KeySetting1 for Application Settings or PICC Setting
/// </summary>
public byte GenerateKeySetting1 ( ChangeApplicationKey changeKey , ChangeMasterKeySettings changeMasterKeySettings , CreateDeleteFile createDeleteFile , FileDirectoryAccess fileDirectoryAccess , ChangeMasterKey changeMasterKey )
{
return ( byte ) ( ( ( byte ) changeKey < < 4 ) | ( byte ) changeMasterKeySettings | ( byte ) createDeleteFile | ( byte ) fileDirectoryAccess | ( byte ) changeMasterKey ) ;
}
/// <summary>
/// Genearte KeySetting1 for Application Settings or PICC Setting
/// </summary>
/// <param name="changeKey">ID of Key for changing Application Keys</param>
/// <returns></returns>
public byte GenerateKeySetting1 ( byte changeKey , ChangeMasterKeySettings changeMasterKeySettings , CreateDeleteFile createDeleteFile , FileDirectoryAccess fileDirectoryAccess , ChangeMasterKey changeMasterKey )
{
if ( changeKey < 0x01 | | changeKey > = 0x0E )
{
throw new ArgumentOutOfRangeException ( ) ;
}
return GenerateKeySetting1 ( changeKey , changeMasterKeySettings , createDeleteFile , fileDirectoryAccess , changeMasterKey ) ;
}
/// <summary>
/// Genearte KeySetting2 for Application Creation
/// </summary>
/// <param name="numberOfKeys">Number of keys that can be stored within the application (0x01-0x0D)</param>
/// <returns></returns>
public byte GenerateKeySetting2 ( CryptoOperationsType cryptoOperations , FileIdentifies fileIdentifies , byte numberOfKeys )
{
if ( numberOfKeys < 0x01 | | numberOfKeys > = 0x0D )
{
throw new ArgumentOutOfRangeException ( ) ;
}
return ( byte ) ( ( byte ) cryptoOperations | ( byte ) fileIdentifies | numberOfKeys ) ;
}
/// <summary>
/// Generate FileAccess Rights for File Settings
/// Use enum AccesRights for Free or Never Option
/// </summary>
/// <param name="read">KeyID for Read Access</param>
/// <param name="write">KeyID for Write Access</param>
/// <param name="read_write">KeyID for Read and Write Access</param>
/// <param name="configure">KeyID for Configuration Access</param>
public UInt16 GenerateFileAccessRights ( byte read , byte write , byte read_write , byte configure )
{
if ( read > 0x0F | | write > 0x0F | | read_write > 0x0F | | configure > 0x0F )
{
throw new ArgumentOutOfRangeException ( "One KeyID is not valid" ) ;
}
return ( UInt16 ) ( ( read < < 12 ) | ( write < < 8 ) | ( read_write < < 4 ) | configure ) ;
}
#endregion
#endregion
}
}