Plagiarism today III

Things like this drive me nuts.

Even if you take someone else’s work, how hard is it to include a link? A name? Any sort of mention of the original author(s)? I don’t have a beef with this when someone does it with my stuff because most of what I post here is in the Public Domain anyway. But most others do expect some sort of credit.

I frequent a website called Code Project, which programmers and those in the tech industry are quite familiar with. It’s a pretty big site with many, many articles and several orders of magnitude more visitors. Countless members comment, critique and contribute (and occasionally spam) the message boards and article comments all the time.

So then one has to wonder, why would someone risk public ridicule and disparagement by blatantly copying someone else’s work and posting it on this very popular site. I would have missed it too if I hadn’t gone back to an older newsletter and seen this article listed.

Enter Mr. Ram Balak Sharma

On his Code Project profile, he lists his occupation as a .Net Architect. What does that mean anyway? Does it mean programmer? Developer? Manager? Self-titled guru? But I digress…

LOL "passion"!

Mr. Sharma’s credentials include being a “Microsoft Certified Application Developer”. Apparently this is a byword term for not being above blatantly copying posts from other sites and presenting them as your own. His article “Security in ASP.NET MVC by using Anti-Forgery Token” is a complete ripoff of “Anti-Forgery Request Recipes For ASP.NET MVC And AJAX” by Dixin a year earlier. Note : No where on Sharma’s article does he list any other source.

Also note, unlike Mr. Sharma, Dixin doesn’t call himself an “Architect”. He’s just “a UI designer and knows a little bit about programming”.

Proving once again that the magnitude of someone’s espoused prowess is usually inversely proportional to true skill.

TL;DR

Here are both articles compared side by side.

Copy pasta!

I was browsing his site and thought if he’s brazen enough to do this on Code Project, surely he’s done it on his own site. Sure enough, “How to convert List to Datatable in C#” is a rip off of AroLibraries IEnumerableExt class, which is MIT licensed, but good luck finding a single credit on his site. And I don’t see his name listed anywhere on the project “People” section.

If someone from Code Project comes across this post, please send this joker a message and ban his ass.

In case Mr. Sharma or other plagiarists come to wonder how they always, always, ALWAYS end up being outed, I would like to leave you with this helpful message…

...And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers.

Update

Some more nuggets…

Original : “jQuery DataTables and ASP.NET MVC integration
Copy: “JQuery Table in Asp.net MVC on dropdown selection changed
Excerpts taken without credit, but at least he used different images and modify the wording.

Original : “Improving SQL Server Performance
Copy : “How optimized sql stored procdure Performance?
Dude, MSDN?! Really?

Advertisements

Font reference revamp

A while ago, I created a single small HTML page with a bunch of easy to read fonts for web publishing. This afternoon, I got some free time so I did a rewrite of the whole thing as a web application.

Font reference

The biggest problem with the old version is that every font was displayed all on one page which would have made expanding the list more cumbersome. Also, a lot of people had started to hotlink to the old font images (not just these, but a lot of other images on my server which was starting to affect my bandwith), so I’ve instead added permalinks to each font and the letter index as an alternative.

There’s no server-side scripting and the whole thing is basically JavaScript courtesy of jQuery. You can take a look at the old version at the end of this post.

Sourcecode of “fref.js” (please be advised that I may change the actual running version at any time and this is only current as of this post).

$(function() {
	var pIndex, pFont, fCanvas;
	var ta = [];

	Init();

	function Init() {

		fCanvas = $("#fonts");

		// Titles list
		var t = $('<ul />');

		// Unique index
		for(var i = 0; i < fonts.length; i++) {
			var f = fonts[i];
			var ni = true;

			for(var j = 0; j < ta.length; j++) {
				if(ta[j] == f[0])
					ni = false;
			}

			if(ni)
				ta[ta.length] = f[0];
		}

		for(var i = 0; i < ta.length; i++) {
			t.append('<li><a href="#'+ ta[i] +'">'+ ta[i] +'</a></li>');
			var s = $('<div id="'+ ta[i] +'" />');
			var u = $('<ul />');

			for(var j = 0; j < fonts.length; j++) {
				if(fonts[j][0] == ta[i]) {
					var f = fonts[j];
					u.append(felement(f));
				}
			}

			s.append('<h2>“'+ ta[i] +'” Fonts '+
				'<span><a href="http://eksith.com/experiments/fontreference/?i='+
				ta[i] +'">Permalink</a></span></h2>');
			s.append(u);
			fCanvas.append(s);
		}

		fCanvas.prepend(t);
		fCanvas.tabs({
			create: function(e, ui) {
				searchValidate();
				findFont(pIndex, pFont);
			}
		});
	}

	function searchValidate() {
		if(window.location.search.indexOf("?i=") > -1) {

			var pn = $.trim(window.location.search)
					.replace(/\s/g, "");

			var s = pn.indexOf("?i=") + 3;
			var e = pn.indexOf("&f=");

			if(e > s)
				pIndex = pn.substr(s, e - 3);
			else
				pIndex = pn.substr(s);

			pIndex = (!pIndex)? "0-9" : pIndex;

			if((e > 0) && (e + 3 < pn.length))
				pFont = pn.substr(e + 3, pn.length);
		}

		if(ta.indexOf(pIndex) < 0)
			pIndex = ta[0];
	}

	function findFont(i, f) {
		fCanvas.tabs("option", "selected", ta.indexOf(i));
		var fnt = $('#' + f);

		if(fnt.length > 0) {
			$('html,body').animate({ scrollTop: fnt.offset().top - 10 }, 1000);
			fnt.effect("highlight", {}, 5000);
		}
	}

	function felement(f) {
		var a = f[2].replace(".png", ""); // Image without .png extension becomes font ID
		var st = '<li id="'+ a +'">' +
			'<ul><li>'+ f[1] +'</li>';

		// Additional attributes
		for(var i = 0; i < f[3].length; i++)
			st += '<li>'+ f[3][i] +'</li>';

		// Permalink
		st += '<li><a href="http://eksith.com/experiments/fontreference/?i='+ f[0] +'&f='+ a +'">Permalink</a></li></ul>' +
			'<img src="fonts/'+ f[2] +'" alt="'+ a +'" /><hr /></li>';

		return st;
	}
});

The data is stored in a single “data.js” file as an array. I may change this to JSON in the future.

// Convention : index, title, font image, description array (new item per line)
var fonts = [
	["A", "Am Sans light", "am-sans-light.png", ["20pt", "Sans-serif"]],
	["A", "Andalé Mono", "andale-mono.png", ["20pt", "Monospace", "Sans-serif"]],
	["A", "Arial", "arial.png", ["20pt", "Sans-serif"]],
	["A", "Avenir - Book <strong>Commercial</strong>", "avenir-book.png", ["20pt", "Sans-serif"]],
	["B", "Bitstream Vera Sans (Roman)", "bitstream-vera-sans-roman.png", ["20pt", "Roman", "Sans-serif"]],
	["B", "Bitstream Vera Sans Mono (Roman)", "bitstream-vera-sans-m-roman.png", ["20pt", "Roman", "Monospace", "Sans-serif"]],
	["B", "Book Antiqua", "book-antiqua.png", ["20pt"]],
	["B", "Bank Gothic Lt BT", "bank-gothic-light-bt.png", ["20pt", "Small caps", "Sans-serif"]],
	["C", "Calibri", "calibri.png", ["20pt", "Sans-serif"]],
	["C", "Candara", "candara.png", ["20pt", "Sans-serif"]],
	["C", "Century Gothic", "century-gothic.png", ["20pt", "Modern, Geometric, Bold", "Sans-serif"]],
	["C", "Consolas", "consolas.png", ["20pt", "Sans-serif"]],
	["C", "Courier Std", "courier-std.png", ["20pt", "Monospace"]],
	["D", "Dutch801 Rm BT <strong>Commercial</strong>", "dutch801-rm-bt.png", ["20pt"]],
	["E", "Eurostile", "consolas.png", ["20pt", "Modern", "Sans-serif"]],
	["F", "Florencesans", "florencesans.png", ["20pt", "Sans-serif"]],
	["F", "Franklin Gothic Book", "franklin-gothic-book.png", ["20pt", "Modern, Geometric", "Sans-serif"]],
	["G", "Georgia", "georgia.png", ["20pt"]],
	["G", "Gill Sans MT", "gill-sans-mt.png", ["20pt",  "Sans-serif"]],
	["G", "Gotham Light <strong>Commercial</strong>", "gotham-light.png", ["20pt", "Mdoern, Geometric", "Light", "Sans-serif"]],
	["H", "Humanist521 BT (Roman) <strong>Commercial</strong>", "humanist521-bt-roman.png", ["20pt", "Roman", "Sans-serif"]],
	["L", "Lucida Sans", "lucida-sans.png", ["20pt", "Sans-serif"]],
	["L", "Lucida Unicode", "lucida-unicode.png", ["20pt", "Unicode", "Sans-serif"]],
	["M", "Microsoft Sans Serif <strong>*</strong>", "microsoft-sans-serif.png", ["<strong>* Not the same as MS Sans Serif</strong>", "20pt", "Sans-Serif"]],
	["M", "Monaco", "monaco.png", ["20pt", "Modern, Condensed", "Sans-serif"]],
	["M", "MS Sans Serif <strong>*</strong>", "ms-sans-serif.png", ["<strong>* Not the same as Microsoft Sans Serif</strong>", "20pt", "Sans-serif"]],
	["M", "Myriad", "myriad.png", ["20pt", "Sans-serif"]],
	["T", "Tahoma", "tahoma.png", ["20pt", "Sans-serif"]],
	["T", "Trebuchet MS", "trebuchet-ms.png", ["20pt", "Sans-serif"]],
	["U", "Univers <strong>Commercial</strong>", "univers.png", ["20pt", "Sans-serif"]],
	["V", "Verdana", "verdana.png", ["20pt", "Sans-serif"]]
];

It still leaves a lot of work to be done; most obviously, the reference phrase “The quick brown fox jumps over the dirty dog” is wrong. It should be “The quick brown fox jumps over the lazy dog”. Also the list is pretty small and limited only to a handful of fonts I’ve used. I’m planning to add a full collection of possibly every font I’ve used in the past (even perhaps the stylish and not-so-easy-to-read variety)

Old font reference index

I’m thinking of writing a very basic discussion board in ASP.Net MVC and I may use the new design in that. The CSS is very minimal and most of the extra jQuery UI styles are from the customized Smoothness theme.

Brainfart Saturday

I need to switch coffee brands…

Yesterday, for no apparent reason, I thought it may be a good idea to create a file transfer app that will asynchronously send files in slices(chunks) and still ensure the receiving party’s checksum will mach the sender’s. I was planning on adding public key security to the whole thing, but I can’t seem to get past step 1 without issues.

I tried testing splitting a file into slices and merging them immediately after and it seems to work just fine for small files.

Blob blob = FileUtils.GetBlob("C:\\Users\\Portable\\Downloads\\smalldoc.pdf");

FileUtils.SplitSlices(ref blob);

// Change the filename
blob.Path = "C:\\Users\\Portable\\Downloads\\smalldocCopy.pdf";
// Merge the slices back into one under the new filename
FileUtils.MergeSlices(ref blob);

The head-scratching starts when splitting and merging a large-ish file (50Mb+). The “Size on disk” identical to the original, but the “Size” is smaller than the original Size. Meaning it’s taking up the same disk allocation, but some bits got lost along the way. The funny thing is that if I then split the merged copy and merge it again into another copy, then this third copy is identical to the second. So original is still the odd one out.

I can’t seem to find the reason for this other than I’m missing something really obvious or this is a platform issue. I hope it’s the former because cursing at the latter feels… weird.

Here’s the “Slice” class where data would be stored and sent/received async.

public class Slice
{
	// Slice Id (Checksum / Currently not used)
	public string Id { get; set; }
	
	// File(Blob) Id (Checksum)
	public string SourceId { get; set; }

	// Blob location index
	public int Index { get; set; }

	// Slice byte length
	public int Size { get; set; }

	// Slice data
	public string Data { get; set; }

	public bool Complete { get; set; }

	public Slice()
	{
		Complete = false;
	}
}

And the “Blob” class that use the above slice(s)

public class Blob
{
	// File Id (Checksum)
	public string Id { get; set; }

	// Slice collection
	public SortedDictionary<int, Slice> Slices { get; set; }

	// Save path
	public string Path { get; set; }

	// File size
	public int Size { get; set; }

	// Assembled file size
	public int CompletedSize { get; set; }

	public Blob()
	{
		Slices = new SortedDictionary<int, Slice>();
		Size = 0;
		CompletedSize = 0;
	}
}

And of course, the uglier-than-sin FileUtils class (those with weak hearts, avert your eyes).

public static class FileUtils
{
	private static int _blockSize = 65536;

	public static void SplitSlices(ref Blob blob)
	{
		FileInfo info = new FileInfo(blob.Path);
		string source = info.FullName;
		string dir = info.DirectoryName;

		using (FileStream fs = new FileStream(source, FileMode.Open, FileAccess.Read))
		{
			foreach (KeyValuePair<int, Slice> kv in blob.Slices)
			{
				Slice slice = kv.Value;
				byte[] data = new byte[slice.Size];
				int read = 0;

				fs.Seek(slice.Index, SeekOrigin.Begin);
				if ((read = fs.Read(data, 0, slice.Size)) > 0)
				{
					WriteSlice(ref slice, data, dir);
				}
			}
		}
	}

	public static void WriteSlice(ref Slice slice, byte[] data, string dir)
	{
		string slicePath = SourceFromSlice(slice, dir);
		using (FileStream ofs =
			new FileStream(slicePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
		{
			ofs.Write(data, 0, slice.Size);
			slice.Complete = true;
		}
	}

	public static void MergeSlices(ref Blob blob)
	{
		FileInfo blobInfo = new FileInfo(blob.Path);
		string dir = blobInfo.DirectoryName;

		using (FileStream outfs =
			new FileStream(blobInfo.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
		{
			foreach (KeyValuePair<int, Slice> kv in blob.Slices)
			{
				Slice slice = kv.Value;
				if (slice.Complete)
				{
					byte[] bytes = ReadSlice(ref slice, dir, true);
					outfs.Seek(slice.Index, SeekOrigin.Begin);
					outfs.Write(bytes, 0, slice.Size);

					// Update the completed count
					blob.CompletedSize += slice.Size;
				}
			}
		}
	}

	public static byte[] ReadSlice(ref Slice slice, string dir, bool delAfterReading)
	{
		int read = 0;
		byte[] data = new byte[slice.Size];
		string slicePath = SourceFromSlice(slice, dir);

		using (FileStream ifs = new FileStream(slicePath, FileMode.Open, FileAccess.Read))
		{
			read = ifs.Read(data, 0, slice.Size);
		}

		if (delAfterReading)
			File.Delete(slicePath);

		return data;
	}

	public static void InitBlob(ref Blob blob)
	{
		int sliceCount = 0;
		int sliceSize;

		// Catch remaining byte length after splitting
		int remainder = (blob.Size > _blockSize)? (blob.Size % _blockSize) : 0;

		// If this is a big file that can be split...
		if (blob.Size > _blockSize)
		{
			sliceCount = blob.Size / _blockSize;
			sliceSize = blob.Size / sliceCount;
		}
		else // Slice size same as blob size and only one slice needed
		{
			sliceCount = 1;
			sliceSize = blob.Size;
		}

		for (int i = 0; i < sliceCount; i++)
		{
			Slice slice = new Slice();
			slice.SourceId = blob.Id;
			slice.Size = (i == 0) ? sliceSize + remainder : sliceSize;
			slice.Index = i * slice.Size;

			blob.Slices.Add(slice.Index, slice);
		}
	}

	public static Blob GetBlob(string source)
	{
		Blob blob = new Blob();
		FileInfo info = new FileInfo(source);

		blob.Id = FileId(source);
		blob.Size = LengthToInt(info.Length);
		blob.Path = info.FullName;
		blob.CompletedSize = LengthToInt(info.Length);

		InitBlob(ref blob);
		return blob;
	}

	public static string GetChecksum(string source, string mode = "md5", bool isFile = false)
	{
		byte[] bytes = { };
		Stream fs;

		if (isFile)
			fs = new BufferedStream(File.OpenRead(source), 120000);
		else
			fs = new MemoryStream(Encoding.UTF8.GetBytes(source));

		switch (mode.ToLower())
		{
			case "sha1":
				using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
					bytes = sha1.ComputeHash(fs);
				break;

			case "sha256":
				using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider())
					bytes = sha256.ComputeHash(fs);
				break;

			case "sha512":
				using (SHA512CryptoServiceProvider sha512 = new SHA512CryptoServiceProvider())
					bytes = sha512.ComputeHash(fs);
				break;

			case "md5":
			default:
				using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
					bytes = md5.ComputeHash(fs);
				break;
		}

		// Cleanup
		fs.Close();
		fs = null;

		return BitConverter
			.ToString(bytes)
			.Replace("-", "")
			.ToLower();
	}

	private static int LengthToInt(long length)
	{
		return (int)Math.Ceiling((double)length);
	}

	private static string FileId(string source)
	{
		return GetChecksum(new FileInfo(source).FullName, "sha256", true);
	}

	private static string SourceFromSlice(Slice slice, string dir)
	{
		return dir + "\\" + slice.SourceId + "_" + slice.Index + ".slice";
	}
}

Cryptographically secure One-time Pads

It’s the end of Christmas day… And I’ve got a splitting headache (because I don’t drink and had to watch everything). Luckily I’m not covered in someone else’s puke or urine, which is always nice.  No one drove into any trees (as far as I know), lost their pants or an eye.

Super…

Just finished checking my email and it seems a quite a few people were interested in my last post on the one-time pad and one frequent question was how to make it secure enough for truly private communication. First off, the JavaScript version is out if you want true security. Second, it’s best to implement something in a reusable class that can be used perhaps in a web application or client-side app. I chose an MVC web app in C# for this demonstration because my brain won’t let me stay up for much longer.

To make a large enough one-time pad that is both cryptographically secure and still computationally practical, we have to balance between how strong the algorithm is and how often it is iterated. In my original example, I opted to shuffle the character pool using the Fisher-Yates algorithm before a character is picked and each time, the pick was also random from the shuffled pool.

Considering JavaScript’s inherent weakness in that it must rely on the browser’s scripting engine for the psudorandom number, these were necessary improvements even with the added overhead. However, since modern browers do have optimized JS engines, this wasn’t a huge concren.

The problem is when we move toward much stronger cryptographic functions where computation starts to become non-trivial.

In the case of the RNGCryptoServiceProvider, the class provides a much stronger random number than the simple Random function. The output is spectrally white and is better suited for generating keys. The main point here is that it is cryptographically secure. I.E. It’s random enough to be used for proper encryption while still being a psudorandom number generator. The down side is that it is more computationally intensive than just plain Random.

The solution is to not shuffle the pool between character picks, but randomize between “segments”; the separated 6-8 character “words” in the pad. This strikes a good balance between randomness and speed.

Then, the issue comes down to how the pad is generated and presented to the user. Conventionally, this was in the form of plain text or as a downloadable file, however one of the requests I received was to make something that can do both. If the one-time pad can be saved as an image file, it can be sent via encrypted email to the recipient. The risk is that browsers store images and the like and the browser cache must be emptied after each generation. If a printer is used, it must also be cleared of its cache because some printers save a history of printed documents.

The following is a quick class that has both text and image generation. The GetImg function can be used to turn any sort of text into an image byte array, not just pad text.

/**
 * THIS 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.
 */

using System;
using System.Security;
using System.Security.Cryptography;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Text;

namespace OneTimePad
{
	public class PadModel
	{
		// Render settings
		FontFamily renderFont = FontFamily.GenericMonospace;
		FontStyle renderStyle = FontStyle.Bold;
		GraphicsUnit renderUnit = GraphicsUnit.Pixel;
		int renderSize = 10;

		// Creates formatted pages of keys
		public string RenderPad(int s, int l, string chars)
		{
			// Result
			StringBuilder sb = new StringBuilder();

			// First page
			int p = 1;

			for (int i = 0; i < l; i++)
			{
				// First page number
				if (p == 1 && i == 0)
					sb.Append("1.\n\n");

				// Generate segment
				sb.Append(GenerateRandomString(s, chars));

				// Page, number and segment separartion
				if (i % 63 == 62)
				{
					if (i + 1 < l)
					{
						p++;
						sb.Append("\n\n\n");
						sb.Append(p);
						sb.Append(".\n\n");
					}
				}
				else if (i % 7 == 6) // Line separation
				{
					sb.Append("\n");
				}
				else // Segment separation
				{
					sb.Append("   ");
				}
			}

			return sb.ToString();
		}

		// Generates a random string of given length
		public static string GenerateRandomString(int len, string range)
		{
			Byte[] _bytes = new Byte[len];
			char[] _chars = new char[len];

			// Shuffle the range first
			range = Shuffle(range);

			using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
			{
				rng.GetBytes(_bytes);

				for (int i = 0; i < len; i++)
					_chars[i] = range[(int)_bytes[i] % range.Length];
			}

			return new string(_chars);
		}

		// Implements the Fisher-Yates algorithm to shuffle the range
		public static string Shuffle(string range)
		{
			char[] _chars = range.ToCharArray();
			int len = _chars.Length;
			Byte[] _bytes = new Byte[len];

			using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
			{
				for (int i = len - 1; i > 1; i--)
				{
					// New set of random bytes
					rng.GetBytes(_bytes);

					int r = (int)_bytes[i] % len;
					char c = _chars[i];
					_chars[i] = _chars[r]; // Swap
					_chars[r] = c;
				}
			}

			return new string(_chars);
		}

		// Generates a jpeg of given text
		public byte[] GetImg(string txt)
		{
			// Blank image
			Bitmap bmp = new Bitmap(1, 1);
			Graphics gfx = Graphics.FromImage(bmp);

			// Font settings
			Font fnt = new Font(renderFont, renderSize, renderStyle, renderUnit);

			// Image dimensions
			int w = (int)gfx.MeasureString(txt, fnt).Width;
			int h = (int)gfx.MeasureString(txt, fnt).Height;

			// New image to text size
			bmp = new Bitmap(bmp, new Size(w, h));

			gfx = Graphics.FromImage(bmp);

			// Defaults
			gfx.Clear(Color.White);
			gfx.SmoothingMode = SmoothingMode.Default;

			gfx.TextRenderingHint =
				System.Drawing.Text.TextRenderingHint.AntiAlias;

			gfx.DrawString(txt, fnt, new SolidBrush(Color.Black), 0, 0);

			// Cleanup
			gfx.Flush();

			MemoryStream ms = new MemoryStream();
			bmp.Save(ms, ImageFormat.Png);
			return ms.ToArray();
		}
	}
}

 

To use this in an MVC application, for example, I would use the following ActionResult.

public ActionResult Index(FormCollection collection)
{
	// Generate
	string chars = "2346789ABCDEFGHKLMNPQRTWXYZ";

	// Default values
	int ds = 8, dl = 882;

	// Store (s = segment size, l = number of segments)
	int s = 0, l = 0;

	// Assign values
	if (Int32.TryParse(collection["s"], out s) || Int32.TryParse(collection["l"], out l))
	{
		// Set defaults to practical limits
		s = (s > 0 && s <= 20) ? s : ds;
		l = (l > 0 && l <= 1000) ? l : dl;
	}
	else
	{
		// Set defaults
		s = ds;
		l = dl;
	}

	PadModel model = new PadModel();
	string txt = model.RenderPad(s, l, chars);
	string img = Convert.ToBase64String(model.GetImg(txt));

	ViewData["s"] = s; // Segment size to be shown
	ViewData["l"] = l; // Total segment count
	ViewData["pad"] = txt; // Plain text version of the pad

	// Instead of sending binary data, I opted to use a base64 encoded image instead
	// since most modern browsers support it anyway
	ViewData["img"] = string.Format("data:image/png;base64,{0}", img);

	return View();
}

 

And in the View page, we can display both the plain text version and the image version of the pad using the following two lines

<img src="<%= ViewData["img"] %>" alt="PadImage" />
<pre><%= ViewData["Pad"] %></pre>

 

As an added benefit of sending a base64 encoded image instead of a binary file is that the base64 text itself can be sent via encrypted email that can be reconstituted by the recipient. This added layer of security is also handy if the user intends to hide the pad in its entirety in another data file.

The image version should produce something like this…

An image based one time pad that can be printed

 

I generated that pad just a little while ago and printed it out on my laser printer. Of course the quality is rubbish because my printer is low-res and only meant for office documents, but with a proper high resolution inkjet, we can get much finer details.

 

One-time pad close-up

 

Because the sheets are numbered, the previous message can contain details on which sheet to use for the next communication. Ideally, these pages should be cut into individual sheets and destroyed after each use.

Hope this was helpful.

Now I’m off to hit the hay!

An Encrypted Christmas Greeting

A little while ago, I wrote a simple one-time pad utility in JavaScript that can be used to send encrypted messages with relative security. One-time-pad is technically cryptographically secure, however it’s only as secure as how it’s used and the strength of the random number generator used to create the pad. My script must rely on the strength of the psudo random number generator of the browser scripting engine, so security is relatively weak and this must be taken into consideration before using it for anything important.

I’ve been getting some emails asking about using the utility and I think there was some added confusion since my version uses numbers as well. We’ll here’s a little tutorial on how to use a one-time pad…

Encrypting the message

Take the following simple message for example, and take the corresponding number from the values list on the one-time-pad.

 

M E R R Y C H R I S T M A S
13 05 18 18 25 03 08 18 09 19 20 13 01 19

 

Now, using the one-time pad, I got the following set of random characters and their corresonding values.

 

D 9 D F D B L M L W W 8 8 A
04 35 04 06 04 02 12 13 12 23 23 34 34 01

 

If I take the corresponding value of each character from both lists and add them together, I can get the new ciphertext that can be sent securely to the recipient. Obviously we can’t use the numbers in green because our list of available characters only go up to 36, however, we can subtract 36 from these numbers (mod 36) so it will cycle back to the available pool.

 

13 05 18 18 25 03 08 18 09 19 20 13 01 19 +
04 35 04 06 04 02 12 13 12 23 23 34 34 01
17 40 22 24 29 05 20 31 21 42 43 47 35 20 =
17 04 22 24 29 05 20 31 21 06 07 11 35 20 mod 36

 

This new set of numbers can be turned into the ciphertext using that same values list.

 

17 04 22 24 29 05 20 31 21 06 07 11 35 20
Q D V X 3 E T 5 U F G K 9 T

Decrypting the message

So, our recipient got the encrypted ciphertext, QDVX3ET5UFGK9T, and now he/she must take these charaters and turn them into a list of values in order to decrypt it.

 

Q D V X 3 E T 5 U F G K 9 T
17 04 22 24 29 05 20 31 21 06 07 11 35 20

 

Then, using the same one-time pad key values (since they’ll both be using the same sheet) the recipient will get the random characters and their associated values. Same as above.

 

D 9 D F D B L M L W W 8 8 A
04 35 04 06 04 02 12 13 12 23 23 34 34 01

 

The recipient will then subtract the one-time pad values from the encrypted message text. Basically the reverse of what the sender did. Again, this may result in some numbers going out of bounds of the available values list and become negative (marked in red), which we can fix by adding 36, again the opposite of what we did above, to bring it back to the available character pool.

 

17 04 22 24 29 05 20 31 21 06 07 11 35 20
04 35 04 06 04 02 12 13 12 23 23 34 34 01
13 31 18 18 25 03 08 18 09 17 16 23 01 19 =
13 05 18 18 25 03 08 18 09 19 20 13 01 19 mod 36

 

And when we turn those numbers back into the original text using the values list, we get :

 

13 05 18 18 25 03 08 18 09 19 20 13 01 19
M E R R Y C H R I S T M A S

 

… And a very Happy New Year!