Introduction
Welcome to Object Oriented JavaScript class library in C#/.NET style. This JavaScript library contains hashing (MD5, HMACMD5, SHA1, HMACSHA256, SHA256), encryption (AES, RSA) and some other JavaScript classes compatible with Microsoft .NET Framework. Examples for server are (Federal Information Processing Standard) FIPS-compliant. You can use these classes for end-to-end encryption between web clients.
It allows you to write some JavaScript code 100% identical to C#. For example, this is JavaScript code which converts unicode text to bytes and then creates Base64 string from it:
var text = "おはようございます – Good morning!";
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
var base64 = System.Convert.ToBase64String(bytes);
Background
I like coding with JavaScript in object oriented style. But one day, I decided to bring my code into another level and make my JavaScript code to look like C# as much as possible. So I did the following:
- Started to use .NET coding standards on my JavaScripts. You can find them on MSDN - .NET Framework: Guidelines for Names.
- Ported some useful classes and methods from .NET to JavaScript with the same class and property names. Some code parts were written from scratch, some parts were borrowed from the Internet and some parts were ported from C# directly.
- Started to use XML Comments inside JavaScript. They are not supported very well by Visual Studio 2008 but I hope support will be better in the future.
https://www.jocys.com/Common/JsClasses/Documents:
Benefits
Coding with JavaScript in C# .NET style provides these benefits:
- Any C# developer instantly understands the purpose of JavaScript code.
- You don't need to write help for your new JavaScript classes because Microsoft did it already.
- When porting a new class from C# to JavaScript, you don't need to think about how to name it or where to put it. All you need is to look for the same class in C# and use the same naming.
- More JavaScript classes you have, the easier it will be to port new ones.
- By using C# classes as primary reference, it will be much easier for different developers to write and integrate JavaScript classes into one big file library. It is because by looking at some C# class, the developer knows what type of input and output function must support/produce and he doesn't need to coordinate this with other developers.
- And many more...
Example: Hash Algorithm - HMAC-MD5 Checksum
C# (3.0) code to create HMAC-MD5 checksum:
var hmac = new System.Security.Cryptography.HMACMD5();
var key = System.Text.Encoding.UTF8.GetBytes("test key");
var data = System.Text.Encoding.UTF8.GetBytes("test data");
var hashBytes = hmac.ComputeHash(key, data);
var hex = System.BitConverter.ToString(hashBytes);
var guid = new System.Guid(hashBytes);
HMAC-MD5 checksum code written with this JavaScript library:
Include JavaScripts:
- System.js
- System.BitConverter.js
- System.Text.js
- System.Security.Cryptography.MD5.js
- System.Security.Cryptography.HMACMD5.js
var hmac = new System.Security.Cryptography.HMACMD5();
var key = System.Text.Encoding.UTF8.GetBytes("test key");
var data = System.Text.Encoding.UTF8.GetBytes("test data");
var hashBytes = hmac.ComputeHash(key, data);
var hex = System.BitConverter.ToString(hashBytes);
var guid = new System.Guid(hashBytes);
As you can see, the code is 100% identical. SHA-1 and SHA-256 hash algorithm class is also available:
Example: Symmetric algorithm - AES-256 Encryption
Online examples:
JavaScript code for AES-256 encryption is identical to C# code except for only one minor difference. In JavaScript, I need to use "new System.Byte(length)
" (line 20) instead of simple "new byte[length]
". Of course, I can create a class alias by doing "byte = System.Byte
" inside JavaScript and make that difference smaller. You can use "System.Security.Cryptography.AesCryptoServiceProvider
" .NET class, instead of "RijndaelManaged
" class, to decrypt/encrypt data on computers where Federal Information Processing Standard (FIPS) is enforced.
Include JavaScripts:
- System.js
- System.IO.js
- System.Text.js
- System.Convert.js
- System.BitConverter.js
- System.Security.Cryptography.js
- System.Security.Cryptography.SHA1.js
- System.Security.Cryptography.HMACSHA1.js
- System.Security.Cryptography.RijndaelManaged.js
var input = System.Text.Encoding.UTF8.GetBytes("Plain Text");
var cipher = new System.Security.Cryptography.RijndaelManaged();
var passwordBytes = System.Text.Encoding.UTF8.GetBytes("password");
var hmac = new System.Security.Cryptography.HMACSHA1(passwordBytes);
var salt = hmac.ComputeHash(passwordBytes);
var secretKey =
new System.Security.Cryptography.Rfc2898DeriveBytes(passwordBytes, salt, 10);
var key = secretKey.GetBytes(32);
var iv = secretKey.GetBytes(16);
var cryptor = cipher.CreateEncryptor(key, iv);
var inputBuffer = new System.Byte(input.length);
System.Buffer.BlockCopy(input, 0, inputBuffer, 0, inputBuffer.length);
var stream = new System.IO.MemoryStream();
var mode = System.Security.Cryptography.CryptoStreamMode.Write;
var cryptoStream = new System.Security.Cryptography.CryptoStream(stream, cryptor, mode);
cryptoStream.Write(inputBuffer, 0, inputBuffer.length);
cryptoStream.FlushFinalBlock();
var outputBuffer = stream.ToArray();
stream.Close();
cryptoStream.Close();
var base64String = System.Convert.ToBase64String(outputBuffer);
Example: Asymmetric algorithm - RSA Encryption
RSA JavaScript classes are compatible with Microsoft .NET Framework. It means that you can encrypt/decrypt data with JavaScript and encrypt/decrypt it with "System.Security.Cryptography.RSACryptoServiceProvider
" Microsoft .NET Framework class. You can export, import, generate RSA Keys and use "Direct Encryption (PKCS#1 v1.5)" and "OAEP padding (PKCS#1 v2)" padding.
RSA allows you to encrypt and submit data securely without Secure Sockets Layer (SSL). You can check System.Security.Cryptography.RSA.aspx example. This is done in 3 simple steps:
- Step 1: Server generates RSA key and shows only public key to the user on the web page.
Note: Private RSA key is stored on server side and only server can decrypt submitted data. - Step 2: User enters password or other sensitive data into textbox.
- Step 3: User hits [Submit] button. JavaScript will encrypt password with RSA public key, replace plain text with encrypted Base64 code and submit web form to the server.
Note: Then you can use strong password and AES symmetric encryption to submit extra data. In this way, you will protect sensitive data with military grade encryption.
Online examples:
Include JavaScripts:
- System.js
- System.IO.js
- System.Text.js
- System.Convert.js
- System.BitConverter.js
- System.Security.Cryptography.js
- System.Security.Cryptography.SHA1.js
- System.Security.Cryptography.HMACSHA1.js
- System.Security.Cryptography.RSA.js
C# and JavaScript code for RSA encryption/decryption is 100% identical:
var text = "plain text";
var doOaepPadding = true;
var xmlParams =
"<RSAKeyValue>" +
"<Modulus>pxtmFnrGI6Sb8ziyY+NRUDuQ4b/ETw5WabQ4daFQqzsCEr/6J/
LLBU/2D5mO5/Wu5U/Rya1E55aYFZeaZMNqAw==</Modulus>" +
"<Exponent>AQAB</Exponent>" +
"<P>2TsVXWPEvDIJv/gd2rX9k0UOyXuaYgoAchIH6vUicis=</P>" +
"<Q>xO4+OYREQfqYRQK7y73+RaUG0IxobT0OQ0c+Ok2hc4k=</Q>" +
"<DP>K7/xgpiIU9rECeyfnp/OjS14V+3T3vDivBaTj6eFI3c=</DP>" +
"<DQ>K4N9ClZ4gp+tn6oP9t//XEIvtEsiE+kmyqTmUhmvMAk=</DQ>" +
"<InverseQ>p7o4BOlKZQZ693R1ViZ66y5gTjUkNNTd2za7/1YGBCs=</InverseQ>" +
"<D>XZqFVrYy4qhECruJgVZFp/GVuD5Y0gev88nVjl5r911QT+
I8vgJSklTso7jTlpMtf2oe7UZ0WRWEtgPS3tZn4Q==</D>" +
"</RSAKeyValue>";
var rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
rsa.FromXmlString(xmlParams);
var rsaParamsPublic = rsa.ExportParameters(false);
var rsaParamsPrivate = rsa.ExportParameters(true);
var decryptedBytes = System.Text.Encoding.UTF8.GetBytes(text);
rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
rsa.ImportParameters(rsaParamsPublic);
var encryptedBytes = rsa.Encrypt(decryptedBytes, doOaepPadding);
var encryptedString = System.Convert.ToBase64String(encryptedBytes);
encryptedBytes = System.Convert.FromBase64String(encryptedString);
rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
rsa.ImportParameters(rsaParamsPrivate);
decryptedBytes = rsa.Decrypt(encryptedBytes, doOaepPadding);
text = System.Text.Encoding.UTF8.GetString(decryptedBytes);
var keySize = 512;
rsa = new System.Security.Cryptography.RSACryptoServiceProvider(keySize);
xmlParams = rsa.ToXmlString(true);
Example: Mobile Apps, Encryption and Compression
RSA encryption is very useful for mobile devices (jQuery Mobile). You can store sensitive information which belongs to the client (like credit cards, addresses, passwords, etc.) in encrypted state on device itself. Data can be decrypted only by submitting it to your server where RSA private decryption key is stored. Data is safe even if client device or server disk is lost. Client can't decrypt the data and no sensitive information is stored on the server. Compression can be used to reduce client data bill.
Online examples:
Example: User Interface
Library contains some user interface classes.
function firstButton_Click(){
Trace.Write("First Button Click");
}
function secondButton_Click(){
Trace.Write("Second Button Click");
}
function Window_Load(){
Trace.IsEnabled = true;
Trace.Write("Start Demo");
var toolBar = new System.Web.UI.Interface.ToolBar("MyToolBar");
document.body.appendChild(toolBar.Node);
var bar = new System.Web.UI.Interface.Bar("MainBar", document, "Bar Title");
toolBar.Add(bar);
var firstButton = new System.Web.UI.Interface.Button("FirstButton", document);
firstButton.SetText("First");
firstButton.SetImage("Images/Icons/Options-16x16.png");
firstButton.SetTitle("First Button");
firstButton.customAction = firstButton_Click;
bar.Add(firstButton);
var secondButton = new System.Web.UI.Interface.Button("SecondButton", document);
secondButton.SetText("Second");
secondButton.SetImage("Images/Icons/Trace.16x16.png");
secondButton.SetTitle("Second Button");
secondButton.customAction = secondButton_Click;
bar.Add(secondButton);
}
window.onload = Window_Load;
It will produce this interface on the web page:
Requirements
JavaScript has a very limited number of types:
JavaScript Object | typeof(Object) |
Object | 'object ' |
Array | 'object ' |
Function | 'function ' |
String | 'string ' |
Number | 'number ' |
Boolean | 'boolean ' |
null | 'object ' |
undefined | 'undefined ' |
But by combining the existing types, we can create JavaScript objects similar to C#. For example:
C# Type | JavaScript Type |
public | property declared with "this. " prefix: this.Name = new String; |
private | property declared with "var " prefix: var name = new String; |
class | this.[ClassName] = function(){... without "return value;" at the end |
void | function which has no "return value;" at the end |
short /Int16 | whole Number from [-2^15, 2^15-1] range |
int /Int32 | whole Number from [-2^31, 2^31-1] range |
long /Int64 | whole Number from [-2^63, 2^63-1] range (Requires BigInteger class) |
byte | whole Number from [0, 255] range: var b = 14; |
sbyte | whole Number from [-128, 127] range: var sb = -14; |
bytes[] | Array() filled with integers from [0-255] range. |
bit | Number: 0 or 1 |
bit[] | Array() filled with integers from [0-1] range. |
char | String which contains a single character. Declared with single quotes: var c = 's' |
char[] | Array() filled single characters:
var chars = new Array(1); chars[0] = 's'; |
object | parameter which was declared with "{ } ": var o = {}; |
enum | Object with "Enum " suffix and comma separated values: this.TriStateEnum = { Unknown: -2, False: 0, True: 1 } |
EventHandler | function with parameters "sender " and "e ": function(sender, e) or this.Click(sender, e) |
NUMBERS: All numbers in JavaScript are 64-bit (8 bytes) floating point numbers (double: 1-bit sign, 11-bits exponent, 52-bits mantissa). There is no Double
, Single
/Float
, Boolean
, Int16
, UInt16
, Int32
or UInt32
. But you can use public static
methods of System.BitConverter JavaScript
class in order to treat the same JavaScript number as a different type:
var bytes = System.BitConverter.GetBytes(-859045888, System.TypeCode.Int32);
var n = System.BitConverter.ToInt32(bytes, 0);
System.BitConverter
JavaScript class supports little-endian (default), big-endian byte orders and numeric arrays. System.BitConverter
class is very useful in encoding/decoding/encryption/decryption classes. Please note that you need to specify number type when using GetBytes(value, typeCode)
method by using System.TypeCode
enumeration values (this enumeration is located inside System.js file).
I've added System.BigInt
class (same as .NET internal System.Security.Cryptography.BigInt
class). It represents an arbitrarily large signed integer whose value in theory has no upper or lower bounds. It means you can add, subtract, multiply, divide numbers of Godzilla proportions in JavaScript which can be useful with client side encryption:
System.BigInt.MaxBytes = 512;
var n1 = new System.BigInt("0x010203040506");
var n2 = new System.BigInt("-280422911905295");
var n3 = System.BigInt.Multiply(n2, n1);
var h = n3.ToHex()
var d = n3.ToDecimal()
var bytes = n3.Elements
NOTE: You can use <param type="byte[]" name="data">...</param>
inside JavaScript XML Comments in order to specify type of input data and <returns type="double">...</returns>
- for output.
JavaScript IntelliSense
Visual Studio 2010 has built-in support for JavaScript IntelliSense. This means that if you open file, place cursor at the end of file and type "System.
" then straight after the dot, Visual Studio will bring up a menu containing all available properties of System
namespace:
System.Type.Inherits
method allows to use IntelliSense from inside of inherited class:
The good news here is that Microsoft is moving in the right direction. The bad news is that JavaScript IntelliSense works only with specific JavaScript coding style and sometimes needs workarounds. In other words, it works in mysterious ways or doesn't work at all :). Some upgrades are needed on my code too.
Installation
Extract source archive into webroot (/) folder of your website.
Example: System.Security.Password
Inside the source code, you can find examples (Examples/) including password generator example. You can run it:
To make a suggestion or report bugs, please write to evaldas@jocys.com.
History
- 2017-09-08 - Fixed bug inside System.Web.debug.js class, updated security and examples.
- Updated examples to be FIPS-compliant:
System.Security.Cryptography.AES.aspx
System.Security.Cryptography.AES.aspx.cs
System.Security.Cryptography.aspx
System.Security.Cryptography.aspx.cs
System.Web.Mobile.htm
- 2017-05-25 - Refactored some code. Fixed issue with TraceLog time format.
- New Classes:
System.Security.Cryptography.SHA256
System.Security.Cryptography.HMACSHA256
- New Examples:
- System.Security.Cryptography.SHA256.htm
- 2017-05-21 - Fixed compatibility issues with ASP.NET AJAX Control Toolkit. Resolved hundreds of errors and warnings, reported by Visual Studio ESLint. TraceLog is using DIV instead of IFRAME now.
- 2011-08-29 - GZip compression classes and encryption example with web service for mobile application was added:
- New Classes:
System.IO.Compression.DeflateInput
System.IO.Compression.HuffmanTree
System.IO.Compression.FastEncoderWindow
System.IO.Compression.FastEncoder
System.IO.Compression.Deflater
System.IO.Compression.Inflater
Etc...
- New Examples:
- System.Web.Mobile.htm
- System.IO.Compression.htm
- System.IO.Compression.aspx
- 2011-07-27 - Intellise RSA encryption bug fix. JavaScript IntelliSense "type icon" support added. Other various changes. Project file updated to Visual Studio 2010. Fixed code to work on Google Chrome. You must start Chrome with --allow-file-access-from-files option in order for demo to run locally (with the file:/// in the URL).
- New Classes:
System.IO.Stream
System.Diagnostics.TraceListener
- 2010-02-24 - RSA encryption and Unit Testing classes were added:
- New Classes:
System.Security.Cryptography.RSAParameters
System.Security.Cryptography.RSACryptoServiceProvider
System.Security.Cryptography.PKCS1Padding
System.Security.Cryptography.PKCS1MaskGenerationMethod
System.Security.Cryptography.HashAlgorithm
System.TestTools.UnitTesting.Assert
- New Examples:
- System.Security.Cryptography.RSA.aspx
- System.Security.Cryptography.RSA.htm
- System.TestTools.UnitTesting.htm
- 2009-06-21 - New
System.BigInt
(.js file) class with examples:
- Examples/System.BigInt.htm
- Examples/System.BigInt.aspx
- 2009-03-14 - PassGen now works in Internet Explorer again. Some cross-domain security issues with FX fixed. Adjusted to work better with "Microsoft AJAX Framework" scripts (Resource of System.Web.Extensions.dll/MicrosoftAjax.debug.js). Microsoft has some cool JavaScript classes there.
- 2009-02-04 - New fixes and new bugs. Moved everything to /Common/JsClasses folder. Latest source available from SVN server (see above).
- 2008-03-14 - Some bug fixes:
- New Classes:
System.Web.UI.HtmlControls.TextBox.CommandLine
- Converts input to command line. Will be used later to create plain JavaScript console and in chat applications.
- Examples Updated (Examples/ folder):
- System.Web.UI.HtmlControls.TextBox.CommandLine.htm
- System.Web.UI.ShortKeys/System.Web.UI.ShortKeys.htm - Shows how to override and use custom windows keyboard layout on the web page. Can also capture keys and perform non-default custom actions.
- 2008-01-27
- New enumerations:
- New classes:
System.Collections.BitArray
System.BitConverter
(System.BitConverter.js) class was updated with methods: System.BitConverter.GetByte(value, typeCode)
- get bytes from Double
, Single
, Boolean
, Int16
, UInt16
, Int32
, UInt32
. You need to use values of System.TypeCode
to specify how JavaScript must treat a number.
You also can convert byte[]
back to numbers by using methods
System.BitConverter.ToDouble(bytes, startIndex)
System.BitConverter.ToSingle(bytes, startIndex)
System.BitConverter.ToBoolean(bytes, startIndex)
System.BitConverter.ToInt16(bytes, startIndex)
System.BitConverter.ToUInt16(bytes, startIndex)
System.BitConverter.ToInt32(bytes, startIndex)
System.BitConverter.ToUInt32(bytes, startIndex)
Int64
and UInt64
types are not available yet because JavaScript 64-bit (8 bytes) float point numbers have only 52-bit mantissa which means that it is not possible to work with 64-bit whole numbers properly (possible by reusing BigInt
class).
- Updated Examples:
- System.BitConverter.htm
- System.BitConverter.aspx
- 2008-01-13 - Some bugs were fixed and new JavaScript classes were added:
- System.Security.Cryptography.js file:
System.Security.Cryptography.Rfc2898DeriveBytes
System.Security.Cryptography.ICryptoTransform
System.Security.Cryptography.RNGCryptoServiceProvider
System.Security.Cryptography.CryptoStrea
- System.Security.Cryptography.RijndaelManaged.js file (AES encryption):
System.Security.Cryptography.RijndaelManaged
- System.js file (new methods):
System.Buffer.BlockCopy
System.Array.Reverse
System.Array.Clear
System.Array.GetMultiDimensional
System.Array.FillMultiDimensiona
- Examples Created (Examples/ folder):
- System.Security.Cryptography.AES.htm
- System.Security.Cryptography.AES.aspx
- System.Security.Cryptography.htm
- System.Security.Cryptography.aspx
- Some interface parts/classes/examples were updated to Office 2007 style:
- System.Web.UI.Interface.ToolBar.htm
- System.Web.UI.Interface.TabStrip.htm
- Methods
System.BitConverter static
class was updated.
- 2007-12-15 - New '
System.IO.MemoryStream
' class. I will use it later with symmetric encryption algorithms so encryption can be done between two web browser clients without any ActiveX.
Now you can get byte[]
arrays filled with 0 numbers in JavaScript easier:
var bytes = new System.Byte(10);
It's the same as 'byte[] bytes = new System.Byte[10];
' or 'byte[] bytes = new byte[10];
' in C#. You can define multi-dimensional arrays filled with zeroes too:
var bytes = new System.Byte(16,16); bytes[4][5] = 10;
- 2007-12-12 - Created. Some links inside examples were fixed. New source code was uploaded. Alex's Code Syntax Highlighter was updated to 1.5.1 version.