Refactoring CryptoJS in Modern ECMAScript | by Entronad | Frontend Weekly


Repository: entronad/crypto-es

npm: crypto-es

Needs of encryption, decryption and hash are quite common in both front and back end projects. When dealing with sensitive data, functions with the name like MD5, Base64 or AES may be quite often seen in your codes.

Of all JavaScript cryptography libraries, CryptoJS is mostly widely used for its simple APIs and rich variety of functions. It derives in early years, and the main codebase is still on the Google Code. Although it has been migrated to npm, the last update was 3 years ago. For historical reasons, some of it’s features seem out of date for modern usages:

  • It creates an unique object oriented system based on prototypal inheritance to simulate class inheritance.
  • The files use Immediately Invoked Function Expression (IIFE) to export modules.

Before ECMAScript 6, these features avoided certain defects of JavaScript while ensuring browser compatibility and out-of-the-box usage. But since the new ECMAScript standard has specified the Class and Module system to solve those defects, I would try to experimentally refactor CryptoJS in modern ECMAScript.

The project is called CryptoES . As an experiment, the compatibility would not be the first concern, and the only rule is to meet the latest ECMAScript standard. For example, I would only use ECMAScript Module for the module system, with out CommonJS support. With the help of Babel and loader hook, this project could satisfy any production application. And as the ECMAScript standard gets more widespread, there would be more directly usages of it.

Besides, as a refactoring project, it’s APIs is all the same as CryptoJS.

CryptoJS extends the JavaScript prototypal inheritance and implements an unique “base objects inheritance” system. It has functions such as extend, override, mixin, etc. which makes it like general class-based OOP languages. This is defferent in approach but the same in purpose of the ECMAScript Class. Our first step is to replace this unique inheritance system with classes, which would make the code concise. But before that, let’s have a review of some key concepts of the ECMAScript Class:


We know that in ECMAScript, class definition is a syntactic sugar of traditional JavaScript constructor. So we could get access to an instance’s class through it’s constructor field. What could we do with this knowledge? In an instance’s instance methods, we could create a new instance which has the same class as the former one by expression new this.constructor() .


Unlike in the traditional JavaScript prototypal inheritance, in ECMAScript Class inheritance, while creating an instance, the constructor of it’s super class will firstly called, and then the fields and methods of the super class will be added to the instance, finally the constructor of the instance will be called. This makes sure that the fields and methods defined in the sub class will override the super class’s correctly.

Note that this in instance methods refers to the instance, while this in static methods refers to the class. So we could implement factory mode by calling new this() in the static methods of a class.


In the class definition, super() with parentheses refers to super class’s constructor, while super without parentheses in static methods, just like this , refers to super class. So, when overriding methods, we could call the overridden method of the super class first by expression .

prototype & __proto__

A class is a constructor in essence, so it has a prototype field referring to its prototype object. And a class is also an object, so it has a __proto__ field referring to it’s super class too. Since the prototype of a class has a __proto__ field referring to it’s super class’s prototype object, this composes a prototype chain.

An instance’s __proto__ field refers to the prototype object of it’s class.

With these features, we could get the inheritance relations of both instances and classes.

The commonly used version of CryptoJS nowadays is hosted on the GitHub: brix/crypto-js,which CryptoES will mainly based on. It’s “base objects” are defined in the core.js file.

The inheritance is implemented in the object named Base :

In fact, the inheritance is implemented by calling the extend method of the “super object” with arguments of overriding fields and methods, and the extend method creates a new “sub object”. The real instance will be returned by the create method of this “sub object”, of which the init method will be called as a constructor. The disadvantage of this approach is that instances are not created with the keyword new as regular. And an instance will recursively keeps all the “ancestor objects” of its inheritance chain in the $super field, which is certainly redundant.

These goals could easily achieved with the keyword extend and class constructor of ECMAScript Class, with out any extra codes or problems above. But for the consistence of the APIs, the static method create is kept, so that you could create instances with ClassName.create() . The arguments of the create method will be passed to the real constructor by the rest operator and the argument destruction:

the basic purpose of Base is to provide the mixin method. In CryptoJS, the boundary between “class objects” like Base and real instance objects is fuzzy, and the mixin method could be called by “class objects”:

But in both logic and fact, the mixin method should be an instance method, which just acts like Object.assign() :

Finally, the copying of instances. With prototypal inheritance, the CryptoJS implementation is quite odd:

Since new this.constructor() could be used in any instances with out indicating it’s the class name, we could do it in a more straight way:

Then, by inheriting the Base class, all other core classes will have these methods. And with ECMAScript Class, the usage of methods would be more standardized. For example, in CryptoJS, some instance creating methods of Wordarray are:

But now they are standard constructor or static methods:

After this refactoring to class, we should add some extra unit test for the inheritance relations:

  • __Proto__ of the sub class must refer to the super class.
  • prototype objects of sub class and super class are of right order in the prototype chain.

Bitwise operations are the foundation of cryptography algorithms.

What ever the data type is, bitwise operation treats them as a contiguous sequence. For sack of performance, bitwise operation would better acting on a section of contiguous memory. Some languages provide ways to operate the contiguous memory, such as pointer in C++ and ArrayBuffer in ECMAScript 6.

JavaScript was designed as a script language for browser at first, so there was no memory operation before. But there is still a way to get the abstraction of the bitwise sequence, which is Binary Bitwise Operators.

According to the specification, in the operation with binary bitwise operators, all operands, whatever their origin types are, will be convert to 32 bits unsighed int by ToInt32() . Then they are treated as 32 bits length sequences, and the result is a 32 bits unsighed int. So, by splicing these 32 bits unsighed ints, we could simulate the operation on a contiguous memory.

Based on this, CryptoJS implemented a class called WordArray, as the abstraction of the bitwise sequence. WordArray is the most important basic class of CryptoJS, and all it’s algorithms handle with WordArray objects in underlying implementation. Thus understanding WordArray is the precondition to understand it’s algorithms.

The definition of WordArray is in the core.js file:

Note that all codes below are of entronad/crypto-es .

WordArray directly inherits from Base . It has two fields: word and sigBytes . words is an array of 32 bits unsighed ints, and By splicing elements of this array in order we can get the bitwise sequence needed. In JavaScript conversion between the 32 bits unsighed int and the bit is through Binary Complement. But we don’t have to get involved with that because the value of this int is meaningless. Generally the bitwise sequence is measured by bytes, or presented as hex numbers, so we just need to know that 32 bits equal to 4 bytes, or 8 hex numbers.

Encoding algorithms’ subjects are strings. So the bitwise sequences are all of whole bytes, or times of 8 bits. But they are not certainly times of 32 bits. So only by the length of words we can’t get the actual length of bitwise sequence, for there may be some empty tailing bytes. So we need the field sigBytes indicates the actual significant bytes length.

We could create a WordArray by directly passing these two fields:

For convenience of pruning the words with the sigBytes , there is a clamp method in WordArray:

It will remove the “insignificant bytes” of the words . In the words array, the starting elements full of significant bytes will be kept, and the tailing elements with no significant bytes will be ignored through words.length = Math.ceil(sigBytes / 4) .

The middle element with both significant and insignificant bytes is a bit difficult to deal with. Firstly we should calculate the length to remove: (32 - (sigBytes % 4) * 8) , and left move 0xffffffff bitwise by this length to get a 32 bits mask, then locate this middle element by sigBytes >>> 2 (just the same as int divided by 4) , finally and it with the mask to set the insignificant bytes to 0.

Locating elements by >>> and making and with masks is widely used in CryptoJS.

Just like clamp , the troublesome part of concat is also to handle the middle element:

Inside CryptoJs, WordArray is both input and output of most functions, but the external users concerns mostly about the string result. So WordArray provides overriding toString method:

Because the words array is of reference type, we should create a new copy of it by slice in the clone method:

Except the constructor, the static method random provides a random WordArray of certain length. Because Math.random() of JavaScript is unsafe and returns a 64 bits float, we will do some extra processing:

Since the ArrayBuffer is included to the ECMAScript, it has been used in more and more scenes, such as WebSocket, file objects, and canvas outputs. While handling with these forms of objects, we also need to encrypt, decrypt or hash them in some cases.

So CryptoJS extended the WordArray creator to allow ArrayBuffer and TypedArray as input. this extension is in a individual lib-typedArrays.js file, and dose a lot of checks and reconstructs the WordArray creator to ensure the compatibility. We integrate this to the origin WordArray constructor and simplified the these checks:

Then WordArray creator could recive an ArrayBuffer or TypedArray so that CryptoES algorisms could apply to them:

Note that ArrayBuffer could not directly passed to algorisms, you should change them to WordArray first.

With this, encrypting files would be easier:

What do you think?

10 Points
Upvote Downvote

Leave a Reply

Your email address will not be published. Required fields are marked *

GIPHY App Key not set. Please check settings

The Beacon Book is live! Read and Mint NFTs from a book about the Beacon Chain launch

Debugging JSON RPC calls