mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2026-04-22 22:19:27 +00:00
265 lines
7.3 KiB
C++
265 lines
7.3 KiB
C++
/*
|
|
* This file is part of the Aaru Data Preservation Suite.
|
|
* Copyright (c) 2019-2026 Natalia Portillo.
|
|
*
|
|
* PS3 encryption map parsing, serialization, and sector lookup tests.
|
|
*/
|
|
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include "../src/ps3/ps3_encryption_map.h"
|
|
}
|
|
|
|
/*
|
|
* Build a synthetic sector 0 in big-endian format:
|
|
* offset 0x00: region_count = 2 (BE)
|
|
* offset 0x04: unknown = 0 (BE)
|
|
* offset 0x08: region[0].start = 0 (BE)
|
|
* offset 0x0C: region[0].end = 31 (BE)
|
|
* offset 0x10: region[1].start = 256 (BE)
|
|
* offset 0x14: region[1].end = 511 (BE)
|
|
*/
|
|
static void build_synthetic_sector0(uint8_t *buf, uint32_t size)
|
|
{
|
|
memset(buf, 0, size);
|
|
|
|
/* region_count = 2, big-endian */
|
|
buf[0] = 0;
|
|
buf[1] = 0;
|
|
buf[2] = 0;
|
|
buf[3] = 2;
|
|
|
|
/* unknown field */
|
|
buf[4] = 0;
|
|
buf[5] = 0;
|
|
buf[6] = 0;
|
|
buf[7] = 0;
|
|
|
|
/* region[0]: start=0, end=31 */
|
|
buf[8] = 0;
|
|
buf[9] = 0;
|
|
buf[10] = 0;
|
|
buf[11] = 0; /* start=0 */
|
|
buf[12] = 0;
|
|
buf[13] = 0;
|
|
buf[14] = 0;
|
|
buf[15] = 31; /* end=31 */
|
|
|
|
/* region[1]: start=256, end=511 */
|
|
buf[16] = 0;
|
|
buf[17] = 0;
|
|
buf[18] = 1;
|
|
buf[19] = 0; /* start=256 */
|
|
buf[20] = 0;
|
|
buf[21] = 0;
|
|
buf[22] = 1;
|
|
buf[23] = 0xFF; /* end=511 */
|
|
}
|
|
|
|
/* Test: parse valid sector 0 */
|
|
TEST(PS3EncMap, ParseValid)
|
|
{
|
|
uint8_t sector0[2048];
|
|
build_synthetic_sector0(sector0, 2048);
|
|
|
|
Ps3PlaintextRegion *regions = NULL;
|
|
uint32_t count = 0;
|
|
|
|
int32_t ret = ps3_parse_encryption_map(sector0, 2048, ®ions, &count);
|
|
ASSERT_EQ(0, ret);
|
|
ASSERT_EQ(2u, count);
|
|
ASSERT_NE(nullptr, regions);
|
|
|
|
EXPECT_EQ(0u, regions[0].start_sector);
|
|
EXPECT_EQ(31u, regions[0].end_sector);
|
|
EXPECT_EQ(256u, regions[1].start_sector);
|
|
EXPECT_EQ(511u, regions[1].end_sector);
|
|
|
|
free(regions);
|
|
}
|
|
|
|
/* Test: parse zero regions */
|
|
TEST(PS3EncMap, ParseZeroRegions)
|
|
{
|
|
uint8_t sector0[2048];
|
|
memset(sector0, 0, 2048); /* region_count = 0 */
|
|
|
|
Ps3PlaintextRegion *regions = NULL;
|
|
uint32_t count = 99;
|
|
|
|
int32_t ret = ps3_parse_encryption_map(sector0, 2048, ®ions, &count);
|
|
ASSERT_EQ(0, ret);
|
|
EXPECT_EQ(0u, count);
|
|
EXPECT_EQ(nullptr, regions);
|
|
}
|
|
|
|
/* Test: parse rejects too many regions */
|
|
TEST(PS3EncMap, ParseTooManyRegions)
|
|
{
|
|
uint8_t sector0[2048];
|
|
memset(sector0, 0, 2048);
|
|
/* region_count = 33 (> max 32) */
|
|
sector0[3] = 33;
|
|
|
|
Ps3PlaintextRegion *regions = NULL;
|
|
uint32_t count = 0;
|
|
|
|
int32_t ret = ps3_parse_encryption_map(sector0, 2048, ®ions, &count);
|
|
EXPECT_LT(ret, 0);
|
|
}
|
|
|
|
/* Test: parse rejects invalid region (start > end) */
|
|
TEST(PS3EncMap, ParseInvalidRegion)
|
|
{
|
|
uint8_t sector0[2048];
|
|
memset(sector0, 0, 2048);
|
|
sector0[3] = 1; /* 1 region */
|
|
/* start=100, end=50 (invalid) */
|
|
sector0[11] = 100;
|
|
sector0[15] = 50;
|
|
|
|
Ps3PlaintextRegion *regions = NULL;
|
|
uint32_t count = 0;
|
|
|
|
int32_t ret = ps3_parse_encryption_map(sector0, 2048, ®ions, &count);
|
|
EXPECT_LT(ret, 0);
|
|
}
|
|
|
|
/* Test: parse rejects too-short buffer */
|
|
TEST(PS3EncMap, ParseBufferTooShort)
|
|
{
|
|
uint8_t sector0[8];
|
|
memset(sector0, 0, 8);
|
|
sector0[3] = 1; /* 1 region, but buffer is only 8 bytes (need 16) */
|
|
|
|
Ps3PlaintextRegion *regions = NULL;
|
|
uint32_t count = 0;
|
|
|
|
int32_t ret = ps3_parse_encryption_map(sector0, 8, ®ions, &count);
|
|
EXPECT_LT(ret, 0);
|
|
}
|
|
|
|
/* Test: serialize and deserialize round-trip */
|
|
TEST(PS3EncMap, SerializeDeserializeRoundTrip)
|
|
{
|
|
Ps3PlaintextRegion input[3] = {{0, 31}, {256, 511}, {1024, 2047}};
|
|
|
|
uint8_t *data = NULL;
|
|
uint32_t length = 0;
|
|
|
|
int32_t ret = ps3_serialize_encryption_map(input, 3, &data, &length);
|
|
ASSERT_EQ(0, ret);
|
|
ASSERT_NE(nullptr, data);
|
|
ASSERT_EQ(4u + 3u * 8u, length); /* 4 + 24 = 28 */
|
|
|
|
Ps3PlaintextRegion *output = NULL;
|
|
uint32_t count = 0;
|
|
|
|
ret = ps3_deserialize_encryption_map(data, length, &output, &count);
|
|
ASSERT_EQ(0, ret);
|
|
ASSERT_EQ(3u, count);
|
|
ASSERT_NE(nullptr, output);
|
|
|
|
for(uint32_t i = 0; i < 3; i++)
|
|
{
|
|
EXPECT_EQ(input[i].start_sector, output[i].start_sector);
|
|
EXPECT_EQ(input[i].end_sector, output[i].end_sector);
|
|
}
|
|
|
|
free(data);
|
|
free(output);
|
|
}
|
|
|
|
/* Test: serialize zero regions */
|
|
TEST(PS3EncMap, SerializeZeroRegions)
|
|
{
|
|
uint8_t *data = NULL;
|
|
uint32_t length = 0;
|
|
|
|
int32_t ret = ps3_serialize_encryption_map(NULL, 0, &data, &length);
|
|
ASSERT_EQ(0, ret);
|
|
ASSERT_NE(nullptr, data);
|
|
ASSERT_EQ(4u, length);
|
|
|
|
/* First 4 bytes should be 0 (LE) */
|
|
EXPECT_EQ(0, data[0]);
|
|
EXPECT_EQ(0, data[1]);
|
|
EXPECT_EQ(0, data[2]);
|
|
EXPECT_EQ(0, data[3]);
|
|
|
|
free(data);
|
|
}
|
|
|
|
/* Test: sector encrypted — outside plaintext regions */
|
|
TEST(PS3EncMap, SectorEncryptedOutside)
|
|
{
|
|
Ps3PlaintextRegion regions[2] = {{0, 31}, {256, 511}};
|
|
|
|
/* Sector 32: between regions → encrypted */
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 32));
|
|
/* Sector 100: between regions → encrypted */
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 100));
|
|
/* Sector 255: just before second region → encrypted */
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 255));
|
|
/* Sector 512: just after second region → encrypted */
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 512));
|
|
/* Sector 10000: way past all regions → encrypted */
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(regions, 2, 10000));
|
|
}
|
|
|
|
/* Test: sector not encrypted — inside plaintext regions */
|
|
TEST(PS3EncMap, SectorPlaintextInside)
|
|
{
|
|
Ps3PlaintextRegion regions[2] = {{0, 31}, {256, 511}};
|
|
|
|
/* Sector 0: first sector of first region → plaintext */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 0));
|
|
/* Sector 15: middle of first region → plaintext */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 15));
|
|
/* Sector 31: last sector of first region → plaintext */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 31));
|
|
/* Sector 256: first sector of second region → plaintext */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 256));
|
|
/* Sector 400: middle of second region → plaintext */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 400));
|
|
/* Sector 511: last sector of second region → plaintext */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, 2, 511));
|
|
}
|
|
|
|
/* Test: sector encrypted when no regions defined */
|
|
TEST(PS3EncMap, SectorEncryptedNoRegions)
|
|
{
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(NULL, 0, 0));
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(NULL, 0, 100));
|
|
}
|
|
|
|
/* Test: parse then use for sector lookup */
|
|
TEST(PS3EncMap, ParseThenLookup)
|
|
{
|
|
uint8_t sector0[2048];
|
|
build_synthetic_sector0(sector0, 2048);
|
|
|
|
Ps3PlaintextRegion *regions = NULL;
|
|
uint32_t count = 0;
|
|
|
|
int32_t ret = ps3_parse_encryption_map(sector0, 2048, ®ions, &count);
|
|
ASSERT_EQ(0, ret);
|
|
|
|
/* Sector 0: in first plaintext region */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, count, 0));
|
|
/* Sector 50: between regions → encrypted */
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(regions, count, 50));
|
|
/* Sector 300: in second plaintext region */
|
|
EXPECT_FALSE(ps3_is_sector_encrypted(regions, count, 300));
|
|
/* Sector 600: past all regions → encrypted */
|
|
EXPECT_TRUE(ps3_is_sector_encrypted(regions, count, 600));
|
|
|
|
free(regions);
|
|
}
|