MSR JavaScript Cryptography Library
msrCrypto is a JavaScript cryptography library, originally developed by Microsoft Research and subsequently maintained by Kevlened. It serves as a polyfill for the W3C Web Cryptography API, enabling modern cryptographic primitives like RSA-OAEP, AES-CBC, SHA-256/384/512, HMAC, ECDH, and ECDSA in environments where native Web Crypto API support is absent or inconsistent. Its primary differentiation is its broad browser compatibility, extending to older browsers like Internet Explorer 8, 9, 10, and 11, alongside modern browsers. Since version 1.4, it has adopted a Promise-based API for asynchronous operations, aligning with the Web Crypto API specification. The current stable version, as per the user's input, is 1.5.8, though a `1.6.5` version appears on npm under `@dashdot/msrcrypto` with the last publish 4 years ago, and `1.5.8` itself was published 6 years ago. Its release cadence appears infrequent, with updates primarily addressing API compliance, security bug fixes, and feature enhancements for specific algorithms.
Common errors
-
TypeError: cryptoOperation.onComplete is not a function
cause Attempting to use the pre-1.4 event-based API (`onComplete`, `onError`) after upgrading to version 1.4 or higher, which uses Promises.fixUpdate your code to use the Promise-based `.then()` and `.catch()` syntax for cryptographic operations. -
SyntaxError: Expected identifier, string or number
cause Calling `promise.catch()` directly in Internet Explorer 8, where `catch` is a reserved keyword.fixUse bracket notation to access the `catch` method: `promise['catch'](function(error) { /* handle error */ });`. -
ReferenceError: msrCrypto is not defined
cause The `msrcrypto.js` script was not loaded via a `<script>` tag, or it was loaded in a module environment without being exposed globally, or the script failed to load.fixEnsure `msrcrypto.js` is included in your HTML using a `<script>` tag before any code attempts to access `msrCrypto`. Verify the script path is correct and accessible. -
TypeError: Object doesn't support property or method 'fill' (or similar errors related to Typed Arrays in IE8/9)
cause Attempting to use Typed Arrays (like `Uint8Array` or `ArrayBuffer`) as input or expecting them as output in IE8 or IE9, which do not support them.fixProvide input data as regular JavaScript Arrays and handle returned data as regular Arrays when targeting IE8/9. For IE10+, `ArrayBuffer` is used. You may need to write compatibility layers. -
SecurityError: Failed to create a new Worker: Script resource is blocked by Content Security Policy.
cause The Content Security Policy (CSP) of your application is preventing the creation of Web Workers, which `msrCrypto` tries to use for performance.fixModify your CSP to allow worker scripts. For example, add `worker-src 'self' blob:` or `script-src 'self' blob:` depending on how your workers are loaded. Alternatively, bundle `msrCrypto` in a way that disables web workers, or use a version that has web workers disabled by default (e.g., `@dashdot/msrcrypto@1.6`).
Warnings
- breaking The API significantly changed in version 1.4 from event-based callbacks (common in IE11 native crypto) to Promise-based returns, aligning with the modern Web Crypto API specification. Code using `cryptoOperation.onComplete` or `cryptoOperation.onError` will break.
- breaking Version 1.4.1 included critical bug fixes for the elliptic curve module, addressing erroneous calculations that could theoretically leak private data, correcting the NIST p-521 curve definition, and preventing rare ECDSA failures. Users on older versions are exposed to these vulnerabilities.
- gotcha In Internet Explorer 8 (IE8), `catch` is a reserved JavaScript keyword. Directly calling `promise.catch()` will throw a `SyntaxError`.
- gotcha IE8 and IE9 do not support Typed Arrays (e.g., `ArrayBuffer`, `Uint8Array`). When using these browsers, `msrCrypto` expects and returns regular JavaScript Arrays for input and output data. For IE10 and up, it uses `ArrayBuffer`.
- gotcha Automatic web worker usage (for offloading crypto work) can fail if `msrCrypto` is bundled into a larger JavaScript file. The library attempts to determine its own path to instantiate new workers (`new Worker(pathToJavaScriptFile)`), and bundling breaks this path resolution.
- gotcha For older browsers (IE8, 9, 10) lacking `window.crypto.getRandomValues`, `msrCrypto`'s internal Pseudo-Random Number Generator (PRNG) requires explicit seeding with cryptographically secure random bytes (e.g., 48 bytes) via `msrCrypto.initPrng()` for secure operation. Without this, cryptographic operations may not be truly random.
Install
-
npm install msrcrypto -
yarn add msrcrypto -
pnpm add msrcrypto
Imports
- msrCrypto
import * as msrCrypto from 'msrcrypto'; import { subtle } from 'msrcrypto'; const msrCrypto = require('msrcrypto');<script src="path/to/msrcrypto.js"></script>
- msrCrypto.subtle
window.crypto.subtle.encrypt(...);
msrCrypto.subtle.encrypt(...)
- msrCrypto.initPrng
msrCrypto.subtle.generateKey(...); // without prior PRNG initialization on older browsers
if (window.msrCrypto && typeof window.msrCrypto.initPrng === 'function') { // Obtain 48 random bytes from a secure source (e.g., server-side) const entropy = new Uint8Array(48); // Populate entropy with cryptographically strong random values // For example, if on Node.js: require('crypto').randomBytes(48); // For modern browser: window.crypto.getRandomValues(entropy); window.msrCrypto.initPrng(entropy); }
Quickstart
// This quickstart assumes msrcrypto.js has been loaded via a <script> tag,
// making the global `msrCrypto` object available.
// 1. Generate an AES-CBC key
const iv = new new Uint8Array(16); // Initialization Vector
// On modern browsers, use window.crypto.getRandomValues(iv);
// On older browsers, ensure PRNG is seeded (see warnings) or provide secure random bytes
// For this example, we'll simulate random values or assume a modern environment fallback
// For a truly secure setup in older IE, you'd need server-side entropy for msrCrypto.initPrng()
// Simulate getRandomValues for environments where it might not be available or fully polyfilled for iv generation
if (typeof window.crypto !== 'undefined' && typeof window.crypto.getRandomValues === 'function') {
window.crypto.getRandomValues(iv);
} else {
// Fallback for demonstration, NOT cryptographically secure in production for IV
for (let i = 0; i < iv.length; i++) iv[i] = Math.floor(Math.random() * 256);
}
msrCrypto.subtle.generateKey(
{
name: "AES-CBC",
length: 256, // For AES-256
},
true, // key is extractable
["encrypt", "decrypt"]
)
.then(function(key) {
console.log("AES-CBC Key generated successfully.");
// 2. Encrypt some data
const dataToEncrypt = new TextEncoder().encode("Hello, msrcrypto, this is a secret message!");
return msrCrypto.subtle.encrypt(
{
name: "AES-CBC",
iv: iv,
},
key,
dataToEncrypt
);
})
.then(function(encryptedData) {
console.log("Data encrypted successfully (ArrayBuffer):");
// In IE8/9, this might be a regular Array, convert for consistent logging if needed
console.log(new Uint8Array(encryptedData));
// Further steps would involve decrypting or sending the data
})
.catch(function(error) {
console.error("Encryption failed:", error);
});