#ifndef ORBITHUB_VNC_APPLE_RSA_AUTH_H #define ORBITHUB_VNC_APPLE_RSA_AUTH_H #include #include // Apple Screen Sharing's RSA-based authentication scheme (RFB security // type 33, sometimes called "MacAuthentication" or "ARD authentication"). // Distinct from security type 30 (Diffie-Hellman + AES, see // vnc_apple_dh_auth.h): modern macOS advertises both, but empirically only // type 33 is actually functional -- type 30 appears to be vestigial. // Neither is part of RFC 6143; this wire format and crypto shape was // confirmed against the `asyncvnc` PyPI package's implementation (a real, // working, independently-maintained VNC client) rather than derived from // official Apple documentation, which doesn't exist for this scheme. // // Scheme: the server hands the client its RSA public key (DER-encoded // X.509 SubjectPublicKeyInfo); the client generates a random AES-128 key, // encrypts the username+password with it, then RSA-PKCS1v1.5-encrypts // that AES key with the server's public key and sends both back. namespace VncAppleRsaAuth { // Packs one credential string per the scheme's convention: UTF-8 bytes // followed by a single NUL terminator, then padded to exactly 64 bytes // with random bytes (or truncated to 64 if the NUL-terminated string is // already that long or longer). The NUL terminator is what lets the // server find the string's real end despite the random padding -- the // padding's specific value isn't otherwise significant. Exposed publicly // so it's independently unit-testable. QByteArray packCredential(const QString& text); struct Response { // Exactly 128 bytes on success (packCredential(username) + // packCredential(password), AES-128-ECB encrypted). Empty on failure. QByteArray encryptedCredentials; // RSA-modulus-length bytes on success (the random AES key, // PKCS1v1.5-encrypted with the server's public key). Empty on // failure. QByteArray encryptedAesKey; }; // Computes the full type-33 response from the server's DER-encoded RSA // public key and the credentials to authenticate with. Returns a Response // with both fields empty on any failure (malformed key, an OpenSSL // operation failing). Response computeResponse(const QByteArray& hostKeyDer, const QString& username, const QString& password); } #endif