Кафедра ИСиТ УО ВГТУ
  • Специальности
    • Экономика электронного бизнеса
    • Информационные системы
    • Information Control Systems
  • Каталог
  • Сайт кафедры
  • Сервисы
    • GitLab
    • JupyterHub
    • Soft
  1. ICS
  2. ITCS
  3. Practice
  4. Steganographic Methods
  • ICS
    • ITCS
      • Theory
        • Computer security issues
        • Computer Security Mechanisms
        • Common Principles of Cryptography
        • Asymmetric encryption
        • Data integrity
        • Steganographic methods for information protection
      • Practice
        • Basics of Symmetric Encryption Algorithms
        • Asymmetric crypto algorithms
        • Data Integrity
        • Steganographic Methods
    • TSTPI
      • Theory
        • Fundamentals of Data Transmission Networks
        • Fundamentals of digital data transmission
        • Network interconnection using network layer protocols
        • Trends in the development of telecommunication technologies and computer networks
        • Search Engines
        • Information security. Confidential information
      • Practice
        • Basic Network Utilities
        • Installing of Network OS
        • Linux network utilities
        • SSH Protocol
        • User Accounts Management
        • Protocol Analysis Using a Network Traffic Analyzer

Contents

  • Laboratory Assignment: Steganographic Methods
    • Objective
    • Tools Required
    • Part 1: Introduction to Steganography
      • Task 1: Understanding Steganography
    • Part 2: LSB Image Steganography
      • Task 2: Installing Required Libraries
      • Task 3: Basic LSB Encoding
      • Task 4: Testing LSB Steganography
      • Task 5: Advanced LSB with RGB Channels
    • Part 3: Text-Based Steganography
      • Task 6: Whitespace Steganography
      • Task 7: Word Length Steganography
    • Part 4: Steganalysis and Detection
      • Task 8: Basic Steganalysis
    • Part 5: Advanced Techniques
      • Task 9: Error-Correction and Encryption
    • Part 6: Practical Exercises
      • Task 10: Complete Steganography System
    • Part 7: Testing and Validation
      • Task 11: Create Test Suite
    • Part 8: Real-World Applications
      • Task 12: Create a Digital Watermarking System
    • Submission Guidelines
    • Additional Challenges (Optional)
  1. ICS
  2. ITCS
  3. Practice
  4. Steganographic Methods

Steganographic Methods

Innovative Technologies for Computer Security
Practice
Author
Affiliation

Andrei Biziuk

VSTU

Published

November 28, 2025

Laboratory Assignment: Steganographic Methods

Objective

  1. Understand the concept of steganography and its difference from cryptography.
  2. Learn to implement basic steganographic techniques using Python.
  3. Gain hands-on experience with LSB (Least Significant Bit) image steganography.
  4. Explore text-based steganography methods.
  5. Understand the challenges and limitations of steganographic techniques.

Tools Required

  1. Python 3.x
  2. Python libraries: Pillow (PIL), numpy
  3. Text editor or IDE
  4. Sample image files (PNG format recommended)

Part 1: Introduction to Steganography

Task 1: Understanding Steganography

  • Read the theory: Steganographic methods for information protection
  • Understand the difference between steganography and cryptography
  • Learn about different types of steganography (image, audio, text)

Part 2: LSB Image Steganography

Task 2: Installing Required Libraries

Install the necessary Python libraries:

pip install pillow numpy

Task 3: Basic LSB Encoding

Create a Python script to hide text in an image using LSB technique:

from PIL import Image
import numpy as np

def text_to_binary(text):
    """Convert text to binary string"""
    binary = ''.join(format(ord(char), '08b') for char in text)
    return binary

def binary_to_text(binary):
    """Convert binary string to text"""
    text = ''
    for i in range(0, len(binary), 8):
        byte = binary[i:i+8]
        if len(byte) == 8:
            text += chr(int(byte, 2))
    return text

def hide_text_in_image(image_path, text, output_path):
    """Hide text in image using LSB technique"""
    # Open image
    img = Image.open(image_path)
    pixels = np.array(img)
    
    # Convert text to binary
    binary_text = text_to_binary(text)
    binary_text += '1111111111111110'  # Delimiter
    
    # Flatten pixel array
    flat_pixels = pixels.flatten()
    
    # Check if image is large enough
    if len(binary_text) > len(flat_pixels):
        raise ValueError("Text too long for this image")
    
    # Hide text in LSB
    for i in range(len(binary_text)):
        # Modify LSB of pixel value
        flat_pixels[i] = (flat_pixels[i] & ~1) | int(binary_text[i])
    
    # Reshape and save
    modified_pixels = flat_pixels.reshape(pixels.shape)
    result_img = Image.fromarray(modified_pixels.astype(np.uint8))
    result_img.save(output_path)
    print(f"Text hidden successfully in {output_path}")

def extract_text_from_image(image_path):
    """Extract hidden text from image"""
    # Open image
    img = Image.open(image_path)
    pixels = np.array(img)
    
    # Flatten pixel array
    flat_pixels = pixels.flatten()
    
    # Extract LSB
    binary_text = ''
    for pixel in flat_pixels:
        binary_text += str(pixel & 1)
        # Check for delimiter
        if binary_text[-16:] == '1111111111111110':
            break
    
    # Remove delimiter and convert to text
    binary_text = binary_text[:-16]
    return binary_to_text(binary_text)

# Example usage
if __name__ == "__main__":
    # Hide text
    secret_message = "Hello, this is a secret message!"
    hide_text_in_image("sample_image.png", secret_message, "stego_image.png")
    
    # Extract text
    extracted = extract_text_from_image("stego_image.png")
    print(f"Extracted message: {extracted}")

Task 4: Testing LSB Steganography

  1. Create or download a sample PNG image (name it sample_image.png)
  2. Run the script to hide a secret message
  3. Verify that the extracted message matches the original
  4. Compare the original and stego images visually

Task 5: Advanced LSB with RGB Channels

Enhance the LSB technique to use all RGB channels:

def hide_text_rgb(image_path, text, output_path):
    """Hide text using all RGB channels"""
    img = Image.open(image_path)
    pixels = np.array(img)
    height, width, channels = pixels.shape
    
    binary_text = text_to_binary(text)
    binary_text += '1111111111111110'  # Delimiter
    
    # Calculate required pixels
    required_pixels = len(binary_text) // 3 + (1 if len(binary_text) % 3 else 0)
    
    if required_pixels > height * width:
        raise ValueError("Text too long for this image")
    
    # Hide text in RGB channels
    index = 0
    for i in range(height):
        for j in range(width):
            for c in range(channels):
                if index < len(binary_text):
                    pixels[i, j, c] = (pixels[i, j, c] & ~1) | int(binary_text[index])
                    index += 1
                else:
                    break
            if index >= len(binary_text):
                break
        if index >= len(binary_text):
            break
    
    result_img = Image.fromarray(pixels.astype(np.uint8))
    result_img.save(output_path)
    print(f"Text hidden in RGB channels: {output_path}")

def extract_text_rgb(image_path):
    """Extract text from RGB channels"""
    img = Image.open(image_path)
    pixels = np.array(img)
    height, width, channels = pixels.shape
    
    binary_text = ''
    for i in range(height):
        for j in range(width):
            for c in range(channels):
                binary_text += str(pixels[i, j, c] & 1)
                if binary_text[-16:] == '1111111111111110':
                    break
            if binary_text[-16:] == '1111111111111110':
                break
        if binary_text[-16:] == '1111111111111110':
            break
    
    binary_text = binary_text[:-16]
    return binary_to_text(binary_text)

Part 3: Text-Based Steganography

Task 6: Whitespace Steganography

Create a script to hide text using whitespace manipulation:

def hide_text_whitespace(text, output_file):
    """Hide text using whitespace (spaces and tabs)"""
    binary_text = text_to_binary(text)
    
    # Use space for '0' and tab for '1'
    whitespace_text = ''
    for bit in binary_text:
        if bit == '0':
            whitespace_text += ' '
        else:
            whitespace_text += '\t'
    
    # Add some visible text to make it look normal
    cover_text = "This is a normal looking text file.\n" + whitespace_text + "\nEnd of file."
    
    with open(output_file, 'w') as f:
        f.write(cover_text)
    
    print(f"Text hidden in whitespace: {output_file}")

def extract_text_whitespace(input_file):
    """Extract text from whitespace"""
    with open(input_file, 'r') as f:
        content = f.read()
    
    # Extract whitespace between lines
    lines = content.split('\n')
    if len(lines) >= 3:
        whitespace_line = lines[1]
        
        binary_text = ''
        for char in whitespace_line:
            if char == ' ':
                binary_text += '0'
            elif char == '\t':
                binary_text += '1'
        
        return binary_to_text(binary_text)
    
    return ""

# Example usage
hide_text_whitespace("Secret message here!", "whitespace_secret.txt")
extracted = extract_text_whitespace("whitespace_secret.txt")
print(f"Extracted: {extracted}")

Task 7: Word Length Steganography

Implement word-length based text steganography:

def hide_text_word_length(text, cover_text, output_file):
    """Hide text using word lengths (even=0, odd=1)"""
    binary_text = text_to_binary(text)
    
    words = cover_text.split()
    if len(words) < len(binary_text):
        raise ValueError("Cover text too short for message")
    
    # Modify word lengths
    modified_words = []
    for i, word in enumerate(words):
        if i < len(binary_text):
            if binary_text[i] == '0':
                # Ensure even length
                if len(word) % 2 == 1:
                    word += 's'  # Add 's' to make even
            else:
                # Ensure odd length
                if len(word) % 2 == 0:
                    word += 'x'  # Add 'x' to make odd
        modified_words.append(word)
    
    result_text = ' '.join(modified_words)
    
    with open(output_file, 'w') as f:
        f.write(result_text)
    
    print(f"Text hidden using word lengths: {output_file}")

def extract_text_word_length(input_file):
    """Extract text from word lengths"""
    with open(input_file, 'r') as f:
        text = f.read()
    
    words = text.split()
    binary_text = ''
    
    for word in words:
        if len(word) % 2 == 0:
            binary_text += '0'
        else:
            binary_text += '1'
        # Look for delimiter pattern (8 consecutive zeros)
        if binary_text[-8:] == '00000000':
            break
    
    # Remove delimiter and convert
    binary_text = binary_text[:-8]
    return binary_to_text(binary_text)

Part 4: Steganalysis and Detection

Task 8: Basic Steganalysis

Create a simple steganalysis tool to detect LSB steganography:

import statistics

def analyze_lsb_distribution(image_path):
    """Analyze LSB distribution to detect hidden data"""
    img = Image.open(image_path)
    pixels = np.array(img)
    flat_pixels = pixels.flatten()
    
    # Extract LSBs
    lsb_values = [pixel & 1 for pixel in flat_pixels]
    
    # Calculate statistics
    zeros = lsb_values.count(0)
    ones = lsb_values.count(1)
    total = len(lsb_values)
    
    print(f"LSB Analysis for {image_path}:")
    print(f"Total pixels: {total}")
    print(f"Zeros: {zeros} ({zeros/total*100:.2f}%)")
    print(f"Ones: {ones} ({ones/total*100:.2f}%)")
    
    # Simple detection: if distribution is too close to 50-50, it might be suspicious
    ratio = min(zeros, ones) / max(zeros, ones)
    if ratio > 0.9:
        print("⚠️  Suspicious: LSB distribution is very balanced (possible steganography)")
    elif ratio > 0.7:
        print("⚠️  Moderately suspicious: LSB distribution is quite balanced")
    else:
        print("✓ Normal: LSB distribution shows natural variation")

def analyze_image_quality(original_path, stego_path):
    """Compare original and stego images"""
    original = Image.open(original_path)
    stego = Image.open(stego_path)
    
    # Convert to same mode if needed
    if original.mode != stego.mode:
        stego = stego.convert(original.mode)
    
    # Calculate MSE (Mean Squared Error)
    orig_pixels = np.array(original)
    stego_pixels = np.array(stego)
    
    mse = np.mean((orig_pixels - stego_pixels) ** 2)
    print(f"Mean Squared Error: {mse}")
    
    if mse < 1:
        print("✓ Very low visual distortion")
    elif mse < 10:
        print("✓ Low visual distortion")
    else:
        print("⚠️  Significant visual distortion detected")

Part 5: Advanced Techniques

Task 9: Error-Correction and Encryption

Enhance steganography with error correction and encryption:

import hashlib
from cryptography.fernet import Fernet

def generate_key(password):
    """Generate encryption key from password"""
    return hashlib.sha256(password.encode()).digest()

def encrypt_message(message, password):
    """Encrypt message using password"""
    key = generate_key(password)
    fernet = Fernet(Fernet.generate_key())
    return fernet.encrypt(message.encode())

def decrypt_message(encrypted_message, password):
    """Decrypt message using password"""
    key = generate_key(password)
    fernet = Fernet(key)
    return fernet.decrypt(encrypted_message).decode()

def hide_encrypted_text(image_path, text, password, output_path):
    """Hide encrypted text in image"""
    # Encrypt the message
    encrypted = encrypt_message(text, password)
    
    # Convert to binary and hide
    binary_encrypted = ''.join(format(byte, '08b') for byte in encrypted)
    
    # Use the LSB function to hide encrypted data
    img = Image.open(image_path)
    pixels = np.array(img)
    flat_pixels = pixels.flatten()
    
    if len(binary_encrypted) + 16 > len(flat_pixels):  # +16 for delimiter
        raise ValueError("Encrypted text too long for this image")
    
    binary_encrypted += '1111111111111110'  # Delimiter
    
    for i in range(len(binary_encrypted)):
        flat_pixels[i] = (flat_pixels[i] & ~1) | int(binary_encrypted[i])
    
    modified_pixels = flat_pixels.reshape(pixels.shape)
    result_img = Image.fromarray(modified_pixels.astype(np.uint8))
    result_img.save(output_path)
    print(f"Encrypted text hidden: {output_path}")

Part 6: Practical Exercises

Task 10: Complete Steganography System

Create a comprehensive steganography tool with command-line interface:

import argparse
import os

def main():
    parser = argparse.ArgumentParser(description='Steganography Tool')
    parser.add_argument('action', choices=['hide', 'extract', 'analyze'], 
                       help='Action to perform')
    parser.add_argument('-i', '--input', required=True, 
                       help='Input image file')
    parser.add_argument('-o', '--output', 
                       help='Output file')
    parser.add_argument('-t', '--text', 
                       help='Text to hide')
    parser.add_argument('-f', '--file', 
                       help='File containing text to hide')
    parser.add_argument('-p', '--password', 
                       help='Password for encryption')
    parser.add_argument('-m', '--method', choices=['lsb', 'rgb', 'text'], 
                       default='lsb', help='Steganography method')
    
    args = parser.parse_args()
    
    try:
        if args.action == 'hide':
            if not args.output:
                print("Error: Output file required for hiding")
                return
            
            # Get text to hide
            if args.file:
                with open(args.file, 'r') as f:
                    text = f.read()
            elif args.text:
                text = args.text
            else:
                print("Error: Text or file required for hiding")
                return
            
            # Hide text
            if args.method == 'lsb':
                hide_text_in_image(args.input, text, args.output)
            elif args.method == 'rgb':
                hide_text_rgb(args.input, text, args.output)
            elif args.method == 'text':
                hide_text_whitespace(text, args.output)
            
            print(f"Text hidden successfully in {args.output}")
            
        elif args.action == 'extract':
            # Extract text
            if args.method == 'lsb':
                text = extract_text_from_image(args.input)
            elif args.method == 'rgb':
                text = extract_text_rgb(args.input)
            elif args.method == 'text':
                text = extract_text_whitespace(args.input)
            
            if args.output:
                with open(args.output, 'w') as f:
                    f.write(text)
                print(f"Text extracted to {args.output}")
            else:
                print(f"Extracted text: {text}")
                
        elif args.action == 'analyze':
            analyze_lsb_distribution(args.input)
            
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

Part 7: Testing and Validation

Task 11: Create Test Suite

Create a comprehensive test to validate your steganography implementation:

import unittest
import os
import tempfile

class TestSteganography(unittest.TestCase):
    
    def setUp(self):
        """Create temporary files for testing"""
        self.temp_dir = tempfile.mkdtemp()
        self.test_image = os.path.join(self.temp_dir, "test.png")
        self.stego_image = os.path.join(self.temp_dir, "stego.png")
        self.test_text = os.path.join(self.temp_dir, "secret.txt")
        
        # Create a simple test image
        test_img = Image.new('RGB', (100, 100), color='red')
        test_img.save(self.test_image)
        
        # Create test text
        with open(self.test_text, 'w') as f:
            f.write("This is a secret test message!")
    
    def tearDown(self):
        """Clean up temporary files"""
        import shutil
        shutil.rmtree(self.temp_dir)
    
    def test_text_to_binary_conversion(self):
        """Test text to binary conversion"""
        text = "ABC"
        binary = text_to_binary(text)
        self.assertEqual(binary, "010000010100001001000011")
        
        # Test reverse conversion
        converted_back = binary_to_text(binary)
        self.assertEqual(converted_back, text)
    
    def test_lsb_hide_extract(self):
        """Test LSB hiding and extraction"""
        secret_message = "Hello, Steganography!"
        
        # Hide message
        hide_text_in_image(self.test_image, secret_message, self.stego_image)
        
        # Extract message
        extracted = extract_text_from_image(self.stego_image)
        
        self.assertEqual(extracted, secret_message)
    
    def test_rgb_hide_extract(self):
        """Test RGB channel hiding and extraction"""
        secret_message = "RGB steganography test"
        
        # Hide message
        hide_text_rgb(self.test_image, secret_message, self.stego_image)
        
        # Extract message
        extracted = extract_text_rgb(self.stego_image)
        
        self.assertEqual(extracted, secret_message)
    
    def test_whitespace_hide_extract(self):
        """Test whitespace steganography"""
        secret_message = "Whitespace test"
        
        # Hide message
        output_file = os.path.join(self.temp_dir, "whitespace.txt")
        hide_text_whitespace(secret_message, output_file)
        
        # Extract message
        extracted = extract_text_whitespace(output_file)
        
        self.assertEqual(extracted, secret_message)

# Run tests
if __name__ == '__main__':
    unittest.main()

Part 8: Real-World Applications

Task 12: Create a Digital Watermarking System

Implement a simple digital watermarking system:

def create_watermark(original_image, watermark_text, output_image):
    """Create a simple digital watermark"""
    # Hide watermark in multiple locations for robustness
    img = Image.open(original_image)
    pixels = np.array(img)
    
    # Convert watermark to binary
    binary_watermark = text_to_binary(watermark_text)
    
    # Embed watermark in multiple locations (corners and center)
    locations = [
        (0, 0),  # Top-left
        (pixels.shape[1]-50, 0),  # Top-right
        (0, pixels.shape[0]-50),  # Bottom-left
        (pixels.shape[1]//2, pixels.shape[0]//2)  # Center
    ]
    
    for start_x, start_y in locations:
        index = 0
        for y in range(start_y, min(start_y + 50, pixels.shape[0])):
            for x in range(start_x, min(start_x + 50, pixels.shape[1])):
                if index < len(binary_watermark):
                    for c in range(3):  # RGB channels
                        if index < len(binary_watermark):
                            pixels[y, x, c] = (pixels[y, x, c] & ~1) | int(binary_watermark[index])
                            index += 1
    
    result_img = Image.fromarray(pixels.astype(np.uint8))
    result_img.save(output_image)
    print(f"Watermark embedded: {output_image}")

def verify_watermark(watermarked_image, original_watermark):
    """Verify if watermark exists in image"""
    img = Image.open(watermarked_image)
    pixels = np.array(img)
    
    # Try to extract watermark from different locations
    locations = [
        (0, 0),  # Top-left
        (pixels.shape[1]-50, 0),  # Top-right
        (0, pixels.shape[0]-50),  # Bottom-left
        (pixels.shape[1]//2, pixels.shape[0]//2)  # Center
    ]
    
    binary_watermark = text_to_binary(original_watermark)
    
    for start_x, start_y in locations:
        extracted_binary = ''
        index = 0
        for y in range(start_y, min(start_y + 50, pixels.shape[0])):
            for x in range(start_x, min(start_x + 50, pixels.shape[1])):
                if index < len(binary_watermark):
                    for c in range(3):  # RGB channels
                        if index < len(binary_watermark):
                            extracted_binary += str(pixels[y, x, c] & 1)
                            index += 1
        
        # Check if extracted matches original
        if extracted_binary == binary_watermark:
            return True, f"Watermark found at location ({start_x}, {start_y})"
    
    return False, "Watermark not found"

Submission Guidelines

  • Submit a report that includes:
    • Detailed explanation of each steganographic technique implemented
    • Screenshots of original and modified images
    • Code snippets for each implementation
    • Analysis of capacity vs. detectability trade-offs
    • Discussion of ethical considerations and legitimate use cases
    • Reflection on the challenges of steganalysis and detection
  • Include all Python scripts and test results
  • Demonstrate successful hiding and extraction of messages using different techniques
  • Discuss the robustness of each method against various attacks (compression, filtering, etc.)

Additional Challenges (Optional)

  1. Audio Steganography: Implement LSB steganography for WAV files
  2. Adaptive Steganography: Create a system that adapts embedding based on image characteristics
  3. Multi-layer Security: Combine steganography with strong encryption
  4. Steganalysis Tools: Develop more sophisticated detection algorithms
  5. Performance Analysis: Compare different techniques for capacity, speed, and detectability
Back to top
Data Integrity
TSTPI