我正在尝试使用我的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;
}
根据DesFire文件,我需要两种解密模式,即发送和接收。这篇博客文章对此有一些解释。
但是,DESFire加密与普通的DES /
CBC方案有所不同:PCD在发送数据时使用DES“发送模式”(在DES之前的Xor),而卡在接收数据时使用DES“接收模式”(在DES之后的Xor)。
)。但是,当PCD接收数据时,它将使用普通的DES /
CBC模式(在DES之后的Xor),而卡在发送数据时(在DES之前的Xor)将使用普通的DES发送模式。
在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。但是,第二个“结果”始终为“ 91ae”,表示身份验证错误。我在这里做错了事,向卡发送了错误的数据。
谁能告诉我在这些模式下工作必须更改哪些代码?我应该对TripleDES之前/之后的数据进行XOR运算吗?
这不是真正的问题,但是我读到DesFire卡中的默认“密钥”是16个零字节。另外,文档指出,我需要将TripleDES用于密钥的16个字节,将DES用于密钥的8个字节。所以我正在使用并且需要使用TripleDES,因为我没有更改默认密钥,对吗?
对于那些需要了解CipherBlockChaining的人。
编辑 :我发现我需要在TripleDES之前和之后进行XOR,而且我完全不应该涉及TripleDES的内部操作。我会在一段时间内尝试。
删除了内部的TripleDES行,只说了第一次看到问题的人。
好,我知道了。我的错误是我正在发送
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));
TripleDes是问题之一。wrapMessage函数:
public static byte[] wrapMessage (byte command, byte[] parameters) throws Exception {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write((byte) 0x90);
stream.write(command);
stream.write((byte) 0x00);
stream.write((byte) 0x00);
if (parameters != null) {
stream.write((byte) parameters.length);
stream.write(parameters);
}
stream.write((byte) 0x00);
return stream.toByteArray();
}
编辑: 感谢VGe0rge,我们发现了这种身份验证有时不起作用的原因。不用调用问题中的3DES函数,只需调用:
Cipher.getInstance("DESede/CBC/NoPadding");
我试图在PhantomJS中打开一个需要HTTP身份验证的网页。我的脚本基于loadspeed.js示例: 我可以从渲染的page.jpg中看到,我每次都得到401分。我还使用Wireshark跟踪了HTTP会话,这表明GET请求中没有向给定URL发送身份验证标头。 我到底做错了什么?我刚刚开始使用PhantomJS,但我整个晚上都在寻找,没有走远...
我试图将用于需要基本HTTP身份验证的第三方服务。我正在使用。以下是我到目前为止的结论:
我试图为AWS实现“开发人员身份验证身份”,如下所示:https://AWS.amazon.com/blogs/mobile/amazon-cognito-innecling-developer-authenticated-identities/ 我很好地理解了基本流程。 我怎样才能做到这一点?
问题内容: 我的Web服务器托管在具有基本身份验证的Apache Tomcat 7中。我有Tomcat用户“ tomcat”,角色为“ tomcat”,密码为“ tomcat”。以下分别是我在客户端的web.xml文件和脚本片段。 Web.xml 客户端脚本: 我很确定Web服务和基本身份验证没有问题。但是从客户端脚本中,没有发送身份验证标头。我也尝试过 但是请求发送时没有身份验证头。任何帮助将不
规定使用JWT而不是用户名和密码进行授权。 在服务器端,文档建议修改文件(可在) 但如何从Gajim或Java代码进行身份验证呢?
问题内容: 确保GWT + Tomcat应用程序执行身份验证和授权的最佳策略是什么? 问题答案: 有两种基本策略: 确保入口点; 保护远程服务。 最简单的方法是使用常规的Web应用程序安全工具来限制对GWT生成的html / js文件的访问: 春季安全; web.xml约束。 这样可以让您拥有eg 和。 保护远程服务 如果上述解决方案还不够,您可以进行更深入的研究。我已经通过Spring Secu