mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-05-28 14:41:41 +00:00
152 lines
3.1 KiB
JavaScript
152 lines
3.1 KiB
JavaScript
'use strict'
|
|
|
|
const webcrypto = require('../webcrypto')
|
|
const randomBytes = require('../random-bytes')
|
|
|
|
exports.utils = require('./rsa-utils')
|
|
|
|
exports.generateKey = async function (bits) {
|
|
const pair = await webcrypto.get().subtle.generateKey(
|
|
{
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
modulusLength: bits,
|
|
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
hash: { name: 'SHA-256' }
|
|
},
|
|
true,
|
|
['sign', 'verify']
|
|
)
|
|
|
|
const keys = await exportKey(pair)
|
|
|
|
return {
|
|
privateKey: keys[0],
|
|
publicKey: keys[1]
|
|
}
|
|
}
|
|
|
|
// Takes a jwk key
|
|
exports.unmarshalPrivateKey = async function (key) {
|
|
const privateKey = await webcrypto.get().subtle.importKey(
|
|
'jwk',
|
|
key,
|
|
{
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
hash: { name: 'SHA-256' }
|
|
},
|
|
true,
|
|
['sign']
|
|
)
|
|
|
|
const pair = [
|
|
privateKey,
|
|
await derivePublicFromPrivate(key)
|
|
]
|
|
|
|
const keys = await exportKey({
|
|
privateKey: pair[0],
|
|
publicKey: pair[1]
|
|
})
|
|
|
|
return {
|
|
privateKey: keys[0],
|
|
publicKey: keys[1]
|
|
}
|
|
}
|
|
|
|
exports.getRandomValues = randomBytes
|
|
|
|
exports.hashAndSign = async function (key, msg) {
|
|
const privateKey = await webcrypto.get().subtle.importKey(
|
|
'jwk',
|
|
key,
|
|
{
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
hash: { name: 'SHA-256' }
|
|
},
|
|
false,
|
|
['sign']
|
|
)
|
|
|
|
const sig = await webcrypto.get().subtle.sign(
|
|
{ name: 'RSASSA-PKCS1-v1_5' },
|
|
privateKey,
|
|
Uint8Array.from(msg)
|
|
)
|
|
|
|
return Buffer.from(sig)
|
|
}
|
|
|
|
exports.hashAndVerify = async function (key, sig, msg) {
|
|
const publicKey = await webcrypto.get().subtle.importKey(
|
|
'jwk',
|
|
key,
|
|
{
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
hash: { name: 'SHA-256' }
|
|
},
|
|
false,
|
|
['verify']
|
|
)
|
|
|
|
return webcrypto.get().subtle.verify(
|
|
{ name: 'RSASSA-PKCS1-v1_5' },
|
|
publicKey,
|
|
sig,
|
|
msg
|
|
)
|
|
}
|
|
|
|
function exportKey (pair) {
|
|
return Promise.all([
|
|
webcrypto.get().subtle.exportKey('jwk', pair.privateKey),
|
|
webcrypto.get().subtle.exportKey('jwk', pair.publicKey)
|
|
])
|
|
}
|
|
|
|
function derivePublicFromPrivate (jwKey) {
|
|
return webcrypto.get().subtle.importKey(
|
|
'jwk',
|
|
{
|
|
kty: jwKey.kty,
|
|
n: jwKey.n,
|
|
e: jwKey.e
|
|
},
|
|
{
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
hash: { name: 'SHA-256' }
|
|
},
|
|
true,
|
|
['verify']
|
|
)
|
|
}
|
|
|
|
/*
|
|
|
|
RSA encryption/decryption for the browser with webcrypto workarround
|
|
"bloody dark magic. webcrypto's why."
|
|
|
|
Explanation:
|
|
- Convert JWK to nodeForge
|
|
- Convert msg buffer to nodeForge buffer: ByteBuffer is a "binary-string backed buffer", so let's make our buffer a binary string
|
|
- Convert resulting nodeForge buffer to buffer: it returns a binary string, turn that into a uint8array(buffer)
|
|
|
|
*/
|
|
|
|
const { jwk2pub, jwk2priv } = require('./jwk2pem')
|
|
|
|
function convertKey (key, pub, msg, handle) {
|
|
const fkey = pub ? jwk2pub(key) : jwk2priv(key)
|
|
const fmsg = Buffer.from(msg).toString('binary')
|
|
const fomsg = handle(fmsg, fkey)
|
|
return Buffer.from(fomsg, 'binary')
|
|
}
|
|
|
|
exports.encrypt = function (key, msg) {
|
|
return convertKey(key, true, msg, (msg, key) => key.encrypt(msg))
|
|
}
|
|
|
|
exports.decrypt = function (key, msg) {
|
|
return convertKey(key, false, msg, (msg, key) => key.decrypt(msg))
|
|
}
|