From 31d36cf2ed982d364df475f994906751f23c0796 Mon Sep 17 00:00:00 2001 From: Fergal Moran Date: Thu, 23 Mar 2017 19:03:46 +0000 Subject: [PATCH] Fucking line endings --- .gitignore | 506 +++++++++++++++---------------- AddFingerprintCommand.cs | 58 ++-- App.cs | 22 +- ExtractFingerprintCommand.cs | 48 +-- Fingerprinter.cs | 200 ++++++------- Program.cs | 30 +- Properties/launchSettings.json | 14 +- WaveFormat.cs | 56 ++-- WaveStream.cs | 524 ++++++++++++++++----------------- WaveUtility.cs | 404 ++++++++++++------------- commands.txt | 2 +- stegoprint.csproj | 18 +- 12 files changed, 941 insertions(+), 941 deletions(-) diff --git a/.gitignore b/.gitignore index 12818cd..70a3da5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,254 +1,254 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + .vscode/ \ No newline at end of file diff --git a/AddFingerprintCommand.cs b/AddFingerprintCommand.cs index abae9ce..4bacce1 100644 --- a/AddFingerprintCommand.cs +++ b/AddFingerprintCommand.cs @@ -1,29 +1,29 @@ -using Microsoft.Extensions.CommandLineUtils; -using System; - -namespace StegoPrint { - public class AddFingerprintCommand : CommandLineApplication { - CommandOption _message; - CommandOption _keyfile; - CommandOption _input; - CommandOption _output; - - public AddFingerprintCommand() { - Name = "add"; - Description = "Adds a fingerprint to an audio file"; - - _message = Option("-$|-m |--message ", "The message to embed in the file", CommandOptionType.SingleValue); - _keyfile = Option("-$|-k |--keyfile ", "The keyfile for the fingerprint", CommandOptionType.SingleValue); - _input = Option("-$|-i |--input ", "The input audio file to process", CommandOptionType.SingleValue); - _output = Option("-$|-o |--output ", "The output file", CommandOptionType.SingleValue); - - HelpOption("-h | -? | --help"); - OnExecute((Func)RunCommand); - } - - private int RunCommand() { - new Fingerprinter().AddMessage(_message.Value(), _keyfile.Value(), _input.Value(), _output.Value()); - return -1; - } - } -} +using Microsoft.Extensions.CommandLineUtils; +using System; + +namespace StegoPrint { + public class AddFingerprintCommand : CommandLineApplication { + CommandOption _message; + CommandOption _keyfile; + CommandOption _input; + CommandOption _output; + + public AddFingerprintCommand() { + Name = "add"; + Description = "Adds a fingerprint to an audio file"; + + _message = Option("-$|-m |--message ", "The message to embed in the file", CommandOptionType.SingleValue); + _keyfile = Option("-$|-k |--keyfile ", "The keyfile for the fingerprint", CommandOptionType.SingleValue); + _input = Option("-$|-i |--input ", "The input audio file to process", CommandOptionType.SingleValue); + _output = Option("-$|-o |--output ", "The output file", CommandOptionType.SingleValue); + + HelpOption("-h | -? | --help"); + OnExecute((Func)RunCommand); + } + + private int RunCommand() { + new Fingerprinter().AddMessage(_message.Value(), _keyfile.Value(), _input.Value(), _output.Value()); + return -1; + } + } +} diff --git a/App.cs b/App.cs index 9180bfd..a8e67cb 100644 --- a/App.cs +++ b/App.cs @@ -1,11 +1,11 @@ -using Microsoft.Extensions.CommandLineUtils; -using System; - -namespace StegoPrint { - class App : CommandLineApplication { - public App() { - Commands.Add(new AddFingerprintCommand()); - Commands.Add(new ExtractFingerprintCommand()); - } - } -} +using Microsoft.Extensions.CommandLineUtils; +using System; + +namespace StegoPrint { + class App : CommandLineApplication { + public App() { + Commands.Add(new AddFingerprintCommand()); + Commands.Add(new ExtractFingerprintCommand()); + } + } +} diff --git a/ExtractFingerprintCommand.cs b/ExtractFingerprintCommand.cs index cea58d6..95017c3 100644 --- a/ExtractFingerprintCommand.cs +++ b/ExtractFingerprintCommand.cs @@ -1,24 +1,24 @@ -using Microsoft.Extensions.CommandLineUtils; -using System; - -namespace StegoPrint { - public class ExtractFingerprintCommand : CommandLineApplication { - CommandOption _keyfile; - CommandOption _input; - public ExtractFingerprintCommand() { - Name = "extract"; - Description = "Extracts a fingerprint from a file"; - - _keyfile = Option("-$|-k |--keyfile ", "The keyfile for the fingerprint", CommandOptionType.SingleValue); - _input = Option("-$|-i |--input ", "The input audio file to process", CommandOptionType.SingleValue); - - HelpOption("-h | -? | --help"); - OnExecute((Func)RunCommand); - } - - private int RunCommand() { - new Fingerprinter().ExtractMessage(_keyfile.Value(), _input.Value()); - return -1; - } - } -} +using Microsoft.Extensions.CommandLineUtils; +using System; + +namespace StegoPrint { + public class ExtractFingerprintCommand : CommandLineApplication { + CommandOption _keyfile; + CommandOption _input; + public ExtractFingerprintCommand() { + Name = "extract"; + Description = "Extracts a fingerprint from a file"; + + _keyfile = Option("-$|-k |--keyfile ", "The keyfile for the fingerprint", CommandOptionType.SingleValue); + _input = Option("-$|-i |--input ", "The input audio file to process", CommandOptionType.SingleValue); + + HelpOption("-h | -? | --help"); + OnExecute((Func)RunCommand); + } + + private int RunCommand() { + new Fingerprinter().ExtractMessage(_keyfile.Value(), _input.Value()); + return -1; + } + } +} diff --git a/Fingerprinter.cs b/Fingerprinter.cs index c3303ad..c44e1a7 100644 --- a/Fingerprinter.cs +++ b/Fingerprinter.cs @@ -1,101 +1,101 @@ -using System; -using System.IO; -using System.Text; - -namespace StegoPrint { - public class Fingerprinter { - private Stream GetMessageStream(string message) { - BinaryWriter messageWriter = new BinaryWriter(new MemoryStream()); - messageWriter.Write(message.Length); - messageWriter.Write(Encoding.ASCII.GetBytes(message)); - messageWriter.Seek(0, SeekOrigin.Begin); - return messageWriter.BaseStream; - } - - public void AddMessage(string message, string keyFile, string inputFile, string outputFile) { - Stream sourceStream = null; - FileStream destinationStream = null; - WaveStream audioStream = null; - - //create a stream that contains the message, preceeded by its length - Stream messageStream = GetMessageStream(message); - //open the key file - Stream keyStream = new FileStream(keyFile, FileMode.Open); - - try { - - //how man samples do we need? - long countSamplesRequired = WaveUtility.CheckKeyForMessage(keyStream, messageStream.Length); - - if (countSamplesRequired > Int32.MaxValue) { - throw new Exception("Message too long, or bad key! This message/key combination requires " + countSamplesRequired + " samples, only " + Int32.MaxValue + " samples are allowed."); - } - - sourceStream = new FileStream(inputFile, FileMode.Open); - - //create an empty file for the carrier wave - destinationStream = new FileStream(outputFile, FileMode.Create); - - //copy the carrier file's header - audioStream = new WaveStream(sourceStream, destinationStream); - if (audioStream.Length <= 0) { - throw new Exception("Invalid WAV file"); - } - - //are there enough samples in the carrier wave? - if (countSamplesRequired > audioStream.CountSamples) { - String errorReport = "The carrier file is too small for this message and key!\r\n" + - "Samples available: " + audioStream.CountSamples + "\r\n" + - "Samples needed: " + countSamplesRequired; - throw new Exception(errorReport); - } - - //hide the message - WaveUtility utility = new WaveUtility(audioStream, destinationStream); - utility.Hide(messageStream, keyStream); - } catch (Exception ex) { - Console.WriteLine($"Error: {ex.Message}"); - } finally { - if (keyStream != null) { keyStream.Dispose(); } - if (messageStream != null) { messageStream.Dispose(); } - if (audioStream != null) { audioStream.Dispose(); } - if (sourceStream != null) { sourceStream.Dispose(); } - if (destinationStream != null) { destinationStream.Dispose(); } - } - } - public void ExtractMessage(string keyFile, string inputFile) { - FileStream sourceStream = null; - WaveStream audioStream = null; - //create an empty stream to receive the extracted message - MemoryStream messageStream = new MemoryStream(); - //open the key file - Stream keyStream = new FileStream(keyFile, FileMode.Open); - - try { - //open the carrier file - sourceStream = new FileStream(inputFile, FileMode.Open); - audioStream = new WaveStream(sourceStream); - WaveUtility utility = new WaveUtility(audioStream); - - //exctract the message from the carrier wave - utility.Extract(messageStream, keyStream); - - messageStream.Seek(0, SeekOrigin.Begin); - string extractedMessage = new StreamReader(messageStream).ReadToEnd(); - - Console.WriteLine("Message is....."); - Console.WriteLine(extractedMessage); - - Console.ReadKey(); - } catch (Exception ex) { - Console.WriteLine($"Error extracting message {ex.Message}"); - } finally { - if (keyStream != null) { keyStream.Dispose(); } - if (messageStream != null) { messageStream.Dispose(); } - if (audioStream != null) { audioStream.Dispose(); } - if (sourceStream != null) { sourceStream.Dispose(); } - } - } - - } +using System; +using System.IO; +using System.Text; + +namespace StegoPrint { + public class Fingerprinter { + private Stream GetMessageStream(string message) { + BinaryWriter messageWriter = new BinaryWriter(new MemoryStream()); + messageWriter.Write(message.Length); + messageWriter.Write(Encoding.ASCII.GetBytes(message)); + messageWriter.Seek(0, SeekOrigin.Begin); + return messageWriter.BaseStream; + } + + public void AddMessage(string message, string keyFile, string inputFile, string outputFile) { + Stream sourceStream = null; + FileStream destinationStream = null; + WaveStream audioStream = null; + + //create a stream that contains the message, preceeded by its length + Stream messageStream = GetMessageStream(message); + //open the key file + Stream keyStream = new FileStream(keyFile, FileMode.Open); + + try { + + //how man samples do we need? + long countSamplesRequired = WaveUtility.CheckKeyForMessage(keyStream, messageStream.Length); + + if (countSamplesRequired > Int32.MaxValue) { + throw new Exception("Message too long, or bad key! This message/key combination requires " + countSamplesRequired + " samples, only " + Int32.MaxValue + " samples are allowed."); + } + + sourceStream = new FileStream(inputFile, FileMode.Open); + + //create an empty file for the carrier wave + destinationStream = new FileStream(outputFile, FileMode.Create); + + //copy the carrier file's header + audioStream = new WaveStream(sourceStream, destinationStream); + if (audioStream.Length <= 0) { + throw new Exception("Invalid WAV file"); + } + + //are there enough samples in the carrier wave? + if (countSamplesRequired > audioStream.CountSamples) { + String errorReport = "The carrier file is too small for this message and key!\r\n" + + "Samples available: " + audioStream.CountSamples + "\r\n" + + "Samples needed: " + countSamplesRequired; + throw new Exception(errorReport); + } + + //hide the message + WaveUtility utility = new WaveUtility(audioStream, destinationStream); + utility.Hide(messageStream, keyStream); + } catch (Exception ex) { + Console.WriteLine($"Error: {ex.Message}"); + } finally { + if (keyStream != null) { keyStream.Dispose(); } + if (messageStream != null) { messageStream.Dispose(); } + if (audioStream != null) { audioStream.Dispose(); } + if (sourceStream != null) { sourceStream.Dispose(); } + if (destinationStream != null) { destinationStream.Dispose(); } + } + } + public void ExtractMessage(string keyFile, string inputFile) { + FileStream sourceStream = null; + WaveStream audioStream = null; + //create an empty stream to receive the extracted message + MemoryStream messageStream = new MemoryStream(); + //open the key file + Stream keyStream = new FileStream(keyFile, FileMode.Open); + + try { + //open the carrier file + sourceStream = new FileStream(inputFile, FileMode.Open); + audioStream = new WaveStream(sourceStream); + WaveUtility utility = new WaveUtility(audioStream); + + //exctract the message from the carrier wave + utility.Extract(messageStream, keyStream); + + messageStream.Seek(0, SeekOrigin.Begin); + string extractedMessage = new StreamReader(messageStream).ReadToEnd(); + + Console.WriteLine("Message is....."); + Console.WriteLine(extractedMessage); + + Console.ReadKey(); + } catch (Exception ex) { + Console.WriteLine($"Error extracting message {ex.Message}"); + } finally { + if (keyStream != null) { keyStream.Dispose(); } + if (messageStream != null) { messageStream.Dispose(); } + if (audioStream != null) { audioStream.Dispose(); } + if (sourceStream != null) { sourceStream.Dispose(); } + } + } + + } } \ No newline at end of file diff --git a/Program.cs b/Program.cs index 490bdec..42daae1 100644 --- a/Program.cs +++ b/Program.cs @@ -1,16 +1,16 @@ -using Microsoft.Extensions.CommandLineUtils; -using System; -using System.Collections.Generic; - -namespace StegoPrint { - class Program { - static int Main(string[] args) { - try { - return new App().Execute(args); - } catch (Exception ex) { - Console.Write(ex); - return 1; - } - } - } +using Microsoft.Extensions.CommandLineUtils; +using System; +using System.Collections.Generic; + +namespace StegoPrint { + class Program { + static int Main(string[] args) { + try { + return new App().Execute(args); + } catch (Exception ex) { + Console.Write(ex); + return 1; + } + } + } } \ No newline at end of file diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 99fe029..109592b 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -1,8 +1,8 @@ -{ - "profiles": { - "stegoprint": { - "commandName": "Project", - "commandLineArgs": "extract -k \"C:\\dev\\working\\stegano\\mylib\\keyfile.txt\" -i \"C:\\dev\\working\\stegano\\mylib\\out.wav\"" - } - } +{ + "profiles": { + "stegoprint": { + "commandName": "Project", + "commandLineArgs": "extract -k \"C:\\dev\\working\\stegano\\mylib\\keyfile.txt\" -i \"C:\\dev\\working\\stegano\\mylib\\out.wav\"" + } + } } \ No newline at end of file diff --git a/WaveFormat.cs b/WaveFormat.cs index 794c1e2..0e73150 100644 --- a/WaveFormat.cs +++ b/WaveFormat.cs @@ -1,29 +1,29 @@ -using System.Runtime.InteropServices; - -namespace StegoPrint { - public enum WaveFormats { - Pcm = 1, - Float = 3 - } - [StructLayout (LayoutKind.Sequential)] - public class WaveFormat { - public short wFormatTag; - public short nChannels; - public int nSamplesPerSec; - public int nAvgBytesPerSec; - public short nBlockAlign; - public short wBitsPerSample; - public short cbSize; - - public WaveFormat (int rate, int bits, int channels) { - wFormatTag = (short) WaveFormats.Pcm; - nChannels = (short) channels; - nSamplesPerSec = rate; - wBitsPerSample = (short) bits; - cbSize = 0; - - nBlockAlign = (short) (channels * (bits / 8)); - nAvgBytesPerSec = nSamplesPerSec * nBlockAlign; - } - } +using System.Runtime.InteropServices; + +namespace StegoPrint { + public enum WaveFormats { + Pcm = 1, + Float = 3 + } + [StructLayout (LayoutKind.Sequential)] + public class WaveFormat { + public short wFormatTag; + public short nChannels; + public int nSamplesPerSec; + public int nAvgBytesPerSec; + public short nBlockAlign; + public short wBitsPerSample; + public short cbSize; + + public WaveFormat (int rate, int bits, int channels) { + wFormatTag = (short) WaveFormats.Pcm; + nChannels = (short) channels; + nSamplesPerSec = rate; + wBitsPerSample = (short) bits; + cbSize = 0; + + nBlockAlign = (short) (channels * (bits / 8)); + nAvgBytesPerSec = nSamplesPerSec * nBlockAlign; + } + } } \ No newline at end of file diff --git a/WaveStream.cs b/WaveStream.cs index 877a49a..cb453a1 100644 --- a/WaveStream.cs +++ b/WaveStream.cs @@ -1,263 +1,263 @@ -using System; -using System.IO; - -namespace StegoPrint { - public class WaveStream : Stream, IDisposable { - private Stream m_Stream; - private long m_DataPos; - private int m_Length; - - private WaveFormat m_Format; - - public WaveFormat Format { - get { return m_Format; } - } - - private string ReadChunk (BinaryReader reader) { - byte[] ch = new byte[4]; - reader.Read (ch, 0, ch.Length); - return System.Text.Encoding.ASCII.GetString (ch); - } - - private void ReadHeader () { - BinaryReader Reader = new BinaryReader (m_Stream); - if (ReadChunk (Reader) != "RIFF") - throw new Exception ("Invalid file format"); - - Reader.ReadInt32 (); // File length minus first 8 bytes of RIFF description, we don't use it - - if (ReadChunk (Reader) != "WAVE") - throw new Exception ("Invalid file format"); - - if (ReadChunk (Reader) != "fmt ") - throw new Exception ("Invalid file format"); - - int len = Reader.ReadInt32 (); - if (len < 16) // bad format chunk length - throw new Exception ("Invalid file format"); - - m_Format = new WaveFormat (22050, 16, 2); // initialize to any format - m_Format.wFormatTag = Reader.ReadInt16 (); - m_Format.nChannels = Reader.ReadInt16 (); - m_Format.nSamplesPerSec = Reader.ReadInt32 (); - m_Format.nAvgBytesPerSec = Reader.ReadInt32 (); - m_Format.nBlockAlign = Reader.ReadInt16 (); - m_Format.wBitsPerSample = Reader.ReadInt16 (); - - // advance in the stream to skip the wave format block - len -= 16; // minimum format size - while (len > 0) { - Reader.ReadByte (); - len--; - } - - // assume the data chunk is aligned - while (m_Stream.Position < m_Stream.Length && ReadChunk (Reader) != "data") - ; - - if (m_Stream.Position >= m_Stream.Length) - throw new Exception ("Invalid file format"); - - m_Length = Reader.ReadInt32 (); - m_DataPos = m_Stream.Position; - - Position = 0; - } - - /// ReadChunk(reader) - Changed to CopyChunk(reader, writer) - /// source stream - /// four characters - private string CopyChunk (BinaryReader reader, BinaryWriter writer) { - byte[] ch = new byte[4]; - reader.Read (ch, 0, ch.Length); - - //copy the chunk - writer.Write (ch); - - return System.Text.Encoding.ASCII.GetString (ch); - } - - /// ReadHeader() - Changed to CopyHeader(destination) - private void CopyHeader (Stream destinationStream) { - BinaryReader reader = new BinaryReader (m_Stream); - BinaryWriter writer = new BinaryWriter (destinationStream); - - if (CopyChunk (reader, writer) != "RIFF") - throw new Exception ("Invalid file format"); - - writer.Write (reader.ReadInt32 ()); // File length minus first 8 bytes of RIFF description - - if (CopyChunk (reader, writer) != "WAVE") - throw new Exception ("Invalid file format"); - - if (CopyChunk (reader, writer) != "fmt ") - throw new Exception ("Invalid file format"); - - int len = reader.ReadInt32 (); - if (len < 16) { // bad format chunk length - throw new Exception ("Invalid file format"); - } else { - writer.Write (len); - } - - m_Format = new WaveFormat (22050, 16, 2); // initialize to any format - m_Format.wFormatTag = reader.ReadInt16 (); - m_Format.nChannels = reader.ReadInt16 (); - m_Format.nSamplesPerSec = reader.ReadInt32 (); - m_Format.nAvgBytesPerSec = reader.ReadInt32 (); - m_Format.nBlockAlign = reader.ReadInt16 (); - m_Format.wBitsPerSample = reader.ReadInt16 (); - - //copy format information - writer.Write (m_Format.wFormatTag); - writer.Write (m_Format.nChannels); - writer.Write (m_Format.nSamplesPerSec); - writer.Write (m_Format.nAvgBytesPerSec); - writer.Write (m_Format.nBlockAlign); - writer.Write (m_Format.wBitsPerSample); - - // advance in the stream to skip the wave format block - len -= 16; // minimum format size - writer.Write (reader.ReadBytes (len)); - len = 0; - /*while (len > 0) - { - reader.ReadByte(); - len--; - }*/ - - // assume the data chunk is aligned - while (m_Stream.Position < m_Stream.Length && CopyChunk (reader, writer) != "data") - ; - - if (m_Stream.Position >= m_Stream.Length) - throw new Exception ("Invalid file format"); - - m_Length = reader.ReadInt32 (); - writer.Write (m_Length); - - m_DataPos = m_Stream.Position; - Position = 0; - } - - /// Write a new header - public static Stream CreateStream (Stream waveData, WaveFormat format) { - MemoryStream stream = new MemoryStream (); - BinaryWriter writer = new BinaryWriter (stream); - - writer.Write (System.Text.Encoding.ASCII.GetBytes ("RIFF".ToCharArray ())); - - writer.Write ((Int32) (waveData.Length + 36)); //File length minus first 8 bytes of RIFF description - - writer.Write (System.Text.Encoding.ASCII.GetBytes ("WAVEfmt ".ToCharArray ())); - - writer.Write ((Int32) 16); //length of following chunk: 16 - - writer.Write ((Int16) format.wFormatTag); - writer.Write ((Int16) format.nChannels); - writer.Write ((Int32) format.nSamplesPerSec); - writer.Write ((Int32) format.nAvgBytesPerSec); - writer.Write ((Int16) format.nBlockAlign); - writer.Write ((Int16) format.wBitsPerSample); - - writer.Write (System.Text.Encoding.ASCII.GetBytes ("data".ToCharArray ())); - - writer.Write ((Int32) waveData.Length); - - waveData.Seek (0, SeekOrigin.Begin); - byte[] b = new byte[waveData.Length]; - waveData.Read (b, 0, (int) waveData.Length); - writer.Write (b); - - writer.Seek (0, SeekOrigin.Begin); - return stream; - } - - public WaveStream (Stream sourceStream, Stream destinationStream) { - m_Stream = sourceStream; - CopyHeader (destinationStream); - } - - public WaveStream (Stream sourceStream) { - m_Stream = sourceStream; - ReadHeader (); - } - - ~WaveStream () { - Dispose (); - } - - public new void Dispose () { - base.Dispose (); - GC.SuppressFinalize (this); - } - - public override bool CanRead { - get { return true; } - } - public override bool CanSeek { - get { return true; } - } - public override bool CanWrite { - get { return false; } - } - public override long Length { - get { return m_Length; } - } - - /// Length of the data (in samples) - public long CountSamples { - get { return (long) ((m_Length - m_DataPos) / (m_Format.wBitsPerSample / 8)); } - } - - public override long Position { - get { return m_Stream.Position - m_DataPos; } - set { Seek (value, SeekOrigin.Begin); } - } - public override void Flush () { } - public override void SetLength (long len) { - throw new InvalidOperationException (); - } - public override long Seek (long pos, SeekOrigin o) { - switch (o) { - case SeekOrigin.Begin: - m_Stream.Position = pos + m_DataPos; - break; - case SeekOrigin.Current: - m_Stream.Seek (pos, SeekOrigin.Current); - break; - case SeekOrigin.End: - m_Stream.Position = m_DataPos + m_Length - pos; - break; - } - return this.Position; - } - - public override int Read (byte[] buf, int ofs, int count) { - int toread = (int) Math.Min (count, m_Length - Position); - return m_Stream.Read (buf, ofs, toread); - } - - /// Read - Changed to Copy - /// Buffer to receive the data - /// Offset - /// Count of bytes to read - /// Where to copy the buffer - /// Count of bytes actually read - public int Copy (byte[] buf, int ofs, int count, Stream destination) { - int toread = (int) Math.Min (count, m_Length - Position); - int read = m_Stream.Read (buf, ofs, toread); - destination.Write (buf, ofs, read); - - if (m_Stream.Position != destination.Position) { - Console.WriteLine (); - } - - return read; - } - - public override void Write (byte[] buf, int ofs, int count) { - throw new InvalidOperationException (); - } - } +using System; +using System.IO; + +namespace StegoPrint { + public class WaveStream : Stream, IDisposable { + private Stream m_Stream; + private long m_DataPos; + private int m_Length; + + private WaveFormat m_Format; + + public WaveFormat Format { + get { return m_Format; } + } + + private string ReadChunk (BinaryReader reader) { + byte[] ch = new byte[4]; + reader.Read (ch, 0, ch.Length); + return System.Text.Encoding.ASCII.GetString (ch); + } + + private void ReadHeader () { + BinaryReader Reader = new BinaryReader (m_Stream); + if (ReadChunk (Reader) != "RIFF") + throw new Exception ("Invalid file format"); + + Reader.ReadInt32 (); // File length minus first 8 bytes of RIFF description, we don't use it + + if (ReadChunk (Reader) != "WAVE") + throw new Exception ("Invalid file format"); + + if (ReadChunk (Reader) != "fmt ") + throw new Exception ("Invalid file format"); + + int len = Reader.ReadInt32 (); + if (len < 16) // bad format chunk length + throw new Exception ("Invalid file format"); + + m_Format = new WaveFormat (22050, 16, 2); // initialize to any format + m_Format.wFormatTag = Reader.ReadInt16 (); + m_Format.nChannels = Reader.ReadInt16 (); + m_Format.nSamplesPerSec = Reader.ReadInt32 (); + m_Format.nAvgBytesPerSec = Reader.ReadInt32 (); + m_Format.nBlockAlign = Reader.ReadInt16 (); + m_Format.wBitsPerSample = Reader.ReadInt16 (); + + // advance in the stream to skip the wave format block + len -= 16; // minimum format size + while (len > 0) { + Reader.ReadByte (); + len--; + } + + // assume the data chunk is aligned + while (m_Stream.Position < m_Stream.Length && ReadChunk (Reader) != "data") + ; + + if (m_Stream.Position >= m_Stream.Length) + throw new Exception ("Invalid file format"); + + m_Length = Reader.ReadInt32 (); + m_DataPos = m_Stream.Position; + + Position = 0; + } + + /// ReadChunk(reader) - Changed to CopyChunk(reader, writer) + /// source stream + /// four characters + private string CopyChunk (BinaryReader reader, BinaryWriter writer) { + byte[] ch = new byte[4]; + reader.Read (ch, 0, ch.Length); + + //copy the chunk + writer.Write (ch); + + return System.Text.Encoding.ASCII.GetString (ch); + } + + /// ReadHeader() - Changed to CopyHeader(destination) + private void CopyHeader (Stream destinationStream) { + BinaryReader reader = new BinaryReader (m_Stream); + BinaryWriter writer = new BinaryWriter (destinationStream); + + if (CopyChunk (reader, writer) != "RIFF") + throw new Exception ("Invalid file format"); + + writer.Write (reader.ReadInt32 ()); // File length minus first 8 bytes of RIFF description + + if (CopyChunk (reader, writer) != "WAVE") + throw new Exception ("Invalid file format"); + + if (CopyChunk (reader, writer) != "fmt ") + throw new Exception ("Invalid file format"); + + int len = reader.ReadInt32 (); + if (len < 16) { // bad format chunk length + throw new Exception ("Invalid file format"); + } else { + writer.Write (len); + } + + m_Format = new WaveFormat (22050, 16, 2); // initialize to any format + m_Format.wFormatTag = reader.ReadInt16 (); + m_Format.nChannels = reader.ReadInt16 (); + m_Format.nSamplesPerSec = reader.ReadInt32 (); + m_Format.nAvgBytesPerSec = reader.ReadInt32 (); + m_Format.nBlockAlign = reader.ReadInt16 (); + m_Format.wBitsPerSample = reader.ReadInt16 (); + + //copy format information + writer.Write (m_Format.wFormatTag); + writer.Write (m_Format.nChannels); + writer.Write (m_Format.nSamplesPerSec); + writer.Write (m_Format.nAvgBytesPerSec); + writer.Write (m_Format.nBlockAlign); + writer.Write (m_Format.wBitsPerSample); + + // advance in the stream to skip the wave format block + len -= 16; // minimum format size + writer.Write (reader.ReadBytes (len)); + len = 0; + /*while (len > 0) + { + reader.ReadByte(); + len--; + }*/ + + // assume the data chunk is aligned + while (m_Stream.Position < m_Stream.Length && CopyChunk (reader, writer) != "data") + ; + + if (m_Stream.Position >= m_Stream.Length) + throw new Exception ("Invalid file format"); + + m_Length = reader.ReadInt32 (); + writer.Write (m_Length); + + m_DataPos = m_Stream.Position; + Position = 0; + } + + /// Write a new header + public static Stream CreateStream (Stream waveData, WaveFormat format) { + MemoryStream stream = new MemoryStream (); + BinaryWriter writer = new BinaryWriter (stream); + + writer.Write (System.Text.Encoding.ASCII.GetBytes ("RIFF".ToCharArray ())); + + writer.Write ((Int32) (waveData.Length + 36)); //File length minus first 8 bytes of RIFF description + + writer.Write (System.Text.Encoding.ASCII.GetBytes ("WAVEfmt ".ToCharArray ())); + + writer.Write ((Int32) 16); //length of following chunk: 16 + + writer.Write ((Int16) format.wFormatTag); + writer.Write ((Int16) format.nChannels); + writer.Write ((Int32) format.nSamplesPerSec); + writer.Write ((Int32) format.nAvgBytesPerSec); + writer.Write ((Int16) format.nBlockAlign); + writer.Write ((Int16) format.wBitsPerSample); + + writer.Write (System.Text.Encoding.ASCII.GetBytes ("data".ToCharArray ())); + + writer.Write ((Int32) waveData.Length); + + waveData.Seek (0, SeekOrigin.Begin); + byte[] b = new byte[waveData.Length]; + waveData.Read (b, 0, (int) waveData.Length); + writer.Write (b); + + writer.Seek (0, SeekOrigin.Begin); + return stream; + } + + public WaveStream (Stream sourceStream, Stream destinationStream) { + m_Stream = sourceStream; + CopyHeader (destinationStream); + } + + public WaveStream (Stream sourceStream) { + m_Stream = sourceStream; + ReadHeader (); + } + + ~WaveStream () { + Dispose (); + } + + public new void Dispose () { + base.Dispose (); + GC.SuppressFinalize (this); + } + + public override bool CanRead { + get { return true; } + } + public override bool CanSeek { + get { return true; } + } + public override bool CanWrite { + get { return false; } + } + public override long Length { + get { return m_Length; } + } + + /// Length of the data (in samples) + public long CountSamples { + get { return (long) ((m_Length - m_DataPos) / (m_Format.wBitsPerSample / 8)); } + } + + public override long Position { + get { return m_Stream.Position - m_DataPos; } + set { Seek (value, SeekOrigin.Begin); } + } + public override void Flush () { } + public override void SetLength (long len) { + throw new InvalidOperationException (); + } + public override long Seek (long pos, SeekOrigin o) { + switch (o) { + case SeekOrigin.Begin: + m_Stream.Position = pos + m_DataPos; + break; + case SeekOrigin.Current: + m_Stream.Seek (pos, SeekOrigin.Current); + break; + case SeekOrigin.End: + m_Stream.Position = m_DataPos + m_Length - pos; + break; + } + return this.Position; + } + + public override int Read (byte[] buf, int ofs, int count) { + int toread = (int) Math.Min (count, m_Length - Position); + return m_Stream.Read (buf, ofs, toread); + } + + /// Read - Changed to Copy + /// Buffer to receive the data + /// Offset + /// Count of bytes to read + /// Where to copy the buffer + /// Count of bytes actually read + public int Copy (byte[] buf, int ofs, int count, Stream destination) { + int toread = (int) Math.Min (count, m_Length - Position); + int read = m_Stream.Read (buf, ofs, toread); + destination.Write (buf, ofs, read); + + if (m_Stream.Position != destination.Position) { + Console.WriteLine (); + } + + return read; + } + + public override void Write (byte[] buf, int ofs, int count) { + throw new InvalidOperationException (); + } + } } \ No newline at end of file diff --git a/WaveUtility.cs b/WaveUtility.cs index 0b0e31d..5ed31d2 100644 --- a/WaveUtility.cs +++ b/WaveUtility.cs @@ -1,203 +1,203 @@ -using System.IO; - -namespace StegoPrint { - public class WaveUtility { - /// - /// The read-only stream. - /// Clean wave for hiding, - /// Carrier wave for extracting - /// - private WaveStream sourceStream; - - /// Stream to receive the edited carrier wave - private Stream destinationStream; - - /// bits per sample / 8 - private int bytesPerSample; - - /// Initializes a new WaveUtility for hiding a message - /// Clean wave - /// - /// Header of the clean wave - /// This stream will receive the complete carrier wave - /// - public WaveUtility (WaveStream sourceStream, Stream destinationStream) : this (sourceStream) { - this.destinationStream = destinationStream; - } - - /// Initializes a new WaveUtility for extracting a message - /// Carrier wave - public WaveUtility (WaveStream sourceStream) { - this.sourceStream = sourceStream; - this.bytesPerSample = sourceStream.Format.wBitsPerSample / 8; - } - - /// - /// Hide [messageStream] in [sourceStream], - /// write the result to [destinationStream] - /// - /// The message to hide - /// - /// A key stream that specifies how many samples shall be - /// left clean between two changed samples - /// - public void Hide (Stream messageStream, Stream keyStream) { - - byte[] waveBuffer = new byte[bytesPerSample]; - byte message, bit, waveByte; - int messageBuffer; //receives the next byte of the message or -1 - int keyByte; //distance of the next carrier sample - - while ((messageBuffer = messageStream.ReadByte ()) >= 0) { - //read one byte of the message stream - message = (byte) messageBuffer; - - //for each bit in message - for (int bitIndex = 0; bitIndex < 8; bitIndex++) { - - //read a byte from the key - keyByte = GetKeyValue (keyStream); - - //skip a couple of samples - for (int n = 0; n < keyByte - 1; n++) { - //copy one sample from the clean stream to the carrier stream - sourceStream.Copy (waveBuffer, 0, waveBuffer.Length, destinationStream); - } - - //read one sample from the wave stream - sourceStream.Read (waveBuffer, 0, waveBuffer.Length); - waveByte = waveBuffer[bytesPerSample - 1]; - - //get the next bit from the current message byte... - bit = (byte) (((message & (byte) (1< 0) ? 1 : 0); - - //...place it in the last bit of the sample - if ((bit == 1) && ((waveByte % 2) == 0)) { - waveByte += 1; - } else if ((bit == 0) && ((waveByte % 2) == 1)) { - waveByte -= 1; - } - - waveBuffer[bytesPerSample - 1] = waveByte; - - //write the result to destinationStream - destinationStream.Write (waveBuffer, 0, bytesPerSample); - } - } - - //copy the rest of the wave without changes - waveBuffer = new byte[sourceStream.Length - sourceStream.Position]; - sourceStream.Read (waveBuffer, 0, waveBuffer.Length); - destinationStream.Write (waveBuffer, 0, waveBuffer.Length); - } - - /// Extract a message from [sourceStream] into [messageStream] - /// Empty stream to receive the extracted message - /// - /// A key stream that specifies how many samples shall be - /// skipped between two carrier samples - /// - public void Extract (Stream messageStream, Stream keyStream) { - - byte[] waveBuffer = new byte[bytesPerSample]; - byte message, bit, waveByte; - int messageLength = 0; //expected length of the message - int keyByte; //distance of the next carrier sample - - while ((messageLength == 0 || messageStream.Length < messageLength)) { - //clear the message-byte - message = 0; - - //for each bit in message - for (int bitIndex = 0; bitIndex < 8; bitIndex++) { - - //read a byte from the key - keyByte = GetKeyValue (keyStream); - - //skip a couple of samples - for (int n = 0; n < keyByte - 1; n++) { - //read one sample from the wave stream - sourceStream.Read (waveBuffer, 0, waveBuffer.Length); - } - sourceStream.Read (waveBuffer, 0, waveBuffer.Length); - waveByte = waveBuffer[bytesPerSample - 1]; - - //get the last bit of the sample... - bit = (byte) (((waveByte % 2) == 0) ? 0 : 1); - - //...write it into the message-byte - message += (byte) (bit << bitIndex); - } - - //add the re-constructed byte to the message - messageStream.WriteByte (message); - - if (messageLength == 0 && messageStream.Length == 4) { - //first 4 bytes contain the message's length - messageStream.Seek (0, SeekOrigin.Begin); - messageLength = new BinaryReader (messageStream).ReadInt32 (); - messageStream.Seek (0, SeekOrigin.Begin); - messageStream.SetLength (0); - } - } - - } - - /// Counts the samples that will be skipped using the specified key stream - /// Key stream - /// Length of the message - /// Minimum length (in samples) of an audio file - public static long CheckKeyForMessage (Stream keyStream, long messageLength) { - long messageLengthBits = messageLength * 8; - long countRequiredSamples = 0; - - if (messageLengthBits > keyStream.Length) { - long keyLength = keyStream.Length; - - // read existing key - byte[] keyBytes = new byte[keyLength]; - keyStream.Read (keyBytes, 0, keyBytes.Length); - - // Every byte stands for the distance between two useable samples. - // The sum of those distances is the required count of samples. - countRequiredSamples = SumKeyArray (keyBytes); - - // The key must be repeated, until every bit of the message has a key byte. - double countKeyCopies = messageLengthBits / keyLength; - countRequiredSamples = (long) (countRequiredSamples * countKeyCopies); - } else { - byte[] keyBytes = new byte[messageLengthBits]; - keyStream.Read (keyBytes, 0, keyBytes.Length); - countRequiredSamples = SumKeyArray (keyBytes); - } - - keyStream.Seek (0, SeekOrigin.Begin); - return countRequiredSamples; - } - - private static long SumKeyArray (byte[] values) { - long sum = 0; - foreach (int value in values) { // '0' causes a distance of one sample, - // every other key causes a distance of its exact value. - sum += (value == 0) ? 1 : value; - } - return sum; - } - - /// - /// Read the next byte of the key stream. - /// Reset the stream if it is too short. - /// - /// The key stream - /// The next key byte - private static byte GetKeyValue (Stream keyStream) { - int keyValue; - if ((keyValue = keyStream.ReadByte ()) < 0) { - keyStream.Seek (0, SeekOrigin.Begin); - keyValue = keyStream.ReadByte (); - if (keyValue == 0) { keyValue = 1; } - } - return (byte) keyValue; - } - } +using System.IO; + +namespace StegoPrint { + public class WaveUtility { + /// + /// The read-only stream. + /// Clean wave for hiding, + /// Carrier wave for extracting + /// + private WaveStream sourceStream; + + /// Stream to receive the edited carrier wave + private Stream destinationStream; + + /// bits per sample / 8 + private int bytesPerSample; + + /// Initializes a new WaveUtility for hiding a message + /// Clean wave + /// + /// Header of the clean wave + /// This stream will receive the complete carrier wave + /// + public WaveUtility (WaveStream sourceStream, Stream destinationStream) : this (sourceStream) { + this.destinationStream = destinationStream; + } + + /// Initializes a new WaveUtility for extracting a message + /// Carrier wave + public WaveUtility (WaveStream sourceStream) { + this.sourceStream = sourceStream; + this.bytesPerSample = sourceStream.Format.wBitsPerSample / 8; + } + + /// + /// Hide [messageStream] in [sourceStream], + /// write the result to [destinationStream] + /// + /// The message to hide + /// + /// A key stream that specifies how many samples shall be + /// left clean between two changed samples + /// + public void Hide (Stream messageStream, Stream keyStream) { + + byte[] waveBuffer = new byte[bytesPerSample]; + byte message, bit, waveByte; + int messageBuffer; //receives the next byte of the message or -1 + int keyByte; //distance of the next carrier sample + + while ((messageBuffer = messageStream.ReadByte ()) >= 0) { + //read one byte of the message stream + message = (byte) messageBuffer; + + //for each bit in message + for (int bitIndex = 0; bitIndex < 8; bitIndex++) { + + //read a byte from the key + keyByte = GetKeyValue (keyStream); + + //skip a couple of samples + for (int n = 0; n < keyByte - 1; n++) { + //copy one sample from the clean stream to the carrier stream + sourceStream.Copy (waveBuffer, 0, waveBuffer.Length, destinationStream); + } + + //read one sample from the wave stream + sourceStream.Read (waveBuffer, 0, waveBuffer.Length); + waveByte = waveBuffer[bytesPerSample - 1]; + + //get the next bit from the current message byte... + bit = (byte) (((message & (byte) (1< 0) ? 1 : 0); + + //...place it in the last bit of the sample + if ((bit == 1) && ((waveByte % 2) == 0)) { + waveByte += 1; + } else if ((bit == 0) && ((waveByte % 2) == 1)) { + waveByte -= 1; + } + + waveBuffer[bytesPerSample - 1] = waveByte; + + //write the result to destinationStream + destinationStream.Write (waveBuffer, 0, bytesPerSample); + } + } + + //copy the rest of the wave without changes + waveBuffer = new byte[sourceStream.Length - sourceStream.Position]; + sourceStream.Read (waveBuffer, 0, waveBuffer.Length); + destinationStream.Write (waveBuffer, 0, waveBuffer.Length); + } + + /// Extract a message from [sourceStream] into [messageStream] + /// Empty stream to receive the extracted message + /// + /// A key stream that specifies how many samples shall be + /// skipped between two carrier samples + /// + public void Extract (Stream messageStream, Stream keyStream) { + + byte[] waveBuffer = new byte[bytesPerSample]; + byte message, bit, waveByte; + int messageLength = 0; //expected length of the message + int keyByte; //distance of the next carrier sample + + while ((messageLength == 0 || messageStream.Length < messageLength)) { + //clear the message-byte + message = 0; + + //for each bit in message + for (int bitIndex = 0; bitIndex < 8; bitIndex++) { + + //read a byte from the key + keyByte = GetKeyValue (keyStream); + + //skip a couple of samples + for (int n = 0; n < keyByte - 1; n++) { + //read one sample from the wave stream + sourceStream.Read (waveBuffer, 0, waveBuffer.Length); + } + sourceStream.Read (waveBuffer, 0, waveBuffer.Length); + waveByte = waveBuffer[bytesPerSample - 1]; + + //get the last bit of the sample... + bit = (byte) (((waveByte % 2) == 0) ? 0 : 1); + + //...write it into the message-byte + message += (byte) (bit << bitIndex); + } + + //add the re-constructed byte to the message + messageStream.WriteByte (message); + + if (messageLength == 0 && messageStream.Length == 4) { + //first 4 bytes contain the message's length + messageStream.Seek (0, SeekOrigin.Begin); + messageLength = new BinaryReader (messageStream).ReadInt32 (); + messageStream.Seek (0, SeekOrigin.Begin); + messageStream.SetLength (0); + } + } + + } + + /// Counts the samples that will be skipped using the specified key stream + /// Key stream + /// Length of the message + /// Minimum length (in samples) of an audio file + public static long CheckKeyForMessage (Stream keyStream, long messageLength) { + long messageLengthBits = messageLength * 8; + long countRequiredSamples = 0; + + if (messageLengthBits > keyStream.Length) { + long keyLength = keyStream.Length; + + // read existing key + byte[] keyBytes = new byte[keyLength]; + keyStream.Read (keyBytes, 0, keyBytes.Length); + + // Every byte stands for the distance between two useable samples. + // The sum of those distances is the required count of samples. + countRequiredSamples = SumKeyArray (keyBytes); + + // The key must be repeated, until every bit of the message has a key byte. + double countKeyCopies = messageLengthBits / keyLength; + countRequiredSamples = (long) (countRequiredSamples * countKeyCopies); + } else { + byte[] keyBytes = new byte[messageLengthBits]; + keyStream.Read (keyBytes, 0, keyBytes.Length); + countRequiredSamples = SumKeyArray (keyBytes); + } + + keyStream.Seek (0, SeekOrigin.Begin); + return countRequiredSamples; + } + + private static long SumKeyArray (byte[] values) { + long sum = 0; + foreach (int value in values) { // '0' causes a distance of one sample, + // every other key causes a distance of its exact value. + sum += (value == 0) ? 1 : value; + } + return sum; + } + + /// + /// Read the next byte of the key stream. + /// Reset the stream if it is too short. + /// + /// The key stream + /// The next key byte + private static byte GetKeyValue (Stream keyStream) { + int keyValue; + if ((keyValue = keyStream.ReadByte ()) < 0) { + keyStream.Seek (0, SeekOrigin.Begin); + keyValue = keyStream.ReadByte (); + if (keyValue == 0) { keyValue = 1; } + } + return (byte) keyValue; + } + } } \ No newline at end of file diff --git a/commands.txt b/commands.txt index c8a110b..e513082 100644 --- a/commands.txt +++ b/commands.txt @@ -1,2 +1,2 @@ -add -m "ArgleBargle" -k "C:\dev\working\stegano\mylib\keyfile.txt" -i "C:\dev\working\stegano\mylib\candidate.wav" -o "C:\dev\working\stegano\mylib\out.wav" +add -m "ArgleBargle" -k "C:\dev\working\stegano\mylib\keyfile.txt" -i "C:\dev\working\stegano\mylib\candidate.wav" -o "C:\dev\working\stegano\mylib\out.wav" extract -k "C:\dev\working\stegano\mylib\keyfile.txt" -i "C:\dev\working\stegano\mylib\out.wav" \ No newline at end of file diff --git a/stegoprint.csproj b/stegoprint.csproj index a296963..44d2032 100644 --- a/stegoprint.csproj +++ b/stegoprint.csproj @@ -1,10 +1,10 @@ - - - Exe - netcoreapp1.1 - - - - - + + + Exe + netcoreapp1.1 + + + + + \ No newline at end of file