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.");
            }
        }
Пример #3
0
        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;
 }
Пример #5
0
 public void ProcessExternalAuthResponse(ResponseAPDU response)
 {
     checkResponse(response.SW1, response.SW2, "EXTERNAL AUTHENTICATE command failed.");
     mSecureChannel.SecurityLevel = mSecurityLevel;
 }
Пример #6
0
        /// <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.");
        }