/* * Copyright (C) 2011 Digital Security group, Radboud University * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package openemv; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.DESKey; import javacard.security.KeyBuilder; import javacard.security.Signature; import javacardx.crypto.Cipher; /* An object of this class is responsible for all crypto-related stuff. * It provides methods for computing Applications Cryptograms and * contains all the cryptographic keys needed for this. * * One design choice is whether the client passes the ATC (and maybe other data) * explicitly as parameters, or whether this object obtain them from the applet as needed. * We go for the latter approach. The former leads to a 'cleaner' interface, but with many * more parameters. * * @author joeri (joeri@cs.ru.nl) * @author erikpoll (erikpoll@cs.ru.nl) */ public class EMVCrypto implements EMVConstants { /* Reference back to the applet that uses this EMVCrypto object */ private final SimpleEMVApplet theApplet; private final byte[] sessionkey; /** 3DESKey ICC Master Key, shared with the bank */ private final DESKey mk; private final Cipher desCipher; private final Signature desMAC; /** 3DESKey session keys, derived from Master Key mk */ private final DESKey sk; /** Scratchpad transient byte array for diversification data used to build session key */ private final byte[] diversification_data; /** Transient byte array for storing ac transaction_data */ byte[] transaction_data; public EMVCrypto(SimpleEMVApplet x){ theApplet = x; // reference back to the applet diversification_data = JCSystem.makeTransientByteArray((short)8, JCSystem.CLEAR_ON_DESELECT); sessionkey = JCSystem.makeTransientByteArray((short)16, JCSystem.CLEAR_ON_DESELECT); transaction_data = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT); desCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false); desMAC = Signature.getInstance(Signature.ALG_DES_MAC8_ISO9797_M2, false); mk = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_2KEY, false); mk.setKey(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }, (short) 0); sk = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_2KEY, false); } /* Sets the current 3DES session key, based on the Application Transaction Counter (ATC). * * It is done as described in Book 2, Annex A1.3.1, by encrypting * ATC || F0 || 00 || 00 || 00 || 00 || 00 * with the card's 3DES Master Key to obtain the left 8 bytes, and encrypting * ATC || OF || 00 || 00 || 00 || 00 || 00 * with the card's 3DES Master Key to obtain the right 8 bytes. * */ private void setSessionKey(){ // as 8-byte diversification data we take the ATC followed by all zeroes Util.setShort(diversification_data, (short)0, theApplet.protocolState.getATC()); Util.arrayFillNonAtomic(diversification_data, (short)2, (short)6, (byte)0); desCipher.init(mk, Cipher.MODE_ENCRYPT); //compute left 8 bytes of the session key diversification_data[2] = (byte)0xF0; desCipher.doFinal(diversification_data , (short)0, (short)8, sessionkey, (short)0); //compute right 8 byte of the session key diversification_data[2] = (byte)0x0F; desCipher.doFinal(diversification_data, (short)0, (short)8, sessionkey, (short)0); sk.setKey(sessionkey, (short)0); } /* * Computes a cryptogram, as described in Book 2, Sec 8.1, and stores it in the * given response buffer at the given offset. * * The cryptogram is an 8 byte MAC over data supplied by the terminal * (as specified by the CDOL1 or CDOL2) and data provided by the ICC. * * The data supplied by the terminal is in the ADPU buffer. This method does * not need to know what this data is, ie. does not need to know the CDOLs, * but only needs to know the total length of these data elements. * * As data provided by the ICC this method just uses the minimum recommended * set of data elements, ie the AIP and ATC (see Book 2, Sect 8.1.1), for * both the first and the second AC. Hence one method can be used for both. * * @requires apduBuffer != response, to avoid problems overwriting the apduBuffer?? * * @param cid the type of AC, ie. AAC_CODE, TC_CODE, or ARCQ_CODE * @param apduBuffer contains the terminal-supplied data to be signed in the AC * @param length length of the terminal-supplied data * @param response the destination array where the AC is stored at given offset * @param offset offset in this response array */ private void computeAC(byte cid, byte[] apduBuffer, short length, byte[] response, short offset){ /* Collect the data to be MAC-ed in the array transaction_data */ // Copy CDOL from the APDU buffer, at offset 0: Util.arrayCopy(apduBuffer, OFFSET_CDATA, transaction_data, (short)0, length); // 2 bytes AIP, at offset length: Util.setShort(transaction_data, length, theApplet.staticData.getAIP()); // 2 bytes ATC, at offset length + 2: Util.setShort(transaction_data, (short)(length+2), theApplet.protocolState.getATC()); //TODO What is the following data? transaction_data[(short)(length+4)] = (byte) 0x80; transaction_data[(short)(length+5)] = (byte) 0x0; transaction_data[(short)(length+6)] = (byte) 0x0; // MAC is a CBC-MAC computed according to ISO/IEC 9797-1, padding method 2 desMAC.init(sk, Signature.MODE_SIGN); desMAC.sign(transaction_data, (short)0, (short)(length+7), response, offset); } /* * Compute the first AC response APDU using Format 1. (See Book 3, Section 6.5.5.4.) * This method also sets the session key. * * The response contains the * - CID: Cryptogram Information Data, 1 byte long * - ATC Application Transaction Counter, 2 bytes long * - AC: Application Cryptogram, 8 bytes long * - optionally, IAD: Issuer Application Data, 30 bytes long * * @param cid the type of AC, ie. AAC_CODE, TC_CODE, or ARCQ_CODE * @param apduBuffer contains the terminal-supplied data * @param length length of the terminal-supplied data * @param iad the IAD, or null, if IAD is omitted * @param response the destination array where the response is stored, at given offset */ public void generateFirstACReponse(byte cid, byte[] apduBuffer, short length, byte[] iad, short iad_length, byte[] response, short offset) { setSessionKey(); generateSecondACReponse(cid,apduBuffer,length, iad, iad_length, response, offset); } /* * Compute the second AC response APDU using Format 1. (See Book 3, Section 6.5.5.4.) * */ public void generateSecondACReponse(byte cid, byte[] apduBuffer, short length, byte[] iad, short iad_length, byte[] response, short offset) { response[offset] = (byte) 0x80; // Tag for Format 1 cryptogram if (iad==null) { // Length: 1 byte CID + 2 byte ATC + 8 byte AC = 11 response[(short)(offset+1)] = (byte)11; } else { // Length: 1 byte CID + 2 byte ATC + 8 byte AC + iad_length byte IAD response[(short)(offset+1)] = (byte)(11+iad_length); } // 1 byte CID, ie the type of AC returned response[(short)(offset+2)] = cid; // 2 byte ATC, at offset 3: Util.setShort(response, (short)(offset+3), theApplet.protocolState.getATC()); // the AC itself computeAC(cid, apduBuffer, length, response, (short)(offset+5)); // finally we get the (optional) IAD if (iad!=null) { Util.arrayCopy(iad, (short)0, response, (short)(offset+13), (short)18); } // Force an IAD of 18 bytes consisting of all 0s // Needed for EMV-CAP reader response[(short)(offset+1)] = (byte)29; Util.arrayFillNonAtomic(response, (short)(offset+13), (short)18, (byte)0x0); } }