Ceci est une ancienne révision du document !
Cette page résume des opérations similaires entre WebCrypto et d'autres outils
Pour importer une clé en JavaScript, le format PKCS#8 est préféré
$ openssl pkcs8 -topk8 -nocrypt -in rsakey.pem -out rsakey.pkcs8 # converti pkcs8
Convertir une clé PKCS#8 format PEM vers un ArrayBuffer utilisable avec crypto.subtle.importKey
function b64Decode (text) { let s = atob(text.trim().replace(/\r?\n|\r/g, '')) const buffer = new ArrayBuffer(s.length) const bview = new Uint8Array(buffer) for (let i = 0; i < s.length; i++) { bview[i] = s.charCodeAt(i) } return buffer } function readPEM (text) { const pemRegex = /^-----BEGIN (?:PRIVATE|PUBLIC) KEY-----$([a-zA-Z0-9\/\+=\r\n]*)^-----END (?:PRIVATE|PUBLIC) KEY-----$/mg let m = pemRegex.exec(text) if (m && m.length > 1) { return b64Decode(m[1]) } return undefined }
Convertir un ArrayBuffer obtenu avec crypto.subtle.exportKey (avec une mise en forme similaire à OpenSSL)
function b64Encode (buffer) { let txt = '' let b64 = btoa(String.fromCharCode.apply(null, new Uint8Array(buffer))) for (let i = 0; i < (Math.ceil(b64.length / 64)); i++) { txt += b64.substring(i * 64, (i + 1) * 64) + "\n" } return txt } function writePEM (buffer, priv = false) { let txt = `-----BEGIN ${priv ? 'PRIVATE' : 'PUBLIC'} KEY-----` + "\n" txt += b64Encode(buffer) return txt + `-----END ${priv ? 'PRIVATE' : 'PUBLIC'} KEY-----` }
OpenSSL génère, avec genrsa, une clé au format pkcs#1 codé avec PEM
$ openssl genrsa -F4 2048 > rsakey.pem # clé privée 2048bits pkcs1 $ openssl rsa -in rsakey.pem -pubout > rsapub.pem # clé publique
function genKeyPair() { return new Promise((resolve, reject) => { /* same as openssl genrsa -F4 2048 */ crypto.subtle.generateKey( { name: 'RSA-PSS', hash: 'SHA-256', modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]) }, true, ['sign', 'verify']).then((key) => { Promise.all([ crypto.subtle.exportKey('pkcs8', key.privateKey), crypto.subtle.exportKey('spki', key.publicKey) ]).then((keys) => { resolve([writePEM(keys[0], true), writePEM(keys[1], false)]) }) }) }) }
echo -n "Texte à signer" | openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -sign fromjs.key -out - - | base64
function signFromPKCS8 (text, privkey) { return new Promise((resolve, reject) => { const key = readPEM(privkey) if (key) { crypto.subtle.importKey( 'pkcs8', key, { name: 'RSA-PSS', hash: { name: 'SHA-256' } }, false, [ 'sign' ] ).then((key) => { crypto.subtle.sign( { name: 'RSA-PSS', saltLength: 0 }, key, (new TextEncoder).encode(text) ).then((signed) => { resolve(b64Encode(signed)) }) }) } }) }
$ base64 -d < fromjs.sig - > fromjs.bin.sig $ echo -n "Texte à signer" | openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -verify fromjs.pem -signature fromjs.bin.sig -
function verifyFromPKCS8 (text, signature, pubkey) { return new Promise((resolve, reject) => { const cert = readPEM(pubkey) if (cert) { crypto.subtle.importKey( 'spki', cert, { name: 'RSA-PSS', hash: { name: 'SHA-256' } }, false, [ 'verify' ] ).then((key) => { crypto.subtle.verify( { name: 'RSA-PSS', saltLength: 0 }, key, b64Decode(signature), (new TextEncoder).encode(text) ).then((verified) => { resolve(verified) }) }) } }) }