Java DESFire身份验证的DES发送和接收模式

Java DESFire身份验证的DES发送和接收模式,java,android,nfc,des,mifare,Java,Android,Nfc,Des,Mifare,我正在尝试用我的android应用程序验证DESFire卡。我过去常常从卡片上取字节。为此,我排除了解密中的填充(在下面注释掉),因为DESFire文档指出了这一点。另外,如果我不这样做,解密将返回7个字节作为8个字节的输入。下面是我使用的DES和TripleDES解密函数: public static byte[] TripleDES_Decrypt(byte[] data,byte[][] keys) { int i; byte[] tmp = new byte[data.l

我正在尝试用我的android应用程序验证DESFire卡。我过去常常从卡片上取字节。为此,我排除了解密中的填充(在下面注释掉),因为DESFire文档指出了这一点。另外,如果我不这样做,解密将返回7个字节作为8个字节的输入。下面是我使用的DES和TripleDES解密函数:

public static byte[] TripleDES_Decrypt(byte[] data,byte[][] keys)
{
    int i;
    byte[] tmp = new byte[data.length];
    byte[] bloc = new byte[8];

    K = generateSubKeys(keys[0]);
    K1 = generateSubKeys(keys[1]);
    K2 = generateSubKeys(keys[2]);

    for (i = 0; i < data.length; i++) {
        if (i > 0 && i % 8 == 0) {
            bloc = encrypt64Bloc(bloc,K2, true);
            bloc = encrypt64Bloc(bloc,K1, false);
            bloc = encrypt64Bloc(bloc,K, true);
            System.arraycopy(bloc, 0, tmp, i - 8, bloc.length);
        }
        if (i < data.length)
            bloc[i % 8] = data[i];
    }
    bloc = encrypt64Bloc(bloc,K2, true);
    bloc = encrypt64Bloc(bloc,K1, false);
    bloc = encrypt64Bloc(bloc,K, true);
    System.arraycopy(bloc, 0, tmp, i - 8, bloc.length);


    //tmp = deletePadding(tmp);

    return tmp;
}

public static byte[] decrypt(byte[] data, byte[] key) {
    int i;
    byte[] tmp = new byte[data.length];
    byte[] bloc = new byte[8];

    K = generateSubKeys(key);

    for (i = 0; i < data.length; i++) {
        if (i > 0 && i % 8 == 0) {
            bloc = encrypt64Bloc(bloc,K, true);
            System.arraycopy(bloc, 0, tmp, i - 8, bloc.length);
        }
        if (i < data.length)
            bloc[i % 8] = data[i];
    }
    bloc = encrypt64Bloc(bloc,K, true);
    System.arraycopy(bloc, 0, tmp, i - 8, bloc.length);

    //tmp = deletePadding(tmp);

    return tmp;
}
公共静态字节[]三重解密(字节[]数据,字节[]密钥)
{
int i;
字节[]tmp=新字节[data.length];
byte[]bloc=新字节[8];
K=生成子键(键[0]);
K1=生成子键(键[1]);
K2=生成子键(键[2]);
对于(i=0;i0&&i%8==0){
bloc=encrypt64Bloc(bloc,K2,true);
bloc=encrypt64Bloc(bloc,K1,false);
bloc=bloc(bloc,K,true);
数组复制(bloc,0,tmp,i-8,bloc.length);
}
if(i<数据长度)
集团[i%8]=数据[i];
}
bloc=encrypt64Bloc(bloc,K2,true);
bloc=encrypt64Bloc(bloc,K1,false);
bloc=bloc(bloc,K,true);
数组复制(bloc,0,tmp,i-8,bloc.length);
//tmp=删除填充(tmp);
返回tmp;
}
公共静态字节[]解密(字节[]数据,字节[]密钥){
int i;
字节[]tmp=新字节[data.length];
byte[]bloc=新字节[8];
K=生成子键(键);
对于(i=0;i0&&i%8==0){
bloc=bloc(bloc,K,true);
数组复制(bloc,0,tmp,i-8,bloc.length);
}
if(i<数据长度)
集团[i%8]=数据[i];
}
bloc=bloc(bloc,K,true);
数组复制(bloc,0,tmp,i-8,bloc.length);
//tmp=删除填充(tmp);
返回tmp;
}
根据DesFire文档,我需要两种解密模式,发送和接收。有一些解释

然而,DESFire加密与普通DES/CBC方案有点不同:PCD在发送数据时使用DES“发送模式”(DES之前的xor),而卡在接收数据时使用DES“接收模式”(DES之后的xor)。但当PCD接收数据时,它使用正常DES/CBC模式(DES后的xor),而卡在发送数据时使用正常DES发送模式(DES前的xor)

在Android端,我遵循以下示例和建议:

// connected to tag and application     

// result = encoded(randB) + af 
byte[] result = idTag.transceive(Utils.wrapMessage((byte)0x0a, new byte[]{(byte)0x0}));

byte[] b0 = new byte[8];
for(int i = 0; i < 8; i++) {
    b0[i] = result[i];
}

// key
byte[] key = new byte[] {(byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
                 (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
                 (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
                 (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0 };
byte[][] keys = new byte[3][];
keys[0]=key; keys[1]=key; keys[2]=key;

// decrypt encoded(randB)
byte[] r0 = DES.TripleDES_Decrypt(b0, keys);

// generate randA (integer 0-7 for trying) 
byte[] nr = new byte[8];
for(int i = 0; i < 8; i++) {
    nr[i] = Byte.parseByte(Integer.toString(i), 16);
}
// decrypt randA
byte[] b1 = DES.TripleDES_Decrypt(nr, keys);

// shift randB and get randB'
byte[] r1 =new byte[8];
for(int i = 0; i < 7; i++) {
    r1[i] = r0[i + 1];
}
r1[7]=r0[0];

// concat (randA + randB')
byte[] b2 = new byte[16];
for(int i = 0; i < 16; i++)
{
    if(i <= 7) {
    b2[i] = b1[i];
} else {
    b2[i] = r1[i - 8];
}
}

// XOR (randA + randB') with IV
// IV is told to be consisting of 0's, 
// but XOR something with 0 results the same? 
for(int i=0;i<16;i++) {
    b2[i] = (byte) (b2[i] ^ (byte)0x0);
}

// send AF and decrypt(A+B) 
// wrap message adds needed wrapping to message (90 to left, offset bytes etc.)
result = isodepTag.transceive(Utils.wrapMessage((byte)0xaf, DES.TripleDES_Decrypt(b2, keys)));
//连接到标记和应用程序
//结果=编码(randB)+af
byte[]result=idTag.transceive(Utils.wrapMessage((字节)0x0a,新字节[]{(字节)0x0}));
字节[]b0=新字节[8];
对于(int i=0;i<8;i++){
b0[i]=结果[i];
}
//钥匙
字节[]键=新字节[]{(字节)0x0,(字节)0x0,(字节)0x0,(字节)0x0,(字节)0x0,
(字节)0x0,(字节)0x0,(字节)0x0,(字节)0x0,
(字节)0x0,(字节)0x0,(字节)0x0,(字节)0x0,
(字节)0x0,(字节)0x0,(字节)0x0,(字节)0x0};
字节[][]键=新字节[3][];
键[0]=键;键[1]=键;键[2]=键;
//解密编码(randB)
字节[]r0=DES.TripleDES_解密(b0,密钥);
//生成randA(整数0-7用于尝试)
字节[]nr=新字节[8];
对于(int i=0;i<8;i++){
nr[i]=Byte.parseByte(整数.toString(i),16);
}
//解密兰达
字节[]b1=DES.TripleDES_解密(nr,密钥);
//转移randB并得到randB'
字节[]r1=新字节[8];
对于(int i=0;i<7;i++){
r1[i]=r0[i+1];
}
r1[7]=r0[0];
//concat(randA+randB')
字节[]b2=新字节[16];
对于(int i=0;i<16;i++)
{

如果(iOK),我得到了解决方案。我的错误是我发送了

3DES(randA + randB') 
但是我应该送

3DES(randA) + 3DES(randB' XOR 3DES(randA))
以下是Android/Java的身份验证代码(很遗憾,这是目前唯一可以在网上找到的代码!):

实际身份验证代码:

// send initial authentication request
byte[] result = idTag.transceive(Utils.wrapMessage((byte)0x0a, new byte[]{(byte)0x0}));

// get encrypted(randB) from the response
byte[] b0 = new byte[8];
for(int i = 0; i < 8; i++) {
    b0[i] = result[i];
}

// 16 bytes default key
byte[] key = new byte[] {(byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
    (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
    (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
    (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0 };
// keys for TripleDes
byte[][] keys = new byte[3][];
keys[0] = key; keys[1] = key; keys[2] = key;

// decrypt encoded(randB)
byte[] r0 = DES.TripleDES_Decrypt(b0, keys);

// generate randA (integer 0-7 for trying, should randomize for real-life use) 
byte[] nr = new byte[8];
for(int i = 0; i < 8; i++) {
    nr[i] = Byte.parseByte(Integer.toString(i), 16);
}

// decrypt randA, should XOR with IV, but IV is all 0's, not necessary
byte[] b1 = DES.TripleDES_Decrypt(nr, keys);

// shift randB one byte left and get randB'
byte[] r1 =new byte[8];
for(int i = 0; i < 7; i++) {
    r1[i] = r0[i + 1];
}
r1[7]=r0[0];

// xor randB' with randA and decrypt
byte[] b2 = new byte[8];
for(int i = 0; i < 8; i++) {
    b2[i] = (byte) (b1[i] ^ r1[i]);
}
b2 = DES.TripleDES_Decrypt(b2, keys);

// concat (randA + randB')
byte[] b1b2 = new byte[16];

for (int i = 0; i < b1b2.length; i++) {
    if(i <= 7) {
        b1b2[i] = b1[i];
    } else {
        b1b2[i]=b2[i-8];
    }
}

result = idTag.transceive(Utils.wrapMessage((byte)0xaf, b1b2));
编辑:多亏了VGe0rge,我们发现了此身份验证不起作用的原因。与其调用问题中的3DES函数,不如调用:

Cipher.getInstance("DESede/CBC/NoPadding");

伊斯马特,你有没有试着把数据写入DESFIRE文件

正如您所解释的,向卡发送数据时:PCD在发送数据时使用DES“发送模式”(DES之前的xor),而卡在接收数据时使用DES“接收模式”(DES之后的xor)

因此,我之前无法获得正确的代码来使用XOR实现TDE..我需要执行所有的crypt decrypt crypt,而我的应用程序的过程会变慢:

res = criptoTransformDec.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);
res = criptoTransformEnc.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);
res = criptoTransformDec1.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);

int l_iAux = 0;
while (l_iAux < (datosEscribir.Length - 8))
    {
        criptoTransformDec2 = desDec.CreateDecryptor(claveSes1, tdesInitialVector);
        //desEnc2 = new DESCryptoServiceProvider();
        criptoTransformEnc2 = desEnc.CreateEncryptor(claveSes2, tdesInitialVector);
        //desDec3 = new DESCryptoServiceProvider();
                criptoTransformDec3 = desDec.CreateDecryptor(claveSes1, tdesInitialVector);

        Array.Copy(datosEscribir, 8 + l_iAux, aux1, 0, 8);
        Array.Copy(datosEscribir, l_iAux, aux2, 0, 8);
        DesfireBarik.XorStr(ref aux1, ref aux2, 8);
        res = criptoTransformDec2.TransformBlock(aux1, 0, 8, datosEscribir, 8 + l_iAux);
        res = criptoTransformEnc2.TransformBlock(datosEscribir, 8 + l_iAux, 8, datosEscribir, 8 + l_iAux);
        res = criptoTransformDec3.TransformBlock(datosEscribir, 8 + l_iAux, 8, datosEscribir, 8 + l_iAux);

        l_iAux += 8;
    }

private static void XorStr (ref byte[] str1, ref byte[] str2, int qty )
    {
        int i = 0;
        for (i = 0; i < qty; i++ )
            str1[i] = (byte)(str1[i] ^ str2[i]);
    }
res=scriptotransformdec.TransformBlock(datosEscribir,0,8,datosEscribir,0);
res=scriptotransformenc.TransformBlock(datosEscribir,0,8,datosEscribir,0);
res=scriptotransformdec1.TransformBlock(datosEscribir,0,8,datosEscribir,0);
int l_iAux=0;
而(l_iAux<(datosEscribir.Length-8))
{
criptoTransformDec2=desDec.CreateDecryptor(claveSes1,tdesInitialVector);
//desEnc2=新的DESCryptoServiceProvider();
scriptotransformenc2=desEnc.CreateEncryptor(claveSes2,tdesInitialVector);
//desDec3=新的DESCryptoServiceProvider();
criptoTransformDec3=desDec.CreateDecryptor(claveSes1,tdesInitialVector);
拷贝(datosEscribir,8+l_-iAux,aux1,0,8);
数组.Copy(datosEscribir,l_iAux,aux2,0,8);
XorStr(参考aux1,参考aux2,8);
res=scriptotransformdec2.TransformBlock(aux1,0,8,datosEscribir,8+l_iAux);
res=scriptotransformenc2.TransformBlock(datosEscribir,8+l_-iAux,8,datosEscribir,8+l_-iAux);
res=scriptotransformdec3.TransformBlock(datosEscribir,8+l_-iAux,8,datosEscribir,8+l_-iAux);
l_iAux+=8;
}
专用静态无效XorStr(参考字节[]str1,参考字节[]str2,整数数量)
{
int i=0;
对于(i=0;i
我记得有一位同事在做DESFire,我认为它处理TDE的方式没有什么特别之处。我记得IV在命令和响应之间是“链接”的:命令的最后一个块是u
res = criptoTransformDec.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);
res = criptoTransformEnc.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);
res = criptoTransformDec1.TransformBlock(datosEscribir, 0, 8, datosEscribir, 0);

int l_iAux = 0;
while (l_iAux < (datosEscribir.Length - 8))
    {
        criptoTransformDec2 = desDec.CreateDecryptor(claveSes1, tdesInitialVector);
        //desEnc2 = new DESCryptoServiceProvider();
        criptoTransformEnc2 = desEnc.CreateEncryptor(claveSes2, tdesInitialVector);
        //desDec3 = new DESCryptoServiceProvider();
                criptoTransformDec3 = desDec.CreateDecryptor(claveSes1, tdesInitialVector);

        Array.Copy(datosEscribir, 8 + l_iAux, aux1, 0, 8);
        Array.Copy(datosEscribir, l_iAux, aux2, 0, 8);
        DesfireBarik.XorStr(ref aux1, ref aux2, 8);
        res = criptoTransformDec2.TransformBlock(aux1, 0, 8, datosEscribir, 8 + l_iAux);
        res = criptoTransformEnc2.TransformBlock(datosEscribir, 8 + l_iAux, 8, datosEscribir, 8 + l_iAux);
        res = criptoTransformDec3.TransformBlock(datosEscribir, 8 + l_iAux, 8, datosEscribir, 8 + l_iAux);

        l_iAux += 8;
    }

private static void XorStr (ref byte[] str1, ref byte[] str2, int qty )
    {
        int i = 0;
        for (i = 0; i < qty; i++ )
            str1[i] = (byte)(str1[i] ^ str2[i]);
    }