Watermarking Text
Overview
Tesla used space characters in internal emails to identify leaks
Github: https://github.com/gitorko/project06
Watermarking
The below code embeds a binary message with spaces in a given text, this can be used to trace the origin of the text message and which user it belonged to.
Code
1package com.demo.project06;
2
3import java.util.ArrayList;
4import java.util.List;
5
6public class Main {
7
8 public static String[] userNames = {"jack@company.com", "adam@company.com", "sally@company.com"};
9
10 public static String[][] users;
11
12 public static void main(String[] args) {
13 String message = "Hello, How are you today? This is a test message for watermarking. Have a great day!";
14 String[] sentences = message.split("(?<=[.\\?])");
15 if (sentences.length < 3) {
16 throw new RuntimeException("Sentences are too few to encode watermark");
17 }
18 generateUserBinaryIds();
19 // Encoding and Decoding process
20 String user = "adam@company.com";
21 String encodedMessage = encodeMessage(message, user);
22 System.out.println("Watermarked message for " + user + ": \n" + encodedMessage);
23
24 String decodedUser = decodeMessage(encodedMessage);
25 System.out.println("Message belongs to: " + decodedUser);
26 }
27
28 private static void generateUserBinaryIds() {
29
30 users = new String[userNames.length + 1][2];
31 users[0][0] = "NA";
32 users[0][1] = "000";
33
34 for (int i = 1; i <= userNames.length; i++) {
35 // Convert the index into a binary string with padding (e.g., "001", "010", "011", ...)
36 String binaryId = String.format("%3s", Integer.toBinaryString(i)).replace(' ', '0');
37 users[i][0] = userNames[i - 1];
38 users[i][1] = binaryId;
39 }
40 }
41
42 public static String encodeMessage(String message, String user) {
43 // Loop through the users to find the binary ID of the user
44 for (String[] u : users) {
45 if (user.equals(u[0])) {
46 String binaryId = u[1];
47 return watermarkMessage(message, binaryId);
48 }
49 }
50 throw new RuntimeException("Unknown user: " + user);
51 }
52
53 public static String decodeMessage(String message) {
54 // Split the message into sentences, keeping the period (. or ?)
55 String[] sentences = message.split("(?<=[.\\?])");
56 StringBuilder binaryPattern = new StringBuilder();
57 for (String sentence : sentences) {
58 int spaceCount = countLeadingSpaces(sentence);
59 binaryPattern.append(spaceCount == 0 ? "0" : "1");
60 }
61 System.out.println("Binary Code: " + binaryPattern);
62 for (String[] user : users) {
63 String name = user[0];
64 String binaryId = user[1];
65 if (binaryPattern.toString().equals(binaryId)) {
66 return name;
67 }
68 }
69 return "Unknown User";
70 }
71
72 private static String watermarkMessage(String message, String binaryId) {
73 // Split the message into sentences, keeping the period (. or ?)
74 String[] sentences = message.split("(?<=[.\\?])");
75
76 List<String> watermarkedSentences = new ArrayList<>();
77 for (int i = 0; i < sentences.length; i++) {
78 char spaceCount = binaryId.charAt(i % binaryId.length());
79 int spacesToAdd = spaceCount == '1' ? 1 : 0; // If '1', add 1 space; if '0', add 0 spaces
80 String sentenceWithSpaces = " ".repeat(spacesToAdd) + sentences[i];
81 watermarkedSentences.add(sentenceWithSpaces);
82 }
83 return String.join("", watermarkedSentences);
84 }
85
86 private static int countLeadingSpaces(String sentence) {
87 int count = 0;
88 int length = sentence.length();
89 while (count < length && sentence.charAt(count) == ' ') {
90 count++;
91 }
92 return count > 1 ? 1 : 0;
93 }
94}
Setup
1# Project06
2
3Encode and Decode watermarked text message
4
5### Version
6
7Check version
8
9```bash
10$java --version
11openjdk 21
12```
References
comments powered by Disqus