|
34 | 34 |
|
35 | 35 |
|
36 | 36 | class FairPlayAES(): |
37 | | - def __init__(self, fpaeskey=None, rsaaeskey=None, aesiv=None): |
| 37 | + def __init__(self, |
| 38 | + rsaaeskeyb64=None, # either RSA |
| 39 | + fpaeskeyb64=None, aesivb64=None, # or b64 encoded key+iv |
| 40 | + fpaeskey=None, aesiv=None, # or binary key+iv |
| 41 | + keymsg=None, # Needed to decrypt the FP AES keys |
| 42 | + ): |
38 | 43 | self.logger = get_screen_logger(__name__, 'DEBUG') |
39 | | - if rsaaeskey: |
| 44 | + if rsaaeskeyb64: |
40 | 45 | airportkey = RSA.importKey(AIRPORT_PRIVATE_KEY) |
41 | 46 | cipher = PKCS1_OAEP.new(airportkey) |
42 | 47 |
|
43 | | - binkey = base64.standard_b64decode(rsaaeskey + '==') |
| 48 | + binkey = self.decodeb64(rsaaeskeyb64) |
| 49 | + """ |
| 50 | + Decoded RSA keys are 256 bytes |
| 51 | + """ |
44 | 52 | self.aeskey = cipher.decrypt(binkey) |
45 | | - if len(self.aeskey) == 16: |
46 | | - self.logger.info('Got RSA AES key') |
47 | 53 | """ |
48 | | - Decoded keys look like (length 256 bytes): |
49 | | - '\xbf\x92\xc0k-N\xb5\xdf\xbfwM\xda\xc0\xb0\xf1K\xe8\xab4\x83\xd4:V' |
50 | | - '\xc6dS#\xe3\xce\xd3?E\xe2x\xc5\x1e\x9e\xd0\xc6\x028\x90\xa76\x1f~' |
51 | | - '\xa7j\xbcuH\x16\xbe\xb9\x1c\xd7\xb7\xd5X\x8b\x81\x9d\xa0\x82\xd4\' |
52 | | - '\\x1a\x81\xf5\xa0R\xc2|H\xc4\xca\x1d\xef\xd0\x1b\xd6&\xc3\xb9P`i' |
53 | | - '\xa6r\x97\xd2\x0e^\xa7\xa8\x9aHa\x06\x91\x04J(\x08\xa4P\xf9C\x7f' |
54 | | - '\x15\xee\xa8|\x1b\xcb\xc9\xd1\xc7\xa1\xcc\x95\xef-+;\xbb\x8e$\xcax' |
55 | | - '\x8a\xeb\xbf;\xdf\xc8\xa8)\xe6\x17jp\x85O7i\xd4A=\x9a\xaeEb\x92\x9f' |
56 | | - '\x95\xce\xb3\xf6\x82\xb8d\x1d\xe1o;\xce\x81\x90\xe6lC\xa7\x0b\xd4' |
57 | | - '\xc6@\x8dN\xe9"\xf5.p\xd8\xde\x97`~~\xd3\xe8=\xa1\x88\\\x04\xfb\x0c' |
58 | | - '\xd9Y\xb5\x0b\x05\xdd\x8dz2M\x1e\xa90\xfbQ6$\xa1\xf7\x05\x01[\xa0^' |
59 | | - '\x1e\xf2G\xf2$\x8a$&\xaa\xc5\xaf\xd8\xa9p\xbb\x9b\x95\x9b\'\xf4@.o7' |
60 | | - '\x91\x1c\xbb\x1a\xbb\xec\x1a3\x96' |
| 54 | + AES keys obtained are 16 bytes |
61 | 55 | """ |
62 | | - |
63 | | - else: |
64 | | - self.logger.info('Got FP AES key: Cannot yet decrypt.') # , fpaeskey) |
65 | | - self.aeskey = base64.standard_b64decode(fpaeskey) |
66 | | - # TODO: Now decode/decrypt the AES key... |
| 56 | + if len(self.aeskey) == 16: |
| 57 | + self.logger.info('Got RSA AES key (base64)') |
| 58 | + elif fpaeskeyb64: |
| 59 | + self.logger.info('Got FP AES key (base64)') |
| 60 | + self.aeskey = self.decodeb64(fpaeskeyb64) |
67 | 61 | """ |
68 | | - Decoded keys look like (length 72 bytes): |
69 | | - 'FPLY\x01\x02\x01\x00\x00\x00\x00<\x00\x00\x00\x00\xe4\x90V\xc8\xf2%' |
70 | | - '\xebP:k\xe3\xd41\xe8\xa7{\x00\x00\x00\x10\xbfs\xc8\xb0\x9c\x9b7\xe8Fb#' |
71 | | - '\xbfN\xa6\xa7\xa5I\x9cW\xe6\x0b\xf6GC\x8f\xd2\xbb\x7f@3s\xef\x06i2\x7f' |
| 62 | + Decoded AES keys are 72 bytes long starting: |
| 63 | + 'FPLY...' |
| 64 | + Note: they are not yet decrypted (MFi) |
72 | 65 | """ |
73 | 66 | # Just to keep the Audio module happy later with a 32 byte key size. |
74 | 67 | self.aeskey = self.aeskey[16:48] |
75 | | - self.aesiv = base64.standard_b64decode(aesiv + '==') |
76 | | - if len(self.aesiv) == 16: |
| 68 | + elif fpaeskey: |
| 69 | + # Just to keep the Audio module happy later with a 32 byte key size. |
| 70 | + self.aeskey = fpaeskey[16:48] |
| 71 | + self.logger.info('Got FP AES key') |
| 72 | + |
| 73 | + # Handle AES IV |
| 74 | + if aesivb64: |
| 75 | + self.aesiv = self.decodeb64(aesivb64) |
| 76 | + self.logger.info('Got AES IV (base64)') |
| 77 | + elif aesiv: |
| 78 | + self.aesiv = aesiv |
77 | 79 | self.logger.info('Got AES IV') |
78 | 80 |
|
79 | | - # @property |
80 | | - def aesiv(self): |
81 | | - return self.aesiv |
82 | | - |
83 | | - # @aesiv.setter |
84 | | - # def aesiv(self, _val): |
85 | | - # self.aesiv = _val |
86 | | - |
87 | | - # @property |
88 | | - def aeskey(self): |
89 | | - return self.aeskey |
90 | | - |
91 | | - # @aeskey.setter |
92 | | - # def aeskey(self, _val): |
93 | | - # self.aeskey = _val |
94 | | - |
95 | | - |
96 | | -""" FOR FAIRPLAY |
97 | | -if (fpaeskeystr) { |
98 | | - unsigned char fpaeskey[72]; |
99 | | - int fpaeskeylen; |
100 | | -
|
101 | | - fpaeskeylen = rsakey_decode(conn->raop->rsakey, fpaeskey, sizeof(fpaeskey), fpaeskeystr); |
102 | | - if (fpaeskeylen > 0) { |
103 | | - fairplay_decrypt(conn->fairplay, fpaeskey, aeskey); |
104 | | - aeskeylen = sizeof(aeskey); |
105 | | - } |
106 | | - } |
107 | | -
|
108 | | -input key is 72 bytes |
109 | | -output msg is 16 bytes |
110 | | -
|
111 | | -void generate_key_schedule(unsigned char* key_material, uint32_t key_schedule[11][4]); |
112 | | -void generate_session_key(unsigned char* oldSap, unsigned char* messageIn, unsigned char* sessionKey); |
113 | | -void cycle(unsigned char* block, uint32_t key_schedule[11][4]); |
114 | | -void z_xor(unsigned char* in, unsigned char* out, int blocks); |
115 | | -void x_xor(unsigned char* in, unsigned char* out, int blocks); |
116 | | -
|
117 | | -extern unsigned char default_sap[]; |
118 | | -
|
119 | | -void playfair_decrypt(unsigned char* message3, unsigned char* cipherText, unsigned char* keyOut) |
120 | | -{ |
121 | | - unsigned char* chunk1 = &cipherText[16]; |
122 | | - unsigned char* chunk2 = &cipherText[56]; |
123 | | - int i; |
124 | | - unsigned char blockIn[16]; |
125 | | - unsigned char sapKey[16]; |
126 | | - uint32_t key_schedule[11][4]; |
127 | | - generate_session_key(default_sap, message3, sapKey); |
128 | | - generate_key_schedule(sapKey, key_schedule); |
129 | | - z_xor(chunk2, blockIn, 1); |
130 | | - cycle(blockIn, key_schedule); |
131 | | - for (i = 0; i < 16; i++) { |
132 | | - keyOut[i] = blockIn[i] ^ chunk1[i]; |
133 | | - } |
134 | | - x_xor(keyOut, keyOut, 1); |
135 | | - z_xor(keyOut, keyOut, 1); |
136 | | -} |
137 | | -
|
138 | | -""" |
| 81 | + def decodeb64(self, _input): |
| 82 | + return base64.standard_b64decode(_input + '==') |
| 83 | + |
| 84 | +# =========== |
139 | 85 |
|
140 | 86 |
|
141 | 87 | class PlayFair: |
|
0 commit comments