libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
ps3_encryption_map.c
Go to the documentation of this file.
1/*
2 * This file is part of the Aaru Data Preservation Suite.
3 * Copyright (c) 2019-2026 Natalia Portillo.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see
16 * <https://www.gnu.org/licenses/>.
17 *
18 * PS3 encryption map: plaintext region parsing, serialization, and lookup.
19 */
20
21#include <stdint.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "ps3_encryption_map.h"
26
27/* Read a big-endian uint32 from a byte buffer. */
28static uint32_t read_be32(const uint8_t *p)
29{
30 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
31}
32
33/* Read a little-endian uint32 from a byte buffer. */
34static uint32_t read_le32(const uint8_t *p)
35{
36 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
37}
38
39/* Write a little-endian uint32 to a byte buffer. */
40static void write_le32(uint8_t *p, uint32_t v)
41{
42 p[0] = (uint8_t)(v & 0xFF);
43 p[1] = (uint8_t)((v >> 8) & 0xFF);
44 p[2] = (uint8_t)((v >> 16) & 0xFF);
45 p[3] = (uint8_t)((v >> 24) & 0xFF);
46}
47
48int32_t ps3_parse_encryption_map(const uint8_t *sector0, uint32_t length, Ps3PlaintextRegion **regions,
49 uint32_t *count)
50{
51 if(sector0 == NULL || regions == NULL || count == NULL) return -1;
52
53 /* Minimum required: 4 (region_count) + 4 (unknown) = 8 bytes */
54 if(length < 8) return -2;
55
56 uint32_t region_count = read_be32(sector0);
57
58 if(region_count > PS3_MAX_PLAINTEXT_REGIONS) return -3;
59
60 if(region_count == 0)
61 {
62 *regions = NULL;
63 *count = 0;
64 return 0;
65 }
66
67 /* Need 8 + region_count * 8 bytes */
68 uint32_t required = 8 + region_count * 8;
69 if(length < required) return -2;
70
71 Ps3PlaintextRegion *r = (Ps3PlaintextRegion *)malloc(region_count * sizeof(Ps3PlaintextRegion));
72 if(r == NULL) return -4;
73
74 const uint8_t *ptr = sector0 + 8; /* skip region_count (4) + unknown (4) */
75
76 for(uint32_t i = 0; i < region_count; i++)
77 {
78 r[i].start_sector = read_be32(ptr);
79 r[i].end_sector = read_be32(ptr + 4);
80 ptr += 8;
81
82 if(r[i].start_sector > r[i].end_sector)
83 {
84 free(r);
85 return -5;
86 }
87 }
88
89 *regions = r;
90 *count = region_count;
91 return 0;
92}
93
94int32_t ps3_serialize_encryption_map(const Ps3PlaintextRegion *regions, uint32_t count, uint8_t **out_data,
95 uint32_t *out_length)
96{
97 if(out_data == NULL || out_length == NULL) return -1;
98 if(count > PS3_MAX_PLAINTEXT_REGIONS) return -3;
99
100 uint32_t size = 4 + count * 8;
101 uint8_t *buf = (uint8_t *)malloc(size);
102 if(buf == NULL) return -4;
103
104 write_le32(buf, count);
105
106 for(uint32_t i = 0; i < count; i++)
107 {
108 write_le32(buf + 4 + i * 8, regions[i].start_sector);
109 write_le32(buf + 4 + i * 8 + 4, regions[i].end_sector);
110 }
111
112 *out_data = buf;
113 *out_length = size;
114 return 0;
115}
116
117int32_t ps3_deserialize_encryption_map(const uint8_t *data, uint32_t length, Ps3PlaintextRegion **regions,
118 uint32_t *count)
119{
120 if(data == NULL || regions == NULL || count == NULL) return -1;
121 if(length < 4) return -2;
122
123 uint32_t region_count = read_le32(data);
124
125 if(region_count > PS3_MAX_PLAINTEXT_REGIONS) return -3;
126
127 if(region_count == 0)
128 {
129 *regions = NULL;
130 *count = 0;
131 return 0;
132 }
133
134 uint32_t required = 4 + region_count * 8;
135 if(length < required) return -2;
136
137 Ps3PlaintextRegion *r = (Ps3PlaintextRegion *)malloc(region_count * sizeof(Ps3PlaintextRegion));
138 if(r == NULL) return -4;
139
140 for(uint32_t i = 0; i < region_count; i++)
141 {
142 r[i].start_sector = read_le32(data + 4 + i * 8);
143 r[i].end_sector = read_le32(data + 4 + i * 8 + 4);
144 }
145
146 *regions = r;
147 *count = region_count;
148 return 0;
149}
150
151bool ps3_is_sector_encrypted(const Ps3PlaintextRegion *plaintext_regions, uint32_t region_count,
152 uint64_t sector_address)
153{
154 if(plaintext_regions == NULL || region_count == 0) return true;
155
156 for(uint32_t i = 0; i < region_count; i++)
157 if(sector_address >= plaintext_regions[i].start_sector && sector_address <= plaintext_regions[i].end_sector)
158 return false;
159
160 return true;
161}
bool ps3_is_sector_encrypted(const Ps3PlaintextRegion *plaintext_regions, uint32_t region_count, uint64_t sector_address)
Check whether a sector is encrypted (i.e., not in any plaintext region).
static uint32_t read_le32(const uint8_t *p)
static uint32_t read_be32(const uint8_t *p)
int32_t ps3_deserialize_encryption_map(const uint8_t *data, uint32_t length, Ps3PlaintextRegion **regions, uint32_t *count)
Deserialize plaintext regions from little-endian binary (media tag format).
static void write_le32(uint8_t *p, uint32_t v)
int32_t ps3_parse_encryption_map(const uint8_t *sector0, uint32_t length, Ps3PlaintextRegion **regions, uint32_t *count)
Parse the encryption map from PS3 disc sector 0 (big-endian on disc).
int32_t ps3_serialize_encryption_map(const Ps3PlaintextRegion *regions, uint32_t count, uint8_t **out_data, uint32_t *out_length)
Serialize plaintext regions to little-endian binary for storage as a media tag.
#define PS3_MAX_PLAINTEXT_REGIONS
A plaintext (unencrypted) region on a PS3 disc.
uint32_t start_sector
First sector of plaintext region (inclusive).
uint32_t end_sector
Last sector of plaintext region (inclusive).