ctru/services/
ps.rs

1//! Process Services.
2//!
3//! This service handles miscellaneous utility tasks used by the various processes.
4//! However, it is particularly important because it is used to generate cryptographically secure random data, which
5//! is required for commonly used functionality such as hashing (e.g. [`HashMap`](std::collections::HashMap) will not work without it).
6//!
7//! See also <https://www.3dbrew.org/wiki/Process_Services>
8
9use crate::Result;
10use crate::error::ResultCode;
11
12/// Type of AES algorithm to use.
13#[doc(alias = "PS_AESAlgorithm")]
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[repr(u8)]
16pub enum AESAlgorithm {
17    /// CBC encryption.
18    CbcEnc = ctru_sys::PS_ALGORITHM_CBC_ENC,
19    /// CBC decryption.
20    CbcDec = ctru_sys::PS_ALGORITHM_CBC_DEC,
21    /// CTR encryption.
22    CtrEnc = ctru_sys::PS_ALGORITHM_CTR_ENC,
23    /// CTR decryption.
24    CtrDec = ctru_sys::PS_ALGORITHM_CTR_DEC,
25    /// CCM encryption.
26    CcmEnc = ctru_sys::PS_ALGORITHM_CCM_ENC,
27    /// CCM decryption.
28    CcmDec = ctru_sys::PS_ALGORITHM_CCM_DEC,
29}
30
31/// PS Key slot to use.
32#[doc(alias = "PS_AESKeyType")]
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[repr(u8)]
35pub enum AESKeyType {
36    /// Keyslot 0x0D.
37    Keyslot0D = ctru_sys::PS_KEYSLOT_0D,
38    /// Keyslot 0x2D.
39    Keyslot2D = ctru_sys::PS_KEYSLOT_2D,
40    /// Keyslot 0x2E.
41    Keyslot2E = ctru_sys::PS_KEYSLOT_2E,
42    /// Keyslot 0x31.
43    Keyslot31 = ctru_sys::PS_KEYSLOT_31,
44    /// Keyslot 0x32.
45    Keyslot32 = ctru_sys::PS_KEYSLOT_32,
46    /// Keyslot 0x36.
47    Keyslot36 = ctru_sys::PS_KEYSLOT_36,
48    /// Keyslot 0x38.
49    Keyslot38 = ctru_sys::PS_KEYSLOT_38,
50    /// Keyslot 0x39 (DLP).
51    Keyslot39Dlp = ctru_sys::PS_KEYSLOT_39_DLP,
52    /// Keyslot 0x39 (NFC).
53    Keyslot39Nfc = ctru_sys::PS_KEYSLOT_39_NFC,
54    /// Invalid keyslot.
55    KeyslotInvalid = ctru_sys::PS_KEYSLOT_INVALID,
56}
57
58/// Handle to the PS service.
59pub struct Ps(());
60
61impl Ps {
62    /// Initialize a new service handle.
63    ///
64    /// # Example
65    ///
66    /// ```
67    /// # let _runner = test_runner::GdbRunner::default();
68    /// # use std::error::Error;
69    /// # fn main() -> Result<(), Box<dyn Error>> {
70    /// #
71    /// use ctru::services::ps::Ps;
72    ///
73    /// let ps = Ps::new()?;
74    /// #
75    /// # Ok(())
76    /// # }
77    /// ```
78    #[doc(alias = "psInit")]
79    pub fn new() -> Result<Self> {
80        unsafe {
81            ResultCode(ctru_sys::psInit())?;
82            Ok(Ps(()))
83        }
84    }
85
86    /// Returns the console's local friend code seed.
87    ///
88    /// # Example
89    ///
90    /// ```
91    /// # let _runner = test_runner::GdbRunner::default();
92    /// # use std::error::Error;
93    /// # fn main() -> Result<(), Box<dyn Error>> {
94    /// #
95    /// use ctru::services::ps::Ps;
96    /// let ps = Ps::new()?;
97    ///
98    /// let friend_code_seed = ps.local_friend_code_seed()?;
99    /// #
100    /// # Ok(())
101    /// # }
102    /// ```
103    #[doc(alias = "PS_GetLocalFriendCodeSeed")]
104    pub fn local_friend_code_seed(&self) -> crate::Result<u64> {
105        let mut seed: u64 = 0;
106
107        ResultCode(unsafe { ctru_sys::PS_GetLocalFriendCodeSeed(&mut seed) })?;
108        Ok(seed)
109    }
110
111    /// Returns the console's devide ID.
112    ///
113    /// # Example
114    ///
115    /// ```
116    /// # let _runner = test_runner::GdbRunner::default();
117    /// # use std::error::Error;
118    /// # fn main() -> Result<(), Box<dyn Error>> {
119    /// #
120    /// use ctru::services::ps::Ps;
121    /// let ps = Ps::new()?;
122    ///
123    /// let device_id = ps.device_id()?;
124    /// #
125    /// # Ok(())
126    /// # }
127    /// ```
128    #[doc(alias = "PS_GetDeviceId")]
129    pub fn device_id(&self) -> crate::Result<u32> {
130        let mut id: u32 = 0;
131
132        ResultCode(unsafe { ctru_sys::PS_GetDeviceId(&mut id) })?;
133        Ok(id)
134    }
135
136    /// Generates cryptografically secure random bytes and writes them into the `out` buffer.
137    ///
138    /// # Example
139    ///
140    /// ```
141    /// # let _runner = test_runner::GdbRunner::default();
142    /// # use std::error::Error;
143    /// # fn main() -> Result<(), Box<dyn Error>> {
144    /// #
145    /// use ctru::services::ps::Ps;
146    /// let ps = Ps::new()?;
147    ///
148    /// let mut buffer = vec![0; 128];
149    ///
150    /// // The buffer is now randomized!
151    /// ps.generate_random_bytes(&mut buffer)?;
152    /// #
153    /// # Ok(())
154    /// # }
155    /// ```
156    #[doc(alias = "PS_GenerateRandomBytes")]
157    pub fn generate_random_bytes(&self, out: &mut [u8]) -> crate::Result<()> {
158        ResultCode(unsafe {
159            ctru_sys::PS_GenerateRandomBytes(out.as_mut_ptr().cast(), out.len())
160        })?;
161        Ok(())
162    }
163}
164
165impl Drop for Ps {
166    #[doc(alias = "psExit")]
167    fn drop(&mut self) {
168        unsafe {
169            ctru_sys::psExit();
170        }
171    }
172}
173
174from_impl!(AESAlgorithm, ctru_sys::PS_AESAlgorithm);
175from_impl!(AESKeyType, ctru_sys::PS_AESKeyType);
176
177#[cfg(test)]
178mod tests {
179    use std::collections::HashMap;
180
181    #[test]
182    fn construct_hash_map() {
183        let mut input = vec![
184            (1_i32, String::from("123")),
185            (2, String::from("2")),
186            (6, String::from("six")),
187        ];
188
189        let map: HashMap<i32, String> = HashMap::from_iter(input.clone());
190
191        let mut actual: Vec<_> = map.into_iter().collect();
192        input.sort();
193        actual.sort();
194
195        assert_eq!(input, actual);
196    }
197}