Ejemplo n.º 1
0
		public virtual sbyte[] DecryptSavedata(sbyte[] buf, int size, sbyte[] key)
		{
			// Initialize the context structs.
			int sdDecMode;
			SD_Ctx1 ctx1 = new SD_Ctx1();
			SD_Ctx2 ctx2 = new SD_Ctx2();

			// Setup the buffers.
			int alignedSize = (((size + 0xF) >> 4) << 4) - 0x10;
			sbyte[] decbuf = new sbyte[size - 0x10];
			sbyte[] tmpbuf = new sbyte[alignedSize];

			// Set the decryption mode.
			if (isNullKey(key))
			{
				sdDecMode = 1;
			}
			else
			{
				// After firmware version 2.7.1 the decryption mode used is 5.
				// Note: Due to a mislabel, 3 games from firmware 2.8.1 (Sonic Rivals, 
				// Star Trek: Tactical Assault and Brothers in Arms: D-Day) 
				// still use the decryption mode 3.
				if (Emulator.Instance.FirmwareVersion > 271 && !((State.discId.Equals("ULUS10195") || State.discId.Equals("ULES00622")) || (State.discId.Equals("ULUS10193") || State.discId.Equals("ULES00608")) || (State.discId.Equals("ULUS10150") || State.discId.Equals("ULES00623"))))
				{
					sdDecMode = 5;
				}
				else
				{
					sdDecMode = 3;
				}
			}

			// Perform the decryption.
			hleSdSetIndex(ctx1, sdDecMode);
			hleSdCreateList(ctx2, sdDecMode, 2, buf, key);
			hleSdRemoveValue(ctx1, buf, 0x10);

			Array.Copy(buf, 0x10, tmpbuf, 0, size - 0x10);
			hleSdRemoveValue(ctx1, tmpbuf, alignedSize);

			hleSdSetMember(ctx2, tmpbuf, alignedSize);

			// Clear context 2.
			hleSdCleanList(ctx2);

			// Copy back the data.
			Array.Copy(tmpbuf, 0, decbuf, 0, size - 0x10);

			return decbuf;
		}
Ejemplo n.º 2
0
		/*
		 * sceSd - chnnlsv.prx
		 */
		public virtual int hleSdSetIndex(SD_Ctx1 ctx, int encMode)
		{
			// Set all parameters to 0 and assign the encMode.
			ctx.mode = encMode;
			ctx.padSize = 0;
			for (int i = 0; i < 0x10; i++)
			{
				ctx.pad[i] = 0;
			}
			for (int i = 0; i < 0x10; i++)
			{
				ctx.key[i] = 0;
			}
			return 0;
		}
Ejemplo n.º 3
0
		private sbyte[] GenerateSavedataHash(sbyte[] data, int size, int mode)
		{
			SD_Ctx1 ctx1 = new SD_Ctx1();
			sbyte[] hash = new sbyte[0x10];

			// Generate a new hash using a key.
			hleSdSetIndex(ctx1, mode);
			hleSdRemoveValue(ctx1, data, size);
			if (hleSdGetLastIndex(ctx1, hash, null) < 0)
			{
				for (int i = 0; i < 0x10; i++)
				{
					// Generate a dummy hash in case of failure.
					hash[i] = 1;
				}
			}
			return hash;
		}
Ejemplo n.º 4
0
		public virtual sbyte[] EncryptSavedata(sbyte[] buf, int size, sbyte[] key)
		{
			// Initialize the context structs.
			int sdEncMode;
			SD_Ctx1 ctx1 = new SD_Ctx1();
			SD_Ctx2 ctx2 = new SD_Ctx2();

			// Setup the buffers.
			int alignedSize = ((size + 0xF) >> 4) << 4;
			sbyte[] tmpbuf1 = new sbyte[alignedSize + 0x10];
			sbyte[] tmpbuf2 = new sbyte[alignedSize];
			sbyte[] hash = new sbyte[0x10];

			// Copy the plain data to tmpbuf.
			Array.Copy(buf, 0, tmpbuf1, 0x10, size);

			// Set the encryption mode.
			if (isNullKey(key))
			{
				sdEncMode = 1;
			}
			else
			{
				// After firmware version 2.7.1 the encryption mode used is 5.
				// Note: Due to a mislabel, 3 games from firmware 2.8.1 (Sonic Rivals, 
				// Star Trek: Tactical Assault and Brothers in Arms: D-Day) 
				// still use the encryption mode 3.
				if (Emulator.Instance.FirmwareVersion > 271 && !((State.discId.Equals("ULUS10195") || State.discId.Equals("ULES00622")) || (State.discId.Equals("ULUS10193") || State.discId.Equals("ULES00608")) || (State.discId.Equals("ULUS10150") || State.discId.Equals("ULES00623"))))
				{
					sdEncMode = 5;
				}
				else
				{
					sdEncMode = 3;
				}
			}

			// Generate the encryption IV (first 0x10 bytes).
			hleSdCreateList(ctx2, sdEncMode, 1, tmpbuf1, key);
			hleSdSetIndex(ctx1, sdEncMode);
			hleSdRemoveValue(ctx1, tmpbuf1, 0x10);

			Array.Copy(tmpbuf1, 0x10, tmpbuf2, 0, alignedSize);
			hleSdSetMember(ctx2, tmpbuf2, alignedSize);

			// Clear extra bytes.
			for (int i = 0; i < (alignedSize - size); i++)
			{
				tmpbuf2[size + i] = 0;
			}

			// Encrypt the data.
			hleSdRemoveValue(ctx1, tmpbuf2, alignedSize);

			// Copy back the encrypted data + IV.
			for (int i = 0; i < (tmpbuf1.Length - 0x10); i++)
			{
				tmpbuf1[0x10 + i] = 0;
			}
			Array.Copy(tmpbuf2, 0, tmpbuf1, 0x10, alignedSize);
			Array.Copy(tmpbuf1, 0, buf, 0, buf.Length);

			// Clear context 2.
			hleSdCleanList(ctx2);

			// Generate a file hash for this data.
			hleSdGetLastIndex(ctx1, hash, key);

			return hash;
		}
Ejemplo n.º 5
0
		public virtual int hleSdGetLastIndex(SD_Ctx1 ctx, sbyte[] hash, sbyte[] key)
		{
			if (ctx.padSize > 0x10)
			{
				// Invalid key Length.
				return -1;
			}

			// Calculate the seed.
			int seed = getModeSeed(ctx.mode);

			// Set up the buffer.
			sbyte[] scrambleBuf = new sbyte[0x800 + 0x14];

			// Set up necessary buffers.
			sbyte[] keyBuf = new sbyte[0x10];
			sbyte[] resultBuf = new sbyte[0x10];

			// Encrypt the buffer with KIRK CMD 4.
			ScrambleSD(scrambleBuf, 0x10, seed, 0x4, KIRK.PSP_KIRK_CMD_ENCRYPT);

			// Store the generated key.
			Array.Copy(scrambleBuf, 0x14, keyBuf, 0, 0x10);

			// Apply custom padding management to the stored key.
			sbyte b = ((keyBuf[0] & unchecked((sbyte) 0x80)) != 0) ? unchecked((sbyte) 0x87) : 0;
			for (int i = 0; i < 0xF; i++)
			{
				int b1 = ((keyBuf[i] & 0xFF) << 1);
				int b2 = ((keyBuf[i + 1] & 0xFF) >> 7);
				keyBuf[i] = (sbyte)(b1 | b2);
			}
			sbyte t = (sbyte)((keyBuf[0xF] & 0xFF) << 1);
			keyBuf[0xF] = (sbyte)(t ^ b);

			if (ctx.padSize < 0x10)
			{
				sbyte bb = ((keyBuf[0] < 0)) ? unchecked((sbyte) 0x87) : 0;
				for (int i = 0; i < 0xF; i++)
				{
					int bb1 = ((keyBuf[i] & 0xFF) << 1);
					int bb2 = ((keyBuf[i + 1] & 0xFF) >> 7);
					keyBuf[i] = (sbyte)(bb1 | bb2);
				}
				sbyte tt = (sbyte)((keyBuf[0xF] & 0xFF) << 1);
				keyBuf[0xF] = (sbyte)(tt ^ bb);

				ctx.pad[ctx.padSize] = unchecked((sbyte) 0x80);
				if ((ctx.padSize + 1) < 0x10)
				{
					for (int i = 0; i < (0x10 - ctx.padSize - 1); i++)
					{
						ctx.pad[ctx.padSize + 1 + i] = 0;
					}
				}
			}

			// XOR previous pad key with new one and copy the result back to the buffer.
			ctx.pad = xorKey(ctx.pad, 0, keyBuf, 0, 0x10);
			Array.Copy(ctx.pad, 0, scrambleBuf, 0x14, 0x10);

			// Save the previous result key.
			Array.Copy(ctx.key, 0, resultBuf, 0, 0x10);

			// XOR the decrypted key with the result key.
			scrambleBuf = xorKey(scrambleBuf, 0x14, resultBuf, 0, 0x10);

			// Encrypt the key with KIRK CMD 4.
			ScrambleSD(scrambleBuf, 0x10, seed, 0x4, KIRK.PSP_KIRK_CMD_ENCRYPT);

			// Copy back the key into the result buffer.
			Array.Copy(scrambleBuf, 0x14, resultBuf, 0, 0x10);

			// If ctx.mode is new mode 0x5 or 0x6, XOR with the new hash key 5, else, XOR with hash key 2.
			if ((ctx.mode == 0x5) || (ctx.mode == 0x6))
			{
				resultBuf = xorHash(resultBuf, 0, KeyVault.sdHashKey5, 0, 0x10);
			}
			else if ((ctx.mode == 0x3) || (ctx.mode == 0x4))
			{
				resultBuf = xorHash(resultBuf, 0, KeyVault.sdHashKey2, 0, 0x10);
			}

			// If mode is 2, 4 or 6, encrypt again with KIRK CMD 5 and then KIRK CMD 4.
			if ((ctx.mode == 0x2) || (ctx.mode == 0x4) || (ctx.mode == 0x6))
			{
				// Copy the result buffer into the data buffer.
				Array.Copy(resultBuf, 0, scrambleBuf, 0x14, 0x10);

				// Encrypt with KIRK CMD 5 (seed is always 0x100).
				ScrambleSD(scrambleBuf, 0x10, 0x100, 0x4, KIRK.PSP_KIRK_CMD_ENCRYPT_FUSE);

				// Encrypt again with KIRK CMD 4.
				ScrambleSD(scrambleBuf, 0x10, seed, 0x4, KIRK.PSP_KIRK_CMD_ENCRYPT);

				// Copy back into result buffer.
				Array.Copy(scrambleBuf, 0x14, resultBuf, 0, 0x10);
			}

			// XOR with the supplied key and encrypt with KIRK CMD 4.
			if (key != null)
			{
				// XOR result buffer with user key.
				resultBuf = xorKey(resultBuf, 0, key, 0, 0x10);

				// Copy the result buffer into the data buffer.
				Array.Copy(resultBuf, 0, scrambleBuf, 0x14, 0x10);

				// Encrypt with KIRK CMD 4.
				ScrambleSD(scrambleBuf, 0x10, seed, 0x4, KIRK.PSP_KIRK_CMD_ENCRYPT);

				// Copy back into the result buffer.
				Array.Copy(scrambleBuf, 0x14, resultBuf, 0, 0x10);
			}

			// Copy back the generated hash.
			Array.Copy(resultBuf, 0, hash, 0, 0x10);

			// Clear the context fields.
			ctx.mode = 0;
			ctx.padSize = 0;
			for (int i = 0; i < 0x10; i++)
			{
				ctx.pad[i] = 0;
			}
			for (int i = 0; i < 0x10; i++)
			{
				ctx.key[i] = 0;
			}

			return 0;
		}
Ejemplo n.º 6
0
		public virtual int hleSdRemoveValue(SD_Ctx1 ctx, sbyte[] data, int Length)
		{
			if (ctx.padSize > 0x10 || (Length < 0))
			{
				// Invalid key or Length.
				return -1;
			}
			else if (((ctx.padSize + Length) <= 0x10))
			{
				// The key hasn't been set yet.
				// Extract the hash from the data and set it as the key.
				Array.Copy(data, 0, ctx.pad, ctx.padSize, Length);
				ctx.padSize += Length;
				return 0;
			}
			else
			{
				// Calculate the seed.
				int seed = getModeSeed(ctx.mode);

				// Setup the buffer. 
				sbyte[] scrambleBuf = new sbyte[0x800 + 0x14];

				// Copy the previous pad key to the buffer.
				Array.Copy(ctx.pad, 0, scrambleBuf, 0x14, ctx.padSize);

				// Calculate new key Length.
				int kLen = ((ctx.padSize + Length) & 0x0F);
				if (kLen == 0)
				{
					kLen = 0x10;
				}

				// Calculate new data Length.
				int nLen = ctx.padSize;
				ctx.padSize = kLen;

				// Copy data's footer to make a new key.
				int remaining = Length - kLen;
				Array.Copy(data, remaining, ctx.pad, 0, kLen);

				// Process the encryption in 0x800 blocks.
				int blockSize = 0x800;

				for (int i = 0; i < remaining; i++)
				{
					if (nLen == blockSize)
					{
						// XOR with result and encrypt with KIRK CMD 4.
						scrambleBuf = xorKey(scrambleBuf, 0x14, ctx.key, 0, 0x10);
						ScrambleSD(scrambleBuf, blockSize, seed, 0x4, KIRK.PSP_KIRK_CMD_ENCRYPT);
						Array.Copy(scrambleBuf, blockSize + 0x4, ctx.key, 0, 0x10);
						// Reset Length.
						nLen = 0;
					}
					// Keep copying data.
					scrambleBuf[0x14 + nLen] = data[i];
					nLen++;
				}

				// Process any leftover data.
				if (nLen > 0)
				{
					scrambleBuf = xorKey(scrambleBuf, 0x14, ctx.key, 0, 0x10);
					ScrambleSD(scrambleBuf, nLen, seed, 0x4, KIRK.PSP_KIRK_CMD_ENCRYPT);
					Array.Copy(scrambleBuf, nLen + 0x4, ctx.key, 0, 0x10);
				}

				return 0;
			}
		}