Advertisement
Guest User

Untitled

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