function encrypt(public_key, file) {
var pem_pub_key = sshKeyToPEM(public_key); // convert rsa to pem
var chunks = [];
var buffer = new Buffer(fs.readFileSync(file, 'utf8'));
// work around for 214 character limit for encrypting
// text with small openssh rsa pub key
for (var i = 0; i <= (buffer.length / 214); i++) {
chunks.push(buffer.slice(i * 214, (i * 214) + 214));
}
chunks.forEach(function(chunk) {
var encrypted = crypto.publicEncrypt(pem_pub_key, new Buffer(chunk));
console.log(encrypted.toString('base64'));
});
}
According to the docs, crypto.publicEncrypt uses OAEP by default, so the bulk of the terribleness should mainly be how horribly slow this is. It does clearly indicate that the author has no idea what they're doing, though.Edit: For some reason I thought OAEP included randomness. It does not, which should mean you can guess-and-check the plaintext.
1. Tools to encrypt messages using Github SSH keys are probably not a good idea. They're no more usable than real message encryption solutions, but have far more constraints.
2. You cannot safely use RSA like a normal cipher. RSA is a tool for building crypto protocols. The way you've deployed it here has a serious vulnerability.
If you want to build things that use cryptography, I think you really need to work with a high-level library. Nacl (or libsodium) is a great example of a package that goes out of its way to bulletproof itself.
I'd say we need more effort on small, focus built libraries for tasks such as these. You can talk about how people need to add in Nacl into their project, but actually doing that is simply not possible for many developers.
eg, more libraries like this one: https://github.com/tozny/java-aes-crypto
If you're worried about size, use Tweetnacl:
TweetNaCl is the world's first auditable high-security cryptographic library. TweetNaCl fits into just 100 tweets while supporting all 25 of the C NaCl functions used by applications. TweetNaCl is a self-contained public-domain C library, so it can easily be integrated into applications.
I definitely do not think the proliferation of unvetted, anonymous crypto libraries is a good thing. How many people have the expertise to write this kind of thing? How many have the expertise to evaluate its quality?
For example, the documentation for the linked library says: "we've also added integrity checking in the form of a SHA 256 hash." This is a huge red flag: hashes provide integrity, but not authenticity, which is really what you want here. But then you go and look at the source code and find that they are actually using HMAC-SHA256, which does provide authenticity. So the documentation is not an accurate description of what's going on, and you need to go and look at the source to find out that it really is okay (in this particular aspect, though it doesn't inspire confidence for the future).
My point is not to say that this particular library is terrible or anything. Just that we have limited resources, and we're better off consolidating to a very small number of solutions designed, written, and validated by experts.
https://nodejs.org/api/crypto.html#crypto_crypto_publicencry...
Not sure why it says DSA is supported, the crypto library only supports RSA.
It uses this library that stitches together a PEM from an ssh public key:
https://github.com/dominictarr/ssh-key-to-pem/blob/master/in...
In encryptMessage.js, the plaintext is split into chunks, and then chunks.forEach encrypts each chunk (via crypto.publicEncrypt) independently, and concatenates the chunks to form the ciphertext, aka ECB mode. You shouldn't use ECB mode with any cipher because it is not semantically secure. This is Crypto 101.
In addition, it's a bit wacky to use RSA encryption on your entire message because RSA operations are slow and you are limited to encrypting messages that are the length of your RSA key (well, minus the padding, which is how this developer arrived at the "split plaintext into 214 byte chunks" workaround).
A better solution (in every way) would be to use a "hybrid" encryption scheme, similar to TLS or GPG. To do this, you would:
1. Generate a random key for use with a symmetric cipher (e.g. AES-256) 2. Encrypt the plaintext with the random key, using a secure block mode (e.g. CBC, CTR) 3. Encrypt the random key with the RSA public key 4. Package those things together and share it on Github
Efficient and secure. Also totally unnecessary (you basically just reinvented a subset of GPG) but that's neither here nor there.
- https://www.crypto101.io/ both the presentation and the book.
I think those are good to begin with.