1 2 3 Previous Next 71 Replies Latest reply: Oct 12, 2009 7:35 PM by safarmer RSS

    Global Platform- MACing MAC Retail

    843851
      Hi all,

      Someone can tell me how to caculate a MAC of 24 byte data with a 16 byte key in order to open an open session with GlobalPlatform?


      Thank you,

      Adrien.

      Edited by: Adrien843 on Jul 17, 2009 1:56 AM
        • 1. Re: Global Platform- MACing MAC Retail
          Sebastien_Lorquet
          Did you read the global platform specification before asking this question? This is a free download. See the 2.1.1 archived spec.

          => http://globalplatform.org/specificationscard.asp

          your question is answered page 205 for SCP01 and page 220 for SCP02. The used algorithms are listed in appendix B, and defined in ISO ISO9797, which must be bought, but the draft is freely available and should not be too different from the final release. Just google "ISO 9797 draft"
          • 2. Re: Global Platform- MACing MAC Retail
            843851
            yes I read this spec many time but i don't know how to proceed to compute this MAC ( in fact I don't understand any thing in that spec about security).
            • 3. Re: Global Platform- MACing MAC Retail
              843851
              I have to open a secure session between a NFC reader and a card. I do not devellop the card and i think that the API you are soeaking is lade for a smard card
              • 4. Re: Global Platform- MACing MAC Retail
                safarmer
                Adrien843 wrote:
                Hi all,

                Someone can tell me how to caculate a MAC of 24 byte data with a 16 byte key in order to open an open session with GlobalPlatform?


                Thank you,

                Adrien.

                Edited by: Adrien843 on Jul 17, 2009 1:56 AM
                The MAC algorithm is deffined in ISO 9797-1. It was a little tricky to find the right information on this when I was implementing SCP02 off card. The most helpful information was from this forum so here is my chance to give a little back.

                I am assuming you have generated the session keys correctly. Once you have these, the MAC is a combination of single DES MAC with a final triple DES MAC.

                Here is an example of how to do the MAC.
                byte[] mac;
                byte[] icv = new byte[8];
                Cipher desedeCBCCipher = Cipher.getInstance("DESede/CBC/NoPadding");
                Cipher desCipher = Cipher.getInstance("DES/CBC/NoPadding");
                
                IvParameterSpec ivSpec = new IvParameterSpec(icv);
                
                if (data.length % 8 != 0)
                    throw new Exception("data block size must be multiple of 8");
                
                int blocks = data.length / 8;
                
                for (int i = 0; i < blocks - 1; i++) {
                    desCipher.init(Cipher.ENCRYPT_MODE, singledesCMAC, ivSpec);
                    byte[] block = desCipher.doFinal(data, i * 8, 8);
                    ivSpec = new IvParameterSpec(block);
                }
                
                int offset = (blocks - 1) * 8;
                
                desedeCBCCipher.init(Cipher.ENCRYPT_MODE, sessionCMAC, ivSpec);
                mac = desedeCBCCipher.doFinal(data, offset, 8);
                
                ivSpec = new IvParameterSpec(new byte[8]);
                desCipher.init(Cipher.ENCRYPT_MODE, singledesCMAC, ivSpec);
                icv = desCipher.doFinal(data);
                Note:
                icv is set to 00:00:00:00:00:00:00:00 for the external authenticate call and the resulting icv from each command is used as the ICV for the next command.
                sessionCMAC is the session MAC key
                singledesCMAC is left half (8 bytes) of the session MAC key.

                I hope this helps.

                Cheers,
                Shane
                • 5. Re: Global Platform- MACing MAC Retail
                  843851
                  Hi,

                  Thanks for your answer it was very helpfull.

                  Can you say me how to compute the session key because I have a problem, my calculation of the card cryptogram do not match with the card crypto give by the card.


                  Thanks
                  • 6. Re: Global Platform- MACing MAC Retail
                    safarmer
                    Do you know if your card has diversified keys or standard development keys? Have you tried authenticating to the card through some other means (such as JCOP Tools etc)?

                    Here are some other forum posts on this topic:
                    [http://forums.sun.com/thread.jspa?forumID=23&threadID=5378661|http://forums.sun.com/thread.jspa?forumID=23&threadID=5378661]
                    [http://forums.sun.com/thread.jspa?forumID=23&threadID=5238866|http://forums.sun.com/thread.jspa?forumID=23&threadID=5238866]
                    [http://forums.sun.com/thread.jspa?forumID=23&threadID=708402|http://forums.sun.com/thread.jspa?forumID=23&threadID=708402]

                    The general approach is as follows (for SCP02 with i=15):

                    sessionCMAC = 3DES(01:01:xx:xx:00:00:00:00:00:00:00:00:00:00:00:00) with master ENC key and IV = 00:00:00:00:00:00:00:00
                    sessionDEK = 3DES(01:81:xx:xx:00:00:00:00:00:00:00:00:00:00:00:00) with master DEK key and IV = 00:00:00:00:00:00:00:00
                    sessionENC = 3DES(01:82:xx:xx:00:00:00:00:00:00:00:00:00:00:00:00) with master ENC key and IV = 00:00:00:00:00:00:00:00

                    xx:xx is the sequence counter for the key set you are using.

                    Once you have the key, you need to adjust the parity to ensure it is a valid DES key.
                        /**
                         * Adjust a DES key to odd parity
                         * 
                         * @param key
                         *            to be adjusted
                         */
                        private static void adjustParity(byte[] key) {
                            for (int i = 0; i < key.length; i++) {
                                int akku = (key[i] & 0xFF) | 1;
                    
                                for (int c = 7; c > 0; c--) {
                                    akku = (akku & 1) ^ (akku >> 1);
                                }
                                key[i] = (byte) ((key[i] & 0xFE) | akku);
                            }
                        }
                    Hopefully this is enough to get you started.

                    Cheers,
                    Shane
                    • 7. Re: Global Platform- MACing MAC Retail
                      843851
                      My card is a Nokia 6212 phone that I have unlock to install applications. So I know the key and the key set version.
                      No I never try to use other tools because my reader is incompatible with it.

                      Thank you for your answer but i don't understand why i have to adjust the parity of my key.

                      I will try that and i will say you the result.

                      Thank you very much.
                      • 8. Re: Global Platform- MACing MAC Retail
                        safarmer
                        2 key triple DES is actually a 112bit key, but when you use one in Java, it is a 128bit value (16 bytes). Java uses the first 7 bits of each byte as the key and the last bit is a parity bit to ensure the key is not corrupt. The Java code I included with set the key parity as required.

                        Cheers,
                        Shane
                        • 9. Re: Global Platform- MACing MAC Retail
                          843851
                          I have another problem because the result do not match.

                          This is my code to compute the Session Key
                                                public byte[] calculSessionKey(byte[] sequenceCounter){
                                    byte[] sessionKey = new byte[16];
                                    byte[] icv = new byte[8];
                                    
                                    byte[] cte = Hex.decode("0182");
                          
                                    byte[] aChiffrer = new byte[16];
                                    
                                    System.arraycopy(cte, 0, aChiffrer, 0, cte.length);
                                    System.arraycopy(sequenceCounter, 0, aChiffrer, cte.length, sequenceCounter.length);
                          
                                    try {
                                         Cipher desedeCipher = Cipher.getInstance("DESede/CBC/NoPadding");
                                         IvParameterSpec ivSpec = new IvParameterSpec(icv);
                                         SecretKeySpec sessionCMAC = new SecretKeySpec(Hex.decode("404142434445464748494A4B4C4D4E4F4041424344454647"),"DESede");
                          
                                         desedeCipher.init(Cipher.ENCRYPT_MODE, sessionCMAC,ivSpec);
                                         
                                         sessionKey = desedeCipher.doFinal(aChiffrer);
                                         
                                    } catch (NoSuchAlgorithmException e) {
                                         e.printStackTrace();
                                    } catch (NoSuchPaddingException e) {
                                         e.printStackTrace();
                                    } catch (InvalidKeyException e) {
                                         e.printStackTrace();
                                    } catch (InvalidAlgorithmParameterException e) {
                                         e.printStackTrace();
                                    } catch (IllegalBlockSizeException e) {
                                         e.printStackTrace();
                                    } catch (BadPaddingException e) {
                                         e.printStackTrace();
                                    }
                                    
                                    
                                    return sessionKey;
                               }
                          Do you see something wrong.

                          This is the function I use to compute the card cryptogram :
                                                               byte[] SequenceCounter = {00,01};
                          
                                     TestMac.keyBytes = this.calculSessionKey(SequenceCounter);
                                     this.adjustParity(TestMac.keyBytes);
                                     
                                     System.out.println("MAC : "+new String( Hex.encode(this.calculMac(input1, TestMac.keyBytes))));
                          Is the right way?

                          Thank you
                          • 10. Re: Global Platform- MACing MAC Retail
                            safarmer
                            I don't have the reference code in front of me, but you could try 404142434445464748494a4b4c4d4e4f ("@ABCDEFGHIJKLMNO".getBytes()) as the master key. You only need a 2 key triple DES key, not a 3 key triple DES key. This is just off the top of my head so I hope it is right :)

                            You will also have to adjust the parity of the result as well.

                            Cheers,
                            Shane

                            Edited by: safarmer on 19/08/2009 22:28
                            • 11. Re: Global Platform- MACing MAC Retail
                              843851
                              If I don't use a 24 byte long key, java throw an exception saying that the length of the key is wrong.

                              Edited by: Adrien843 on Aug 19, 2009 6:28 AM
                              • 12. Re: Global Platform- MACing MAC Retail
                                safarmer
                                What does the this.calculMac(input1, TestMac.keyBytes) method do? This may be where your issue is

                                You are correct about the key size. Here is some code I use to derive a key from derivation data.
                                private SecretKey getSecretKey(byte[] keyData) throws GeneralSecurityException {
                                    if (keyData.length == 16) {
                                        byte[] temp = (byte[]) keyData.clone();
                                        keyData = new byte[24];
                                        System.arraycopy(temp, 0, keyData, 0, temp.length);
                                        System.arraycopy(temp, 0, keyData, 16, 8);
                                    }
                                
                                    DESedeKeySpec keySpec = new DESedeKeySpec(keyData);
                                    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
                                    SecretKey key = secretKeyFactory.generateSecret(keySpec);
                                
                                    return key;
                                }
                                
                                private Key deriveKey(byte[] keyData, byte[] data) throws GeneralSecurityException {
                                    Key key = getSecretKey(keyData);
                                    IvParameterSpec dps = new IvParameterSpec(DEFAULT_ICV);
                                    desedeCBCCipher.init(Cipher.ENCRYPT_MODE, key, dps);
                                
                                    byte[] result = desedeCBCCipher.doFinal(data);
                                    adjustParity(result);
                                
                                    return getSecretKey(result);
                                }
                                
                                
                                /**
                                 * Adjust a DES key to odd parity
                                 * 
                                 * @param key
                                 *            to be adjusted
                                 */
                                private static void adjustParity(byte[] key) {
                                    for (int i = 0; i < key.length; i++) {
                                        int akku = (key[i] & 0xFF) | 1;
                                
                                        for (int c = 7; c > 0; c--) {
                                            akku = (akku & 1) ^ (akku >> 1);
                                        }
                                        key[i] = (byte) ((key[i] & 0xFE) | akku);
                                    }
                                }
                                • 13. Re: Global Platform- MACing MAC Retail
                                  843851
                                  Hi,

                                  the the this.calculMac(input1, TestMac.keyBytes) method is your function to compute the MAC.

                                  The result of your function is the same of mine so the error do not became of this.

                                  Have you got another idea?


                                  Thank you very much.
                                  • 14. Re: Global Platform- MACing MAC Retail
                                    safarmer
                                    Would you be able to provide an example of the output you are getting and what you expect to get?

                                    Cheers,
                                    Shane
                                    1 2 3 Previous Next