public override void doUpdate(byte[] i, int inOffset, int len) { byte[] data; if (nonProcessed != null) { int totalLen = len + nonProcessed.Length; data = new byte[totalLen]; ConversionUtils.arraycopy(nonProcessed, 0, data, 0, nonProcessed.Length); ConversionUtils.arraycopy(i, inOffset, data, nonProcessed.Length, len); } else { data = new byte[len]; ConversionUtils.arraycopy(i, inOffset, data, 0, len); } int count = 0; while (count < data.Length - 0x10) { byte[] aux = new byte[0x10]; ConversionUtils.arraycopy(data, count, aux, 0, aux.Length); ToolsImpl.XOR(aux, aux, previous); ToolsImpl.aesecbEncrypt(key, aux, 0, previous, 0, aux.Length); count += 0x10; } nonProcessed = new byte[data.Length - count]; ConversionUtils.arraycopy(data, count, nonProcessed, 0, nonProcessed.Length); }
private static byte[] getPerConsoleKey(String IDPSFile) { FileStream raf = File.Open(IDPSFile, FileMode.Open); byte[] idps = new byte[0x10]; raf.Read(idps, 0, idps.Length); raf.Close(); byte[] result = new byte[0x10]; ToolsImpl.aesecbEncrypt(idps, ACTDAT_KEY, 0, result, 0, ACTDAT_KEY.Length); return(result); }
private void calculateSubkey(byte[] key, byte[] K1, byte[] K2) { byte[] zero = new byte[0x10]; byte[] L = new byte[0x10]; ToolsImpl.aesecbEncrypt(key, zero, 0, L, 0, zero.Length); BigInteger aux = new BigInteger(ConversionUtils.reverseByteWithSizeFIX(L)); if ((L[0] & 0x80) != 0) { //Case MSB is set aux = (aux << 1) ^ (new BigInteger(0x87)); } else { aux = aux << 1; } byte[] aux1 = ConversionUtils.reverseByteWithSizeFIX(aux.ToByteArray()); if (aux1.Length >= 0x10) { ConversionUtils.arraycopy(aux1, aux1.Length - 0x10, K1, 0, 0x10); } else { ConversionUtils.arraycopy(zero, 0, K1, 0, zero.Length); ConversionUtils.arraycopy(aux1, 0, K1, 0x10 - aux1.Length, aux1.Length); } aux = new BigInteger(ConversionUtils.reverseByteWithSizeFIX(K1)); if ((K1[0] & 0x80) != 0) { aux = (aux << 1) ^ (new BigInteger(0x87)); } else { aux = aux << 1; } aux1 = ConversionUtils.reverseByteWithSizeFIX(aux.ToByteArray()); if (aux1.Length >= 0x10) { ConversionUtils.arraycopy(aux1, aux1.Length - 0x10, K2, 0, 0x10); } else { ConversionUtils.arraycopy(zero, 0, K2, 0, zero.Length); ConversionUtils.arraycopy(aux1, 0, K2, 0x10 - aux1.Length, aux1.Length); } }
public override bool doFinal(byte[] expectedhash, int hashOffset, bool hashDebug) { byte[] aux = new byte[0x10]; ConversionUtils.arraycopy(nonProcessed, 0, aux, 0, nonProcessed.Length); if (nonProcessed.Length == 0x10) { ToolsImpl.XOR(aux, aux, K1); } else { aux[nonProcessed.Length] = (byte)0x80; ToolsImpl.XOR(aux, aux, K2); } ToolsImpl.XOR(aux, aux, previous); byte[] calculatedhash = new byte[0x10]; ToolsImpl.aesecbEncrypt(key, aux, 0, calculatedhash, 0, aux.Length); return(hashDebug || compareBytes(expectedhash, hashOffset, calculatedhash, 0, hashLen)); }
public static byte[] CMAC128(byte[] key, byte[] i, int inOffset, int len) { byte[] K1 = new byte[0x10]; byte[] K2 = new byte[0x10]; calculateSubkey(key, K1, K2); byte[] input = new byte[0x10]; byte[] previous = new byte[0x10]; int currentOffset = inOffset; int remaining = len; //System.out.println(ConversionUtils.getHexString(key)); while (remaining > 0x10) { ConversionUtils.arraycopy(i, currentOffset, input, 0, 0x10); //System.out.println(ConversionUtils.getHexString(previous) + " - " + ConversionUtils.getHexString(input)); XOR(input, input, previous); ToolsImpl.aesecbEncrypt(key, input, 0, previous, 0, input.Length); currentOffset += 0x10; remaining -= 0x10; } //System.out.println(ConversionUtils.getHexString(previous)); input = new byte[0x10]; //Memset 0 ConversionUtils.arraycopy(i, currentOffset, input, 0, remaining); if (remaining == 0x10) { XOR(input, input, previous); XOR(input, input, K1); } else { input[remaining] = (byte)0x80; XOR(input, input, previous); XOR(input, input, K2); } //System.out.println(" - " + ConversionUtils.getHexString(input)); ToolsImpl.aesecbEncrypt(key, input, 0, previous, 0, input.Length); return(previous); }
private int decryptData(FileStream ii, FileStream o, NPD npd, EDATData data, byte[] rifkey) { int numBlocks = (int)((data.getFileLen() + data.getBlockSize() - 1) / data.getBlockSize()); int metadataSectionSize = ((data.getFlags() & FLAG_COMPRESSED) != 0 || (data.getFlags() & FLAG_0x20) != 0) ? 0x20 : 0x10; int baseOffset = 0x100; //+ offset (unknown) for (int i = 0; i < numBlocks; i++) { ii.Seek(baseOffset + i * metadataSectionSize, SeekOrigin.Begin); byte[] expectedHash = new byte[0x10]; long offset; int len; int compressionEndBlock = 0; if ((data.getFlags() & FLAG_COMPRESSED) != 0) { byte[] metadata = new byte[0x20]; ii.Read(metadata, 0, metadata.Length); byte[] result = decryptMetadataSection(metadata); offset = (int)(ConversionUtils.be64(result, 0)); // + offset (unknown) len = (int)(ConversionUtils.be32(result, 8)); compressionEndBlock = (int)(ConversionUtils.be32(result, 0xC)); ConversionUtils.arraycopy(metadata, 0, expectedHash, 0, 0x10); } else if ((data.getFlags() & FLAG_0x20) != 0) { //NOT TESTED: CASE WHERE METADATASECTION IS 0x20 BYTES LONG byte[] metadata = new byte[0x20]; ii.Read(metadata, 0, metadata.Length); for (int j = 0; j < 0x10; j++) { expectedHash[j] = (byte)(metadata[j] ^ metadata[j + 0x10]); } offset = baseOffset + i * data.getBlockSize() + numBlocks * metadataSectionSize; len = (int)(data.getBlockSize()); if (i == numBlocks - 1) { len = (int)(data.getFileLen() % (new BigInteger(data.getBlockSize()))); } } else { ii.Read(expectedHash, 0, expectedHash.Length); offset = baseOffset + i * data.getBlockSize() + numBlocks * metadataSectionSize; len = (int)(data.getBlockSize()); if (i == numBlocks - 1) { len = (int)(data.getFileLen() % (new BigInteger(data.getBlockSize()))); } } int realLen = len; len = (int)((uint)(len + 0xF) & 0xFFFFFFF0); Debug.Print("Offset: %016X, len: %08X, realLen: %08X, endCompress: %d\r\n", offset, len, realLen, compressionEndBlock); ii.Seek(offset, SeekOrigin.Begin); byte[] encryptedData = new byte[len]; byte[] decryptedData = new byte[len]; ii.Read(encryptedData, 0, encryptedData.Length); byte[] key = new byte[0x10]; byte[] hash = new byte[0x10]; byte[] blockKey = calculateBlockKey(i, npd); ToolsImpl.aesecbEncrypt(rifkey, blockKey, 0, key, 0, blockKey.Length); if ((data.getFlags() & FLAG_0x10) != 0) { ToolsImpl.aesecbEncrypt(rifkey, key, 0, hash, 0, key.Length); } else { ConversionUtils.arraycopy(key, 0, hash, 0, key.Length); } int cryptoFlag = ((data.getFlags() & FLAG_0x02) == 0) ? 0x2 : 0x1; int hashFlag; if ((data.getFlags() & FLAG_0x10) == 0) { hashFlag = 0x02; } else if ((data.getFlags() & FLAG_0x20) == 0) { hashFlag = 0x04; } else { hashFlag = 0x01; } if ((data.getFlags() & FLAG_KEYENCRYPTED) != 0) { cryptoFlag |= 0x10000000; hashFlag |= 0x10000000; } if ((data.getFlags() & FLAG_DEBUG) != 0) { cryptoFlag |= 0x01000000; hashFlag |= 0x01000000; } AppLoader a = new AppLoader(); byte[] iv = (npd.getVersion() <= 1)?(new byte[0x10]):npd.getDigest(); bool rresult = a.doAll(hashFlag, cryptoFlag, encryptedData, 0, decryptedData, 0, encryptedData.Length, key, npd.getDigest(), hash, expectedHash, 0); if (!rresult) { Debug.WriteLine("Error decrypting block " + i); // KDSBest find out why block 30 errors //return STATUS_ERROR_DECRYPTING; } if ((data.getFlags() & FLAG_COMPRESSED) != 0) { //byte[] decompress = new byte[Long.valueOf(data.getBlockSize()).intValue()]; //DECOMPRESS: MISSING ALGORITHM //out.write(decompress, 0, data.getBlockSize()); } else { o.Write(decryptedData, 0, realLen); } } return(STATUS_OK); }