2016-11-29 17:54:41 +01:00
|
|
|
'use strict'
|
|
|
|
|
2019-07-17 11:17:18 +01:00
|
|
|
const webcrypto = require('../webcrypto')
|
2019-01-08 18:37:03 +00:00
|
|
|
const randomBytes = require('../random-bytes')
|
2016-11-29 17:54:41 +01:00
|
|
|
|
|
|
|
exports.utils = require('./rsa-utils')
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
exports.generateKey = async function (bits) {
|
2019-07-17 11:17:18 +01:00
|
|
|
const pair = await webcrypto.get().subtle.generateKey(
|
2016-11-29 17:54:41 +01:00
|
|
|
{
|
|
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
|
|
modulusLength: bits,
|
|
|
|
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
2019-01-03 08:13:07 -08:00
|
|
|
hash: { name: 'SHA-256' }
|
2016-11-29 17:54:41 +01:00
|
|
|
},
|
|
|
|
true,
|
|
|
|
['sign', 'verify']
|
|
|
|
)
|
2019-07-10 17:15:26 +01:00
|
|
|
|
|
|
|
const keys = await exportKey(pair)
|
|
|
|
|
|
|
|
return {
|
|
|
|
privateKey: keys[0],
|
|
|
|
publicKey: keys[1]
|
|
|
|
}
|
2016-11-29 17:54:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Takes a jwk key
|
2019-07-10 17:15:26 +01:00
|
|
|
exports.unmarshalPrivateKey = async function (key) {
|
2019-07-17 11:17:18 +01:00
|
|
|
const privateKey = await webcrypto.get().subtle.importKey(
|
2016-11-29 17:54:41 +01:00
|
|
|
'jwk',
|
|
|
|
key,
|
|
|
|
{
|
|
|
|
name: 'RSASSA-PKCS1-v1_5',
|
2019-01-03 08:13:07 -08:00
|
|
|
hash: { name: 'SHA-256' }
|
2016-11-29 17:54:41 +01:00
|
|
|
},
|
|
|
|
true,
|
|
|
|
['sign']
|
|
|
|
)
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
const pair = [
|
2016-11-29 17:54:41 +01:00
|
|
|
privateKey,
|
2019-07-10 17:15:26 +01:00
|
|
|
await derivePublicFromPrivate(key)
|
|
|
|
]
|
|
|
|
|
|
|
|
const keys = await exportKey({
|
|
|
|
privateKey: pair[0],
|
|
|
|
publicKey: pair[1]
|
|
|
|
})
|
|
|
|
|
|
|
|
return {
|
2016-11-29 17:54:41 +01:00
|
|
|
privateKey: keys[0],
|
|
|
|
publicKey: keys[1]
|
2019-07-10 17:15:26 +01:00
|
|
|
}
|
2016-11-29 17:54:41 +01:00
|
|
|
}
|
|
|
|
|
2019-01-08 18:37:03 +00:00
|
|
|
exports.getRandomValues = randomBytes
|
2016-11-29 17:54:41 +01:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
exports.hashAndSign = async function (key, msg) {
|
2019-07-17 11:17:18 +01:00
|
|
|
const privateKey = await webcrypto.get().subtle.importKey(
|
2016-11-29 17:54:41 +01:00
|
|
|
'jwk',
|
|
|
|
key,
|
|
|
|
{
|
|
|
|
name: 'RSASSA-PKCS1-v1_5',
|
2019-01-03 08:13:07 -08:00
|
|
|
hash: { name: 'SHA-256' }
|
2016-11-29 17:54:41 +01:00
|
|
|
},
|
|
|
|
false,
|
|
|
|
['sign']
|
2019-07-10 17:15:26 +01:00
|
|
|
)
|
|
|
|
|
2019-07-17 11:17:18 +01:00
|
|
|
const sig = await webcrypto.get().subtle.sign(
|
2019-07-10 17:15:26 +01:00
|
|
|
{ name: 'RSASSA-PKCS1-v1_5' },
|
|
|
|
privateKey,
|
|
|
|
Uint8Array.from(msg)
|
|
|
|
)
|
|
|
|
|
|
|
|
return Buffer.from(sig)
|
2016-11-29 17:54:41 +01:00
|
|
|
}
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
exports.hashAndVerify = async function (key, sig, msg) {
|
2019-07-17 11:17:18 +01:00
|
|
|
const publicKey = await webcrypto.get().subtle.importKey(
|
2016-11-29 17:54:41 +01:00
|
|
|
'jwk',
|
|
|
|
key,
|
|
|
|
{
|
|
|
|
name: 'RSASSA-PKCS1-v1_5',
|
2019-01-03 08:13:07 -08:00
|
|
|
hash: { name: 'SHA-256' }
|
2016-11-29 17:54:41 +01:00
|
|
|
},
|
|
|
|
false,
|
|
|
|
['verify']
|
2019-07-10 17:15:26 +01:00
|
|
|
)
|
|
|
|
|
2019-07-17 11:17:18 +01:00
|
|
|
return webcrypto.get().subtle.verify(
|
2019-07-10 17:15:26 +01:00
|
|
|
{ name: 'RSASSA-PKCS1-v1_5' },
|
|
|
|
publicKey,
|
|
|
|
sig,
|
|
|
|
msg
|
|
|
|
)
|
2016-11-29 17:54:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function exportKey (pair) {
|
|
|
|
return Promise.all([
|
2019-07-17 11:17:18 +01:00
|
|
|
webcrypto.get().subtle.exportKey('jwk', pair.privateKey),
|
|
|
|
webcrypto.get().subtle.exportKey('jwk', pair.publicKey)
|
2016-11-29 17:54:41 +01:00
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
function derivePublicFromPrivate (jwKey) {
|
2019-07-17 11:17:18 +01:00
|
|
|
return webcrypto.get().subtle.importKey(
|
2016-11-29 17:54:41 +01:00
|
|
|
'jwk',
|
|
|
|
{
|
|
|
|
kty: jwKey.kty,
|
|
|
|
n: jwKey.n,
|
2017-12-20 21:11:47 +13:00
|
|
|
e: jwKey.e
|
2016-11-29 17:54:41 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'RSASSA-PKCS1-v1_5',
|
2019-01-03 08:13:07 -08:00
|
|
|
hash: { name: 'SHA-256' }
|
2016-11-29 17:54:41 +01:00
|
|
|
},
|
|
|
|
true,
|
|
|
|
['verify']
|
|
|
|
)
|
|
|
|
}
|
2019-07-12 18:53:56 +02:00
|
|
|
|
2019-10-23 12:55:43 +02:00
|
|
|
// bloody dark magic. webcrypto's why.
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Explanation:
|
|
|
|
- Convert JWK to PEM
|
|
|
|
- Load PEM with nodeForge
|
|
|
|
- Convert msg buffer to nodeForge buffer
|
|
|
|
- Convert resulting nodeForge buffer to buffer
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
const forge = require('node-forge')
|
|
|
|
const pki = forge.pki
|
|
|
|
const jwkToPem = require('pem-jwk').jwk2pem
|
|
|
|
function convertKey (key, pub, msg, handle) {
|
|
|
|
const pem = jwkToPem(key)
|
|
|
|
const fkey = pki[pub ? 'publicKeyFromPem' : 'privateKeyFromPem'](pem)
|
|
|
|
const fmsg = forge.util.hexToBytes(Buffer.from(msg).toString('hex'))
|
|
|
|
const fomsg = handle(fmsg, fkey)
|
|
|
|
return Buffer.from(forge.util.bytesToHex(fomsg), 'hex')
|
|
|
|
}
|
|
|
|
|
2019-07-12 18:53:56 +02:00
|
|
|
exports.encrypt = async function (key, msg) {
|
2019-10-23 12:55:43 +02:00
|
|
|
return convertKey(key, true, msg, (msg, key) => key.encrypt(msg))
|
|
|
|
|
|
|
|
/* key = Object.assign({}, key)
|
2019-07-12 18:53:56 +02:00
|
|
|
key.key_ops = ['encrypt']
|
|
|
|
|
|
|
|
return webcrypto.subtle.importKey(
|
|
|
|
'jwk',
|
|
|
|
key,
|
|
|
|
{
|
|
|
|
name: 'RSA-OAEP',
|
|
|
|
hash: { name: 'SHA-256' }
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
['encrypt']
|
|
|
|
).then((publicKey) => {
|
|
|
|
return webcrypto.subtle.encrypt(
|
|
|
|
{ name: 'RSA-OEAP' },
|
|
|
|
publicKey,
|
|
|
|
Uint8Array.from(msg)
|
|
|
|
)
|
2019-10-23 12:55:43 +02:00
|
|
|
}).then((enc) => Buffer.from(enc)) */
|
2019-07-12 18:53:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
exports.decrypt = async function (key, msg) {
|
2019-10-23 12:55:43 +02:00
|
|
|
return convertKey(key, false, msg, (msg, key) => key.decrypt(msg))
|
|
|
|
|
|
|
|
/* key = Object.assign({}, key)
|
2019-07-12 18:53:56 +02:00
|
|
|
key.key_ops = ['decrypt']
|
|
|
|
|
|
|
|
return webcrypto.subtle.importKey(
|
|
|
|
'jwk',
|
|
|
|
key,
|
|
|
|
{
|
|
|
|
name: 'RSA-OAEP',
|
|
|
|
hash: { name: 'SHA-256' }
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
['decrypt']
|
|
|
|
).then((privateKey) => {
|
|
|
|
return webcrypto.subtle.decrypt(
|
|
|
|
{ name: 'RSA-OAEP' },
|
|
|
|
privateKey,
|
|
|
|
Uint8Array.from(msg)
|
|
|
|
)
|
2019-10-23 12:55:43 +02:00
|
|
|
}).then((dec) => Buffer.from(dec)) */
|
2019-07-12 18:53:56 +02:00
|
|
|
}
|