Skip to content

Instantly share code, notes, and snippets.

@nexus166
Created May 26, 2020 17:23
Show Gist options
  • Select an option

  • Save nexus166/f40ae1cf673a89ec0eff4ff002d49d37 to your computer and use it in GitHub Desktop.

Select an option

Save nexus166/f40ae1cf673a89ec0eff4ff002d49d37 to your computer and use it in GitHub Desktop.
zero-width text steganography in go
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"os"
"regexp"
"strconv"
"strings"
"github.com/atotto/clipboard"
)
const (
zwSpaceBin string = " "
zwSpace = '\u200B'
zwSpaceS = "\u200B"
zwNonJoinerBin string = "0"
zwNonJoiner = '\u200C'
zwNonJoinerS = "\u200C"
zwJoinerBin string = "1"
zwJoiner = '\u200D'
zwJoinerS = "\u200D"
empty = ""
space = " "
)
var (
concealer = strings.NewReplacer(
zwSpaceBin, zwSpaceS,
zwNonJoinerBin, zwNonJoinerS,
zwJoinerBin, zwJoinerS,
)
revealer = strings.NewReplacer(
zwSpaceS, zwSpaceBin,
zwNonJoinerS, zwNonJoinerBin,
zwJoinerS, zwJoinerBin,
)
stripper = regexp.MustCompile(
fmt.Sprintf(
"[^%s|%s|%s]+",
zwSpaceS,
zwNonJoinerS,
zwJoinerS,
),
)
)
func conceal(pub, priv string) string {
b := make([]string, len(priv))
for i, r := range priv {
b[i] = fmt.Sprintf("%b", r)
}
var out bytes.Buffer
out.WriteString(pub[:1])
out.WriteString(concealer.Replace(strings.Join(b, space)))
out.WriteString(pub[1:])
return strings.TrimSpace(out.String())
}
func reveal(pub string) string {
pub = stripper.ReplaceAllString(pub, empty)
pub = revealer.Replace(pub)
var out bytes.Buffer
for _, r := range strings.Fields(pub) {
n, _ := strconv.ParseUint(r, 2, 8)
out.WriteByte(byte(n))
}
return strings.TrimSpace(out.String())
}
func main() {
mode := flag.String("m", "conceal", "mode (conceal|reveal)")
flag.Parse()
stdin := bufio.NewReader(os.Stdin)
switch *mode {
case "c", "conceal":
pub := prompt("public message: ", stdin)
fmt.Printf("\npub message is:\n[%s]\n[%x]\n", pub, []byte(pub))
priv := prompt("secret message: ", stdin)
fmt.Printf("\npriv message is:\n[%s]\n[%x]\n", priv, []byte(priv))
if err := clipboard.WriteAll(conceal(pub, priv)); err != nil {
panic(err)
}
fmt.Println("done")
case "r", "reveal":
pub := prompt("public message: ", stdin)
fmt.Printf("\npub message is:\n[%s]\n[%x]\n", pub, []byte(pub))
revealed := reveal(pub)
fmt.Printf("\nrevealed:\n[%s]\n[%x]\n", revealed, []byte(revealed)[:])
fmt.Println(revealed)
default:
fmt.Printf("usage:\n\t%s conceal|reveal\n", os.Args[0])
}
}
func prompt(ask string, r *bufio.Reader) string {
fmt.Print(ask)
pub, _, err := r.ReadLine()
if err != nil {
panic(err)
}
return strings.TrimSpace(string(pub))
}
@nexus166
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment