127 lines
3.7 KiB
C#
127 lines
3.7 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.Text;
|
|||
|
using System.Threading.Tasks;
|
|||
|
|
|||
|
namespace PspCrypto
|
|||
|
{
|
|||
|
public class AtracCrypto
|
|||
|
{
|
|||
|
|
|||
|
const int NBYTES = 0x180;
|
|||
|
private static uint ROTR32(uint v, int n)
|
|||
|
{
|
|||
|
n &= 32 - 1;
|
|||
|
return (v >> n) | (v << (32 - n));
|
|||
|
}
|
|||
|
|
|||
|
public static int UnscrambleAtracData(byte[] data, uint key)
|
|||
|
{
|
|||
|
int blocks = (data.Length / NBYTES) / 0x10;
|
|||
|
int chunks_rest = (data.Length / NBYTES) % 0x10;
|
|||
|
Span<uint> ptr = MemoryMarshal.Cast<byte, uint>(data);
|
|||
|
uint tmp2 = key;
|
|||
|
uint tmp;
|
|||
|
uint value;
|
|||
|
// for each block
|
|||
|
while (blocks > 0)
|
|||
|
{
|
|||
|
// for each chunk of block
|
|||
|
for (int i = 0; i < 0x10; i++)
|
|||
|
{
|
|||
|
tmp = tmp2;
|
|||
|
|
|||
|
// for each value of chunk
|
|||
|
for (int k = 0; k < (NBYTES / 4); k++)
|
|||
|
{
|
|||
|
value = ptr[k];
|
|||
|
ptr[k] = tmp ^ value;
|
|||
|
tmp = tmp2 + (value * 123456789);
|
|||
|
}
|
|||
|
|
|||
|
tmp2 = ROTR32(tmp2, 1);
|
|||
|
ptr = ptr[(NBYTES / 4)..]; // pointer on next chunk
|
|||
|
}
|
|||
|
|
|||
|
blocks--;
|
|||
|
}
|
|||
|
|
|||
|
// do rest chunks
|
|||
|
for (int i = 0; i < chunks_rest; i++)
|
|||
|
{
|
|||
|
tmp = tmp2;
|
|||
|
|
|||
|
// for each value of chunk
|
|||
|
for (int k = 0; k < (NBYTES / 4); k++)
|
|||
|
{
|
|||
|
value = ptr[k];
|
|||
|
ptr[k] = tmp ^ value;
|
|||
|
tmp = tmp2 + (value * 123456789);
|
|||
|
}
|
|||
|
|
|||
|
tmp2 = ROTR32(tmp2, 1);
|
|||
|
ptr = ptr[(NBYTES / 4)..]; // next chunk
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
public static void ScrambleAtracData(Stream input, Stream output, uint key)
|
|||
|
{
|
|||
|
int blocks = (Convert.ToInt32(input.Length) / NBYTES) / 0x10;
|
|||
|
int chunks_rest = (Convert.ToInt32(input.Length) / NBYTES) % 0x10;
|
|||
|
Span<byte> block = stackalloc byte[NBYTES];
|
|||
|
uint tmp2 = key;
|
|||
|
uint tmp;
|
|||
|
// for each block
|
|||
|
while (blocks > 0)
|
|||
|
{
|
|||
|
// for each chunk of block
|
|||
|
for (int i = 0; i < 0x10; i++)
|
|||
|
{
|
|||
|
tmp = tmp2;
|
|||
|
|
|||
|
input.Read(block);
|
|||
|
Span<uint> ptr = MemoryMarshal.Cast<byte, uint>(block);
|
|||
|
|
|||
|
// for each value of chunk
|
|||
|
for (int k = 0; k < (NBYTES / 4); k++)
|
|||
|
{
|
|||
|
ptr[k] ^= tmp;
|
|||
|
tmp = tmp2 + (ptr[k] * 123456789);
|
|||
|
}
|
|||
|
output.Write(block);
|
|||
|
|
|||
|
tmp2 = ROTR32(tmp2, 1);
|
|||
|
ptr = ptr[(NBYTES / 4)..]; // pointer on next chunk
|
|||
|
}
|
|||
|
|
|||
|
blocks--;
|
|||
|
}
|
|||
|
|
|||
|
// do rest chunks
|
|||
|
for (int i = 0; i < chunks_rest; i++)
|
|||
|
{
|
|||
|
tmp = tmp2;
|
|||
|
|
|||
|
input.Read(block);
|
|||
|
Span<uint> ptr = MemoryMarshal.Cast<byte, uint>(block);
|
|||
|
|
|||
|
// for each value of chunk
|
|||
|
for (int k = 0; k < (NBYTES / 4); k++)
|
|||
|
{
|
|||
|
ptr[k] ^= tmp;
|
|||
|
tmp = tmp2 + (ptr[k] * 123456789);
|
|||
|
}
|
|||
|
output.Write(block);
|
|||
|
|
|||
|
tmp2 = ROTR32(tmp2, 1);
|
|||
|
ptr = ptr[(NBYTES / 4)..]; // next chunk
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|