Openpgpjs: able to encrypt but not decrypt

Created on 23 Mar 2016  路  10Comments  路  Source: openpgpjs/openpgpjs

'use strict';

var openpgp = require('openpgp');
require("openpgp/dist/openpgp.min.js");

openpgp.initWorker({ path:'openpgp.worker.js' });

var options, encrypted;

options = {
    data: 'Hello, World!',      // input as String
    passwords: ['secret stuff'] // multiple passwords possible
};

``` openpgp.encrypt(options).then(function(ciphertext) { encrypted = ciphertext.data; console.log(encrypted); // returning the data: { data: '-----BEGIN PGP MESSAGE-----\r\nVersion: OpenPGP.js v2.1.0\r\nComment: http://openpgpjs.org\r\n\r\nwy4ECQMISFGEu/cXS+Bgw3wvwzgNGVpMh4pyiVcSM2EX4P/PB4IWhVQ0Cl2/\nDkPq0kUBPVKbdsKlOLxqbw+Xm6e0GdVF4YPXOzTcC7ac+Of4UEJHESBnBRc1\nTK3eRGy9x6IoXuOJ62PPfdl0r0q5oQTppR+SzDk=\r\n=czJx\r\n-----END PGP MESSAGE-----\r\n' }

});

options = {
message: openpgp.message.readArmored(encrypted),```
--> error here with


text = text.replace(/[\t\r ]+\n/g, '\n');
^
TypeError: Cannot read property 'replace' of undefined


``````

password: 'secret stuff'
};

openpgp.decrypt(options).then(function(plaintext) {
console.log(plaintext.data);
}

It's not possible to decrypt it?

Most helpful comment

@tanx I've poured through the tests. Still having this issue.

All 10 comments

I found that when variable encrypted goes to

options = {
message: openpgp.message.readArmored(encrypted), // parse armored message
password: 'secret stuff' // decrypt with password
};

it's empty. How to assign the real encrypted for openpgp.message.readArmored(encrypted)?

I'm having the exact same issue.

@tanx I've poured through the tests. Still having this issue.

Hello, exact same issue here. There are so many require functions and all in the general test file which makes it more complicated. I am just trying to encrypt and decrypt (and hopefully sign later) using pure JS.

I have two main problems.

  1. Same problem with @kingleecha. Like he said this line:
    message: openpgp.message.readArmored(encrypted)
    gives error: "Cannot read property 'replace' of undefined" Because the variable 'text' is undefined.

But actually if you console.log(openpgp.message.readArmored(encrypted)) you can see some values. But it gives the error when you call the decrypt function.

  1. I am having a problem of 'promise' I think. If I call the openpgp.generateKey, openpgp.encrypt and openpgp.decrypt functions I cannot pass the results to each other as these functions start at the same time. I had to use a bunch of promise functions or call them inside their 'then' functions.

It would be much easier if there was a basic, pure JS example in my opinion, as I cannot find any other on the web. I was glad I found this topic. Sorry for a long post, hopefully someone can state or correct my mistakes. Here is the full code I could manage:

`



Test PGP

<script>
    console.log(openpgp);

    openpgp.initWorker({ path:'openpgp.worker.js' });

    openpgp.config.aead_protect = true;




    var myKey = {};
    var options, encrypted;

// GENERATE KEYS
options = {
userIds: [{ name:'Jon Smith', email:'[email protected]' }], // multiple user IDs
numBits: 1024,                                            // RSA key size
passphrase: 'super long and hard to guess secret'         // protects the private key

};

openpgp.generateKey(options).then(function(key) {
myKey.privkey = key.privateKeyArmored; // '-----BEGIN PGP PRIVATE KEY BLOCK ... '
myKey.pubkey = key.publicKeyArmored; // '-----BEGIN PGP PUBLIC KEY BLOCK ... '

//ENCRYPTION
options = {
data: 'Hello, World!',                             // input as String (or Uint8Array)
publicKeys: openpgp.key.readArmored(myKey.pubkey).keys,  // for encryption
// privateKeys: openpgp.key.readArmored(myKey.privkey).keys // for signing (optional)

};

openpgp.encrypt(options).then(function(ciphertext) {
myKey.encrypted = ciphertext.data; // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'

// Result of public key, private key and encrypted message.
console.log(myKey);

console.log(openpgp.message.readArmored(myKey.privkey));

//DECRYPTION
options = {
message: openpgp.message.readArmored(myKey.encrypted),     // parse armored message
// publicKeys: openpgp.key.readArmored(pubkey).keys,    // for verification (optional)
privateKey: openpgp.key.readArmored(myKey.privkey).keys[0] // for decryption

};

openpgp.decrypt(options).then(function(plaintext) {
return plaintext.data; // 'Hello, World!'
});

});

});



`

Hi @tahaerden,

  1. I didn't try running your code but one issue I see is that you aren't decrypting the private key you are trying to use to decrypt.
  2. Second is yes, you are using promises incorrectly. You need to chain them to get the full encrypt/decrypt cycle you are looking for. As for this statement:

"It would be much easier if there was a basic, pure JS example in my opinion"

The answer is an emphatic "no", for a couple reasons.

  1. Promises are 'basic' JS as of ES6. I think you meant synchronous instead of asynchronous?
  2. Encryption, generation, and decryption take time. If they were synchronous it would block the main execution thread and destroy the performance of whatever JS app you were trying to build.
  3. Promises are awesome and the way of the future. I suggest you learn how to use and structure them effectively (you don't need all the ugly nesting)--all web developers will need to be able to do this in the near future.

Hello @bartbutler ,

Thanks a lot for your great answer. A couple of clarifications:

  1. Exactly! That was one of the errors I was facing actually. How can I decrypt a private key? openpgp.decrypt(privkey)? Also the person who is decrypting should use his own private key right? In this example it is the same one which is used to encrypt the message. So I guess a logical error there?
  2. Yes indeed the nested functions are ugly. I tried some different ways of using promises. Some worked but they were still ugly. Do you have any suggestions how to use them with promise functions asynchronously? Something similar to promise.all() maybe?

And thanks for putting up with me I am new to some of this :)

Hi @tahaerden,

No problem, but @tanx is right that 95% of these issues can be solved by people reading the docs/tests more carefully.

1.You should look at the test code linked by @tanx. In it the private key is decrypted like this:

privKeyDE.keys[0].decrypt(passphrase);

You then pass privKeyDE.keys[0] to the message decryption. Your logic is fine in terms of the keys--whoever's public key is used to encrypt should be the private key used to decrypt.

  1. You could do something like this (untested)

var encryptMessage = function (plaintext) {
//ENCRYPTION
options = {
data: plaintext, // input as String (or Uint8Array)
publicKeys: openpgp.key.readArmored(myKey.pubkey).keys[0], // for encryption
}

return openpgp.encrypt(options).then(function(result) { return result.data; });
}

var decryptMessage = function(ciphertext) {
//DECRYPTION
options = {
message: openpgp.message.readArmored(ciphertext), // parse armored message
privateKey: privKeyDE.keys[0] // for decryption
}
return openpgp.decrypt(options);
}

var logResult = function(text) {
console.log(text);
}

encryptMessage
.then(logResult)
.then(decryptMessage)
.then(logResult);

This assume you have the keys generated already. If you don't, those are promises too and would be added to the beginning of the chain. But you'll notice the part at the end which controls execution is very clean.

Thanks for jumping in @bartbutler

If you don't like the Promise syntax, here is an excellent post from @rauchg on the async functions coming in ES7. If you're fine with using a transpiler like babel, you can use them in your app today:

https://zeit.co/blog/async-and-await

I'm planning to refactor to async functions internally in OpenPGP.js as well. This should allow easier refactoring of the currently synchronous js hashing to async WebCrypto.

@bartbutler @tanx Thanks both of you for jumping in. I will try your suggestions as soon as possible :)

Was this page helpful?
0 / 5 - 0 ratings