读取 MIFARE Classic 卡的第二个扇区和更多扇区时出现错误 6800
Error 6800 on reading 2nd sector and more of a MIFARE Classic card
我使用 nfc-pcsc 通过 ACR122U reader(USB 连接)读取 MIFARE Classic 1K 卡。但我经常得到 0x6800 错误:
- 有时当我读取第一个扇区(块 4-5-6)时
- 总是在我读取第 2 个扇区或更多扇区时(块 8-9-10、12-13-14 等)
但是像 NFC-GUI 这样的原生软件可以read/write 毫无困难地处理所有数据。
键 A/B 是默认键(000000.... 和 FFFFFF....)。访问位具有空卡的默认值。
为什么会出现这个错误?怎样才能读卡不出错?
请注意,我可以毫无困难地读取 MIFARE Ultralight 卡。
NodeJS代码(与NFC-PCSC示例相同):
const { NFC } = require('nfc-pcsc');
const TAG_ISO_14443_3 = 'TAG_ISO_14443_3'; // ISO/IEC 14443-3 tags
const TAG_ISO_14443_4 = 'TAG_ISO_14443_4'; // ISO/IEC 14443-4 tags
const KEY_TYPE_A = 0x60;
const KEY_TYPE_B = 0x61;
const nfc = new NFC(); // optionally you can pass logger
nfc.on('reader', reader => {
console.log(`${reader.reader.name} device attached`);
reader.on('card', card => {
const CLASSIC_1K = '000100000000';
const CLASSIC_4K = '000200000000';
const ULTRALIGHT = '000300000000';
console.log(`${reader.reader.name} card detected`, card);
let buf = card.atr;
let type = buf.slice(0,12).toString('hex').toUpperCase();
let version = null;
if (type == '3B8F8001804F0CA000000306')
{
version = card.atr.slice(13,19).toString('hex');
switch (version)
{
case '000100000000':
console.log('Mifare Classic 1k');
break;
case '000200000000':
console.log('Mifare Classic 4k');
break;
case '000300000000':
console.log('Mifare Ultralight');
break;
default:
console.log('Other card');
}
}
if (version == ULTRALIGHT)
{
.... (no difficulties)
}
else if (version == CLASSIC_1K)
{
const key_a = '000000000000';
const key_b = 'FFFFFFFFFFFF';
const keyTypeA = KEY_TYPE_A;
const keyTypeB = KEY_TYPE_B;
Promise.all([
// Sector 1
reader.authenticate(4, keyTypeB, key_b),
reader.authenticate(5, keyTypeB, key_b),
reader.authenticate(6, keyTypeB, key_b),
// Sector 2
reader.authenticate(8, keyTypeB, key_b),
reader.authenticate(9, keyTypeB, key_b),
reader.authenticate(10, keyTypeB, key_b),
]).
then(() => {
console.info(`blocks successfully authenticated`);
reader.read(4, 32, 16) // Often OK
.then(data => {
console.info(`data read`, data.toString());
return reader.read(8, 32, 16); // Always error
})
.then(data => {
console.info(`data read`, data.toString());
}
.catch(err => {
console.error(`error when reading data`);
})
})
.catch(() => {
console.info(`athentification error`);
});
}
});
reader.on('card.off', card => {
console.log(`${reader.reader.name} card removed`);
});
reader.on('error', err => {
console.log(`${reader.reader.name} an error occurred`, err);
});
reader.on('end', () => {
console.log(`${reader.reader.name} device removed`);
});
});
nfc.on('error', err => {
console.log('an error occurred', err);
});
您似乎首先对所有扇区进行身份验证,然后尝试从这些扇区读取一些数据。但是,这不是 MIFARE Classic 身份验证的工作方式。相反,将需要对一个扇区进行身份验证(例如,使用 reader.authenticate(4, keyTypeB, key_b)
为整个扇区 1 使用密钥 B 进行身份验证)。然后您可以从该扇区的任何块读取数据(其中密钥 B 被授予读取访问权限)。从该扇区读取完毕后,您可以对下一个扇区进行身份验证(例如 reader.authenticate(8, keyTypeB, key_b)
以对整个扇区 2 使用密钥 B 进行身份验证)。然后您可以从该扇区的任何块读取数据(其中密钥 B 被授予读取访问权限)。
另请注意,"empty" MIFARE Classic 卡的默认配置是密钥 A = FFFFFFFFFFFF,密钥 B = 未使用,read/write 仅使用密钥 A。由于包含键的区域不可读(除非未使用键),从这些内存区域读取“000000000000”通常意味着无法读取任何数据,实际键仍可能是其他值。因此,如果您确定卡片是空的并且设置了默认权限,我建议尝试使用 "FFFFFFFFFFFF" 作为密钥 A:
进行身份验证
const key_a = 'FFFFFFFFFFFF';
const keyTypeA = KEY_TYPE_A;
await reader.authenticate(4, keyTypeA, key_a);
console.info(`sector authenticated`);
const data1 = await reader.read(4, 48, 16);
console.info(`data read for sector 1`, data1.toString());
await reader.authenticate(8, keyTypeA, key_a);
const data2 = await reader.read(8, 48, 16);
console.info(`data read for sector 2`, data2.toString());
注意: 似乎混淆的来源是 nfc-pcsc 附带的 MIFARE Classic 示例中的误导性文档。 The documentation has been updated.
我使用 nfc-pcsc 通过 ACR122U reader(USB 连接)读取 MIFARE Classic 1K 卡。但我经常得到 0x6800 错误:
- 有时当我读取第一个扇区(块 4-5-6)时
- 总是在我读取第 2 个扇区或更多扇区时(块 8-9-10、12-13-14 等)
但是像 NFC-GUI 这样的原生软件可以read/write 毫无困难地处理所有数据。
键 A/B 是默认键(000000.... 和 FFFFFF....)。访问位具有空卡的默认值。
为什么会出现这个错误?怎样才能读卡不出错?
请注意,我可以毫无困难地读取 MIFARE Ultralight 卡。
NodeJS代码(与NFC-PCSC示例相同):
const { NFC } = require('nfc-pcsc');
const TAG_ISO_14443_3 = 'TAG_ISO_14443_3'; // ISO/IEC 14443-3 tags
const TAG_ISO_14443_4 = 'TAG_ISO_14443_4'; // ISO/IEC 14443-4 tags
const KEY_TYPE_A = 0x60;
const KEY_TYPE_B = 0x61;
const nfc = new NFC(); // optionally you can pass logger
nfc.on('reader', reader => {
console.log(`${reader.reader.name} device attached`);
reader.on('card', card => {
const CLASSIC_1K = '000100000000';
const CLASSIC_4K = '000200000000';
const ULTRALIGHT = '000300000000';
console.log(`${reader.reader.name} card detected`, card);
let buf = card.atr;
let type = buf.slice(0,12).toString('hex').toUpperCase();
let version = null;
if (type == '3B8F8001804F0CA000000306')
{
version = card.atr.slice(13,19).toString('hex');
switch (version)
{
case '000100000000':
console.log('Mifare Classic 1k');
break;
case '000200000000':
console.log('Mifare Classic 4k');
break;
case '000300000000':
console.log('Mifare Ultralight');
break;
default:
console.log('Other card');
}
}
if (version == ULTRALIGHT)
{
.... (no difficulties)
}
else if (version == CLASSIC_1K)
{
const key_a = '000000000000';
const key_b = 'FFFFFFFFFFFF';
const keyTypeA = KEY_TYPE_A;
const keyTypeB = KEY_TYPE_B;
Promise.all([
// Sector 1
reader.authenticate(4, keyTypeB, key_b),
reader.authenticate(5, keyTypeB, key_b),
reader.authenticate(6, keyTypeB, key_b),
// Sector 2
reader.authenticate(8, keyTypeB, key_b),
reader.authenticate(9, keyTypeB, key_b),
reader.authenticate(10, keyTypeB, key_b),
]).
then(() => {
console.info(`blocks successfully authenticated`);
reader.read(4, 32, 16) // Often OK
.then(data => {
console.info(`data read`, data.toString());
return reader.read(8, 32, 16); // Always error
})
.then(data => {
console.info(`data read`, data.toString());
}
.catch(err => {
console.error(`error when reading data`);
})
})
.catch(() => {
console.info(`athentification error`);
});
}
});
reader.on('card.off', card => {
console.log(`${reader.reader.name} card removed`);
});
reader.on('error', err => {
console.log(`${reader.reader.name} an error occurred`, err);
});
reader.on('end', () => {
console.log(`${reader.reader.name} device removed`);
});
});
nfc.on('error', err => {
console.log('an error occurred', err);
});
您似乎首先对所有扇区进行身份验证,然后尝试从这些扇区读取一些数据。但是,这不是 MIFARE Classic 身份验证的工作方式。相反,将需要对一个扇区进行身份验证(例如,使用 reader.authenticate(4, keyTypeB, key_b)
为整个扇区 1 使用密钥 B 进行身份验证)。然后您可以从该扇区的任何块读取数据(其中密钥 B 被授予读取访问权限)。从该扇区读取完毕后,您可以对下一个扇区进行身份验证(例如 reader.authenticate(8, keyTypeB, key_b)
以对整个扇区 2 使用密钥 B 进行身份验证)。然后您可以从该扇区的任何块读取数据(其中密钥 B 被授予读取访问权限)。
另请注意,"empty" MIFARE Classic 卡的默认配置是密钥 A = FFFFFFFFFFFF,密钥 B = 未使用,read/write 仅使用密钥 A。由于包含键的区域不可读(除非未使用键),从这些内存区域读取“000000000000”通常意味着无法读取任何数据,实际键仍可能是其他值。因此,如果您确定卡片是空的并且设置了默认权限,我建议尝试使用 "FFFFFFFFFFFF" 作为密钥 A:
进行身份验证const key_a = 'FFFFFFFFFFFF';
const keyTypeA = KEY_TYPE_A;
await reader.authenticate(4, keyTypeA, key_a);
console.info(`sector authenticated`);
const data1 = await reader.read(4, 48, 16);
console.info(`data read for sector 1`, data1.toString());
await reader.authenticate(8, keyTypeA, key_a);
const data2 = await reader.read(8, 48, 16);
console.info(`data read for sector 2`, data2.toString());
注意: 似乎混淆的来源是 nfc-pcsc 附带的 MIFARE Classic 示例中的误导性文档。 The documentation has been updated.