<?php

/*  
     ___ _                                              _        
    / __| |_ ___ __ _ __ _ _ _  ___  __ _ _ _ __ _ _ __| |_  _ _ 
    \__ \  _/ -_) _` / _` | ' \/ _ \/ _` | '_/ _` | '_ \ ' \| '_|
    |___/\__\___\__, \__,_|_||_\___/\__, |_| \__,_| .__/_||_|_|  
                |___/               |___/         |_|            
    
    Hide messages within other messages using invisible characters
    
    by Adam Newbold
    https://neatnik.net/adam
    
    Free Public License 1.0.0 [0BSD]
    
    Permission to use, copy, modify, and/or distribute this software
    for any purpose with or without fee is hereby granted.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE 
    FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 
    DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 
    IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 
    OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

*/

// Display this source code when requested
if(isset($_GET['source'])) {
    echo 
'<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Source</title><style type="text/css">body{background:#000;}code{font-family:Menlo,Monaco,"Courier New";font-size: 1.2em;}</style>';
    
ini_set("highlight.comment""#70c0b1");
    
ini_set("highlight.default""#eaeaea");
    
ini_set("highlight.html""#969896");
    
ini_set("highlight.keyword""#e78c45;");
    
ini_set("highlight.string""#e7c547");
    
highlight_file(__FILE__);
    exit;
}

// Set up some variables
$public = isset($_POST['public']) ? $_POST['public'] : null;
$private = isset($_POST['private']) ? $_POST['private'] : null;
$encoded = isset($_POST['encoded']) ? $_POST['encoded'] : null;

// Convert a string into binary data
function str2bin($text){
    
$bin = array();
    for(
$i=0strlen($text)>$i$i++)
        
$bin[] = decbin(ord($text[$i]));
    return 
implode(' ',$bin);
}

// Convert binary data to a string
function bin2str($bin){
    
$text = array();
    
$bin explode(' '$bin);
    for(
$i=0count($bin)>$i$i++)
        
$text[] = chr(bindec($bin[$i]));
    return 
implode($text);
}

// Convert the ones, zeros, and spaces of the hidden binary data to their respective zero-width characters 
function bin2hidden($str) {
    
$str str_replace(' '"\xE2\x81\xA0"$str); // Unicode Character 'WORD JOINER' (U+2060) 0xE2 0x81 0xA0
    
$str str_replace('0'"\xE2\x80\x8B"$str); // Unicode Character 'ZERO WIDTH SPACE' (U+200B) 0xE2 0x80 0x8B
    
$str str_replace('1'"\xE2\x80\x8C"$str); // Unicode Character 'ZERO WIDTH NON-JOINER' (U+200C) 0xE2 0x80 0x8C
    
return $str;
}

// Convert zero-width characters to hidden binary data
function hidden2bin($str) {
    
$str str_replace("\xE2\x81\xA0"' '$str); // Unicode Character 'WORD JOINER' (U+2060) 0xE2 0x81 0xA0
    
$str str_replace("\xE2\x80\x8B"'0'$str); // Unicode Character 'ZERO WIDTH SPACE' (U+200B) 0xE2 0x80 0x8B
    
$str str_replace("\xE2\x80\x8C"'1'$str); // Unicode Character 'ZERO WIDTH NON-JOINER' (U+200C) 0xE2 0x80
    
return $str;
}

?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta property="og:title" content="Steganographr">
<meta property="og:url" content="https://neatnik.net/steganographr/">
<meta property="og:description" content="Hide text in plain sight using secret zero-width characters. Digital steganography made simple.">
<title>Steganographr</title>
<?php include('/var/www/neatnik.net/style.php'); ?>
</head>
<body>

<?php echo file_get_contents('/var/www/neatnik.net/announcement.html'); ?>
<?php 
echo file_get_contents('/var/www/neatnik.net/header.php'); ?>

<main>

<section>

<h1>Steganographr</h1>

<p>Hide text in plain sight using secret zero-width characters. It’s digital steganography made simple. Inspired by <a href="https://www.zachaysan.com/writing/2017-12-30-zero-width-characters">Zach Aysan</a>.</p>

<p>Enter a public message, then a private message, and then click the button to hide your private message within your public message. <a href="#about">How does it work?</a></p>

<form action="?" method="post">
<div class="col">
<h2>Public Message</h2>
<textarea name="public"><?php echo $public?></textarea>
</div>
<div class="col">
<h2>Private Message</h2>
<textarea name="private"><?php echo $private?></textarea>
</div>
<p><button type="submit"><i class="fas fa-pencil-alt"></i> Steganographize</button></p>
</form>

<?php

if(isset($_POST['public'])) {
    echo 
'<hr><div class="col"><h2>Steganographized Message</h2>';
    
    
// Grab the public message string and split it by the space character
    
$public $_POST['public'];
    
$public explode(' '$public);
    
    
// Make sure that the public message has at least one space (since we're going to hide the secret message after the first space)
    
if(count($public) == 1) {
        echo 
'<p class="alert"><i class="fas fa-exclamation-triangle"></i> You need at least one space in your public message.</p>';
    }
    else {
        
// Grab the private message
        
$private $_POST['private'];
        
// Convert it to binary data
        
$str str2bin($private);
        
// And convert that into a string of zero-width characters
        
$private bin2hidden($str);
        
// Display a <textarea> containing the public message with the hidden private embedded
        
echo '<textarea>';
        
// Display the first word of the public message
        
echo $public[0];
        
// Display the private message
        
echo $private;
        
// Display the rest of the public message
        
unset($public[0]);
        echo 
' '.implode(' '$public);
        echo 
'</textarea>';
        echo 
'<br><small style="color: green;">Copy this text your private message will come along for the ride.</small>';
    }
    echo 
'</div>';
}

?>

<hr>

<div class="col">
<form action="?" method="post">
<h2>Reveal Private Message</h2>
<textarea name="encoded"><?php echo $encoded?></textarea>
<p><button type="submit"><i class="fas fa-eye"></i> Desteganographize</button></p>
</form>
</div>

<?php

if(isset($_POST['encoded'])) {
    
    
// Unhide the message
    
$message bin2str(hidden2bin($_POST['encoded']));
    
    
// Display the hidden private message
    
echo '<div class="col"><h2>Private Message</h2>';
    if(
strlen($message) < 2) {
        echo 
'<p class="alert"><i class="fas fa-exclamation-triangle"></i> No hidden message was found.</p>';
    }
    else {
        echo 
'<p style="color: #009900; font-weight: bold;">'.htmlentities($message).'</p>';
    }
    
    echo 
'</div>';
}

?>

<hr>

<h2 id="about">About Steganographr</h2>
<p>Steganographr works by converting your private message into binary data, and then converting that binary data into zero-width characters (which can then be hidden in your public message). These characters are used:</p>
<ul>
    <li>Unicode Character 'WORD JOINER' (U+2060)</li>
    <li>Unicode Character 'ZERO WIDTH SPACE' (U+200B)</li>
    <li>Unicode Character 'ZERO WIDTH NON-JOINER' (U+200C)</li>
</ul>

<p><i class="far fa-file-code"></i> <a href="?source">View the live source (PHP) of this page here.</a> <small>(<a href="https://opensource.org/licenses/FPL-1.0.0">0BSD licensed</a>, so grab it and go!)</small></p>

<hr>

<p>Questions or feedback? I’m <a href="https://twitter.com/nwbld">@nwbld</a> on Twitter and <a href="https://adam.lol/">adam.lol</a> on the web.</p>

</section>

</main>

<?php echo file_get_contents('/var/www/neatnik.net/footer.php'); ?>

</body>
</html>