1
1
/*
2
2
* Copyright (c) 2022 shchmue
3
+ * Copyright (c) 2018 Atmosphère-NX
3
4
*
4
5
* This program is free software; you can redistribute it and/or modify it
5
6
* under the terms and conditions of the GNU General Public License,
27
28
28
29
extern hekate_config h_cfg ;
29
30
31
+ bool check_keyslot_access () {
32
+ u8 test_data [SE_KEY_128_SIZE ] = {0 };
33
+ const u8 test_ciphertext [SE_KEY_128_SIZE ] = {0 };
34
+ se_aes_key_set (KS_AES_ECB , "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" , SE_KEY_128_SIZE );
35
+ se_aes_crypt_block_ecb (KS_AES_ECB , DECRYPT , test_data , test_ciphertext );
36
+
37
+ return memcmp (test_data , "\x7b\x1d\x29\xa1\x6c\xf8\xcc\xab\x84\xf0\xb8\xa5\x98\xe4\x2f\xa6" , SE_KEY_128_SIZE ) == 0 ;
38
+ }
39
+
30
40
bool test_rsa_keypair (const void * public_exponent , const void * private_exponent , const void * modulus ) {
31
41
u32 plaintext [SE_RSA2048_DIGEST_SIZE / 4 ] = {0 },
32
42
ciphertext [SE_RSA2048_DIGEST_SIZE / 4 ] = {0 },
@@ -46,13 +56,82 @@ bool test_rsa_keypair(const void *public_exponent, const void *private_exponent,
46
56
bool test_eticket_rsa_keypair (const rsa_keypair_t * keypair ) {
47
57
// Unlike the SSL RSA key, we don't need to check the gmac - we can just verify the public exponent
48
58
// and test the keypair since we have the modulus
49
- if ((read_be_u32 (keypair -> public_exponent , 0 ) != RSA_PUBLIC_EXPONENT ) ||
50
- (!test_rsa_keypair (keypair -> public_exponent , keypair -> private_exponent , keypair -> modulus ))) {
59
+ if ((byte_swap_32 (keypair -> public_exponent ) != RSA_PUBLIC_EXPONENT ) ||
60
+ (!test_rsa_keypair (& keypair -> public_exponent , keypair -> private_exponent , keypair -> modulus ))
61
+ ) {
51
62
return false;
52
63
}
53
64
return true;
54
65
}
55
66
67
+ // _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère
68
+ static void _mgf1_xor (void * masked , u32 masked_size , const void * seed , u32 seed_size )
69
+ {
70
+ u8 cur_hash [0x20 ] __attribute__((aligned (4 )));
71
+ u8 hash_buf [0xe4 ] __attribute__((aligned (4 )));
72
+
73
+ u32 hash_buf_size = seed_size + 4 ;
74
+ memcpy (hash_buf , seed , seed_size );
75
+ u32 round_num = 0 ;
76
+
77
+ u8 * p_out = (u8 * )masked ;
78
+
79
+ while (masked_size ) {
80
+ u32 cur_size = MIN (masked_size , 0x20 );
81
+
82
+ for (u32 i = 0 ; i < 4 ; i ++ )
83
+ hash_buf [seed_size + 3 - i ] = (round_num >> (8 * i )) & 0xff ;
84
+ round_num ++ ;
85
+
86
+ se_calc_sha256_oneshot (cur_hash , hash_buf , hash_buf_size );
87
+
88
+ for (unsigned int i = 0 ; i < cur_size ; i ++ ) {
89
+ * p_out ^= cur_hash [i ];
90
+ p_out ++ ;
91
+ }
92
+
93
+ masked_size -= cur_size ;
94
+ }
95
+ }
96
+
97
+ u32 rsa_oaep_decode (void * dst , u32 dst_size , const void * label_digest , u32 label_digest_size , u8 * buf , u32 buf_size ) {
98
+ if (dst_size <= 0 || buf_size < 0x43 || label_digest_size != 0x20 )
99
+ return 0 ;
100
+
101
+ bool is_valid = buf [0 ] == 0 ;
102
+
103
+ u32 db_len = buf_size - 0x21 ;
104
+ u8 * seed = buf + 1 ;
105
+ u8 * db = seed + 0x20 ;
106
+ _mgf1_xor (seed , 0x20 , db , db_len );
107
+ _mgf1_xor (db , db_len , seed , 0x20 );
108
+
109
+ is_valid &= memcmp (label_digest , db , 0x20 ) ? 0 : 1 ;
110
+
111
+ db += 0x20 ;
112
+ db_len -= 0x20 ;
113
+
114
+ int msg_ofs = 0 ;
115
+ int looking_for_one = 1 ;
116
+ int invalid_db_padding = 0 ;
117
+ int is_zero ;
118
+ int is_one ;
119
+ for (int i = 0 ; i < db_len ; ) {
120
+ is_zero = (db [i ] == 0 );
121
+ is_one = (db [i ] == 1 );
122
+ msg_ofs += (looking_for_one & is_one ) * (++ i );
123
+ looking_for_one &= ~is_one ;
124
+ invalid_db_padding |= (looking_for_one & ~is_zero );
125
+ }
126
+
127
+ is_valid &= (invalid_db_padding == 0 );
128
+
129
+ const u32 msg_size = MIN (dst_size , is_valid * (db_len - msg_ofs ));
130
+ memcpy (dst , db + msg_ofs , msg_size );
131
+
132
+ return msg_size ;
133
+ }
134
+
56
135
// Equivalent to spl::GenerateAesKek
57
136
void generate_aes_kek (u32 ks , key_storage_t * keys , void * out_kek , const void * kek_source , u32 generation , u32 option ) {
58
137
bool device_unique = GET_IS_DEVICE_UNIQUE (option );
0 commit comments