La méthode habituelle serait SSL, comme déjà dit. Il prend en charge l'authentification et le cryptage (obligatoires) du serveur par défaut, l'authentification du client étant facultative (par exemple, selon la configuration, le serveur peut s'assurer que les clients sont authentifiés).
En Java, vous pouvez utiliser SSLSocket (et SSLServerSocket) (ou les classes de fabrique respectives), ou le SSLEngine (si vous voulez faire des IO non bloquantes). Ou une API de plus haut niveau qui utilise ceci sous couvert.
Une autre option serait le SSH protocole. Cela permet une connexion cryptée et (normalement) authentifiée des deux côtés, sur laquelle on peut acheminer plusieurs canaux . Il est généralement utilisé pour l'exécution de commandes à distance ou le transfert de fichiers, mais il permet également le transfert de port.
En Java, cela serait mis en œuvre (du côté client) par exemple par JSch . Je ne connais pas d'implémentation Java côté serveur - mais vous pouvez utiliser un serveur OpenSSH normal et transférer les ports à votre processus de serveur Java.