I had fun writing a Racket version:
#lang racket/base
(require net/base64
threading)
(define FIRST-INVISIBLE-CHAR 917760)
(define (invis-encode str)
(list->string
(for/list ([c (in-list (string->list str))]
#:do [(define cnum (char->integer c))]
#:when (<= cnum 127))
(integer->char (+ cnum FIRST-INVISIBLE-CHAR)))))
(define (invis-decode str)
(list->string
(for/list ([c (in-list (string->list str))]
#:do [(define plaintxt-c (- (char->integer c) FIRST-INVISIBLE-CHAR))]
#:when (> plaintxt-c 0))
(integer->char plaintxt-c))))
(define (hide secret plain)
(~> (string->bytes/utf-8 secret)
(base64-encode #"") ; use #"" vs #"\r\n" to prevent line-wrapping
(bytes->string/utf-8)
(invis-encode)
(string-append plain _)))
(define (unhide ciphertext)
(~> (invis-decode ciphertext)
(string->bytes/utf-8)
(base64-decode)
(bytes->string/utf-8)))
(module+ test
(require rackunit)
(define secret "this is a s3cret message. ssh")
(define plaintext "Hey you, nothing to see here.")
(define to-share (hide secret plaintext))
(check-equal? (string-length to-share) 69) ; count of bytes
(check-equal? (string-grapheme-count to-share) 29) ; 29 actually-visible graphemes
(check-equal? secret (unhide to-share)))