Want more features on Pastebin? Sign Up, it's FREE!
Guest

Untitled

By: a guest on Dec 12th, 2011  |  syntax: None  |  size: 27.40 KB  |  views: 563  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. package unself;
  2.  
  3. import java.io.File;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. import java.io.RandomAccessFile;
  7. import java.io.UnsupportedEncodingException;
  8. import java.math.BigInteger;
  9. import java.security.InvalidAlgorithmParameterException;
  10. import java.security.InvalidKeyException;
  11. import java.security.NoSuchAlgorithmException;
  12. import java.security.spec.AlgorithmParameterSpec;
  13. import javax.crypto.Cipher;
  14. import javax.crypto.Mac;
  15. import javax.crypto.NoSuchPaddingException;
  16. import javax.crypto.ShortBufferException;
  17. import javax.crypto.spec.IvParameterSpec;
  18. import javax.crypto.spec.SecretKeySpec;
  19.  
  20. public class EDAT {
  21.  
  22.     public static final int STATUS_ERROR_INPUTFILE_IO = -100;
  23.     public static final int STATUS_ERROR_HASHTITLEIDNAME = -1;
  24.     public static final int STATUS_ERROR_HASHDEVKLIC = -2;
  25.     public static final int STATUS_ERROR_MISSINGKEY = -3;
  26.     public static final int STATUS_ERROR_HEADERCHECK = -4;
  27.     public static final int STATUS_ERROR_DECRYPTING = -5;
  28.     public static final int STATUS_OK = 0;
  29.     public static final long FLAG_COMPRESSED = 0x00000001L;
  30.     public static final long FLAG_0x02 = 0x00000002L;
  31.     public static final long FLAG_KEYENCRYPTED = 0x00000008L;
  32.     public static final long FLAG_0x10 = 0x00000010L;
  33.     public static final long FLAG_0x20 = 0x00000020L;
  34.     public static final long FLAG_SDAT = 0x01000000L;
  35.     public static final long FLAG_DEBUG = 0x80000000L;
  36.  
  37.     /**
  38.      *
  39.      * This function reads given file and decrypts it
  40.      *
  41.      * @param inFile EDAT file to decrypt
  42.      * @param outFile Path to store the decrypted data
  43.      * @param devKLic Authentication key. Also used for decryption on free content
  44.      * @param keyFromRif Key obtained after decrypting rif60
  45.      * @return Result of the operation
  46.      */
  47.     public int decryptFile(String inFile, String outFile, byte[] devKLic, byte[] keyFromRif) throws FileNotFoundException, IOException {
  48.         File fin = new File(inFile);
  49.         RandomAccessFile raf = null;
  50.         raf = new RandomAccessFile(fin, "r");
  51.         NPD[] ptr = new NPD[1]; //Ptr to Ptr
  52.         int result = validateNPD(fin.getName(), devKLic, ptr, raf); //Validate NPD hashes
  53.         if (result < 0) {
  54.             return result;
  55.         }
  56.         NPD npd = ptr[0];
  57.         EDATData data = getEDATData(raf);
  58.         byte[] rifkey = getKey(npd, data, devKLic, keyFromRif); //Obtain the key for decryption (result of sc471 or sdatkey)
  59.         if (rifkey == null) {
  60.             System.out.println("ERROR: Key for decryption is missing");
  61.             return STATUS_ERROR_MISSINGKEY;
  62.         } else {
  63.             System.out.println("DECRYPTION KEY: " + ConversionUtils.getHexString(rifkey));
  64.         }
  65.         result = checkHeader(rifkey, data, raf);
  66.         if (result < 0) {
  67.             return result;
  68.         }
  69.         RandomAccessFile out = new RandomAccessFile(outFile, "rw");
  70.         result = decryptData(raf, out, npd, data, rifkey);
  71.         if (result < 0) {
  72.             return result;
  73.         }
  74.         raf.close();
  75.         return STATUS_OK;
  76.     }
  77.     private static final int HEADER_MAX_BLOCKSIZE = 0x3C00;
  78.  
  79.     private int checkHeader(byte[] rifKey, EDATData data, RandomAccessFile in) throws IOException {
  80.         in.seek(0);
  81.         byte[] header = new byte[0xA0];
  82.         byte[] out = new byte[0xA0];
  83.         byte[] expectedHash = new byte[0x10];
  84.  
  85.         int numBlocks = (int) ((data.getFileLen().intValue() + data.getBlockSize() - 11) / data.getBlockSize());
  86.         in.readFully(header);
  87.         in.readFully(expectedHash);
  88.         System.out.println("Checking header hash:");
  89.         AppLoader a = new AppLoader();
  90.         int hashFlag = ((data.getFlags() & FLAG_KEYENCRYPTED) == 0) ? 0x00000002 : 0x10000002;
  91.         //if ((data.getFlags() & DEBUG_FLAG) != 0) hashFlag |= 0x01000000;  //Debug check not implemented
  92.  
  93.         //Veryfing header
  94.         boolean result = a.doAll(hashFlag, 0x00000001, header, 0, out, 0, header.length, new byte[0x10], new byte[0x10], rifKey, expectedHash, 0);
  95.         if (!result) {
  96.             System.out.println("Error verifying header. Is rifKey valid?");
  97.             return STATUS_ERROR_HEADERCHECK;
  98.         }
  99.         System.out.println("Checking metadata hash:");
  100.         a = new AppLoader();
  101.         a.doInit(hashFlag, 0x00000001, new byte[0x10], new byte[0x10], rifKey);
  102.  
  103.         int sectionSize = ((data.getFlags() & FLAG_COMPRESSED) != 0) ? 0x20 : 0x010;
  104.  
  105.         int readed = 0;
  106.         int baseOffset = 0x100;
  107.         //baseOffset +=  modifier; //There is an unknown offset to add to the metadatasection... value seen 0
  108.         long remaining = sectionSize * numBlocks;
  109.         while (remaining > 0) {
  110.             int lenToRead = (HEADER_MAX_BLOCKSIZE > remaining) ? (int) remaining : HEADER_MAX_BLOCKSIZE;
  111.             in.seek(baseOffset + readed);
  112.             byte[] content = new byte[lenToRead];
  113.             out = new byte[lenToRead];
  114.             in.readFully(content);
  115.             a.doUpdate(content, 0, out, 0, lenToRead);
  116.             readed += lenToRead;
  117.             remaining -= lenToRead;
  118.         }
  119.         result = a.doFinal(header, 0x90);
  120.  
  121.  
  122.         if (!result) {
  123.             System.out.println("Error verifying metadatasection. Data tampered");
  124.             return STATUS_ERROR_HEADERCHECK;
  125.         }
  126.         return STATUS_OK;
  127.     }
  128.  
  129.     private byte[] decryptMetadataSection(byte[] metadata) {
  130.         byte[] result = new byte[0x10];
  131.         result[0x00] = (byte) (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]);
  132.         result[0x01] = (byte) (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]);
  133.         result[0x02] = (byte) (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]);
  134.         result[0x03] = (byte) (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]);
  135.         result[0x04] = (byte) (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]);
  136.         result[0x05] = (byte) (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]);
  137.         result[0x06] = (byte) (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]);
  138.         result[0x07] = (byte) (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]);
  139.         result[0x08] = (byte) (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]);
  140.         result[0x09] = (byte) (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]);
  141.         result[0x0A] = (byte) (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]);
  142.         result[0x0B] = (byte) (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]);
  143.         result[0x0C] = (byte) (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]);
  144.         result[0x0D] = (byte) (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]);
  145.         result[0x0E] = (byte) (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]);
  146.         result[0x0F] = (byte) (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]);
  147.         return result;
  148.     }
  149.  
  150.     private EDATData getEDATData(RandomAccessFile in) throws IOException {
  151.         in.seek(0x80);
  152.         byte[] data = new byte[0x10];
  153.         in.readFully(data);
  154.         return EDATData.createEDATData(data);
  155.     }
  156.  
  157.     private boolean compareBytes(byte[] value1, int offset1, byte[] value2, int offset2, int len) {
  158.         boolean result = true;
  159.         for (int i = 0; i < len; i++) {
  160.             if (value1[i + offset1] != value2[i + offset2]) {
  161.                 result = false;
  162.                 break;
  163.             }
  164.         }
  165.         return result;
  166.     }
  167.  
  168.     private int validateNPD(String filename, byte[] devKLic, NPD[] npdPtr, RandomAccessFile in) throws IOException {
  169.         in.seek(0);
  170.         byte[] npd = new byte[0x80];
  171.         in.readFully(npd);
  172.         byte[] extraData = new byte[0x04];
  173.         in.readFully(extraData);
  174.         long flag = ConversionUtils.be32(extraData, 0);
  175.         if ((flag & FLAG_SDAT) != 0) {
  176.             System.out.println("INFO: SDAT detected. NPD header is not validated");
  177.         } else if (!checkNPDHash1(filename, npd)) {
  178.             return STATUS_ERROR_HASHTITLEIDNAME;
  179.         } else if (devKLic == null) {
  180.             System.out.println("WARNING: Can not validate devklic header");
  181.         } else if (!checkNPDHash2(devKLic, npd)) {
  182.             return STATUS_ERROR_HASHDEVKLIC;
  183.         }
  184.         npdPtr[0] = NPD.createNPD(npd);;
  185.         return STATUS_OK;
  186.     }
  187.  
  188.     private boolean checkNPDHash1(String filename, byte[] npd) throws UnsupportedEncodingException {
  189.         byte[] fileBytes = filename.getBytes("US-ASCII");
  190.         byte data1[] = new byte[0x30 + fileBytes.length];
  191.         System.arraycopy(npd, 0x10, data1, 0, 0x30);
  192.         System.arraycopy(fileBytes, 0x00, data1, 0x30, fileBytes.length);
  193.         byte[] hash1 = ToolsImpl.CMAC128(npdrm_omac_key3, data1, 0, data1.length);
  194.         boolean result1 = compareBytes(hash1, 0, npd, 0x50, 0x10);
  195.         if (result1) {
  196.             System.out.println("NPD hash 1 is valid (" + ConversionUtils.getHexString(hash1) + ")");
  197.         }
  198.         return result1;
  199.     }
  200.  
  201.     private boolean checkNPDHash2(byte[] klicensee, byte[] npd) {
  202.         byte[] xoredKey = new byte[0x10];
  203.         ToolsImpl.XOR(xoredKey, klicensee, npdrm_omac_key2);
  204.         byte[] calculated = ToolsImpl.CMAC128(xoredKey, npd, 0, 0x60);
  205.         boolean result2 = compareBytes(calculated, 0, npd, 0x60, 0x10);
  206.         if (result2) {
  207.             System.out.println("NPD hash 2 is valid (" + ConversionUtils.getHexString(calculated) + ")");
  208.         }
  209.         return result2;
  210.     }
  211.  
  212.  
  213.     private byte[] getKey(NPD npd, EDATData data, byte[] devKLic, byte[] keyFromRif) {
  214.         byte[] result = null;
  215.         if ((data.getFlags() & FLAG_SDAT) != 0) {
  216.             //Case SDAT
  217.             result = new byte[0x10];
  218.             ToolsImpl.XOR(result, npd.getDevHash(), SDATKEY);
  219.         } else {
  220.             //Case EDAT
  221.             if (npd.getLicense() == 0x03) {
  222.                 result = devKLic;
  223.             } else if (npd.getLicense() == 0x02) {
  224.                 result = keyFromRif;
  225.             }
  226.         }
  227.         return result;
  228.     }
  229.    
  230.     private int decryptData(RandomAccessFile in, RandomAccessFile out, NPD npd, EDATData data, byte[] rifkey) throws IOException {
  231.         int numBlocks = (int) ((data.getFileLen().intValue() + data.getBlockSize() - 1) / data.getBlockSize());
  232.         int metadataSectionSize = ((data.getFlags() & FLAG_COMPRESSED) != 0 || (data.getFlags() & FLAG_0x20) != 0) ? 0x20 : 0x10;
  233.         int baseOffset = 0x100; //+ offset (unknown)
  234.         for (int i = 0; i < numBlocks; i++) {
  235.             in.seek(baseOffset + i * metadataSectionSize);
  236.             byte[] expectedHash = new byte[0x10];
  237.             long offset;
  238.             int len;
  239.             int compressionEndBlock = 0;
  240.             if ((data.getFlags() & FLAG_COMPRESSED) != 0) {
  241.                 byte[] metadata = new byte[0x20];
  242.                 in.readFully(metadata);
  243.                 byte[] result = decryptMetadataSection(metadata);
  244.                 offset = ConversionUtils.be64(result, 0).intValue(); // + offset (unknown)
  245.                 len = Long.valueOf(ConversionUtils.be32(result, 8)).intValue();
  246.                 compressionEndBlock = Long.valueOf(ConversionUtils.be32(result, 0xC)).intValue();
  247.                 System.arraycopy(metadata, 0, expectedHash, 0, 0x10);            
  248.             } else {
  249.                 in.readFully(expectedHash);
  250.                 offset = baseOffset + i * data.getBlockSize() + numBlocks * metadataSectionSize;
  251.                 len = Long.valueOf(data.getBlockSize()).intValue();
  252.                 if (i == numBlocks - 1) {
  253.                     len = data.getFileLen().mod(BigInteger.valueOf(data.getBlockSize())).intValue();
  254.                 }
  255.             }
  256.             int realLen = len;
  257.             len = (len + 0xF) & 0xFFFFFFF0;
  258.             System.out.printf("Offset: %016X, len: %08X, realLen: %08X, endCompress: %d\r\n", offset, len, realLen,compressionEndBlock);
  259.             in.seek(offset);
  260.             byte[] encryptedData = new byte[len];
  261.             byte[] decryptedData = new byte[len];
  262.             in.readFully(encryptedData);
  263.             byte[] key = new byte[0x10];
  264.             byte[] hash = new byte[0x10];
  265.             byte[] blockKey = calculateBlockKey(i, npd.getDevHash());
  266.  
  267.             ToolsImpl.aesecbEncrypt(rifkey, blockKey, 0, key, 0, blockKey.length);
  268.             if ((data.getFlags() & FLAG_0x10) != 0) {
  269.                 ToolsImpl.aesecbEncrypt(rifkey, key, 0, hash, 0, key.length);
  270.             } else {
  271.                 System.arraycopy(key, 0, hash, 0, key.length);
  272.             }
  273.             int cryptoFlag = ((data.getFlags() & FLAG_0x02) == 0) ? 0x2 : 0x1;
  274.             int hashFlag;
  275.             if ((data.getFlags() & FLAG_0x10) == 0) {
  276.                 hashFlag = 0x02;
  277.             } else if ((data.getFlags() & FLAG_0x20) == 0) {
  278.                 hashFlag = 0x04;
  279.             } else {
  280.                 hashFlag = 0x01;
  281.             }
  282.             if ((data.getFlags() & FLAG_KEYENCRYPTED) != 0) {
  283.                 cryptoFlag |= 0x10000000;
  284.                 hashFlag |= 0x10000000;
  285.             }
  286.             if ((data.getFlags() & FLAG_DEBUG) != 0) {
  287.                 cryptoFlag |= 0x01000000;
  288.                 hashFlag |= 0x01000000;
  289.             }
  290.             AppLoader a = new AppLoader();
  291.             boolean result = a.doAll(hashFlag, cryptoFlag, encryptedData, 0, decryptedData, 0, encryptedData.length, key, npd.getDigest(), hash, expectedHash, 0);
  292.             if (!result) {
  293.                 System.out.println("Error decrypting block " + i);
  294.                 return STATUS_ERROR_DECRYPTING;
  295.             }
  296.             if ((data.getFlags() & FLAG_COMPRESSED) != 0) {
  297.                 //byte[] decompress = new byte[Long.valueOf(data.getBlockSize()).intValue()];
  298.                 //DECOMPRESS: MISSING ALGORITHM                
  299.                 //out.write(decompress, 0, data.getBlockSize());
  300.             } else {
  301.                 out.write(decryptedData, 0, realLen);
  302.             }
  303.         }
  304.         return STATUS_OK;
  305.     }
  306.  
  307.     private byte[] calculateBlockKey(int blk, byte[] baseKey) {
  308.         byte[] result = new byte[0x10];
  309.         System.arraycopy(baseKey, 0, result, 0, 0xC);
  310.         result[0xC] = (byte) (blk >> 24 & 0xFF);
  311.         result[0xD] = (byte) (blk >> 16 & 0xFF);
  312.         result[0xE] = (byte) (blk >> 8 & 0xFF);
  313.         result[0xF] = (byte) (blk & 0xFF);
  314.         return result;
  315.     }
  316.  
  317.     class AppLoader {
  318.  
  319.         private Decryptor dec;
  320.         private Hash hash;
  321.  
  322.         public boolean doAll(int hashFlag, int cryptoFlag, byte[] in, int inOffset, byte[] out, int outOffset, int len, byte[] key, byte[] iv, byte[] hash, byte[] expectedHash, int hashOffset) {
  323.             doInit(hashFlag, cryptoFlag, key, iv, hash);
  324.             doUpdate(in, inOffset, out, outOffset, len);
  325.             return doFinal(expectedHash, hashOffset);
  326.         }
  327.  
  328.         public void doInit(int hashFlag, int cryptoFlag, byte[] key, byte[] iv, byte[] hashKey) {
  329.             byte[] calculatedKey = new byte[key.length];
  330.             byte[] calculatedIV = new byte[iv.length];
  331.             byte[] calculatedHash = new byte[hashKey.length];
  332.             getCryptoKeys(cryptoFlag, calculatedKey, calculatedIV, key, iv);
  333.             getHashKeys(hashFlag, calculatedHash, hashKey);
  334.             setDecryptor(cryptoFlag);
  335.             setHash(hashFlag);
  336.             System.out.println("ERK:  " + ConversionUtils.getHexString(calculatedKey));
  337.             System.out.println("IV:   " + ConversionUtils.getHexString(calculatedIV));
  338.             System.out.println("HASH: " + ConversionUtils.getHexString(calculatedHash));
  339.             dec.doInit(calculatedKey, calculatedIV);
  340.             hash.doInit(calculatedHash);
  341.         }
  342.  
  343.         public void doUpdate(byte[] in, int inOffset, byte[] out, int outOffset, int len) {
  344.             hash.doUpdate(in, inOffset, len);
  345.             dec.doUpdate(in, inOffset, out, outOffset, len);
  346.         }
  347.  
  348.         public boolean doFinal(byte[] expectedhash, int hashOffset) {
  349.             return hash.doFinal(expectedhash, hashOffset);
  350.         }
  351.  
  352.         private void getCryptoKeys(int cryptoFlag, byte[] calculatedKey, byte[] calculatedIV, byte[] key, byte[] iv) {
  353.             int mode = cryptoFlag & 0xF0000000;
  354.             switch (mode) {
  355.                 case 0x10000000:
  356.                     ToolsImpl.aescbcDecrypt(EDATKEY, EDATIV, key, 0, calculatedKey, 0, calculatedKey.length);
  357.                     System.arraycopy(iv, 0, calculatedIV, 0, calculatedIV.length);
  358.                     System.out.println("MODE: Encrypted ERK");
  359.                     break;
  360.                 case 0x20000000:
  361.                     System.arraycopy(EDATKEY, 0, calculatedKey, 0, calculatedKey.length);
  362.                     System.arraycopy(EDATIV, 0, calculatedIV, 0, calculatedIV.length);
  363.                     System.out.println("MODE: Default ERK");
  364.                     break;
  365.                 case 0x00000000:
  366.                     System.arraycopy(key, 0, calculatedKey, 0, calculatedKey.length);
  367.                     System.arraycopy(iv, 0, calculatedIV, 0, calculatedIV.length);
  368.                     System.out.println("MODE: Unencrypted ERK");
  369.                     break;
  370.                 default:
  371.                     throw new IllegalStateException("Crypto mode is not valid: Undefined keys calculator");
  372.             }
  373.         }
  374.  
  375.         private void getHashKeys(int hashFlag, byte[] calculatedHash, byte[] hash) {
  376.             int mode = hashFlag & 0xF0000000;
  377.             switch (mode) {
  378.                 case 0x10000000:
  379.                     ToolsImpl.aescbcDecrypt(EDATKEY, EDATIV, hash, 0, calculatedHash, 0, calculatedHash.length);
  380.                     System.out.println("MODE: Encrypted HASHKEY");
  381.                     break;
  382.                 case 0x20000000:
  383.                     System.arraycopy(EDATHASH, 0, calculatedHash, 0, calculatedHash.length);
  384.                     System.out.println("MODE: Default HASHKEY");
  385.                     break;
  386.                 case 0x00000000:
  387.                     System.arraycopy(hash, 0, calculatedHash, 0, calculatedHash.length);
  388.                     System.out.println("MODE: Unencrypted HASHKEY");
  389.                     break;
  390.                 default:
  391.                     throw new IllegalStateException("Hash mode is not valid: Undefined keys calculator");
  392.             }
  393.         }
  394.  
  395.         private void setDecryptor(int cryptoFlag) {
  396.             int aux = cryptoFlag & 0xFF;
  397.             switch (aux) {
  398.                 case 0x01:
  399.                     dec = new NoCrypt();
  400.                     System.out.println("MODE: Decryption Algorithm NONE");
  401.                     break;
  402.                 case 0x02:
  403.                     dec = new AESCBC128Decrypt();
  404.                     System.out.println("MODE: Decryption Algorithm AESCBC128");
  405.                     break;
  406.                 default:
  407.                     throw new IllegalStateException("Crypto mode is not valid: Undefined decryptor");
  408.  
  409.             }
  410.  
  411.         }
  412.  
  413.         private void setHash(int hashFlag) {
  414.             int aux = hashFlag & 0xFF;
  415.             switch (aux) {
  416.                 case 0x01:
  417.                     hash = new HMAC();
  418.                     hash.setHashLen(0x14);
  419.                     System.out.println("MODE: Hash HMAC Len 0x14");
  420.                     break;
  421.                 case 0x02:
  422.                     hash = new CMAC();
  423.                     hash.setHashLen(0x10);
  424.                     System.out.println("MODE: Hash CMAC Len 0x10");
  425.                     break;
  426.                 case 0x04:
  427.                     hash = new HMAC();
  428.                     hash.setHashLen(0x10);
  429.                     System.out.println("MODE: Hash HMAC Len 0x10");
  430.                     break;
  431.                 default:
  432.                     throw new IllegalStateException("Hash mode is not valid: Undefined hash algorithm");
  433.             }
  434.         }
  435.  
  436.         abstract class Decryptor {
  437.  
  438.             public abstract void doInit(byte[] key, byte[] iv);
  439.  
  440.             public abstract void doUpdate(byte[] in, int inOffset, byte[] out, int outOffset, int len);
  441.         }
  442.  
  443.         class NoCrypt extends Decryptor {
  444.  
  445.             @Override
  446.             public void doInit(byte[] key, byte[] iv) {
  447.                 //Do nothing
  448.             }
  449.  
  450.             @Override
  451.             public void doUpdate(byte[] in, int inOffset, byte[] out, int outOffset, int len) {
  452.                 System.arraycopy(in, inOffset, out, outOffset, len);
  453.             }
  454.         }
  455.  
  456.         class AESCBC128Decrypt extends Decryptor {
  457.  
  458.             Cipher c;
  459.  
  460.             @Override
  461.             public void doInit(byte[] key, byte[] iv) {
  462.                 try {
  463.                     SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
  464.                     c = Cipher.getInstance("AES/CBC/NoPadding");
  465.                     AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
  466.                     c.init(Cipher.DECRYPT_MODE, skeySpec, paramSpec);
  467.                 } catch (InvalidKeyException ex) {
  468.                     throw new IllegalStateException(ex);
  469.                 } catch (InvalidAlgorithmParameterException ex) {
  470.                     throw new IllegalStateException(ex);
  471.                 } catch (NoSuchAlgorithmException ex) {
  472.                     throw new IllegalStateException(ex);
  473.                 } catch (NoSuchPaddingException ex) {
  474.                     throw new IllegalStateException(ex);
  475.                 }
  476.             }
  477.  
  478.             @Override
  479.             public void doUpdate(byte[] in, int inOffset, byte[] out, int outOffset, int len) {
  480.                 try {
  481.                     c.update(in, inOffset, len, out, outOffset);
  482.                 } catch (ShortBufferException ex) {
  483.                     throw new IllegalStateException(ex);
  484.                 }
  485.             }
  486.         }
  487.  
  488.         abstract class Hash {
  489.  
  490.             public abstract void setHashLen(int len);
  491.  
  492.             public abstract void doInit(byte[] key);
  493.  
  494.             public abstract void doUpdate(byte[] in, int inOffset, int len);
  495.  
  496.             public abstract boolean doFinal(byte[] expectedhash, int hashOffset);
  497.         }
  498.  
  499.         class HMAC extends Hash {
  500.  
  501.             private int hashLen;
  502.             private Mac mac;
  503.  
  504.             @Override
  505.             public void setHashLen(int len) {
  506.                 if (len == 0x10 || len == 0x14) {
  507.                     hashLen = len;
  508.                 } else {
  509.                     throw new IllegalArgumentException("Hash len must be 0x10 or 0x14");
  510.                 }
  511.             }
  512.  
  513.             @Override
  514.             public void doInit(byte[] key) {
  515.                 try {
  516.                     SecretKeySpec skeySpec = new SecretKeySpec(key, "HmacSHA1");
  517.                     mac = Mac.getInstance("HmacSHA1");
  518.                     mac.init(skeySpec);
  519.                 } catch (InvalidKeyException ex) {
  520.                     throw new IllegalStateException(ex);
  521.                 } catch (NoSuchAlgorithmException ex) {
  522.                     throw new IllegalStateException(ex);
  523.                 }
  524.             }
  525.  
  526.             @Override
  527.             public void doUpdate(byte[] in, int inOffset, int len) {
  528.                 mac.update(in, inOffset, len);
  529.             }
  530.  
  531.             @Override
  532.             public boolean doFinal(byte[] expectedhash, int hashOffset) {
  533.                 byte[] result = mac.doFinal();
  534.                 return compareBytes(result, 0, expectedhash, hashOffset, hashLen);
  535.             }
  536.         }
  537.  
  538.         class CMAC extends Hash {
  539.  
  540.             int hashLen;
  541.             byte[] key;
  542.             byte[] K1;
  543.             byte[] K2;
  544.             byte[] nonProcessed;
  545.             byte[] previous;
  546.  
  547.             public CMAC() {
  548.                 hashLen = 0x10;
  549.             }
  550.  
  551.             @Override
  552.             public void setHashLen(int len) {
  553.                 if (len == 0x10) {
  554.                     hashLen = len;
  555.                 } else {
  556.                     throw new IllegalArgumentException("Hash len must be 0x10");
  557.                 }
  558.             }
  559.  
  560.             @Override
  561.             public void doInit(byte[] key) {
  562.                 this.key = key;
  563.                 K1 = new byte[0x10];
  564.                 K2 = new byte[0x10];
  565.                 calculateSubkey(key, K1, K2);
  566.                 nonProcessed = null;
  567.                 previous = new byte[0x10];
  568.             }
  569.  
  570.             private void calculateSubkey(byte[] key, byte[] K1, byte[] K2) {
  571.                 byte[] zero = new byte[0x10];
  572.                 byte[] L = new byte[0x10];
  573.                 ToolsImpl.aesecbEncrypt(key, zero, 0, L, 0, zero.length);
  574.                 BigInteger aux = new BigInteger(1, L);
  575.                 if ((L[0] & 0x80) != 0) {
  576.                     //Case MSB is set
  577.                     aux = aux.shiftLeft(1).xor(BigInteger.valueOf(0x87));
  578.                 } else {
  579.                     aux = aux.shiftLeft(1);
  580.                 }
  581.                 byte[] aux1 = aux.toByteArray();
  582.                 if (aux1.length >= 0x10) {
  583.                     System.arraycopy(aux1, aux1.length - 0x10, K1, 0, 0x10);
  584.                 } else {
  585.                     System.arraycopy(zero, 0, K1, 0, zero.length);
  586.                     System.arraycopy(aux1, 0, K1, 0x10 - aux1.length, aux1.length);
  587.                 }
  588.                 aux = new BigInteger(1, K1);
  589.                 if ((K1[0] & 0x80) != 0) {
  590.                     aux = aux.shiftLeft(1).xor(BigInteger.valueOf(0x87));
  591.                 } else {
  592.                     aux = aux.shiftLeft(1);
  593.                 }
  594.                 aux1 = aux.toByteArray();
  595.                 if (aux1.length >= 0x10) {
  596.                     System.arraycopy(aux1, aux1.length - 0x10, K2, 0, 0x10);
  597.                 } else {
  598.                     System.arraycopy(zero, 0, K2, 0, zero.length);
  599.                     System.arraycopy(aux1, 0, K2, 0x10 - aux1.length, aux1.length);
  600.                 }
  601.             }
  602.  
  603.             @Override
  604.             public void doUpdate(byte[] in, int inOffset, int len) {
  605.                 byte[] data;
  606.                 if (nonProcessed != null) {
  607.                     int totalLen = len + nonProcessed.length;
  608.                     data = new byte[totalLen];
  609.                     System.arraycopy(nonProcessed, 0, data, 0, nonProcessed.length);
  610.                     System.arraycopy(in, inOffset, data, nonProcessed.length, len);
  611.                 } else {
  612.                     data = new byte[len];
  613.                     System.arraycopy(in, inOffset, data, 0, len);
  614.                 }
  615.                 int count = 0;
  616.                 while (count < data.length - 0x10) {
  617.                     byte[] aux = new byte[0x10];
  618.                     System.arraycopy(data, count, aux, 0, aux.length);
  619.                     ToolsImpl.XOR(aux, aux, previous);
  620.                     ToolsImpl.aesecbEncrypt(key, aux, 0, previous, 0, aux.length);
  621.                     count += 0x10;
  622.                 }
  623.                 nonProcessed = new byte[data.length - count];
  624.                 System.arraycopy(data, count, nonProcessed, 0, nonProcessed.length);
  625.             }
  626.  
  627.             @Override
  628.             public boolean doFinal(byte[] expectedhash, int hashOffset) {
  629.                 byte[] aux = new byte[0x10];
  630.                 System.arraycopy(nonProcessed, 0, aux, 0, nonProcessed.length);
  631.                 if (nonProcessed.length == 0x10) {
  632.                     ToolsImpl.XOR(aux, aux, K1);
  633.                 } else {
  634.                     aux[nonProcessed.length] = (byte) 0x80;
  635.                     ToolsImpl.XOR(aux, aux, K2);
  636.                 }
  637.                 ToolsImpl.XOR(aux, aux, previous);
  638.                 byte[] calculatedhash = new byte[0x10];
  639.                 ToolsImpl.aesecbEncrypt(key, aux, 0, calculatedhash, 0, aux.length);
  640.                 return compareBytes(expectedhash, hashOffset, calculatedhash, 0, hashLen);
  641.             }
  642.         }
  643.     }
  644. }
  645.  
  646.  
clone this paste RAW Paste Data