public ResponseAPDU unwrap(ResponseAPDU response) { if ((mSecurityLevel & net.SecurityLevel.R_MAC) != 0) { if (response.Data.Length < 8) { throw new Exception("Response data length must be at least 8 bytes."); } if (mRMACStream == null) { throw new Exception("No corresponding wrapped command found while R-MAC security level set. Secure channel can only work correctly if " + "for each wrapped command the corresponding response be unwrapped immediately."); } int realResponseLength = response.Data.Length - 8; mRMACStream.WriteByte((byte)realResponseLength); mRMACStream.Write(response.Data, 0, realResponseLength); mRMACStream.WriteByte((byte)response.SW1); mRMACStream.WriteByte((byte)response.SW2); mRICV = CryptoUtil.SingleDESFullTripleDESMAC(mSessionKeys.RmacKey, mRICV, CryptoUtil.DESPad(mRMACStream.ToArray())); byte[] realMac = new byte[8]; System.Array.Copy(response.Data, realResponseLength, realMac, 0, 8); if (Enumerable.SequenceEqual(realMac, mRICV)) { throw new Exception("Invalid R-MAC."); } mRMACStream = null; response = new ResponseAPDU(response.SW1, response.SW2, CryptoUtil.SubArray(response.Data, 0, realResponseLength)); } return(response); }
/// <summary> /// /// </summary> /// <param name="response"></param> public void ProcessInitUpdateResponse(ResponseAPDU response) { checkResponse(response.SW1, response.SW2, "INITIALIZE UPDATE command failed."); // Check response length it should always be 28 bytes if (response.Data.Length != 28) { throw new Exception("Wrong INIT UPDATE response length."); } System.Array.Copy(response.Data, mInitUpdateResponse, 28); if (mSCPIdentifier == SCP_ANY) { mSCPIdentifier = mInitUpdateResponse[11] == SCP_02 ? SCP_02 : SCP_01; if (mSCPImplementationOption == IMPL_OPTION_ANY) { mSCPImplementationOption = mSCPIdentifier == SCP_02 ? IMPL_OPTION_I_15 : IMPL_OPTION_I_05; } } if (mSCPIdentifier != mInitUpdateResponse[11]) { throw new Exception("Secure channel identifier specified does not match to card"); } // If we use SPC '01' then clear R_MAC bit if (mSCPIdentifier == SCP_01) { mSecurityLevel &= ~SecurityLevel.R_MAC; } // derivate session keys if (mSCPIdentifier == SCP_01) { mSessionKeys = GenerateSessionKeysSCP01(mInitUpdateResponse); } else if (mSCPIdentifier == SCP_02) { byte[] sequenceCoutner = new byte[2]; System.Array.Copy(mInitUpdateResponse, 12, sequenceCoutner, 0, 2); mSessionKeys = GenerateSessionKeysSCP02(sequenceCoutner); } MemoryStream memStream = new MemoryStream(); memStream.Write(mHostChallenge, 0, mHostChallenge.Length); memStream.Write(mInitUpdateResponse, 12, 8); byte[] calculatedCryptogram = CryptoUtil.FullTripleDESMAC(mSessionKeys.RetrieveKey(Key.KEY_TYPE_ENC), CryptoUtil.BINARY_ZEROS_8_BYTE_BLOCK, CryptoUtil.DESPad(memStream.ToArray())); byte[] cardCryptogram = new byte[8]; System.Array.Copy(mInitUpdateResponse, 20, cardCryptogram, 0, 8); if (!Enumerable.SequenceEqual(cardCryptogram, calculatedCryptogram)) { throw new Exception("Invalid cryptogram."); } }
public ResponseAPDU unwrap(ResponseAPDU response) { if ((mSecurityLevel & net.SecurityLevel.R_MAC) != 0) { if(response.Data.Length < 8) throw new Exception("Response data length must be at least 8 bytes."); if (mRMACStream == null) throw new Exception("No corresponding wrapped command found while R-MAC security level set. Secure channel can only work correctly if " + "for each wrapped command the corresponding response be unwrapped immediately."); int realResponseLength = response.Data.Length - 8; mRMACStream.WriteByte((byte) realResponseLength); mRMACStream.Write(response.Data, 0, realResponseLength); mRMACStream.WriteByte((byte) response.SW1); mRMACStream.WriteByte((byte) response.SW2); mRICV = CryptoUtil.SingleDESFullTripleDESMAC(mSessionKeys.RmacKey, mRICV, CryptoUtil.DESPad(mRMACStream.ToArray())); byte[] realMac = new byte[8]; System.Array.Copy(response.Data, realResponseLength, realMac, 0, 8); if(Enumerable.SequenceEqual(realMac, mRICV)) throw new Exception("Invalid R-MAC."); mRMACStream = null; response = new ResponseAPDU(response.SW1, response.SW2, CryptoUtil.SubArray(response.Data, 0, realResponseLength)); } return response; }
public void ProcessExternalAuthResponse(ResponseAPDU response) { checkResponse(response.SW1, response.SW2, "EXTERNAL AUTHENTICATE command failed."); mSecureChannel.SecurityLevel = mSecurityLevel; }
/// <summary> /// /// </summary> /// <param name="response"></param> public void ProcessInitUpdateResponse(ResponseAPDU response) { checkResponse(response.SW1, response.SW2, "INITIALIZE UPDATE command failed."); // Check response length it should always be 28 bytes if (response.Data.Length != 28) throw new Exception("Wrong INIT UPDATE response length."); System.Array.Copy(response.Data, mInitUpdateResponse, 28); if (mSCPIdentifier == SCP_ANY) { mSCPIdentifier = mInitUpdateResponse[11] == SCP_02 ? SCP_02 : SCP_01; if (mSCPImplementationOption == IMPL_OPTION_ANY) mSCPImplementationOption = mSCPIdentifier == SCP_02 ? IMPL_OPTION_I_15 : IMPL_OPTION_I_05; } if (mSCPIdentifier != mInitUpdateResponse[11]) throw new Exception("Secure channel identifier specified does not match to card"); // If we use SPC '01' then clear R_MAC bit if (mSCPIdentifier == SCP_01) mSecurityLevel &= ~SecurityLevel.R_MAC; // derivate session keys if (mSCPIdentifier == SCP_01) mSessionKeys = GenerateSessionKeysSCP01(mInitUpdateResponse); else if (mSCPIdentifier == SCP_02) { byte[] sequenceCoutner = new byte[2]; System.Array.Copy(mInitUpdateResponse, 12, sequenceCoutner, 0, 2); mSessionKeys = GenerateSessionKeysSCP02(sequenceCoutner); } MemoryStream memStream = new MemoryStream(); memStream.Write(mHostChallenge, 0, mHostChallenge.Length); memStream.Write(mInitUpdateResponse, 12, 8); byte[] calculatedCryptogram = CryptoUtil.FullTripleDESMAC(mSessionKeys.RetrieveKey(Key.KEY_TYPE_ENC), CryptoUtil.BINARY_ZEROS_8_BYTE_BLOCK, CryptoUtil.DESPad(memStream.ToArray())); byte[] cardCryptogram = new byte[8]; System.Array.Copy(mInitUpdateResponse, 20, cardCryptogram, 0, 8); if (!Enumerable.SequenceEqual(cardCryptogram, calculatedCryptogram)) throw new Exception("Invalid cryptogram."); }