-
Notifications
You must be signed in to change notification settings - Fork 52
feat: Add (rsa)pubKey.encrypt and (rsa)privKey.decrypt #125
Conversation
3e2c63d
to
02753e1
Compare
1c0eabe
to
61149b5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mkg20001 support needs to be shimmed for the browser as it was before
61149b5
to
55c6908
Compare
Would need some help with finishing this pr. Anyone mind helping here? |
Currently trying to implement this, anyone mind helping? |
What’s the main blockers you are hitting, @mkg20001? |
@daviddias The problem is that webcrypto requires And that's when I decided to just push this incomplete thing that's mostly just an attempt at modifying the jwk to fool webcrypto into thinking it's the right format (I'm guessing contents are identical for both formats because nodeJS allows re-using the same key for encryption and signing, I guess I'm wrong in terms of the JWK contents not needing conversion) and work on another solution based on node-forge. Turns out it's a mess, because encodings are for some reason always messed up (binary <-> utf8). Afterwards I found a stackoverflow answer, which doesn't include any code and advice to not do that. |
Could you explain why RSA encryption suddenly is used/required, and why that is? |
@dignifiedquire libp2p/js-libp2p-stardust#7 is the reason this is being required. It really would make a lot of sense to have those APIs too, because I don't really see any reason against it. It allows for stuff like not having to use nonce-signatures to confirm the identity of a peer, which would allow an attacker to make the client sign arbitrary data. |
Any updates on this? Is anyone going to help me with this one? Still stuck... |
@jacobheun This PR is blocking libp2p/js-libp2p-webrtc-star#148 and js-libp2p-stardust from being ready-to-use |
If we want to match go-libp2p-crypto, RSA encryption should be PKCS1v15, not OAEP. ref https://github.com/libp2p/go-libp2p-crypto/blob/master/rsa.go#L70 |
Okay, ignore my last comment, you already know that we need PKCS1v15, sorry. The state is pretty bad looking at things, both asmcrypto.js and webcrypto.subtle only implement OAEP for encryption/decryption, and these padding algorithms are different enough that transforming one into the other is either very tricky or not possible. |
It looks like the only viable option in the browser is node-forge: https://github.com/digitalbazaar/forge#rsa |
So without using separate keys for signing and encrypting, which is probably not an option for interop at the moment, we'd need to undo some of the work from #12 to go back to node-forge? It looks like the major impact there is bundle size, or are there other drawbacks there? If size is the major drawback I wonder if it would be worth it to move to a plugin based approach. Although as more keys are supported across the network it will create more issues if we have nodes that only come with support for specific keys. Related issue #122 (asymmetric de/encryption) |
So, I've made a test to test node<->browser compatiblity: 'use strict'
const crypto = require('..')
const { deepEqual } = require('assert').strict
async function main () {
// const id = await crypto.keys.generateKeyPair('rsa', 2048)
const id = await crypto.keys.unmarshalPrivateKey(Buffer.from('CAASqAkwggSkAgEAAoIBAQCk0O+6oNRxhcdZe2GxEDrFBkDV4TZFZnp2ly/dL1cGMBql/8oXPZgei6h7+P5zzfDq2YCfwbjbf0IVY1AshRl6B5VGE1WS+9p1y1OZxJf5os6V1ENnTi6FTcyuBl4BN8dmIKOif0hqgqflaT5OhfYZDXfbJyVQj4vb2+Stu2Xpph3nwqAnTw/7GC/7jrt2Cq6Tu1PoZi36wSwEPYW3eQ1HAYxZjTYYDXl2iyHygnTcbkGRwAQ7vjk+mW7u60zyoolCm9f6Y7c/orJ33DDUocbaGJLlHcfd8bioBwaZy/2m7q43X8pQs0Q1/iwUt0HHZj1YARmHKbh0zR31ciFiV37dAgMBAAECggEADtJBNKnA4QKURj47r0YT2uLwkqtBi6UnDyISalQXAdXyl4n0nPlrhBewC5H9I+HZr+zmTbeIjaiYgz7el1pSy7AB4v7bG7AtWZlyx6mvtwHGjR+8/f3AXjl8Vgv5iSeAdXUq8fJ7SyS7v3wi38HZOzCEXj9bci6ud5ODMYJgLE4gZD0+i1+/V9cpuYfGpS/gLTLEMQLiw/9o8NSZ7sAnxg0UlYhotqaQY23hvXPBOe+0oa95zl2n6XTxCafa3dQl/B6CD1tUq9dhbQew4bxqMq/mhRO9pREEqZ083Uh+u4PTc1BeHgIQaS864pHPb+AY1F7KDvPtHhdojnghp8d70QKBgQDeRYFxo6sd04ohY86Z/i9icVYIyCvfXAKnaMKeGUjK7ou6sDJwFX8W97+CzXpZ/vffsk/l5GGhC50KqrITxHAy/h5IjyDODfps7NMIp0Dm9sO4PWibbw3OOVBRc8w3b3i7I8MrUUA1nLHE1T1HA1rKOTz5jYhE0fi9XKiT1ciKOQKBgQC903w+n9y7M7eaMW7Z5/13kZ7PS3HlM681eaPrk8J4J+c6miFF40/8HOsmarS38v0fgTeKkriPz5A7aLzRHhSiOnp350JNM6c3sLwPEs2qx/CRuWWx1rMERatfDdUH6mvlK6QHu0QgSfQR27EO6a6XvVSJXbvFmimjmtIaz/IpxQKBgQDWJ9HYVAGC81abZTaiWK3/A4QJYhQjWNuVwPICsgnYvI4Uib+PDqcs0ffLZ38DRw48kek5bxpBuJbOuDhro1EXUJCNCJpq7jzixituovd9kTRyR3iKii2bDM2+LPwOTXDdnk9lZRugjCEbrPkleq33Ob7uEtfAty4aBTTHe6uEwQKBgQCB+2q8RyMSXNuADhFlzOFXGrOwJm0bEUUMTPrduRQUyt4e1qOqA3klnXe3mqGcxBpnlEe/76/JacvNom6Ikxx16a0qpYRU8OWz0KU1fR6vrrEgV98241k5t6sdL4+MGA1Bo5xyXtzLb1hdUh3vpDwVU2OrnC+To3iXus/b5EBiMQKBgEI1OaBcFiyjgLGEyFKoZbtzH1mdatTExfrAQqCjOVjQByoMpGhHTXwEaosvyYu63Pa8AJPT7juSGaiKYEJFcXO9BiNyVfmQiqSHJcYeuh+fmO9IlHRHgy5xaIIC00AHS2vC/gXwmXAdPis6BZqDJeiCuOLWJ94QXn8JBT8IgGAI', 'base64'))
const msg = Buffer.from('hello')
const enc = await id.public.encrypt(msg)
const dec = await id.decrypt(enc)
deepEqual(dec, msg)
// seems like there's some padding errors
// browser
const dec1 = await id.decrypt(Buffer.from('fEpJkyAhuM19EQioSsJnBXrQ9oiST77PHmVstho/L5iLIHHIK27uv8IQA7AmDMFutzFyg/q+sGmJ93iWo4FINAoj3iFpdHpAGBtXIpqTg+s0rjUP4shfO+mLje2JjzEdyV8BsdcdGP1MHn4+pMITdx4NxCXqA7HgrotT3vgWo4b22NoiPWqxencGQCGUIvahY3NZ/jrohvbJNkidEjyoX54ziVNYWp54kt2dYvAwzFrtXwgogxCKEeNeGkUkY4kDn+O/8HhnLLQjGeVsWXTi8/lpEjdUB3WLvHuY5HutfirQzbB9QMkOy5gJKxxCLjDU8KZiJQE122rcv6wHu/NX1A==', 'base64'))
deepEqual(dec1, msg)
// node
const dec2 = await id.decrypt(Buffer.from('BBuW8erio4kXA9djU0nDo5KxLwcw8/jDqMy9IyXoDsshwfAI5/bztM5fTIoWjEEaK0spdpqJuyB4tYRqe4uf6jRS8Uyq3zdrPq+XubJHXyFY1v8zH+tk8AIx7TnOg61lTw+G4H53m2QCdvDPQfETkmbLQOLtZLPh2GtG2IeRHov7MfGfR4NEJxX0zu5iHtWBiqJ1XVc0KQO+8MHQurC3Cx9pZJ8PFc58gGqdZhsCUi/ScrR1o8UU9IwdII5zbm7cEMwI+VKmUDAL4vhWkYf5r2MId9+5KtpxUxKvp2iIf4eyUFVxN17HZUBWwbnI6GocksGVZRJUboldJJJGUmeNeg==', 'base64'))
deepEqual(dec2, msg)
}
main() Seems like node-forge does padding differently |
Finally, fixed it (for real this time)! 🎉 |
Nice! Overall this looks good but it more than doubles the bundlesize :/. The majority of that is coming from |
An idea would be to use either a smaller module or make it so it's an optional argument where the user needs to pass in the module, e.g. |
8c65c63
to
b922f7f
Compare
src/keys/rsa-browser.js
Outdated
const forge = require('node-forge') | ||
const pki = forge.pki |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing in the module as an extension sounds like a good approach, at least for now, so we can get this released.
Also, changing this to const pki = require('node-forge/lib/pki')
will also shave off some kb, but the majority comes from pem-jwk
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just found this: https://github.com/libp2p/js-libp2p-crypto/blob/master/src/keys/rsa.js#L28-L29
Also, applied that change and removed the PEM intermediary step for converting JWK to Forge
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, for the bundle size:
The biggest dependency is forge's x509 and asn.1's bignumber, in terms of file size We don't need x509, so once it's clear where that comes from we could possible remove it (unless it's needed) |
pki -> pkcs12 -> x509 |
OT, but noticed that parcel & aegir build exactly the same module in terms of size after minification, but the aegir one is bigger unminified 🤔 Edit: We'd save 400kb by using parcel, because dist/ folder is just
|
chore: update deps chore: add bundlesize to ci
I pushed up a commit to update some other dependencies and add the bundlesize to CI (and also more commitlint from ci). I am only seeing an 11kb increase after your changes, nice work! I think this is reasonable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good! 🚀
Can this also get backported to the non-promise version? |
@mkg20001 yes we can do that, would you be able to open up a PR for that against the v0.16.x branch? |
@jacobheun Sure, will do |
I made a pr #160 |
Fixes libp2p/js-peer-id#80