216 lines
10 KiB
Java
216 lines
10 KiB
Java
package sega.a7;
|
|
|
|
import javacard.framework.Util;
|
|
import javacard.security.MessageDigest;
|
|
|
|
public class AuthCommand extends Command {
|
|
private Crypt m_ee_crypt;
|
|
private HmacSha1 m_ee_hmacSha1;
|
|
private byte m_ee_authLevel = 0;
|
|
|
|
public AuthCommand(short cmd, short recvPacketSize, short sendPacketSize, byte authLevel, AppData data,
|
|
MakePacket packet, MessageDigest sha1, HmacSha1 hmacSha1, Crypt crypt) {
|
|
super(cmd, recvPacketSize, sendPacketSize, data, packet, sha1);
|
|
this.m_ee_crypt = crypt;
|
|
this.m_ee_hmacSha1 = hmacSha1;
|
|
this.m_ee_authLevel = authLevel;
|
|
this.m_ee_tag = AppConfig.A7_TAG_RQU_AUTH_COMMAND;
|
|
}
|
|
|
|
public short execute(byte[] data, short dataOffest, short dataLength, byte[] dst, short dstOffset,
|
|
short dstLength) {
|
|
if (this.m_ee_data.getSession_ramD() != 1)
|
|
return makeErrorPacket(AppConfig.A7_INVALID_AUTH, dst, dstOffset, dstLength);
|
|
|
|
if (this.m_ee_authLevel != this.m_ee_data.getLevel_ramD())
|
|
return makeErrorPacket(AppConfig.A7_LV_ERROR, dst, (short) dstOffset, (short) dstLength);
|
|
|
|
short ramD_error = checkHeader(data, dataOffest, dataLength);
|
|
if (ramD_error != AppConfig.A7_SUCCESS)
|
|
return makeErrorPacket(ramD_error, dst, dstOffset, dstLength);
|
|
|
|
ramD_error = checkFooter(data, dataOffest, dataLength);
|
|
if (ramD_error != AppConfig.A7_SUCCESS)
|
|
return makeErrorPacket(ramD_error, dst, dstOffset, dstLength);
|
|
|
|
this.m_ramD_outDataInfo[0] = 0;
|
|
this.m_ramD_outDataInfo[1] = 0;
|
|
ramD_error = core(data, dataOffest, dataLength);
|
|
|
|
if (ramD_error != AppConfig.A7_SUCCESS)
|
|
return makeErrorPacket(ramD_error, dst, dstOffset, dstLength);
|
|
|
|
return makeSendAuthPacket(AppConfig.A7_TAG_RSP_AUTH_COMMAND, this.m_ramD_setSendPacketSize[0], (short) 0,
|
|
this.m_ramD_outData, this.m_ramD_outDataInfo[0], this.m_ramD_outDataInfo[1], data,
|
|
(short) (dataLength - AppConfig.FOOTER_SIZE + dataOffest), (short) 20, dst, dstOffset, dstLength);
|
|
}
|
|
|
|
protected boolean changeConnectionKey_ee(byte[] aesKey, short aesKeyOffset, short aesKeyLength, byte[] aesIv,
|
|
short aesIvOffset, short aesIvLength) {
|
|
byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD();
|
|
Util.arrayFillNonAtomic(ramD_tmp, (short) 0, (short) ramD_tmp.length, (byte) 0);
|
|
|
|
if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length,
|
|
Crypt.AES_MODE_CKEY_ENCRYPT))
|
|
return false;
|
|
|
|
if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length,
|
|
Crypt.AES_MODE_CKEY_DECRYPT))
|
|
return false;
|
|
|
|
this.m_ee_data.setCkeyIv_ramD(aesIv, aesIvOffset, aesIvLength);
|
|
return true;
|
|
}
|
|
|
|
protected boolean changeGKey_ee(byte[] aesKey, short aesKeyOffset, short aesKeyLength, byte[] aesIv,
|
|
short aesIvOffset, short aesIvLength) {
|
|
byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD();
|
|
Util.arrayFillNonAtomic(ramD_tmp, (short) 0, (short) ramD_tmp.length, (byte) 0);
|
|
|
|
if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length,
|
|
Crypt.AES_MODE_GKEY_ENCRYPT))
|
|
return false;
|
|
if (!this.m_ee_crypt.init(aesKey, aesKeyOffset, aesKeyLength, ramD_tmp, (short) 0, (short) ramD_tmp.length,
|
|
Crypt.AES_MODE_GKEY_DECRYPT))
|
|
return false;
|
|
|
|
this.m_ee_data.setGkeyIv_ee(aesIv, aesIvOffset, aesIvLength);
|
|
return true;
|
|
}
|
|
|
|
protected short decData(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset) {
|
|
byte[] ramD_iv = this.m_ee_data.getCkeyIv_ramD();
|
|
short size = this.m_ee_crypt.doFinal(src, srcOffset, srcLength, dst, dstOffset, Crypt.AES_MODE_CKEY_DECRYPT);
|
|
for (short ramD_ii = 0; ramD_ii < ramD_iv.length; ramD_ii++) {
|
|
short offset = (short) (ramD_ii + dstOffset);
|
|
dst[offset] = (byte) (dst[offset] ^ ramD_iv[ramD_ii]);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
protected short decUpdate_Gkey(byte[] src, short srcOffset, short srcLength,
|
|
byte[] dst, short dstOffset, boolean bInit) {
|
|
if (bInit) {
|
|
byte[] tmp = this.m_ee_data.getCryptBuffer_ramD();
|
|
this.m_ee_crypt.doFinal(tmp, (short) 0, AppConfig.AES_DATA_SIZE, tmp, (short) 0,
|
|
Crypt.AES_MODE_GKEY_DECRYPT);
|
|
}
|
|
short size = this.m_ee_crypt.update(src, srcOffset, srcLength, dst, dstOffset, Crypt.AES_MODE_GKEY_DECRYPT);
|
|
if (bInit) {
|
|
byte[] ee_iv = this.m_ee_data.getGkeyIv_ee();
|
|
for (short ramD_ii = 0; ramD_ii < ee_iv.length; ramD_ii++) {
|
|
short offset = (short) (ramD_ii + dstOffset);
|
|
dst[offset] = (byte) (dst[offset] ^ ee_iv[ramD_ii]);
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
protected short encData(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset) {
|
|
byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD();
|
|
byte[] ramD_iv = this.m_ee_data.getCkeyIv_ramD();
|
|
short ramD_ii = (short) 0;
|
|
for (ramD_ii = 0; ramD_ii < 16; ramD_ii++) {
|
|
if (ramD_ii < srcLength) {
|
|
ramD_tmp[ramD_ii] = (byte) (src[ramD_ii + srcOffset] ^ ramD_iv[ramD_ii]);
|
|
} else {
|
|
ramD_tmp[ramD_ii] = (byte) (0x0 ^ ramD_iv[ramD_ii]);
|
|
}
|
|
ramD_tmp[ramD_ii] = (byte) (0x0 ^ ramD_tmp[ramD_ii]);
|
|
}
|
|
if (srcLength > 16) {
|
|
short size = 0;
|
|
size += this.m_ee_crypt.update(ramD_tmp, (short) 0, (short) ramD_tmp.length, dst, dstOffset, (short) 2);
|
|
size += this.m_ee_crypt.doFinal(src,
|
|
(short) (srcOffset + 16), (short) (srcLength - 16), dst,
|
|
(short) (dstOffset + 16), (short) 2);
|
|
return size;
|
|
}
|
|
return this.m_ee_crypt.doFinal(ramD_tmp, (short) 0, (short) ramD_tmp.length,
|
|
dst, dstOffset, Crypt.AES_MODE_CKEY_ENCRYPT);
|
|
}
|
|
|
|
protected short encUpdate_GKey(byte[] src, short srcOffset, short srcLength,
|
|
byte[] dst, short dstOffset, boolean bInit) {
|
|
if (!bInit)
|
|
return this.m_ee_crypt.update(src, srcOffset, srcLength, dst, dstOffset, Crypt.AES_MODE_GKEY_ENCRYPT);
|
|
|
|
byte[] ramD_tmp = this.m_ee_data.getCryptBuffer_ramD();
|
|
byte[] ee_iv = this.m_ee_data.getGkeyIv_ee();
|
|
this.m_ee_crypt.doFinal(ramD_tmp, (short) 0, AppConfig.AES_DATA_SIZE, ramD_tmp, (short) 0,
|
|
Crypt.AES_MODE_GKEY_ENCRYPT);
|
|
|
|
for (short ramD_ii = 0; ramD_ii < AppConfig.AES_DATA_SIZE; ramD_ii++) {
|
|
if (ramD_ii < srcLength) {
|
|
ramD_tmp[ramD_ii] = (byte) (src[ramD_ii + srcOffset] ^ ee_iv[ramD_ii]);
|
|
} else {
|
|
ramD_tmp[ramD_ii] = (byte) (short) (0x0 ^ ee_iv[ramD_ii]);
|
|
}
|
|
ramD_tmp[ramD_ii] = (byte) (short) (0x0 ^ ramD_tmp[ramD_ii]);
|
|
}
|
|
|
|
if (srcLength > AppConfig.AES_DATA_SIZE) {
|
|
short size = 0;
|
|
size += this.m_ee_crypt.update(ramD_tmp, (short) 0, (short) ramD_tmp.length, dst, dstOffset,
|
|
Crypt.AES_MODE_GKEY_ENCRYPT);
|
|
size += this.m_ee_crypt.update(src, (short) (srcOffset + AppConfig.AES_DATA_SIZE),
|
|
(short) (srcLength - AppConfig.AES_DATA_SIZE), dst, (short) (dstOffset + AppConfig.AES_DATA_SIZE),
|
|
Crypt.AES_MODE_GKEY_ENCRYPT);
|
|
return size;
|
|
}
|
|
|
|
return this.m_ee_crypt.update(ramD_tmp, (short) 0, (short) ramD_tmp.length, dst, dstOffset,
|
|
Crypt.AES_MODE_GKEY_ENCRYPT);
|
|
}
|
|
|
|
protected boolean changeRsaKey_ee(byte[] data1, short data1Offset, short data1Length,
|
|
byte[] data2, short data2Offset, short data2Length) {
|
|
return this.m_ee_crypt.init(data1, data1Offset, data1Length, data2, data2Offset, data2Length,
|
|
Crypt.RSA_MODE_DECRYPT);
|
|
}
|
|
|
|
protected short rsaDecData(byte[] src, short srcOffset, short srcLength, byte[] dst, short dstOffset) {
|
|
return this.m_ee_crypt.doFinal(src, srcOffset, srcLength, dst, dstOffset, Crypt.RSA_MODE_DECRYPT);
|
|
}
|
|
|
|
/**
|
|
* Validate authenticated packet footer.
|
|
* The footer is 40 bytes.
|
|
* 20 bytes: nonce
|
|
* 20 bytes: MAC(SHA1(packet[:footer]) | nonce) == signature
|
|
*/
|
|
protected short checkFooter(byte[] data, short dataOffset, short dataLength) {
|
|
short ramD_oddOffset = (short) (dataOffset + dataLength - AppConfig.FOOTER_SIZE);
|
|
short ramD_authOfset = (short) (dataOffset + dataLength - AppConfig.A7_AUTH_SIZE);
|
|
byte[] ramD_buffer = this.m_ee_data.getFooterBuffer_ramD();
|
|
byte[] ramD_kh = this.m_ee_data.getKh_ramD();
|
|
byte[] ramD_lastNonce = this.m_ee_data.getLastNonceEvent_ramD();
|
|
this.m_ee_sha1.reset();
|
|
this.m_ee_sha1.doFinal(data, dataOffset, (short) (dataLength - AppConfig.FOOTER_SIZE), ramD_buffer, (short) 0);
|
|
this.m_ee_hmacSha1.init(ramD_kh, (short) 0, (short) ramD_kh.length);
|
|
this.m_ee_hmacSha1.update(ramD_buffer, (short) 0, (short) 20);
|
|
this.m_ee_hmacSha1.update(ramD_lastNonce, (short) 0, (short) ramD_lastNonce.length);
|
|
this.m_ee_hmacSha1.sign(data, ramD_oddOffset, (short) 20, ramD_buffer, (short) 0);
|
|
if (Util.arrayCompare(data, ramD_authOfset, ramD_buffer, (short) 0, (short) 20) != 0) {
|
|
this.m_ee_data.incrementErrorCount();
|
|
return AppConfig.A7_AUTHFAIL;
|
|
}
|
|
this.m_ee_data.clearErrorCount();
|
|
return AppConfig.A7_SUCCESS;
|
|
}
|
|
|
|
protected short makeSendAuthPacket(short tag, short paramSize, short result,
|
|
byte[] data, short dataOffset, short dataSize, byte[] nonceOdd, short oddOffset,
|
|
short oddLength, byte[] sendPacket, short packetOffset, short packetLength) {
|
|
byte[] ramD_nonceEvent = this.m_ee_data.getNewNonceEvent_ramD();
|
|
if (!this.m_ee_packet.setData(this.m_ee_data.getKh_ramD(), (short) 0,
|
|
(short) this.m_ee_data.getKh_ramD().length, tag, paramSize, result, this.m_ee_cmd, data, dataOffset,
|
|
dataSize, ramD_nonceEvent, (short) 0, (short) ramD_nonceEvent.length, nonceOdd, oddOffset, oddLength,
|
|
sendPacket, packetOffset, packetLength, this.m_ee_sha1, this.m_ee_hmacSha1))
|
|
return makeErrorPacket(AppConfig.A7_FAIL, sendPacket, packetOffset, packetLength);
|
|
|
|
this.m_ee_data.setLastNonceEvent_ramD(ramD_nonceEvent, (short) 0, (short) ramD_nonceEvent.length);
|
|
return paramSize;
|
|
}
|
|
}
|