{"id":28476356,"url":"https://github.com/netflix/nfwebcrypto","last_synced_at":"2026-03-07T18:01:34.344Z","repository":{"id":66225109,"uuid":"10346588","full_name":"Netflix/NfWebCrypto","owner":"Netflix","description":"Web Cryptography API Polyfill","archived":false,"fork":false,"pushed_at":"2017-01-28T22:45:05.000Z","size":15898,"stargazers_count":212,"open_issues_count":1,"forks_count":48,"subscribers_count":461,"default_branch":"master","last_synced_at":"2026-02-02T08:15:32.002Z","etag":null,"topics":["security"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Netflix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2013-05-28T22:02:51.000Z","updated_at":"2025-08-27T16:32:39.000Z","dependencies_parsed_at":"2023-03-10T23:44:08.255Z","dependency_job_id":null,"html_url":"https://github.com/Netflix/NfWebCrypto","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Netflix/NfWebCrypto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2FNfWebCrypto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2FNfWebCrypto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2FNfWebCrypto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2FNfWebCrypto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Netflix","download_url":"https://codeload.github.com/Netflix/NfWebCrypto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netflix%2FNfWebCrypto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30225408,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T17:00:40.062Z","status":"ssl_error","status_checked_at":"2026-03-07T17:00:39.026Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["security"],"created_at":"2025-06-07T15:06:42.957Z","updated_at":"2026-03-07T18:01:34.338Z","avatar_url":"https://github.com/Netflix.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"NOTE: THIS PROJECT IS NO LONGER UNDER ACTIVE MAINTAINENCE.\nWith most browsers now providing W3C Web Crypto implementations and Chrome disallowing 3rd-party PPAPI plugins, there is little use for this project. It will remain here on Github indefinitely, but there are no plans to keep any branch updated. The most recent code lives in the 'newInterface' branch.\n\nNetflix WebCrypto (NfWebCrypto)\n================================\n\nNetflix WebCrypto is a polyfill of the [W3C Web Cryptography API](http://www.w3.org/TR/WebCryptoAPI/),\n22 April 2013 Editor's Draft, as a native Chrome PPAPI plugin. Unlike a javascript polyfill, the native implementation\nsupports a stronger security model with no key material exposed to javascript. The goal is to make the Web Crypto\nJavascript API [freely available](http://www.apache.org/licenses/LICENSE-2.0) to web\ndevelopers for experimentation and use prior to its implementation by browser vendors.\n\nCurrently only Google Chrome / Chromium on linux amd64 is supported.\n\nFeatures\n--------\n\nNfWebCrypto does not implement the Web Crypto API in its entirety, due to\nlimitations of browser plugin technology and initial focus on operations and\nalgorithms most useful to Netflix. However, the existing feature set supports\nmany typical and common crypto use cases targeted by the Web Crypto API.\n\nSupported\n\n* Interfaces supported:\n  + Key, KeyPair\n  + KeyOperation\n  + CryptoOperation\n  + CryptoKeys\n* SubtleCrypto interface methods supported\n  + encrypt, decrypt\n  + sign, verify\n  + generateKey\n  + exportKey, importKey\n  + wrapKey, unwrapKey* **\n* CryptoKeys interface methods supported\n  + getKeyByName\n* Key formats supported\n  + symmetric keys: raw and jwk (raw)\n  + asymmetric keys: pkcs#8 (public), spki (private), and jwk (public only)\n* Algorithms supported\n  + SHA-1, SHA-224, SHA-256, SHA-384, SHA-512: digest\n  + HMAC SHA-256: sign, verify, importKey, exportKey, generateKey\n  + AES-128 CBC w/ PKCS#5 padding: encrypt, decrypt, importKey, exportKey, generateKey\n  + RSASSA-PKCS1-v1_5: sign, verify, importKey, generateKey\n  + RSAES-PKCS1-v1_5: encrypt, decrypt, importKey, exportKey, generateKey\n  + Diffie-Hellman: generateKey, deriveKey\n  + RSA-OAEP: wrapKey, unwrapKey\n  + AES-KW: wrapKey, unwrapKey\n  + AES-GCM: encrypt, decrypt, importKey, exportKey, generateKey\n\n*A special \"Kds\" NamedKey bound to the plugin binary and script origin can be used with (un)wrapKey to export/import\nopaque key representations for persistence in HTML5 local storage or equivalent.\n\n**Wrap/Unwrap operations follow the Netflix [KeyWrap Proposal](http://www.w3.org/2012/webcrypto/wiki/KeyWrap_Proposal)\nand support protection of the JWE payload with AES128-GCM.\nIt is be possible to wrap/unwrap the following key types: HMAC SHA-256 and AES-128 CBC.\n\nNot Supported\n\n* The streaming/progressive processing model in not supported\n* Synchronous API's like getRandomValues() are not supported\n* Algorithm normalizing rules are not fully implemented\n\nMoving forward, Netflix will continue to enhance this implementation and try to keep it as much in sync as possible\nwith the latest draft Web Crypto API spec.\n\nRequirements\n------------\n\nLinux\n\n* Ubuntu 12.04 64-bit with build-essential, libssl-dev-1.0.1c or later, and cmake 2.8 or later\n* 64-bit Google Chrome / Chromium R22 or later (tested with R27)\n\nDirectory Tour\n--------------\n\n    base/\n        Common C++ source for both the plugin and crypto component.\n    cmake/\n        Cmake toolchain files.\n        Linux desktop builds use the linux system build tools and libs.\n        Only 64-bit builds are supported for now.\n    crypto/\n        C++ source for the crypto component. The contents of this directory is\n        of primary interest to native devs; the entry point is the CadmiumCrypto\n        class. This directory currently builds to an archive file.\n    crypto/test/\n        Contains C++ gtest unit tests that exercise the CadmiumCrypto class\n        interface. Not fleshed out yet and currently not built.\n    misc/\n        Miscellaneous code to support development. Currently has code to run and\n        debug the Chrome browser with the plugin properly registered.\n    plugin/\n        C++ source of the PPAPI plugin. This code builds to shared library that\n        is dl-loaded by the browser when the plugin is registered. It handles\n        interfacing with the browser, bridging to the crypto thread, and decode/\n        dispatch of JSON messages to and from the browser. Native devs will\n        probably only be interested in the NativeBridge class here.\n    web/nfcrypto.js\n        The javascript front-end for the plugin. The bottom level of this code\n        handles the transport of JSON-serialized messages to and from the\n        plugin, while the top level implements the W3C WebCrypto interface.\n        Native devs will need to change the bottom level to match their bridge\n        API. This source file borrows heavily from PolyCrypt (polycrypt.net)\n    web/test_qa.html\n        The Jasmine HTML unit tests that exercise the javascript WebCrypto\n        API exposed to the javascript client by nfcrypto.js.\n        \n\nHow to Build\n------------\nThe following has been verified on Ubunutu 12.04. cmake 2.8 or later is required.\n\nNOTE: The SYSTEM key mentioned above depends in part on a secret build-time key \nSECRET\\_SYSTEM\\_KEY that for example purposes is hard-coded in linux_common.cmake.\nActual deployments must change this key.\n\n    $ mkdir buildDir\n    $ cd buildDir\n    $ cmake -DCMAKE_TOOLCHAIN_FILE=(repo)/cmake/toolchains/linux64.cmake -DCMAKE_BUILD_TYPE=[Debug|Release] (repo)\n    $ make -j\u003cN\u003e\n\nBuild Results\n-------------\n\nBrowser plugin - This is registered and run within the Chrome browser.\n\n    (buildDir)/plugin/libnfwebcrypto.so\n    (buildDir)/plugin/nfwebcrypto.info\n    \nNative gtest unit test executable (if built). This is run from the command\nline.\n\n    (buildDir)/crypto/test/test\n    \nNative CadmiumCrypto archive. Native apps will link to this archive.\n\n    (buildDir)/crypto/libcadcrypto.a\n\n\nHow to run the Unit Tests\n-------------------------\n\nChrome must be run with a special command line option to register the plugin.\nThe easiest way to do this is to use the provided start.sh script, which employs\nthe .info file generated by the build.\n\nMake a directory and copy or symlink start.sh, libnfwebcrypto.so, and\nnfwebcrypto.info.\n\n    $ mkdir runNfWebCrypto\n    $ cd !$\n    $ ln -s (repo)/misc/desktop/start.sh\n    $ ln -s (buildDir)/plugin/libnfwebcrypto.so\n    $ ln -s (buildDir)/plugin/nfwebcrypto.info\n\nThe start.sh script depends on the chrome executable present at\n/opt/google/chrome/chrome. Edit the script if this is not true. Finally, start\nchrome and run the [unit tests hosted on github](http://netflix.github.io/NfWebCrypto/web/test_qa.html)\nby running the script.\n\n    $ ./start.sh\n    \nNote that there must not be any other chrome instance running in the system\nbefore the script is executed. Otherwise the action will be to just open a new\ntab on the existing instance without loading the plugin.\n\nThe unit tests will run automatically and all should pass.\n\nSample Code\n-----------\n\nHere are some examples of how to use the Web Cryptography API to perform typical\ncrypto operations. These will work once the plugin is installed and enabled. More\ndetailed usage examples may be found in the javascript unit tests.\n\nThe examples below use the following utility functions to convert between string\nand Uint8Array:\n\n```JavaScript\n\n// string to uint array\nfunction text2ua(s) {\n    var escstr = encodeURIComponent(s);\n    var binstr = escstr.replace(/%([0-9A-F]{2})/g, function(match, p1) {\n        return String.fromCharCode('0x' + p1);\n    });\n    var ua = new Uint8Array(binstr.length);\n    Array.prototype.forEach.call(binstr, function (ch, i) {\n        ua[i] = ch.charCodeAt(0);\n    });\n    return ua;\n}\n\n// uint array to string\nfunction ua2text(ua) {\n    var binstr = Array.prototype.map.call(ua, function (ch) {\n        return String.fromCharCode(ch);\n    }).join('');\n    var escstr = binstr.replace(/(.)/g, function (m, p) {\n        var code = p.charCodeAt(p).toString(16).toUpperCase();\n        if (code.length \u003c 2) {\n            code = '0' + code;\n        }\n        return '%' + code;\n    });\n    return decodeURIComponent(escstr);\n}\n\n```\n\n### Compute SHA-1 hash ###\n\n```JavaScript\n\n\u003cscript src='nfcrypto.js'\u003e\u003c/script\u003e\n\u003cscript\u003e\n    var cryptoSubtle = window.nfCrypto.subtle;\n    var data = \"This is some data to hash\";    \n    var op = cryptoSubtle.digest({ name: \"SHA-1\" }, text2ua(data));\n    op.oncomplete = function (e) {\n        window.alert(\"SHA-1 of \\\"\" + data + \"\\\": \" + btoa(e.target.result));\n    };\n\u003c/script\u003e\n\n```\n\n### AES-CBC Encryption / Decryption ###\n\n```JavaScript\n\n\u003cscript src='nfcrypto.js'\u003e\u003c/script\u003e\n\u003cscript\u003e\n\n    var cryptoSubtle = window.nfCrypto.subtle;\n    var cleartext = \"This is some cleartext to encrypt.\";\n    var key;\n    var iv = new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n                             0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]);\n    var ciphertext;\n    \n    // generate a non-extractable 128-bit AES key\n    function generateKey() {\n        var genKeyOp = cryptoSubtle.generateKey(\n            { name: \"AES-CBC\", params: { length: 128 } },\n            false\n        );\n        genKeyOp.oncomplete = function (e) {\n            key = e.target.result;\n            encryptData();\n        }\n    }\n    \n    // encrypt cleartext to get ciphertext\n    function encryptData() {\n        var encOp = cryptoSubtle.encrypt({\n            name: \"AES-CBC\",\n            params: { iv: iv }\n        }, key, text2ua(cleartext));\n        encOp.oncomplete = function (e) {\n            cipherText = e.target.result;\n            decryptData();\n        }\n    }\n    \n    // decrypt ciphertext to get cleartext\n    function decryptData() {\n        var encOp = cryptoSubtle.decrypt({\n            name: \"AES-CBC\",\n            params: { iv: iv }\n        }, key, cipherText);\n        encOp.oncomplete = function (e) {\n            var cleartext2 = ua2text(e.target.result);\n            if (cleartext2.valueOf() == cleartext.valueOf()) {\n                window.alert(\"Round-trip encryption/decryption works!\");\n            }\n        }\n    }\n\n    generateKey();\n\n\u003c/script\u003e\n\n```\n\n### Sign / Verify Data with HMAC SHA256 ###\n\n```JavaScript\n\n\u003cscript src='nfcrypto.js'\u003e\u003c/script\u003e\n\u003cscript\u003e\n\n    var cryptoSubtle = window.nfCrypto.subtle;\n    var data = \"This is some data to sign\",\n        hmacKey,\n        signature;\n\n    function generateKey() {\n        var genOp = cryptoSubtle.generateKey({ name: \"HMAC\", params: { hash: {name: \"SHA-256\"} } });\n        genOp.oncomplete = function (e) {\n            hmacKey = e.target.result;\n            signData();\n        };\n    }\n    \n    function signData() {\n        var signOp = cryptoSubtle.sign(\n            { name: \"HMAC\", params: { hash: \"SHA-256\" } },\n            hmacKey,\n            text2ua(data)\n        );\n        signOp.oncomplete = function (e) {\n            signature = e.target.result;\n            verifyData();\n        };\n    }\n    \n    function verifyData() {\n        var verifyOp = cryptoSubtle.verify(\n            { name: \"HMAC\", params: { hash: \"SHA-256\" } },\n            hmacKey,\n            signature,\n            text2ua(data)\n        );\n        verifyOp.oncomplete = function (e) {\n            if (e.target.result) {\n                window.alert(\"Round-trip hmac sign/verify works!\");\n            }\n        };\n    }\n\n    generateKey();\n    \n\u003c/script\u003e\n\n```\n\n### RSA Encryption / Decryption ###\n\n```JavaScript\n\n\u003cscript src='nfcrypto.js'\u003e\u003c/script\u003e\n\u003cscript\u003e\n\n    var cryptoSubtle = window.nfCrypto.subtle;\n    var clearText = \"This is some data to encrypt\";\n    var pubKey, privKey;\n    var cipherText;\n    \n    // generate a 1024-bit RSA key pair for encryption\n    function generateKey() {\n        var genOp = cryptoSubtle.generateKey({\n            name: \"RSAES-PKCS1-v1_5\",\n            params: {\n                modulusLength: 1024,\n                publicExponent: new Uint8Array([0x01, 0x00, 0x01]) // Fermat F4\n            }\n        }, false);\n        genOp.oncomplete = function (e) {\n            pubKey  = e.target.result.publicKey;\n            privKey = e.target.result.privateKey;\n            exportKey();\n        }\n    }\n    \n    // export the public key in SPKI format in order to send it to the peer\n    function exportKey() {\n        var exportOp = cryptoSubtle.exportKey(\"spki\", pubKey);\n        exportOp.oncomplete = function (e) {\n            var pubKeySpki = e.target.result;\n            // here you would send pubKeySpki to peer\n            encryptData();\n        }\n    }\n    \n    // simulate peer encryption by encrypting clearText with the public key\n    function encryptData() {\n        var encryptOp = cryptoSubtle.encrypt(\n            { name: \"RSAES-PKCS1-v1_5\" },\n            pubKey,\n            text2ua(clearText)\n        );\n        encryptOp.oncomplete = function (e) {\n            cipherText = e.target.result;\n            decryptData();\n        }\n    }\n    \n    // pretend the cipherText was received from the peer, and decrypt it\n    // with the private key; should get the same clearText back\n    function decryptData() {\n        var decryptOp = cryptoSubtle.decrypt({ name: \"RSAES-PKCS1-v1_5\" }, privKey, cipherText);\n        decryptOp.oncomplete = function (e) {\n            var clearText2 = ua2text(e.target.result);\n            if (clearText2.valueOf() == clearText.valueOf()) {\n                window.alert(\"Round-trip RSA encrypt/decrypt successful!\");\n            }\n        }\n    }\n    \n    generateKey();\n    \n\u003c/script\u003e\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetflix%2Fnfwebcrypto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetflix%2Fnfwebcrypto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetflix%2Fnfwebcrypto/lists"}