2008-12-11 10 views
10

Il semble qu'il y ait 6 variantes à l'algorithme CBC-MAC. J'ai essayé de faire correspondre l'algorithme MAC sur le PINPad 1000SE [qui par manuel est ISO 9797-1 Algorithme 1].ISO 9797-1 Algorithme 1 [CBC-MAC] en C#

J'ai obtenu un excellent départ de here.

Et je l'algorithme codé comme suit:

public static byte[] CalculateMAC(this IPinPad pinpad, byte[] message, byte[] key) 
{ 
    //Divide the key with Key1[ first 64 bits] and key2 [last 64 bits] 
    var key1 = new byte[8]; 
    Array.Copy(key, 0, key1, 0, 8); 

    var key2 = new byte[8]; 
    Array.Copy(key, 8, key2, 0, 8); //64 bits 

    //divide the message into 8 bytes blocks 
    //pad the last block with "80" and "00","00","00" until it reaches 8 bytes 
    //if the message already can be divided by 8, then add 
    //another block "80 00 00 00 00 00 00 00" 
    Action<byte[], int> prepArray = (bArr, offset) => 
            { 
             bArr[offset] = 0; //80 
             for (var i = offset + 1; i < bArr.Length; i++) 
              bArr[i] = 0; 
            }; 
    var length = message.Length; 
    var mod = length > 8? length % 8: length - 8; 

    var newLength = length + ((mod < 0) ? -mod : (mod > 0) ? 8 - mod : 0); 
    //var newLength = length + ((mod < 0) ? -mod : (mod > 0) ? 8 - mod : 8); 
    Debug.Assert(newLength % 8 == 0); 

    var arr = new byte[newLength]; 
    Array.Copy(message, 0, arr, 0, length); 
    //Encoding.ASCII.GetBytes(message, 0, length, arr, 0); 
    prepArray(arr, length); 
    //use initial vector {0,0,0,0,0,0,0,0} 
    var vector = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; 

    //encrypt by DES CBC algorith with the first key KEY 1 
    var des = new DESCryptoServiceProvider { Mode = CipherMode.CBC }; 
    var cryptor = des.CreateEncryptor(key1, vector); 
    var outputBuffer = new byte[arr.Length]; 
    cryptor.TransformBlock(arr, 0, arr.Length, outputBuffer, 0); 

    //Decrypt the result by DES ECB with the second key KEY2 [Original suggestion] 
    //Now I'm Encrypting 
    var decOutputBuffer = new byte[outputBuffer.Length]; 
    des.Mode = CipherMode.ECB; 
    var decryptor = des.CreateEncryptor(key2, vector); 
    //var decryptor = des.CreateDecryptor(key2, vector); 
    decryptor.TransformBlock(outputBuffer, 0, outputBuffer.Length, decOutputBuffer, 0); 

    //Encrypt the result by DES ECB with the first key KEY1 
    var finalOutputBuffer = new byte[decOutputBuffer.Length]; 
    var cryptor2 = des.CreateEncryptor(key1, vector); 
    cryptor2.TransformBlock(decOutputBuffer, 0, decOutputBuffer.Length, finalOutputBuffer, 0); 

    //take the first 4 bytes as the MAC 
    var rval = new byte[4]; 
    Array.Copy(finalOutputBuffer, 0, rval, 0, 4); 
    return rval; 
} 

Puis j'ai découvert il y a 3 sommes systèmes de remplissage et celui qui m'a donné un début peut-être pas nécessairement droit. Le manuel est venu à mon secours à nouveau. Il semble que l'appareil ne comprenne que des 0. bloc supplémentaire est également mentionné nulle part, donc je fait les changements ci-dessous:

Action<byte[], int> prepArray = (bArr, offset) => 
            { 
             bArr[offset] = 0; ... } 

Aucun bloc supplémentaire (si mod 0 [divisible par 8] ne changent pas la longueur du tableau)

var newLength = length + ((mod < 0) ? -mod : (mod > 0) ? 8 - mod : 0); 

La suggestion originale voulait me pour décrypter à la deuxième étape ... mais Valery here suggère qu'il est crypté tout le chemin. J'ai donc changé Decrypt en Encrypt. Mais je n'arrive toujours pas à obtenir le MAC ...

Manuel dit pour la clé "6AC292FAA1315B4D8234B3A3D7D5933A" [puisque la clé devrait être 16 octets, j'ai figuré la clé ici chaîne hexadécimale donc j'ai pris des valeurs de 6A, C2 , 92, FA ... nouvel octet [] {106, 194, 146, ...] le MAC doit être 7B, 40, BA, 95 [4 octets] si le message est [0x1a + tableau d'octets de MENTERODOMETER]

Quelqu'un peut-il aider? S'il vous plaît?


Depuis Pinpad exige que le premier caractère dans le message est un 0x1a ...

public static byte[] CalculateAugmentedMAC(this IPinPad pinpad, string message, byte[] key) 
{ 
    var arr = new byte[message.Length + 1]; 
    var source = Encoding.ASCII.GetBytes(message); 
    arr[0] = 0x1a; //ClearScreenIndicator 
    Array.Copy(source, 0, arr, 1, source.Length); 
    return CalculateMAC(pinpad, arr, key); 
} 

J'appelle le code ci-dessus avec cette entrée:

var result = pad.CalculateAugmentedMAC("MENTERODOMETER", new byte[] { 106, 194, 146, 250, 161, 49, 91, 77, 130, 52, 179, 163, 215, 213, 147, 58 }); 
+2

Curieux. Pourquoi auriez-vous besoin de vous impliquer dans le décryptage/décryptage des données PINPad? Le flux de travail PINPad est conçu pour envoyer des données cryptées directement à la banque du commerçant à l'aide des clés DUKPT générées par la banque et installées dans le clavier NIP par le fournisseur du NIPPad. Même en arrivant au point où nous écrivions un logiciel pour contrôler directement l'interface utilisateur de divers PINPads et d'autres comportements, nous n'avons jamais pu, ni besoin de crypter/décrypter l'enveloppe de données PIN cryptée fournie dans le cadre du processus. – Bill

+0

Bill, tu as raison ... Mais si tu devais écrire une application de gestion de la fidélité qui permet aux clients un code PIN, tu dois l'utiliser sans ces touches pré-programmées .... Le modèle précédent de PINPad 1000SE - ne me souviens pas sur le dessus de ma tête - vous a permis d'obtenir un code PIN et l'envoyer en texte clair. Les derniers modèles chiffrent le code PIN et nous ne pouvons pas y arriver ... –

Répondre

2

La plupart CBC MAC les algorithmes sont implémentés dans le fournisseur JCE de BouncyCastle.

Regardez: BouncyCastleProvider.java

Vous êtes probablement pour DESEDEISO9797ALG1MACWITHISO7816-4PADDING, qui est un alias pour DESEDEMAC64WITHISO7816-4PADDING, mis en œuvre ici (bien, il est une configuration spécifique de CBCBlockCipherMac en utilisant la DESedeEngine et ISO7816d4Padding, vous devrez sauter entre certaines classes pour obtenir l'image complète): JCEMac.java

aussi, jetez un oeil à JEA:

JCESecurityModule.java

et leur mise en œuvre de l'algorithme MAC de détail ont contribué:

retail-mac-contributed-by-vsalaman.zip

0

Je suis assez sûr (IIRC) que vous devez appeler TransformFinalBlock à la fin (par chiffreur).

0

Impossible de répondre à votre terminal spécifique, mais je l'utilise pour tester les MAC.

public static byte[] GenerateMAC(byte[] key, byte[] data) 
{ 
    using (MACTripleDES mac = new MACTripleDES(key)) 
     return mac.ComputeHash(data); 
} 
Questions connexes