Advertisement
Guest User

AES-CMAC for Javacard 2.x

a guest
Apr 5th, 2017
2,431
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 14.76 KB | None | 0 0
  1. package PACSAM;
  2.  
  3. import javacard.framework.*;
  4. import javacard.security.*;
  5. import javacardx.crypto.*;
  6.  
  7. /**
  8.  * Signature algorithm ALG_AES_CMAC_128 generates a 16-byte Cipher-based MAC (CMAC)
  9.  * using AES with blocksize 128 in CBC mode with ISO9797_M2 padding scheme.
  10.  */
  11. public class AESCMAC128 extends Signature  {
  12.  
  13.     // Algorithm constant (Matches the Javacard 3.x value)
  14.     public static final byte ALG_AES_CMAC_128   = (byte)49;
  15.  
  16.     // Cryptographic Service Providers
  17.     // NOTE: We need to use the Cipher instead of
  18.     private Signature cspAESMAC;
  19.  
  20.     private static final short ZERO             = (short)0;
  21.     public static final short LENGTH_BLOCK_AES  = (short)16;
  22.     public static final short LENGTH_KEY_AES    = (short)16;
  23.     public static final short LENGTH_CMAC       = (short)16; // We return the entire CMAC
  24.  
  25.     // Constant XOR value according to AES-CMAC-128 for subkey generation
  26.     final byte CONST_RB                         = (byte)0x87;      
  27.     final byte CONST_PAD                        = (byte)0x80;
  28.  
  29.     // A temporary working space
  30.     private byte[] buffer;
  31.    
  32.     private static final short LENGTH_BUFFER    = (short)48;
  33.  
  34.     // Holds L, K1 and K2 during processing
  35.     private static final short OFFSET_SUBKEY    = (short)0;
  36.     private static final short LENGTH_SUBKEY    = (short)LENGTH_BLOCK_AES;
  37.  
  38.     // Holds the intermediate values as well as the final CMAC
  39.     private static final short OFFSET_CMAC      = (short)(OFFSET_SUBKEY + LENGTH_SUBKEY);
  40.    
  41.     public AESCMAC128() {      
  42.        
  43.         // Create the cryptographic service providers
  44.         cspAESMAC = Signature.getInstance(Signature.ALG_AES_MAC_128_NOPAD, false);
  45.        
  46.         // Allocate transient data
  47.         buffer = JCSystem.makeTransientByteArray(LENGTH_BUFFER, JCSystem.CLEAR_ON_DESELECT);
  48.        
  49.     }
  50.    
  51.     public byte getAlgorithm() {
  52.         return ALG_AES_CMAC_128;
  53.     }
  54.    
  55.     public short getLength() {
  56.         return LENGTH_CMAC;
  57.     }
  58.    
  59.     public void init(Key theKey, byte theMode)  {
  60.         init(theKey, theMode, null, ZERO, ZERO);
  61.     }
  62.  
  63.     public void init(Key theKey, byte theMode, byte[] bArray, short bOff, short bLen)  {
  64.  
  65.         // Reset our entire buffer
  66.         Util.arrayFillNonAtomic(buffer, ZERO, LENGTH_BUFFER, (byte)0x00);
  67.  
  68.         /*
  69.          * SUBKEY GENERATION
  70.          */
  71.          
  72.         // Step 1.  L := AES-128(K, const_Zero);  
  73.         // In step 1, AES-128 with key K is applied to an all-zero input block.
  74.         // NOTE: The IV is always zero for this step as it is not the actual CMAC calculation
  75.         cspAESMAC.init(theKey, Signature.MODE_SIGN);
  76.         cspAESMAC.sign(buffer, OFFSET_SUBKEY, LENGTH_BLOCK_AES, buffer, OFFSET_SUBKEY);    
  77.        
  78.         // buffer[OFFSET_SUBKEY] now contains the value of L, this is the only portion of the Subkey generation
  79.         // we perform here, as the rest is in the sign() or verify() method when we know the length of the
  80.         // final block.
  81.        
  82.         // Now we initialise cspAES with theKey and our IV (if supplied), for the actual CMAC operation
  83.         if (bArray != null) {
  84.             cspAESMAC.init(theKey, theMode, bArray, bOff, bLen);
  85.         } else {
  86.             cspAESMAC.init(theKey, theMode);           
  87.         }      
  88.     }
  89.    
  90.     public short sign(byte[] inBuff, short inOffset, short inLength, byte[] sigBuff, short sigOffset)  {
  91.  
  92.         /*
  93.          * First, call update() until we have <= LENGTH_BLOCK_AES bytes to process (which may be zero times)
  94.          * This ensures we are dealing only with the last block and also handles the case where
  95.          * inLength == 0.
  96.          */
  97.         while (inLength > LENGTH_BLOCK_AES) {
  98.                        
  99.             // Encipher the next block, storing it in the CMAC output
  100.             cspAESMAC.update(inBuff, inOffset, LENGTH_BLOCK_AES);
  101.  
  102.             // Move to the next block
  103.             inLength -= LENGTH_BLOCK_AES;
  104.             inOffset += LENGTH_BLOCK_AES;
  105.                        
  106.         }
  107.        
  108.         // We now know that we are dealing with the last block
  109.         processFinalBlock(inBuff, inOffset, inLength);
  110.  
  111.         // We now know that buffer[OFFSET_CMAC] contains the final block to process
  112.  
  113.         // Perform the final CBC encipherment on the last block, writing it back to the same location
  114.         cspAESMAC.sign(buffer, OFFSET_CMAC, LENGTH_BLOCK_AES, buffer, OFFSET_CMAC);
  115.        
  116.         // buffer[OFFSET_CMAC] now contains the CMAC (untrimmed)
  117.        
  118.         // Write the trimmed CMAC value to the outBuffer
  119.         Util.arrayCopyNonAtomic(buffer, OFFSET_CMAC, sigBuff, sigOffset, LENGTH_CMAC);
  120.  
  121.         // Reset our internal buffer
  122.         Util.arrayFillNonAtomic(buffer, ZERO, LENGTH_BUFFER, (byte)0x00);
  123.        
  124.         // Return the length of the CMAC
  125.         return LENGTH_CMAC;
  126.     }
  127.  
  128.     public boolean verify(byte[] inBuff, short inOffset, short inLength, byte[] sigBuff, short sigOffset, short sigLength) {
  129.  
  130.         /*
  131.          * We allow the applet to compare the first 1 < sigLength < LENGTH_CMAC bytes
  132.          * because it is common to truncate the result of a CMAC and this is certainly
  133.          * true of the DESFire, where it uses the first 8 bytes
  134.          */
  135.  
  136.         // Is the supplied length less than 1 or greater than a full CMAC? If not, instant fail
  137.         if (sigLength <= 0 || sigLength > LENGTH_CMAC) return false;
  138.  
  139.         /*
  140.          * First, call update() until we have <= LENGTH_BLOCK_AES bytes to process (which may be zero times)
  141.          * This ensures we are dealing only with the last block and also handles the case where
  142.          * inLength == 0.
  143.          */
  144.         while (inLength > LENGTH_BLOCK_AES) {
  145.                        
  146.             // Encipher the next block, storing it in the CMAC output
  147.             cspAESMAC.update(inBuff, inOffset, LENGTH_BLOCK_AES);
  148.  
  149.             // Move to the next block
  150.             inLength -= LENGTH_BLOCK_AES;
  151.             inOffset += LENGTH_BLOCK_AES;
  152.                        
  153.         }
  154.        
  155.         // We now know that we are dealing with the last block
  156.         processFinalBlock(inBuff, inOffset, inLength);
  157.  
  158.         // We now know that buffer[OFFSET_CMAC] contains the final block to process
  159.  
  160.         // Perform the final CBC encipherment on the last block, writing it back to the same location
  161.         boolean result = cspAESMAC.verify(buffer, OFFSET_CMAC, LENGTH_BLOCK_AES, sigBuff, sigOffset, sigLength);
  162.  
  163.         // Reset our internal buffer
  164.         Util.arrayFillNonAtomic(buffer, ZERO, LENGTH_BUFFER, (byte)0x00);
  165.  
  166.         // Compare the result against the supplied signature
  167.         return result;
  168.     }
  169.  
  170.     public void update(byte[] inBuff, short inOffset, short inLength) {
  171.        
  172.         // This is an intermediate operation, so the length must be a multiple of the block size and non-zero
  173.         if (inLength == 0 || (inLength % LENGTH_BLOCK_AES != 0)) {
  174.             CryptoException.throwIt(CryptoException.ILLEGAL_USE);
  175.         }
  176.        
  177.         // We now know that this is a multiple of the block length;
  178.         while (inLength != 0) {
  179.                        
  180.             // Encipher the next block, storing it in the CMAC output
  181.             cspAESMAC.update(inBuff, inOffset, LENGTH_BLOCK_AES);
  182.  
  183.             // Move to the next block
  184.             inLength -= LENGTH_BLOCK_AES;
  185.             inOffset += LENGTH_BLOCK_AES;
  186.            
  187.         }
  188.     }
  189.                            
  190.     /*
  191.      * Private helper methods
  192.      */
  193.  
  194.  
  195.     /**
  196.      * This method performs the steps associated with the final message block, including
  197.      * the generation of subkeys, message length checking, padding and final subkey XOR'ing
  198.      */
  199.     private void processFinalBlock(byte[] inBuff, short inOffset, short inLength) {
  200.  
  201.         // In step 2, the number of blocks, n, is calculated.  
  202.         // The number of blocks is the smallest integer value greater than or equal to the quotient
  203.         // determined by dividing the length parameter by the block length, 16 octets.     
  204.         // NOTE: Not necessary as we know we're in the final block
  205.        
  206.         // In step 3, the length of the input message is checked.  
  207.         // If the input length is 0 (null), the number of blocks to be processed shall be 1, and
  208.         //  the flag shall be marked as not-complete-block (false).
  209.         // Otherwise, if the last block length is 128 bits, the flag is marked as complete-block
  210.         //  (true); else mark the flag as not-complete-block (false).
  211.         if (inLength == LENGTH_BLOCK_AES) {        
  212.            
  213.             // We process this as a complete block
  214.  
  215.             // In step 4, M_last is calculated by exclusive-OR'ing M_n and one of the previously calculated subkeys.  
  216.             // If the last block is a complete block (true), then M_last is the exclusive-OR of M_n and K1.
  217.  
  218.             // Generate K1
  219.             generateSubkey(buffer, OFFSET_SUBKEY);
  220.            
  221.             for (short i = 0; i < LENGTH_BLOCK_AES; i++) {
  222.                 buffer[(short)(OFFSET_CMAC + i)] = (byte)(inBuff[(short)(inOffset + i)] ^ buffer[(short)(OFFSET_SUBKEY + i)]);
  223.             }          
  224.            
  225.             // buffer[OFFSET_CMAC] now contains the XOR of M_last and K1
  226.            
  227.            
  228.         } else {
  229.  
  230.             // We process this as a not-complete-block
  231.  
  232.             // In step 4, M_last is calculated by exclusive-OR'ing M_n and one of the previously calculated subkeys.  
  233.             // If the last block is a complete block (true), then M_last is the exclusive-OR of M_n and K1.
  234.             // Otherwise, M_last is the exclusive-OR of padding(M_n) and K2.
  235.  
  236.             // Handle the special case (from step 3) where the input length is zero
  237.             if (inLength == 0) {
  238.                 // Fill the CMAC buffer with zeroes
  239.                 Util.arrayFillNonAtomic(buffer, OFFSET_CMAC, LENGTH_BLOCK_AES, (byte)0x00);
  240.                
  241.                 // Set the first byte to the padding constant
  242.                 buffer[OFFSET_CMAC] = CONST_PAD;               
  243.             } else {
  244.                
  245.                 // Copy the input buffer to our CMAC buffer
  246.                 Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, OFFSET_CMAC, inLength);
  247.                
  248.                 // Set the next byte to the padding constant and increment the length to cover it
  249.                 buffer[(short)(OFFSET_CMAC + inLength++)] = CONST_PAD;
  250.                
  251.                 while (inLength != LENGTH_BLOCK_AES) {
  252.                     // Set the next byte to the zero and increment the length to cover it
  253.                     buffer[(short)(OFFSET_CMAC + inLength++)] = 0x00;
  254.                 }
  255.             }
  256.  
  257.             // Generate K2 (just execute the Subkey routine twice)
  258.             generateSubkey(buffer, OFFSET_SUBKEY);
  259.             generateSubkey(buffer, OFFSET_SUBKEY);         
  260.             for (short i = 0; i < LENGTH_BLOCK_AES; i++) {
  261.                 buffer[(short)(OFFSET_CMAC + i)] ^= buffer[(short)(OFFSET_SUBKEY + i)];
  262.             }          
  263.            
  264.             // buffer[OFFSET_CMAC] now contains the XOR of padding(M_last) and K2
  265.         }      
  266.     }
  267.    
  268.     private void rollLeft(byte[] buffer, short offset, short length) {
  269.                        
  270.         // The carry byte is used to store the carry bit for both the current and previous bytes
  271.         byte carry = 0;
  272.         short end = (short)(offset + length - 1);
  273.  
  274.         // Traverse backwards through the array
  275.         for (short i = end; i >= offset; i-- )
  276.         {
  277.             // Store the carry bit for this byte
  278.             carry |= (buffer[i] & 0x80);
  279.            
  280.             // Shift this byte by 1
  281.             buffer[i] <<= 1;
  282.            
  283.             // Restore the previous byte's carry bit
  284.             buffer[i] |= (carry & 0x01);
  285.            
  286.             // Unsigned-right-shift this byte's carry bit down to first position
  287.             // NOTE: Due to int promotion of this signed type, we have to mask off
  288.             //       to the first byte of the promoted carry value.
  289.             carry = (byte)((carry & 0xFF) >>> 7);
  290.         }
  291.        
  292.         // Apply the final carry bit (it will only ever be 0x01 or 0x00)
  293.         // buffer[end] |= carry;
  294.     }
  295.    
  296.     // This method will generate subkey K1 and return it to the same byte array
  297.     // Calling it twice will generate K2
  298.     private void generateSubkey(byte[] l, short offset) {              
  299.         // Step 1 has already been performed in the init() routine
  300.    
  301.         // In step 2, K1 is derived through the following operation:
  302.        
  303.         // If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit.
  304.         if ((l[offset] & 0x80) == 0x00) {
  305.             rollLeft(buffer, offset, LENGTH_BLOCK_AES);
  306.         }          
  307.         // Otherwise, K1 is the exclusive-OR of const_Rb and the left-shift of L by 1 bit.     
  308.         else {
  309.             rollLeft(l, offset, LENGTH_BLOCK_AES);
  310.             l[(short)(offset + LENGTH_BLOCK_AES - 1)] ^= CONST_RB;             
  311.         }
  312.  
  313.         // In step 3, K2 is derived through the following operation:                           
  314.         // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit.
  315.         // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit.
  316.  
  317.         // NOTE: This is just the same operation as for K1, but twice. So call it twice!
  318.     }
  319.    
  320.     /*
  321.     public static void Test() {
  322.  
  323.         // Tests this implementation according to https://tools.ietf.org/html/rfc4493#section-2.4
  324.        
  325.         Signature sig = new AESCMAC128();
  326.        
  327.         byte[] k = new byte[] {
  328.             (byte)0x2B, (byte)0x7E, (byte)0x15, (byte)0x16, (byte)0x28, (byte)0xAE, (byte)0xD2, (byte)0xA6,
  329.             (byte)0xAB, (byte)0xF7, (byte)0x15, (byte)0x88, (byte)0x09, (byte)0xCF, (byte)0x4F, (byte)0x3C
  330.         }; // Length 16 bytes
  331.        
  332.         byte[] d1 = new byte[0];
  333.         // Expect bb1d6929 e9593728 7fa37d12 9b756746
  334.        
  335.         byte[] d2 = new byte[] {
  336.             (byte)0x6B, (byte)0xC1, (byte)0xBE, (byte)0xE2, (byte)0x2E, (byte)0x40, (byte)0x9F, (byte)0x96,
  337.             (byte)0xE9, (byte)0x3D, (byte)0x7E, (byte)0x11, (byte)0x73, (byte)0x93, (byte)0x17, (byte)0x2A
  338.         }; // Length 16 bytes
  339.         // Expect 070a16b4 6b4d4144 f79bdd9d d04a287c
  340.        
  341.         byte[] d3 = new byte[] {
  342.             (byte)0x6B, (byte)0xC1, (byte)0xBE, (byte)0xE2, (byte)0x2E, (byte)0x40, (byte)0x9F, (byte)0x96,
  343.             (byte)0xE9, (byte)0x3D, (byte)0x7E, (byte)0x11, (byte)0x73, (byte)0x93, (byte)0x17, (byte)0x2A,
  344.             (byte)0xAE, (byte)0x2D, (byte)0x8A, (byte)0x57, (byte)0x1E, (byte)0x03, (byte)0xAC, (byte)0x9C,
  345.             (byte)0x9E, (byte)0xB7, (byte)0x6F, (byte)0xAC, (byte)0x45, (byte)0xAF, (byte)0x8E, (byte)0x51,
  346.             (byte)0x30, (byte)0xC8, (byte)0x1C, (byte)0x46, (byte)0xA3, (byte)0x5C, (byte)0xE4, (byte)0x11
  347.          }; // Length 40 bytes
  348.         // Expect dfa66747 de9ae630 30ca3261 1497c827
  349.        
  350.         byte[] d4 = new byte[] {
  351.             (byte)0x6B, (byte)0xC1, (byte)0xBE, (byte)0xE2, (byte)0x2E, (byte)0x40, (byte)0x9F, (byte)0x96,
  352.             (byte)0xE9, (byte)0x3D, (byte)0x7E, (byte)0x11, (byte)0x73, (byte)0x93, (byte)0x17, (byte)0x2A,
  353.             (byte)0xAE, (byte)0x2D, (byte)0x8A, (byte)0x57, (byte)0x1E, (byte)0x03, (byte)0xAC, (byte)0x9C,
  354.             (byte)0x9E, (byte)0xB7, (byte)0x6F, (byte)0xAC, (byte)0x45, (byte)0xAF, (byte)0x8E, (byte)0x51,
  355.             (byte)0x30, (byte)0xC8, (byte)0x1C, (byte)0x46, (byte)0xA3, (byte)0x5C, (byte)0xE4, (byte)0x11,
  356.             (byte)0xE5, (byte)0xFB, (byte)0xC1, (byte)0x19, (byte)0x1A, (byte)0x0A, (byte)0x52, (byte)0xEF,
  357.             (byte)0xF6, (byte)0x9F, (byte)0x24, (byte)0x45, (byte)0xDF, (byte)0x4F, (byte)0x9B, (byte)0x17,
  358.             (byte)0xAD, (byte)0x2B, (byte)0x41, (byte)0x7B, (byte)0xE6, (byte)0x6C, (byte)0x37, (byte)0x10
  359.          }; // Length 64 bytes
  360.         // Expect 51f0bebf 7e3b9d92 fc497417 79363cfe
  361.  
  362.         byte[] m = new byte[16];
  363.         boolean ok = false;
  364.        
  365.         AESKey key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
  366.         key.setKey(k, ZERO);
  367.        
  368.         sig.init(key, Signature.MODE_SIGN);
  369.         sig.sign(d1, ZERO, (short)d1.length, m, ZERO);     
  370.        
  371.         sig.init(key, Signature.MODE_VERIFY);
  372.         ok = sig.verify(d1, ZERO, (short)d1.length, m, ZERO, (short)16);       
  373.  
  374.         sig.init(key, Signature.MODE_SIGN);
  375.         sig.sign(d2, ZERO, (short)d2.length, m, ZERO);
  376.        
  377.         sig.init(key, Signature.MODE_VERIFY);
  378.         ok = sig.verify(d2, ZERO, (short)d2.length, m, ZERO, (short)16);       
  379.        
  380.         sig.init(key, Signature.MODE_SIGN);
  381.         sig.sign(d3, ZERO, (short)d3.length, m, ZERO);
  382.        
  383.         sig.init(key, Signature.MODE_VERIFY);
  384.         ok = sig.verify(d3, ZERO, (short)d3.length, m, ZERO, (short)16);       
  385.        
  386.         sig.init(key, Signature.MODE_SIGN);
  387.         sig.sign(d4, ZERO, (short)d4.length, m, ZERO);
  388.  
  389.         sig.init(key, Signature.MODE_VERIFY);
  390.         ok = sig.verify(d4, ZERO, (short)d4.length, m, ZERO, (short)16);       
  391.        
  392.        
  393.     }
  394.     */
  395. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement