clean up the issue of ios9 audio descryption

This commit is contained in:
fduncanh
2021-12-28 19:56:16 -05:00
parent c69a54872d
commit 745c2e27f6
7 changed files with 85 additions and 150 deletions

View File

@@ -2,14 +2,13 @@
<p>Highlights:</p>
<ul>
<li>GPLv3, open source.</li>
<li>Support for both AirPlay Mirror and AirPlay Audio-only (Apple Lossless ALAC) protocols for current iOS/iPadOS clients (iOS 12 through 15).<br />
</li>
<li>Support for older protocol (iOS 9, iOS 10) on older 32-bit clients, and on Windows AirPlay-client emulators such as <em>AirMyPC</em>.</li>
<li>Support for both AirPlay Mirror and AirPlay Audio-only (Apple Lossless ALAC) protocols for current iOS/iPadOS 15.2 clients.</li>
<li>Support for older clients (such as iPad 2nd gen, iPhone 4S) when upgraded to iOS 9.3.5 or later, also Windows client AirMyPC.</li>
<li>Uses GStreamer, with options to select different output “videosinks” and “audiosinks”.</li>
<li>Support for server behind a firewall.</li>
</ul>
<p>This project is a GPLv3 open source unix AirPlay2 Mirror server for Linux, macOS, and *BSD. It is now hosted at the github site <a href="https://github.com/FDH2/UxPlay">https://github.com/FDH2/UxPlay</a> (where development and user-assistance now takes place), although it initially was developed by <a href="http://github.com/antimof/Uxplay">antimof</a> using code from <a href="https://github.com/FD-/RPiPlay">RPiPlay</a>, which in turn derives from <a href="https://github.com/KqsMea8/AirplayServer">AirplayServer</a>, <a href="https://github.com/juhovh/shairplay">shairplay</a>, and <a href="https://github.com/EstebanKubata/playfair">playfair</a>. (The antimof site is mainly inactive, but periodically posts updates pulled from the <a href="https://github.com/FDH2/UxPlay">main UxPlay site</a>).</p>
<p>Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/iPadOS/macOS clients (iPhones, iPads, MacBooks) in a window on the server display (with the possibility of sharing that window on screen-sharing applications such as Zoom) on a host running Linux, macOS, or other unix. UxPlay supports a “legacy” form of Apples AirPlay Mirror protocol introduced in iOS 12; client devices running iOS/iPadOS 12 or later are supported, as is a (non-free) Windows-based AirPlay-client software emulator, AirMyPC. Older (32-bit) client devices that can only run iOS 9.3 or iOS 10.3 are currently partially supported by UxPlay: reports indicate that screen-mirroring video works, audio is a work-in-progress, but is correctly decrypted. (Details of what is publically known about Apples AirPlay2 protocol can be found <a href="https://github.com/SteeBono/airplayreceiver/wiki/AirPlay2-Protocol">here</a> and <a href="https://emanuelecozzi.net/docs/airplay2">here</a>).</p>
<p>Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/iPadOS/macOS clients (iPhones, iPads, MacBooks) in a window on the server display (with the possibility of sharing that window on screen-sharing applications such as Zoom) on a host running Linux, macOS, or other unix. UxPlay supports a “legacy” form of Apples AirPlay Mirror protocol introduced in iOS 12; client devices running iOS/iPadOS 9.3.5 or later are supported, as is a (non-free) Windows-based AirPlay-client software emulator, AirMyPC. (Details of what is publically known about Apples AirPlay2 protocol can be found <a href="https://github.com/SteeBono/airplayreceiver/wiki/AirPlay2-Protocol">here</a> and <a href="https://emanuelecozzi.net/docs/airplay2">here</a>).</p>
<p>The UxPlay server and its client must be on the same local area network, on which a <strong>Bonjour/Zeroconf mDNS/DNS-SD server</strong> is also running (only DNS-SD “Service Discovery” service is strictly necessary, it is not necessary that the local network also be of the “.local” mDNS-based type). On Linux and BSD Unix servers, this is usually provided by <a href="https://www.avahi.org">Avahi</a>, through the avahi-daemon service, and is included in most Linux distributions (this service can also be provided by macOS, iOS or Windows servers).</p>
<p>Connections to the UxPlay server by iOS/MacOS clients can be initiated both in AirPlay Mirror mode (which streams lossily-compressed AAC audio while mirroring the client screen, or in the alternative AirPlay Audio mode which streams Apple Lossless (ALAC) audio without screen mirroring (the accompanying metadata and cover art in this mode is not displayed). <em>Switching between these two modes during an active connection is possible: in Mirror mode, close the mirror window and start an Audio mode connection, switch back by initiating a Mirror mode connection.</em> <strong>Note that Apple DRM (as in Apple TV app content on the client) cannot be decrypted by UxPlay, and (unlike with a true AppleTV), the client cannot run a http connection on the server instead of streaming content from one on the client.</strong></p>
<p>UxPlay uses GStreamer Plugins for rendering audio and video, and does not offer the alternative Raspberry-Pi-specific audio and video renderers available in <a href="https://github.com/FD-/RPiPlay">RPiPlay</a>. It is tested on a number of systems, including (among others) Debian 11.2, Ubuntu 20.04 and 21.10, Linux Mint 20.2, Pop!_OS 21.10 (NVIDIA edition), Rocky Linux 8.4 (a CentOS successor), OpenSUSE 15.3, macOS 10.15.7, FreeBSD 13.0.</p>
@@ -94,12 +93,12 @@
<h3 id="gstreamer-issues-missing-plugins-etc.">4. GStreamer issues (missing plugins, etc.):</h3>
<p>To troubleshoot GStreamer execute “export GST_DEBUG=2” to set the GStreamer debug-level environment-variable in the terminal where you will run uxplay, so that you see warning and error messages; (replace “2” by “4” to see much (much) more of what is happening inside GStreamer). Run “gst-inspect-1.0” to see which GStreamer plugins are installed on your system.</p>
<p>Some extra GStreamer packages for special plugins may need to be installed (or reinstalled: a user using a Wayland display system as an alternative to X11 reported that after reinstalling Lubuntu 18.4, UxPlay would not work until gstreamer1.0-x was installed, presumably for Waylands X11-compatibility mode). Different distributions may break up GStreamer 1.x into packages in different ways; the packages listed above in the build instructions should bring in other required GStreamer packages as dependencies, but will not install all possible plugins.</p>
<h3 id="failure-to-decrypt-all-video-andor-audio-streams-from-a-particular-older-client">5. Failure to decrypt ALL video and/or audio streams from a particular (older) client:</h3>
<p>This triggers an error message, and will be due to use of an incorrect protocol for getting the AES decryption key from the client.</p>
<p>Modern Apple clients use a more-encrypted protocol than older ones. Which protocol is used by UxPlay depends on the client <em>User-Agent</em> string (reported by the client and now shown in the terminal output). iOS 9 and 10 clients only use iTunes FairPlay encryption on the AES decryption key they send to the server. Somewhere around iOS sourceVersion 330 (part of the User-Agent string) Apple started to further encrypt it by a sha-512 hash with a “shared secret” created during the Server-Client pairing process. The sourceVersion 330 above which the extra decryption step is carried out is a guess for a value bigger than 320 and smaller than 380, and is set in lib/global.h if you need to change it. (This applies only to audio decryption; since at least iOS 9, the AES key used for video decryption is derived from a hash of a key formed from the “streamConnectionID” received from the client with the <em>hashed</em> audio AES key.)</p>
<p>The third-party non-free Windows software <em>AirMyPC</em> (a commercial AirPlay emulator) uses an even older protocol: it not only uses the unhashed AES key for audio, but also uses a video AES key derived as above, but using the <em>unhashed</em> audio AES key. <em>AirMyPC</em> has a distinctive <em>User-Agent</em> string, which is detected using two other settings in lib/global.h that can be adjusted if necessary. These settings might be useful if other AirPlay-emulators using this protocol need support. Uxplay declares itself to be an AppleTV2,1 with a sourceVersion 220.68 taken from an AppleTV3,1; this can also be changed in global.h. (It is crucial for UxPlay to declare this old value of sourceVersion, as it prompts the client to use a less-encrypted older “legacy” protocol to make the connection with the UxPlay server; it is probably not necessary for UxPlay to claim to be such an old AppleTV model.)</p>
<h3 id="failure-to-decrypt-all-video-andor-audio-streams-from-old-or-non-apple-clients">5. Failure to decrypt ALL video and/or audio streams from old or non-Apple clients:</h3>
<p>This triggers an error messages, and will be probably due to use of an incorrect protocol for getting the AES decryption key from the client.<br />
This happened when a user tried to use the Windows AirPlay-emulator client <em>AirMyPC</em> with UxPlay. It turned out that <em>AirMyPC</em> used an older less-encrypted protocol similar to AirPlay1, relying only on Apples FairPlay encryption of the AES key used to decrypt the encrypted audio stream from the client (and which is also used as part of the video decryption); on top of FairPlay encryption, AirPlay2 adds a hash of the AES key with a “shared secret” created in the initial handshake bewteen client and server. This hash is omitted in the older protocol used by <em>AirMyPC</em>, which is detected using the “User Agent” string it reports: “AirMyPC/2.0”. The client User Agent string is shown in uxplays terminal output; if it is suspected that some other old or non-Apple client is also using this modified protocol, you can add its “User Agent” string to <code>OLD_PROTOCOL_CLIENT_USER_AGENT_LIST</code> in lib/global.c, and rebuild UxPlay.</p>
<p>Note that Uxplay declares itself to be an AppleTV2,1 with a sourceVersion 220.68 taken from an AppleTV3,1; this can also be changed in global.h. (It is crucial for UxPlay to declare this old value of sourceVersion, as this prompts the Apple client to use the iOS 12 “legacy” protocol to make the connection with the UxPlay server; it is probably not necessary for UxPlay to claim to be such an old AppleTV model.)</p>
<h1 id="changelog">ChangeLog</h1>
<p>1.44 2021-12-13 Omit hash of aeskey with ecdh_secret (his supports AirMyPC), or use unhashed key for audio, hashed key for video (this supports iO 9 and iOS 10 clients reporting sourceVersion &lt; 330 ); make internal rearrangement of where this hash is done. Replace decodebin by h264-specific elements in the GStreamer video pipeline. Fully report initial communications between client and server in -d debug mode.</p>
<p>1.44 2021-12-13 Omit hash of aeskey with ecdh_secret for an AirMyPC client; make an internal rearrangement of where this hash is done. Fully report all initial communications between client and server in -d debug mode. Replace decodebin in GStreamer video pipeline by h264-specific elements.</p>
<p>1.43 2021-12-07 Various internal changes, such as tests for successful decryption, uniform treatment of informational/debug messages, etc., updated README.</p>
<p>1.42 2021-11-20 Fix MAC detection to work with modern Linux interface naming practices, MacOS and *BSD.</p>
<p>1.41 2021-11-11 Further cleanups of multiple audio format support (internal changes, separated RAOP and GStreamer audio/video startup)</p>

View File

@@ -3,8 +3,8 @@
Highlights:
* GPLv3, open source.
* Support for both AirPlay Mirror and AirPlay Audio-only (Apple Lossless ALAC) protocols for current iOS/iPadOS clients (iOS 12 through 15).
* Support for older protocol (iOS 9, iOS 10) on older 32-bit clients, and on Windows AirPlay-client emulators such as _AirMyPC_.
* Support for both AirPlay Mirror and AirPlay Audio-only (Apple Lossless ALAC) protocols for current iOS/iPadOS 15.2 clients.
* Support for older clients (such as iPad 2nd gen, iPhone 4S) when upgraded to iOS 9.3.5 or later, also Windows client AirMyPC.
* Uses GStreamer, with options to select different output "videosinks" and "audiosinks".
* Support for server behind a firewall.
@@ -22,10 +22,8 @@ Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/
on the server display (with the possibility of
sharing that window on screen-sharing applications such as Zoom)
on a host running Linux, macOS, or other unix. UxPlay supports a "legacy" form of Apple's AirPlay Mirror protocol introduced
in iOS 12; client devices running iOS/iPadOS 12 or later are supported, as is a (non-free) Windows-based
AirPlay-client software emulator, AirMyPC. Older (32-bit) client devices that can only run iOS 9.3 or iOS 10.3 are
currently partially supported by UxPlay: reports indicate that
screen-mirroring video works, audio is a work-in-progress, but is correctly decrypted.
in iOS 12; client devices running iOS/iPadOS 9.3.5 or later are supported, as is a (non-free) Windows-based
AirPlay-client software emulator, AirMyPC.
(Details of what is publically known about Apple's AirPlay2 protocol can be found
[here](https://github.com/SteeBono/airplayreceiver/wiki/AirPlay2-Protocol) and
[here](https://emanuelecozzi.net/docs/airplay2)).
@@ -420,35 +418,27 @@ reported that after reinstalling Lubuntu 18.4, UxPlay would not work until gstr
Different distributions may break up GStreamer 1.x into packages in different ways; the packages listed above in the build instructions should bring in
other required GStreamer packages as dependencies, but will not install all possible plugins.
### 5. Failure to decrypt ALL video and/or audio streams from a particular (older) client:
### 5. Failure to decrypt ALL video and/or audio streams from old or non-Apple clients:
This triggers an error message, and will be due to use of an incorrect protocol for getting the AES decryption key from the client.
This triggers an error messages, and will be probably due to use of an incorrect protocol for getting the AES decryption key from the client.
This happened when a user tried to use the Windows AirPlay-emulator client _AirMyPC_ with UxPlay. It turned out that _AirMyPC_ used an older
less-encrypted protocol similar to AirPlay1, relying only on Apple's "FairPlay" encryption of the AES key used to decrypt the encrypted
audio stream from the client (and which is also used as part of the video decryption); on top of FairPlay encryption, AirPlay2 adds a hash of the AES key
with a "shared secret" created in the initial handshake bewteen client and server. This hash is omitted in the older protocol used by _AirMyPC_,
which is detected using the "User Agent" string it reports: "AirMyPC/2.0". The client User Agent string is shown in uxplay's terminal output; if it is suspected that
some other old or non-Apple client is also using this modified protocol, you can add its "User Agent" string to ```OLD_PROTOCOL_CLIENT_USER_AGENT_LIST``` in lib/global.c,
and rebuild UxPlay.
Modern Apple clients use a more-encrypted protocol than older ones.
Which protocol is used by UxPlay depends on the client _User-Agent_ string (reported by the client and now shown in the terminal output).
iOS 9 and 10 clients only use iTunes FairPlay encryption on the AES decryption key they send to the server.
Somewhere around iOS sourceVersion 330 (part of the User-Agent string) Apple started to further encrypt it by a sha-512 hash with a "shared secret" created
during the Server-Client pairing process. The sourceVersion 330 above which the extra decryption step is carried out is
a guess for a value bigger than 320 and smaller than 380, and is set in lib/global.h if you need to
change it. (This applies only to audio decryption; since at least iOS 9, the AES key used for video decryption
is derived from a hash of a key formed from the "streamConnectionID" received from the client with the _hashed_ audio AES key.)
The third-party non-free Windows software _AirMyPC_ (a commercial AirPlay emulator) uses an even older protocol:
it not only uses the unhashed AES key for audio, but also uses a video AES key derived as above, but using the _unhashed_
audio AES key. _AirMyPC_ has a distinctive _User-Agent_ string, which is detected using two other settings in lib/global.h
that can be adjusted if necessary. These settings might be useful if
other AirPlay-emulators using this protocol need support. Uxplay declares itself to be an AppleTV2,1 with a
Note that Uxplay declares itself to be an AppleTV2,1 with a
sourceVersion 220.68 taken from an AppleTV3,1;
this can also be changed in global.h. (It is crucial for UxPlay to declare this old value of sourceVersion, as it prompts the client to use
a less-encrypted older "legacy" protocol to make the connection with the UxPlay server; it is probably not necessary for UxPlay to
this can also be changed in global.h. (It is crucial for UxPlay to declare this old value of sourceVersion, as this prompts the Apple client to use
the iOS 12 "legacy" protocol to make the connection with the UxPlay server; it is probably not necessary for UxPlay to
claim to be such an old AppleTV model.)
# ChangeLog
1.44 2021-12-13 Omit hash of aeskey with ecdh_secret (his supports AirMyPC), or use unhashed key for audio, hashed key
for video (this supports iO 9 and iOS 10 clients reporting sourceVersion < 330 );
make internal rearrangement of where this hash is done. Replace decodebin by h264-specific
elements in the GStreamer video pipeline. Fully report initial communications between
client and server in -d debug mode.
1.44 2021-12-13 Omit hash of aeskey with ecdh_secret for an AirMyPC client; make an internal rearrangement of where this hash is
done. Fully report all initial communications between client and server in -d debug mode. Replace decodebin in GStreamer
video pipeline by h264-specific elements.
1.43 2021-12-07 Various internal changes, such as tests for successful decryption, uniform treatment
of informational/debug messages, etc., updated README.

View File

@@ -5,10 +5,9 @@ Highlights:
- GPLv3, open source.
- Support for both AirPlay Mirror and AirPlay Audio-only (Apple
Lossless ALAC) protocols for current iOS/iPadOS clients (iOS 12
through 15).\
- Support for older protocol (iOS 9, iOS 10) on older 32-bit clients,
and on Windows AirPlay-client emulators such as *AirMyPC*.
Lossless ALAC) protocols for current iOS/iPadOS 15.2 clients.
- Support for older clients (such as iPad 2nd gen, iPhone 4S) when
upgraded to iOS 9.3.5 or later, also Windows client AirMyPC.
- Uses GStreamer, with options to select different output "videosinks"
and "audiosinks".
- Support for server behind a firewall.
@@ -31,11 +30,8 @@ the server display (with the possibility of sharing that window on
screen-sharing applications such as Zoom) on a host running Linux,
macOS, or other unix. UxPlay supports a "legacy" form of Apple's AirPlay
Mirror protocol introduced in iOS 12; client devices running iOS/iPadOS
12 or later are supported, as is a (non-free) Windows-based
AirPlay-client software emulator, AirMyPC. Older (32-bit) client devices
that can only run iOS 9.3 or iOS 10.3 are currently partially supported
by UxPlay: reports indicate that screen-mirroring video works, audio is
a work-in-progress, but is correctly decrypted. (Details of what is
9.3.5 or later are supported, as is a (non-free) Windows-based
AirPlay-client software emulator, AirMyPC. (Details of what is
publically known about Apple's AirPlay2 protocol can be found
[here](https://github.com/SteeBono/airplayreceiver/wiki/AirPlay2-Protocol)
and [here](https://emanuelecozzi.net/docs/airplay2)).
@@ -518,37 +514,29 @@ GStreamer 1.x into packages in different ways; the packages listed above
in the build instructions should bring in other required GStreamer
packages as dependencies, but will not install all possible plugins.
### 5. Failure to decrypt ALL video and/or audio streams from a particular (older) client:
### 5. Failure to decrypt ALL video and/or audio streams from old or non-Apple clients:
This triggers an error message, and will be due to use of an incorrect
protocol for getting the AES decryption key from the client.
This triggers an error messages, and will be probably due to use of an
incorrect protocol for getting the AES decryption key from the client.\
This happened when a user tried to use the Windows AirPlay-emulator
client *AirMyPC* with UxPlay. It turned out that *AirMyPC* used an older
less-encrypted protocol similar to AirPlay1, relying only on Apple's
"FairPlay" encryption of the AES key used to decrypt the encrypted audio
stream from the client (and which is also used as part of the video
decryption); on top of FairPlay encryption, AirPlay2 adds a hash of the
AES key with a "shared secret" created in the initial handshake bewteen
client and server. This hash is omitted in the older protocol used by
*AirMyPC*, which is detected using the "User Agent" string it reports:
"AirMyPC/2.0". The client User Agent string is shown in uxplay's
terminal output; if it is suspected that some other old or non-Apple
client is also using this modified protocol, you can add its "User
Agent" string to `OLD_PROTOCOL_CLIENT_USER_AGENT_LIST` in lib/global.c,
and rebuild UxPlay.
Modern Apple clients use a more-encrypted protocol than older ones.
Which protocol is used by UxPlay depends on the client *User-Agent*
string (reported by the client and now shown in the terminal output).
iOS 9 and 10 clients only use iTunes FairPlay encryption on the AES
decryption key they send to the server. Somewhere around iOS
sourceVersion 330 (part of the User-Agent string) Apple started to
further encrypt it by a sha-512 hash with a "shared secret" created
during the Server-Client pairing process. The sourceVersion 330 above
which the extra decryption step is carried out is a guess for a value
bigger than 320 and smaller than 380, and is set in lib/global.h if you
need to change it. (This applies only to audio decryption; since at
least iOS 9, the AES key used for video decryption is derived from a
hash of a key formed from the "streamConnectionID" received from the
client with the *hashed* audio AES key.)
The third-party non-free Windows software *AirMyPC* (a commercial
AirPlay emulator) uses an even older protocol: it not only uses the
unhashed AES key for audio, but also uses a video AES key derived as
above, but using the *unhashed* audio AES key. *AirMyPC* has a
distinctive *User-Agent* string, which is detected using two other
settings in lib/global.h that can be adjusted if necessary. These
settings might be useful if other AirPlay-emulators using this protocol
need support. Uxplay declares itself to be an AppleTV2,1 with a
Note that Uxplay declares itself to be an AppleTV2,1 with a
sourceVersion 220.68 taken from an AppleTV3,1; this can also be changed
in global.h. (It is crucial for UxPlay to declare this old value of
sourceVersion, as it prompts the client to use a less-encrypted older
sourceVersion, as this prompts the Apple client to use the iOS 12
"legacy" protocol to make the connection with the UxPlay server; it is
probably not necessary for UxPlay to claim to be such an old AppleTV
model.)
@@ -556,12 +544,11 @@ model.)
ChangeLog
=========
1.44 2021-12-13 Omit hash of aeskey with ecdh\_secret (his supports
AirMyPC), or use unhashed key for audio, hashed key for video (this
supports iO 9 and iOS 10 clients reporting sourceVersion \< 330 ); make
internal rearrangement of where this hash is done. Replace decodebin by
h264-specific elements in the GStreamer video pipeline. Fully report
initial communications between client and server in -d debug mode.
1.44 2021-12-13 Omit hash of aeskey with ecdh\_secret for an AirMyPC
client; make an internal rearrangement of where this hash is done. Fully
report all initial communications between client and server in -d debug
mode. Replace decodebin in GStreamer video pipeline by h264-specific
elements.
1.43 2021-12-07 Various internal changes, such as tests for successful
decryption, uniform treatment of informational/debug messages, etc.,

View File

@@ -5,13 +5,10 @@
#define GLOBAL_MODEL "AppleTV2,1"
#define GLOBAL_VERSION "220.68"
/* use old protocol (unhashed AESkey for audio decryption if clients source version is not greater than 330.x.x */
#define OLD_PROTOCOL_AUDIO_CLIENT_SOURCEVERSION "330.0.0"
/* use old protocol for audio or video AES key if client's User-Agent string is contained in these strings */
/* use old protocol for audio AES key if client's User-Agent string is contained in these strings */
/* replace xxx by any new User-Agent string as needed */
#define OLD_PROTOCOL_AUDIO_CLIENT_USER_AGENT_LIST "AirMyPC/2.0;xxx"
#define OLD_PROTOCOL_VIDEO_CLIENT_USER_AGENT_LIST "AirMyPC/2.0;xxx"
#define OLD_PROTOCOL_CLIENT_USER_AGENT_LIST "AirMyPC/2.0;xxx"
#define DECRYPTION_TEST 0 /* set to 1 or 2 to examine audio decryption */

View File

@@ -152,8 +152,8 @@ raop_buffer_decrypt(raop_buffer_t *raop_buffer, unsigned char *data, unsigned ch
#endif
if (DECRYPTION_TEST) {
printf("encrypted header %s", utils_data_to_string(data,12,12));
if (payload_size) printf("%d before %s", payload_size, utils_data_to_string(&data[12],16,16 ));
printf("encrypted 12 byte header %s", utils_data_to_string(data,12,12));
if (payload_size) printf("len %d before decryption:\n%s", payload_size, utils_data_to_string(&data[12],16,16 ));
}
encryptedlen = payload_size / 16*16;
memset(output, 0, payload_size);

View File

@@ -350,12 +350,8 @@ raop_handler_setup(raop_conn_t *conn,
// The first SETUP call that initializes keys and timing
unsigned char aesiv[16];
unsigned char aeskey_old[16];
unsigned char aeskey[16];
unsigned char *aeskey_audio = aeskey;
unsigned char *aeskey_video = aeskey;
logger_log(conn->raop->logger, LOGGER_DEBUG, "SETUP 1");
// First setup
@@ -377,9 +373,9 @@ raop_handler_setup(raop_conn_t *conn,
logger_log(conn->raop->logger, LOGGER_DEBUG, "ekey:\n%s", str);
free (str);
int ret = fairplay_decrypt(conn->fairplay, (unsigned char*) ekey, aeskey_old);
int ret = fairplay_decrypt(conn->fairplay, (unsigned char*) ekey, aeskey);
logger_log(conn->raop->logger, LOGGER_DEBUG, "fairplay_decrypt ret = %d", ret);
str = utils_data_to_string(aeskey_old, 16, 16);
str = utils_data_to_string(aeskey, 16, 16);
logger_log(conn->raop->logger, LOGGER_DEBUG, "16 byte aeskey (fairplay-decrypted from ekey):\n%s", str);
free(str);
@@ -389,49 +385,27 @@ raop_handler_setup(raop_conn_t *conn,
logger_log(conn->raop->logger, LOGGER_DEBUG, "32 byte shared ecdh_secret:\n%s", str);
free(str);
unsigned char eaeskey[64] = {};
memcpy(eaeskey, aeskey_old, 16);
sha_ctx_t *ctx = sha_init();
sha_update(ctx, eaeskey, 16);
sha_update(ctx, ecdh_secret, 32);
sha_final(ctx, eaeskey, NULL);
sha_destroy(ctx);
memcpy(aeskey, eaeskey, 16);
str = utils_data_to_string(aeskey, 16, 16);
logger_log(conn->raop->logger, LOGGER_DEBUG, "16 byte aeskey after sha-256 hash with ecdh_secret:\n%s", str);
free(str);
/* old-protocol clients such as AirMyPC use the unhashed key aeskey_old for both audio and video (ios9, ios10 support)*/
/* clients with sourceVersion <= OLD_PROTOCOL_AUDIO_CLIENT_SOURCEVERSION use unhashed aeskey_old for audio decryption */
/* this is also done for audio or video if clients User-Agent string is included in OLD_PROTOCOL_[AUDIO,VIDEO]_CLIENT_LIST (AirMyPC support)*/
/* OLD_PROTOCOL_AUDIO_CLIENT_LIST, OLD_PROTOCOL_VIDEO_CLIENT_LIST, OLD_PROTOCOL_AUDIO_CLIENT_SOURCEVERSION are defined in global.h */
plist_t req_source_version_node = plist_dict_get_item(req_root_node, "sourceVersion");
char *sourceVersion;
plist_get_string_val(req_source_version_node, &sourceVersion);
const char *user_agent = http_request_get_header(request, "User-Agent");
logger_log(conn->raop->logger, LOGGER_INFO, "Client identified as User-Agent: %s, sourceVersion: %s", user_agent, sourceVersion);
logger_log(conn->raop->logger, LOGGER_INFO, "Client identified as User-Agent: %s", user_agent);
#ifdef OLD_PROTOCOL_AUDIO_CLIENT_SOURCEVERSION
char *end_ptr;
if (strtoul(sourceVersion, &end_ptr, 10) <= strtoul(OLD_PROTOCOL_AUDIO_CLIENT_SOURCEVERSION , &end_ptr, 10)) aeskey_audio = aeskey_old;
bool old_protocol = false;
#ifdef OLD_PROTOCOL_CLIENT_USER_AGENT_LIST /* set in global.h */
if (strstr(OLD_PROTOCOL_CLIENT_USER_AGENT_LIST, user_agent)) old_protocol = true;
#endif
#ifdef OLD_PROTOCOL_AUDIO_CLIENT_USER_AGENT_LIST
if (strstr(OLD_PROTOCOL_AUDIO_CLIENT_USER_AGENT_LIST, user_agent)) aeskey_audio = aeskey_old;
#endif
#ifdef OLD_PROTOCOL_VIDEO_CLIENT_USER_AGENT_LIST
if (strstr(OLD_PROTOCOL_AUDIO_CLIENT_USER_AGENT_LIST, user_agent)) aeskey_video = aeskey_old;
#endif
if (aeskey_audio == aeskey_old) {
if (old_protocol) { /* some windows AirPlay-client emulators use old AirPlay 1 protocol with unhashed AES key */
logger_log(conn->raop->logger, LOGGER_INFO, "Client identifed as using old protocol (unhashed) AES audio key)");
}
if (aeskey_video == aeskey_old) {
logger_log(conn->raop->logger, LOGGER_INFO, "Client identifed as using old protocol (unhashed) AES video key)");
} else {
unsigned char eaeskey[64] = {};
memcpy(eaeskey, aeskey, 16);
sha_ctx_t *ctx = sha_init();
sha_update(ctx, eaeskey, 16);
sha_update(ctx, ecdh_secret, 32);
sha_final(ctx, eaeskey, NULL);
sha_destroy(ctx);
memcpy(aeskey, eaeskey, 16);
str = utils_data_to_string(aeskey, 16, 16);
logger_log(conn->raop->logger, LOGGER_DEBUG, "16 byte aeskey after sha-256 hash with ecdh_secret:\n%s", str);
free(str);
}
// Time port
@@ -444,8 +418,8 @@ raop_handler_setup(raop_conn_t *conn,
conn->raop_ntp = raop_ntp_init(conn->raop->logger, conn->remote, conn->remotelen, timing_rport);
raop_ntp_start(conn->raop_ntp, &timing_lport);
conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, conn->remote, conn->remotelen, aeskey_audio, aesiv);
conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, conn->remote, conn->remotelen, aeskey_video);
conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, conn->remote, conn->remotelen, aeskey, aesiv);
conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, conn->remote, conn->remotelen, aeskey);
plist_t res_event_port_node = plist_new_uint(conn->raop->port);
plist_t res_timing_port_node = plist_new_uint(timing_lport);

View File

@@ -23,9 +23,6 @@
#include <gst/app/gstappsrc.h>
#include "audio_renderer.h"
static bool broken_audio;
static int counter;
/* GStreamer Caps strings for Airplay-defined audio compression types (ct) */
/* ct = 1; linear PCM (uncompressed): 44100/16/2, S16LE */
@@ -150,8 +147,6 @@ void audio_renderer_stop() {
void audio_renderer_start(unsigned char *ct) {
unsigned char compression_type = 0, id;
broken_audio = false;
counter = 0;
for (int i = 0; i < NFORMATS; i++) {
if(renderer_type[i]->ct == *ct) {
compression_type = *ct;
@@ -193,7 +188,7 @@ void audio_renderer_render_buffer(raop_ntp_t *ntp, unsigned char* data, int data
switch (renderer->ct) {
case 8: /*AAC-ELD*/
valid = (data[0] == 0x8d || data[0] == 0x8e);
valid = valid || (data[0] == 0x81 || data[0] == 0x82); /* old protocol iOS 8, iOS 9 */
valid = valid || (data[0] == 0x81 || data[0] == 0x82); /* from iOS 9, iOS 10 clients (because 32 bit devices?) */
break;
case 2: /*ALAC*/
valid = (data[0] == 0x20);
@@ -206,17 +201,10 @@ void audio_renderer_render_buffer(raop_ntp_t *ntp, unsigned char* data, int data
break;
}
if (valid) {
if (broken_audio) counter++;
if (counter == 2) broken_audio = false;
if (!broken_audio) gst_app_src_push_buffer(GST_APP_SRC(renderer->appsrc), buffer);
gst_app_src_push_buffer(GST_APP_SRC(renderer->appsrc), buffer);
} else {
if (!broken_audio) {
logger_log(logger, LOGGER_ERR, "*** ERROR decryption of audio frame (compression_type %d) failed ", renderer->ct);
} else {
logger_log(logger, LOGGER_DEBUG, "*** ERROR decryption of audio frame (compression_type %d) failed ", renderer->ct);
}
broken_audio = true;
counter = 0;
logger_log(logger, LOGGER_ERR, "*** ERROR invalid audio frame (compression_type %d) skipped ", renderer->ct);
logger_log(logger, LOGGER_ERR, "*** first byte of invalid frame was 0x%2.2x ", (unsigned int) data[0]);
}
}