diafygi / webcrypto-examples Goto Github PK
View Code? Open in Web Editor NEWWeb Cryptography API Examples Demo: https://diafygi.github.io/webcrypto-examples/
License: GNU General Public License v2.0
Web Cryptography API Examples Demo: https://diafygi.github.io/webcrypto-examples/
License: GNU General Public License v2.0
I exctracted pkcs#8 private key with the help of other JS library (forge). After that I converted pkcs8 to PEM (stripped "BEGIN, END" headers and footers) and tried to give that key to standart web crypto API function:
window.crypto.subtle.importKey(
"pkcs8", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
//der,
//der.getBytes().buffer,
b64ToArrayBuffer(PEM_headers_stripped);
//b64ToArrayBuffer(PEM_headers_NOT_stripped);
{ //these are the algorithm options
name: "RSASSA-PKCS1-v1_5",
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
},
false, //whether the key is extractable (i.e. can be used in exportKey)
["sign"] //"verify" for public key import, "sign" for private key imports
)
.then ...
and in console recieving message "DataError", code: 0
.
You can see above, I tried to pass PEM without stripping headers, passed key in der format but all my efforts failed.
May be you know, how pass a pkcs8 in PEM format to web crypto?
Thanks.
I'm sorry for asking almost similar question to the previous one but I couldn't resolve it by myself.
How RSA public key to web crypto? pkcs#8 relevant only for private key, for public keys I may specify "raw" or "spki". I tried stripped and not stripped PEM with importKey("raw"...), no success. I also tried "raw" and ArrayBuffer(pubKeytoAsn->toDer.getBytes) and again failed.
It seems I have to manually construct JSON parameter in the example below.
window.crypto.subtle.importKey(
"jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
{ //this is an example jwk key, other key types are Uint8Array objects
kty: "RSA",
e: "AQAB",
n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE",
alg: "RS256",
ext: true,
},
A saw n
and e
attributes in my public key but I didn't understand is 'n' valuein JSON a base64 of key's n-array which has 74 elements?
In short, I have e=65537, n=array of 74 integers, how can I convert it to jwk? My algo params are "RSASSA-PKCS1-v1_5", hash: {name: "SHA-256"}
.
Thanks.
I just want to say that this is awesome. Thanks a lot ๐
Just wanted to drop a short note to say it's nice to see people documenting this API.
You might be interested to check out Google's unittests: https://chromium.googlesource.com/chromium/blink/+/master/LayoutTests/crypto/subtle/
And MS has some good docs, but outdated since they Web Crypto API changed after they implemented it:
https://msdn.microsoft.com/en-us/library/ie/dn302338%28v=vs.85%29.aspx
(I'm not sure if this is appropriate for a github issue but I couldn't find a better place)
In the "Web Cryptography API Live Table" some algorithms are marked as "Recommended" and others are "Discouraged! Only use for backwards compatibility!" What is the source of this classification?
I had a quick look at spec and didn't find it there. Though I did find "suggested" algorithms here and according to the list AES-CBC
is suggested/recommended, while according to the project's table it's AES-GCM
which is recommended and all other cypher modes are "discouraged".
One small fix:
By default the HMAC's length parameter is the size of hash function's block, not the size of hash output. So for SHA-1 and SHA-256 that would be 512 bits, for SHA-384 and SHA-512 1024 bits.
This is unlike most other libraries, where the output size is equal to the hash output size.
See http://www.w3.org/TR/WebCryptoAPI/#hmac-keygen-params
Thanks!
The PBKDF2 example only features 1000 iterations. That's quite low and much more are usually recommend.
for example refer this site : mithunvp.com/using-angular-2-asp-net-mvc-5-visual-studio/ open console (f12) and type window.crypto.subtle
it returns undefined
. Can you please tell me what im doing wrong here or are there are any Pure JS libraries to generate crypto.subtle.importKey() ??
Does webcrypto allow for the deterministic generation of RSA key pairs from a seed?
On my browser (FF 61.0.2 on macOS) the PBKDF2+deriveKey() square is marked N/A, with the tooltip AESCBC is not defined
, even though I can actually use PBKDF2+deriveKey() on this browser. Looking at the source code, it seems like the problem is that the AESCBC
variable is defined after many of the places that use it, but this only causes a failure when the relevant promises resolve quickly enough.
Hi,
I was experimenting with your examples to try to recreate a browser version of:
https://www.npmjs.com/package/jwt-simple
Here is a gist to explain end goal (although this gist doesn't work):
https://gist.github.com/mattmazzola/1eafd7aea79e082982da203ec0405997
When attempting to import the key I am receiving the error:
undefined:1 Uncaught (in promise) DOMException: The JWK member "k" could not be base64url decoded or contained padding
I was using this example: https://github.com/diafygi/webcrypto-examples#hmac---importkey
I know the trailing equal signs indicate there is padding on the key ==
, but I'm not sure how to remove it and still import using the same method. It seems like I would have to convert it to an ArrayBuffer and then remove the trailing 0's somehow, but then if we have to use raw key import it makes using jwk seems less useful and I thought there must be a better way or perhaps the import jwk should just handle this for us.
Thanks for your repo, it was really helpful (if not vital) to get started :)
I have a ECDSA P-384 public key as PEM chain that I fetch from a public URL:
-----BEGIN CERTIFICATE-----
MIIC0DCCAlUCCQDh7ZXFZjOO+jAKBggqhkjOPQQDAjCB0DELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHDAa
BgNVBAoME01vemlsbGEgQ29ycG9yYXRpb24xNTAzBgNVBAsMLEF1dG9ncmFwaCBm
b3IgS2ludG8gU2V0dGluZ3MgRGV2IGVudmlyb25tZW50MRYwFAYDVQQDDA1BdXRv
Z3JhcGggWDVVMScwJQYJKoZIhvcNAQkBFhhzdG9yYWdlLXRlYW1AbW96aWxsYS5j
b20wHhcNMTYwNDI5MTQ1ODA4WhcNMTcwNDI5MTQ1ODA4WjCB0DELMAkGA1UEBhMC
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcx
HDAaBgNVBAoME01vemlsbGEgQ29ycG9yYXRpb24xNTAzBgNVBAsMLEF1dG9ncmFw
aCBmb3IgS2ludG8gU2V0dGluZ3MgRGV2IGVudmlyb25tZW50MRYwFAYDVQQDDA1B
dXRvZ3JhcGggWDVVMScwJQYJKoZIhvcNAQkBFhhzdG9yYWdlLXRlYW1AbW96aWxs
YS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAS12UsecmKNRm4+L+jt1++/dENE
EJIICW7X7q8sbaKKlbZWGkcgHqGWrGrIzK0wgMjtLiRKIwwp7izx+XEgueku7K/o
bAKrURi/twi8DGCWOU7JV4Os+MV+pLLab2ehGWcwCgYIKoZIzj0EAwIDaQAwZgIx
AKtsG9nBvvgc81gHZCiVwYgK6qdw1B9eHloKN6aCRfppth/2vLwn4EaB7cmBiI67
UwIxALKkJz8tMlCloUgFaXuuzcoP16O1EB7l9RNM16hrA7Dz3NWMGCUMxSSYBiFo
WHFmvQ==
-----END CERTIFICATE-----
And would like to import it :
const stripped = pemChain.split("\n").slice(1, -2).join("");
const binaryKey = base64ToBinary(stripped);
const usages = ["verify"]; //"verify" for public key import, "sign" for private key imports
return window.crypto.subtle.importKey("spki", binaryKey, {
name: "ECDSA",
namedCurve: "P-384"
},
false, //whether the key is extractable (i.e. can be used in exportKey),
usages
).catch((e) => console.error(e));
function base64ToBinary(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array( len );
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
}
But it throws with DataError: "Data provided to an operation does not meet requirements"
and I can't figure out where to start :)
I will continue to investigate and keep you posted...
I'm working on an example of my own, but I'm having some trouble.
(my example: http://coolaj86.github.io/web-crypto-utahjs-preso)
I found a bit of code to convert back and forth between utf8 and TypedArrays and that seems to be working just fine.
(unibable: https://github.com/coolaj86/unibabel-js)
However, the "encrypted" buffer isn't the length I would expect and it can't be decrypted.
I think I'm missing something. To you see anything out of order here?
'use strict';
var webcrypto = window.crypto || window.msCrypto || window.webkitCrypto || window.mozCrypto;
var keyStr = 'VzC2coGPrvecrigzB38DRLGiwVrgiwnQznyrD9BYxAk=';
var keyBuf = window.Unibabel.base64ToArr(keyStr);
var message = "this is a secret message";
var ivLen = (128 / 8);
var iv = new Uint8Array(ivLen); // defaults to zero
var arrb = window.Unibabel.strToUtf8Arr(message);
var data = arrb.buffer;
console.log('message as buffer', arrb.length);
console.log(arrb);
console.log('keyBuf', keyBuf.length);
console.log(keyBuf);
webcrypto.subtle.importKey(
"raw",
keyBuf,
{ name: "AES-CBC" },
true,
["encrypt", "decrypt"]
)
.then(function(key){
//returns the symmetric key
console.log('key', key);
return window.crypto.subtle.encrypt(
{ name: "AES-CBC", iv: iv },
key, //from generateKey or importKey above
data //ArrayBuffer of data you want to encrypt
).then(function(encrypted){
//returns an ArrayBuffer containing the encrypted data
// TODO base64
//console.log(new Uint8Array(encrypted));
console.log('encrypted');
console.log(new Uint8Array(encrypted));
console.log(new Uint8Array(encrypted).length);
console.log('encrypted', window.Unibabel.arrToBase64(new Uint8Array(encrypted)));
window.crypto.subtle.decrypt(
{ name: "AES-CBC", iv: iv },
key, //from generateKey or importKey above
data //ArrayBuffer of data you want to encrypt
)
.then(function(decrypted){
//returns an ArrayBuffer containing the encrypted data
console.log(new Uint8Array(encrypted));
console.log('decrypted', window.Unibabel.arrToBase64(new Uint8Array(decrypted)));
})
// error handling
.catch(function(err){
console.error(err);
});
})
.catch(function(err){
console.error(err);
});
})
.catch(function(err){
console.error(err);
});
is there any example code with the DHs to encrypt data then trans to others?
Hi, thanks for this, this has been my #1 frequently visited website in the last couple of months.
I have a question. When I look at the demo page at https://diafygi.github.io/webcrypto-examples/ I understand why some of them are "not recommended" and colored out as red, but don't understand why all the RSA APIs are marked as "not recommended".
I don't think there's anything wrong with RSA algorithms, in fact some people don't trust ECC algorithms because of a possible NSA backdoor and also the fact that it could be more vulnerable to quantum computing, etc. I think it's all subjective, and I personally plan on using RSA for my application instead of ECC for these reasons. (My application is not resource constrained so don't really need the keys to be short)
I was wondering if I'm seeing this wrong or if there was a reason behind this decision. Thank you!
Hi,
All the functions that produce "jwk" produce ArrayBuffer, which is clearly different (a bigger) than the "raw" key, but it's always ArrayBuffer object and not something I appear to be able to convert to JSON (as the JSON Web Key spec suggests) like using JSON.stringify. (https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey)
How can get I convert it to the right format?
Do browsers really support generating HMAC keys with PBKDF2? Both Chrome and Firefox seem to complain when I pass {name:"HMAC"} to deriveKey in the 3rd parameter. I can't seem to find a definitive answer anywhere.
Anyone tested this library methods, such as sign, with a python library to verify the signature?
Hi,
I am trying to use RSA public key using RSACryptoServiceProvider and use it for encryption through window.crypto.subtle but ending with Cryptography_OAEPDecoding upon decryption.
//Generating public key:
var cspParams = new CspParameters { KeyContainerName = containerName };
using (var rsa = new RSACryptoServiceProvider(cspParams))
{
var rsaparameters = rsa.ExportParameters(true);
var base64ModulusKey = GetModulusKey(rsaparameters);
return base64ModulusKey;
}
Encryption through window.crypto.subtle:
var jwk_base64 = base64ModulusKey.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
window.crypto.subtle.importKey(
"jwk",
{
kty: "RSA",
e: "AQAB",
n: jwk_base64,
alg: "RSA-OAEP-256",
ext: true,
},
{ name: "RSA-OAEP", hash: { name: "sha-256" } },
false,
["encrypt"]);
window.crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
cryptoKey,
inputMessageBytes
).then(function(encrypted){
console.log("base64 encrypted text: " + arrayToBase64String(new Uint8Array(encrypted)));
});
//Decryption using private key:
using (var rsa = new RSACryptoServiceProvider(cspParams))
{
decryptedBytes = rsa.Decrypt(encryptedBytes, true);
}
Thanks in advance!
When I try to run your Live Table on IE11 I see a bunch of errors in the console:
SCRIPT438: Object doesn't support property or method 'then'
webcrypto-examples (127,25)
...
It looks like you are using Promises which IE11 does not support. Perhaps a polyfill will help? https://github.com/jakearchibald/es6-promise
Thanks for the all the examples; very, very helpful!
Guys,
Now you do not want such simple and almost unusefull examples because in PKIjs we got real using of almost all Web Cryptography API algorithm making real PKI / CMS data (certificates, CRL, PKCS#10, OCSP, TSP, CMS Signed Data, CMS Enveloped Data).
Hi,
As you know following example is explains encryption for the single public key.
https://github.com/diafygi/webcrypto-examples#rsa-oaep---encrypt
So is there any way to encrypt data for multiple public key (so multiple key owner can decrypt data using their private key).
If that is not possible using RSA-OAEP, can you please suggest way for the same?
Thanks
The ECDH examples output the raw bits from the ECDH secret value, either directly or into the importKey operation of AES-CTR. As I pointed out on the WebCrypto spec page this is not secure as the secret value is not uniformly random. The recommendation is usually to pass the value through some key derivation function such as HKDF including some context information such as the public keys used in the agreement (better: a hash of the full transcript of messages exchanged up to that point). See for instance Chapter 11 of Serious Cryptography for a discussion of the issues with using the shared secret directly.
I think it should be possible to create an example that passes the ECDH secret bits into HKDF and then into AES-CTR importKey.
Having the following code I can encrypt a small text file with some small text in it, but when I try with a 1MB text file I get DOMException.
I tried with the same files and even bigger ones with AES and everything worked well. Is there a limit of a file that can be encrypted with RSA-OAEP encrypt method?
var encryptFile = function(keyPair, file) {
var vector = crypto.getRandomValues(new Uint8Array(16));
window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
iv: vector
//label: Uint8Array([...]) //optional
},
keyPair.publicKey, //from generateKey or importKey above
file//ArrayBuffer of the data
)
.then(function(encrypted){
//returns an ArrayBuffer containing the decrypted data
console.log(encrypted);
})
.catch(function(err){
console.error(err);
});
};
What's about to collect some result via screenshot (see #14 ) in the Wiki?!?
Almost all cells are empty
You use ext: true
in many of the JWK examples. I couldn't find reference to it in the spec at https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
Is it deprecated? new? What did / does it mean?
"jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
{ //this is an example jwk key, other key types are Uint8Array objects
kty: "RSA",
e: "AQAB",
n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE",
alg: "RS256",
ext: true,
},
Because of promise .then() usage. See also: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Browser_compatibility
Maybe https://github.com/taylorhakes/promise-polyfill will help here?!?
First, thanks for the great examples.
I'm still a novice with javascript.
I'm trying to mix FileAPI with webcrypto
I would like to select a file in an input type="file" and get the same hash it would obtain when executing sha1sum via terminal
$ sha1sum LICENSE.txt
23a1f87d806ce0330b3d85485e399a5f9f553409 LICENSE.txt
My current doubt is how transform ArrayBuffer get HEX in same output HEX format of sha1sum Linux command.
my test code is this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="" enctype="multipart/form-data">
<p>
<label for="id_file">File:</label>
<input id="id_file" name="file_input" type="file">
</p>
<p>
<label for="id_checksum">checksum:</label>
<input id="id_checksum" maxlength="1000" name="checksum" type="text">
</p>
</form>
<script>
function arrayBuffer_to_hex(array_b) {
// what should I do here
return array_b;
}
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// Loop through the FileList and generate shasum
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
//if (!f.type.match('image.*')) {
// continue;
//}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function (theFile) {
return function (e) {
window.crypto.subtle.digest(
{
name: "SHA-1"
},
e.target.result
)
.then(function (hash) {
//
var hex_value = arrayBuffer_to_hex(hash);
console.log(hex_value);
document.getElementById('id_checksum').value = hex_value;
})
.catch(function (err) {
console.error(err);
});
};
})(f);
// Read in the image file as a data URL.
reader.readAsArrayBuffer(f);
}
}
document.getElementById('id_file').addEventListener('change', handleFileSelect, false);
</script>
</body>
</html>
I am facing an issues on bulk data encryption using rsa algorithm and also aes algorithm..Is there any other way to encrypt and decrypt the data.plz suggest me a solution
Hello,
would be useful to be able to switch on verbose (and the loud setting for errors) to get the actual result objects dumped to web console of possible. Could be triggered with a URL parameter or a dropdown control (so you don't need to modify the source on the live page).
(Sorry JS is not my domain otherwise I would provide patch).
Hey , I try to use 'importkey' on safari 11 and also on outlook for mac and both I get error.
window.crypto.subtle.importKey( "jwk", { "kty": "RSA", "e": difensoPublicKeyE, "n": difensoPublicKeyN, "alg": "RSA-OAEP", "ext": true }, { / name: "RSA-OAEP", hash: { name: "SHA-1" }, }, true, ["encrypt"] ).then(function (publicKey) {
Then I get this error:
OpeartionTypeError: Member JsonWebKey.kty is required and must be an instance of DOMString
Not matter what I try it's same error... maybe someone can help please?
Thx
Check please those functions.
It seems that algorithm must be the same as for encrypt/decrypt - {name: string, label?: ArrayBufferView}
https://code.google.com/p/chromium/issues/detail?id=499573#c4
The usages array needs to be ["encrypt", "decrypt"] for the RSA-OAEP encryption test.
Any suggestions on how to implement public key recovery with WebCrypto ECDSA?
How is (r,s) encoded in the output buffer of sign
?
Is it just r = [0,32)
and s = [32,64)
for curve = P-256
(docs) ?
Seams like elliptic.js implements the recovery and it should be possible to import the recovered public key via jwk back into WebCrypto ...
It would appear the algorithm was changed from NIST SP 800-108 to IETF RFC 5869, and it was renamed to HKDF (so HKDF-CTR is no longer part of the standard?). w3c/webcrypto#27
Would it be better to replace the HKDF-CTR example or somehow mark it as obsolete and add a HKDF example separately?
example: https://github.com/mozilla/send/blob/9410defab6156d29bb705f73aefbd09ec588678e/app/fileSender.js#L126-L140 (does not use the Salt)
It's good with all example but a short summary/desc of what they are good for would be appreciated. Also what the differences between all AES is
Hi @diafygi,
thanks for sharing the examples!
Is it possible to use a key pair to encrypt / decrypt and sign / verify?
Hello! I'm making browser's extensions for every browser. I use webcrypto for chrome and mozilla and it works perfect, but the same code (i replace crypto.subtle to crypto.webkitSubtle) isn't work correctly with Safari. I use RSA-OAEP with Sha-512 hash.
It's correctly generate keys and export them to jwk, but i can't encrypt or decrypt anything with this keys. It is even don't show error just do nothing.
Can you help pls, how use this in Safari?
Thanks in advance.
base64 encoded buffers
I can do a pull as well to add these in
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.