2008-12-11 21 views
10

Parece que hay 6 variaciones del algoritmo CBC-MAC. He intentado hacer coincidir el algoritmo MAC en el PINPad 1000SE [que por manual es ISO 9797-1 Algoritmo 1].ISO 9797-1 Algoritmo 1 [CBC-MAC] en C#

Tengo un excelente comienzo desde here.

Y codifiqué el algoritmo de la siguiente manera:

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; 
} 

Entonces descubrí hay 3 esquemas de relleno y el que me dio un comienzo puede no ser necesariamente correcto. El manual vino a mi rescate otra vez. Parece que el dispositivo solo tiene almohadillas con 0s. bloque adicional también se menciona en ninguna parte, así que hice los siguientes cambios:

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

Sin bloque adicional (si mod 0 [divisible por 8] no cambian longitud de la matriz)

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

La sugerencia original quería descifrar en el segundo paso ... pero Valery here sugiere que está encriptado todo el camino. Así que cambié Decrypt a Encrypt. Pero todavía no soy capaz de conseguir el requisito de MAC ...

Manual dice para la tecla "6AC292FAA1315B4D8234B3A3D7D5933A" [ya que la clave debe ser de 16 bytes, pensé que la clave aquí es cadena hexadecimal así que tomé valores de bytes de 6A, C2 , 92, FA ... nuevo byte [] {106, 194, 146, ...] el MAC debe ser 7B, 40, BA, 95 [4 bytes] si el mensaje es [0x1a + array de bytes de MENTERODOMETER]

¿Alguien puede ayudar? ¿Por favor?


Desde Pinpad requiere que el primer carácter de mensaje es 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); 
} 

Voy a llamar al código anterior con esta entrada:

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

Curious. ¿Por qué deberías involucrarte en/descifrar los datos de PINPad? El flujo de trabajo de PINPad está diseñado para enviar datos encriptados directamente al banco del comerciante utilizando las claves DUKPT generadas por el banco e instaladas en el PINPad por el proveedor de PINPad. Incluso llegando al punto en el que estábamos escribiendo software para controlar directamente la interfaz de usuario de PINPads y otros comportamientos, nunca pudimos, ni tuvimos que encriptar/desencriptar el sobre cifrado de PIN proporcionado como parte del proceso. – Bill

+0

Bill, tienes razón ... Pero si escribieras una aplicación de gestión de lealtad que permita a los usuarios un PIN, debes usarlo sin estas teclas preprogramadas ... El modelo anterior de PINPad 1000SE no puede recordar en la parte superior de mi cabeza, te permití obtener un PIN y enviarlo como texto claro. Los últimos modelos cifran el PIN y no podemos acceder a él ... –

Respuesta

2

más CBC MAC los algoritmos se implementan en el proveedor de JCE BouncyCastle.

Mira: BouncyCastleProvider.java

Probablemente se esté buscando DESEDEISO9797ALG1MACWITHISO7816-4PADDING, que es un alias para DESEDEMAC64WITHISO7816-4PADDING, implementado aquí (bueno, es una configuración específica de CBCBlockCipherMac utilizando el DESedeEngine y ISO7816d4Padding, usted tiene que saltar entre algunas clases para obtener la imagen completa): JCEMac.java

también, echar un vistazo a los JPO:

JCESecurityModule.java

y su contribuido al por menor MAC implementación del algoritmo:

retail-mac-contributed-by-vsalaman.zip

0

Estoy bastante seguro (IIRC) que necesita llamar TransformFinalBlock al final (por encriptador).

0

No puedo responder a su terminal específico, pero utilizo esto para probar los MAC.

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