Advertisement
Guest User

Untitled

a guest
Dec 12th, 2011
723
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.40 KB | None | 0 0
  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.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement