Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Luis Vilca
    @FerLuisxd
    ``` const { keys: [privateKey] } = await openpgp.key.readArmored(process.env.PGP_PRIVATE_KEY)
    await privateKey.decrypt(process.env.PGP_PRIVATE_KEY_PASSPHRASE)
    const message = await openpgp.encrypt({
      message: openpgp.message.fromText(`Hello, World!`), // input as Message object
      publicKeys: (await openpgp.key.readArmored(process.env.PGP_PUBLIC_KEY2)).keys, // for encryption
      armor: false
    })
    console.log(message.message.packets.write())
    const hex = Buffer.from(message.message.packets.write())
    fs.appendFileSync('temp/' + 'test', hex + '\r\n')
    const encryptedData = fs.readFileSync('temp/'+ 'test')
    let encryptedMessage = await openpgp.message.read( encryptedData)
    const  {data:decrypted} = await openpgp.decrypt({
      message: encryptedMessage, // parse armored message
      privateKeys: [privateKey] // for decryption,
    })
    console.log(decrypted) // 'Hello, World!'```
    Luis Vilca
    @FerLuisxd
    Ok finally did it, Will update on the github issue so if Anyone else wants to achieve that will be able to see the solution
    Caleb Callaway
    @cqcallaw
    Hi folks, I've built a browser extension that verifies the detached PGP signatures of dWebsites (i.e. sites hosted on IPFS) using OpenPGP.js. Really glad to have OpenPGP.js to do the heavy lifting. If you'd like to try it out, see https://github.com/cqcallaw/qui. The extension won't (intentionally) share any private data, but constructive criticism and user feedback is of course welcome.
    Daniel Huigens
    @twiss
    Hey @cqcallaw, cool, thanks for sharing!
    I've actually worked on a similar extension before (though not for IPFS), and usually the tricky part is getting the page contents. I've peeked at your code and it seems like you're just doing another fetch of the URL - which normally wouldn't be secure since the server could just respond something different, so then you have to do weird workarounds to make sure it comes from the browser cache etc. But in your case, I guess it's guaranteed by IPFS that fetching the same URL twice returns the same contents? If so that's quite cool ^.^
    Daniel Huigens
    @twiss
    Though - this worries me: https://github.com/cqcallaw/qui/blob/5f413eb79913f22528df3eecba9fd78a3eb98015/main.js#L148-L176
    Is it possible for the response to /index[.html] to be different to the response to /, for example? So that the server could serve a malicious response to / but a valid one to /index? Or does ipfs.localhost resolve / to /index[.html]? (Sorry, I'm not really an expert on IPFS)
    Caleb Callaway
    @cqcallaw

    @twiss thanks for checking it out! Fetching the same IPFS URL twice is very likely to return the same result since IPFS URLs are really a URIs (Uniform Resource Identifiers). The IPFS URI addresses content instead of a location; more at http://docs.ipfs.io.ipns.localhost:8080/concepts/content-addressing/. I should probably change the naming convention in the code.

    If the IPFS URI is resolved to an IPFS CID using a service like ENS (https://ens.domains/), there's a very small window of time in which the first and second fetches could return different results. I think such an attack would be exceptionally difficult to time, as it depends on the state of the Ethereum blockchain changing between two localhost requests. That said, if there's some way to avoid making the second request, I'm all ears, because doubling up on HTTP requests isn't very efficient, even if they're localhost requests.

    WRT the real path concern, maliciously serving different data for / and /index.hml is indeed possible. ipfs.localhost URLs are handled by an IPFS node running on one's local host, so one would have to be running an malicious local node for this attack to be carried out, but it's certainly a legitimate concern. Have you any idea how to address it?
    The extension needs to know the full path so it can construct the signature path; can't use inline signatures because they'd corrupt binary files. The HTTP response for a pathless URL is dependent on server configuration, though; I haven't found any way to determine the full path from HTTP response data alone.
    Daniel Huigens
    @twiss

    I see. So if I understand correctly, the contents at / and /index.html are both fairly constant/deterministic (and you trust this fact, but presumably don't trust that they are the correct contents, and want to verify a PGP signature for this reason?) but not necessarily the same (correct me if I'm wrong).

    So then, what I would recommend is, instead of trying to get the "real filename" of /, to focus only on getting the path of the signature, and then verify that signature against the contents at / (or whatever the URL that the user is looking at is); so that you're reasonably sure that the data you're verifying the signature against is the same as the data the user is seeing. (The way that you find the signature then doesn't matter much, as long as it verifies in the end; but you could just fetch /index.sig or /index.html.sig directly.)

    That said, if there's some way to avoid making the second request, I'm all ears, because doubling up on HTTP requests isn't very efficient, even if they're localhost requests.

    Basically what you want is for the response to be cached somewhere. For me; this was a requirement so I had to "force" the resource to be cached by the browser, which is a bit tricky; but for you, if the server sets normal HTTP Cache headers that should probably be sufficient. Alternatively, maybe the localhost server can or does already cache things?

    Caleb Callaway
    @cqcallaw
    @twiss good idea! I've pushed some updates that removes the "real URL" logic in favor of casting a wider net for signature files. I think it tightens the code up nicely.
    Caleb Callaway
    @cqcallaw
    @twiss the local server is effectively a local cache (that's sort of the point of IPFS--don't want to wait 10 minutes for your request to travel from Mars to Earth and back), but doesn't seem to set Cache Control headers. Looks like it responds with Last-Modified headers, and the browser cache decides whether to use the browser cache based on that header
    Daniel Huigens
    @twiss
    @cqcallaw Makes sense, seems good! :+1:
    Ali Cherry
    @alichry
    Hello peeps, much thanks for the great work!
    Is it possible to encrypt a message using a subkey instead of a primary key? i.e. a openpgp.key.SubKey instead of a openpgp.key.Key. Using a subkey would throw the error "Error encrypting message: privateKey.isPublic is not a function"
    Daniel Huigens
    @twiss
    Hi @alichry :) OpenPGP.js always uses encryption subkeys, you don't have to do anything special for this. They are part of the key.
    If your question is, can you encrypt to a subkey without having the primary key, then the answer is no, you can't, as it's not a valid OpenPGP key
    Ali Cherry
    @alichry

    Hey @twiss :)

    Thank you for the kind reply. From the provided clarification, I understood that OpenPGP.js handles the selection of an encryption key from the list of subkeys, but is it possible to select a specific subkey ?

    My use case is as follows:

    I have an exported OpenPGP key that contains the primary key and one or more subkeys. I loaded the exported key using openpgp.key.readArmored and got an instance of openpgp.key.Key. From there, I selected the desired subkey by iterating over key.getSubkeys() (and of course checking for encryption capabilities).
    I would like to use the selected subkey as the encryption key, any thoughts ?

    Daniel Huigens
    @twiss

    Yes, and no, respectively. OpenPGP.js selects the most recently created valid encryption subkey.

    I see. Could you expand on why you want to select a specific subkey, please? :blush:

    Ali Cherry
    @alichry
    I am working on an Open Source project and would like the user to select a specific subkey, I believe it might be relevant as the user might create an additional subkey just for this purpose
    Daniel Huigens
    @twiss
    Hmhm. In my opinion, selecting the subkeys should be an implementation detail, and not left to the user
    There may be other considerations, such as, a subkey may be expired, or not valid yet
    If the user wants to use different keys for different purposes, they should probably generate separate master keys, IMHO
    Ali Cherry
    @alichry

    How about we specify a specific keyId that is optional in openpgp.encrypt? The underlying function that returns the latest valid encryption subkey can also try to match it against a keyId, just like the current implementation that accepts an optional keyId parameters in many functions to return a specific keyId? I would be happy to start working on this, if you think it's feasible to implement

    Moreover, I understand the reasoning to create a separate OpenPGP key for a different purpose. But I believe having different PGP keys for different purposes adds complexity for the user to keep track of various primary keys. If I am not mistaken, GnuPG allows for encryption of data by specifying a desired subkey which is why this calls for OpenPGP.js to be compatible with the existing conventions

    I am not certain if this is sufficient to make it work: openpgpjs/openpgpjs#1203
    Daniel Huigens
    @twiss

    How about we specify a specific keyId that is optional in openpgp.encrypt? The underlying function that returns the latest valid encryption subkey can also try to match it against a keyId, just like the current implementation that accepts an optional keyId parameters in many functions to return a specific keyId? I would be happy to start working on this, if you think it's feasible to implement

    Hmm, yeah, we could do that :+1: However, we've done a major refactoring in the v5 branch, could you implement it there, instead? There are also many API changes in the v5 branch, that are documented here: https://github.com/openpgpjs/openpgpjs/wiki/V5-Changelog. Implementing it in v5 avoids us having to rebase the v5 branch on top of your changes, or the other way around.

    I am not certain if this is sufficient to make it work: openpgpjs/openpgpjs#1203

    I don't think this would be sufficient, as there is a lot of code beyond that that assumes that we have a full OpenPGP key, and we probably want to keep requiring a valid OpenPGP key, anyway.

    Ali Cherry
    @alichry
    Lovely, thank you for the chat! Very excited to work on the v5 branch
    Daniel Huigens
    @twiss
    Great, thanks as well! Good luck, and lmk if you have any questions :blush:
    will Farrell
    @willfarrell
    Hi, is it possible to sign/verify by passing in the hashAlgorithm/checksum instead of a message? When the digest is known, there is no need to re-calculate it, especially on larger files. Digging into the code, it looks like it is supported, but not exposed. https://github.com/openpgpjs/openpgpjs/blob/master/src/crypto/public_key/elliptic/ecdsa.js#L76
    Daniel Huigens
    @twiss
    Hi @willfarrell :wave:
    For verifying, there may be some way to hack this together, by setting signaturePacket.hashed, and then calling signaturePacket.verify() directly (perhaps with streaming = true, to dissuade it from reading the data directly).
    However, please keep in mind that OpenPGP signatures include some additional metadata into the hash, such as the signature creation time. So if you only know the hash of the file itself, that may not be sufficient.
    will Farrell
    @willfarrell

    @twiss Thank you for the quick reply. I'll take a closer look intosignaturePacket and how I might be able to trick into signing/verifying. That's really good to know that additional metadata is included inside the hash, I'll look in the codebase for how that's applied. That would mean the hash of a file from openpgp wound not match the hash from openssl/shasum/etc, is that right? If so, that would mean when someone verified the detached signature (w/o metadata hashed) not using our system it wouldn't verify.

    

A little background for context; I work on an open data portal (datastream.org) where we currently validate the data schema and creating a digest in web workers during an upload process. This digest is later added to a public ledger (Eth mainnet) for proof of integrity. We're investigating what it could look like to sign the data before the upload starts. Currently i'm imaging the contributor would be given the option to sign after no errors were found in the data schema. Our community is very non-technical, and the files can be multi-GB in size.

    Daniel Huigens
    @twiss

    Yes, correct.

    If you want, you could just sign the hash (as an openpgp message, e.g. using openpgp.message.fromBinary()). Then of course openpgp.js will hash the hash again during signing, but that's a relatively cheap operation.

    will Farrell
    @willfarrell
    Yeah, I was thinking that. But might require extra documentation and steps for those to verify on their own machines. A change in user workflow will be needed to simplify this case, something to relfect on. Thank you for your assitence on this, it's been very helpful. Have a wonderful weekend.
    Kevin Moutet
    @sinderw
    Hi, I don't know if this is the correct place to talk about the openpgp.d.ts file? It is lacking Key.toPacketlist in v5.0.0-1
    Daniel Huigens
    @twiss
    Hi @sinderw :wave: Yeah, this is a fine place to ask, however, if you don't mind me asking, what do you need toPacketListfor? It's kind of considered an internal / private function, which is why it's not exported in openpgp.d.ts.
    Kevin Moutet
    @sinderw
    I use it to export keys as binary (Key.toPacketlist().write()) and import them back with readKey({binaryKey: ...}). Is that a mistake? Other classes like Message and Signature have a public packets member
    Daniel Huigens
    @twiss
    Oh, I see. No, that's fine. But probably we should add a key.write() (and message.write(), etc) function for this, and export that, instead
    Kevin Moutet
    @sinderw
    Thanks, do you want me to do something about it, like creating an issue to follow it?
    Daniel Huigens
    @twiss
    Yes, that'd be great :blush: If you feel like, a PR would also be welcome
    Kevin Moutet
    @sinderw
    Sure, I'll work on it! :)
    Daniel Huigens
    @twiss
    Thanks! :D
    saurabh-pawar96
    @saurabh-pawar96

    Hello,
    Can I get some help with an issue I am currently facing?
    Im using openpgp version 4.10.10 with Node (12.21.0)
    This is the code used to encrypt and sign a file

    const zippedFile = './ZipFile.zip';
    const publicKey = fs.readFileSync(process.env.ENCRYPTION_PUBLIC_KEY_PATH, 'utf8');
    const signingPrivateKey = fs.readFileSync(process.env.PGP_PRIVATE_KEY_PATH, 'utf8');
    openpgp.initWorker({});
    const openpgpPublicKey = await openpgp.key.readArmored(publicKey);
    const openpgpPrivateKey = await openpgp.key.readArmored(signingPrivateKey);
    await openpgpPrivateKey.keys[0].decrypt(process.env.PGP_PRIVATE_KEY_PASSPHRASE);
    const file = fs.readFileSync(zippedFile);
    const options = {
        message: openpgp.message.fromBinary(new Uint8Array(file)),
        publicKeys: openpgpPublicKey.keys,
        privateKeys: [openpgpPrivateKey.keys[0]],
        armor: false,
    };
    const encryptionResponse = await openpgp.encrypt(options);
    const encryptedFile = encryptionResponse.message.packets.write();
    fs.writeFileSync('./FileName.zip.pgp', encryptedFile);

    When I run this code using a macbook, the code works fine, and decryption and verifying the signature works fine as well on a macbook, but there is an error when trying to decrypt it on a windows system using symantec PGP

    FileName.zip.pgp:decrypt (3090:operation failed, encrypted session key is bad)

    Could anyone help out with why this would be happening?

    Daniel Huigens
    @twiss
    Symantec PGP is quite old - could you try decrypting with GnuPG, for example, to verify if there's any issue with the message? The code looks fine to me.
    Kevin Moutet
    @sinderw
    Hi, I was trying to retrieve a signature's creation time, and realized that although it is possible to specify it at creation, it is neither possible to retrieve it nor to specify its expiration time. Should we work on that?
    Daniel Huigens
    @twiss
    Hey :wave: For signature creation time, even though there's no function for it, there's a public property exported here: https://github.com/openpgpjs/openpgpjs/blob/5299561aa35a34282c1a9cc979cf81d498ea933d/openpgp.d.ts#L405 which should be fine to use.
    Re. signature expiration - this is rarely used in OpenPGP, do you have a use case for this?
    We don't even consider signature expiration in some cases (e.g. #1138) - probably that should be fixed first (and #1137)
    Kevin Moutet
    @sinderw
    Oh right. This property is on SignaturePacket so maybe we should actually make Signature.packets public again?
    Well, we communicate signed data over insecure channels. To avoid request duplication we signed the date too.
    As this design is flawed we are moving toward a challenge/response design, but along the way we realized that the signature date/expiration might have been used for that purpose.
    I indeed saw the issues #1137 and #1138. Is any help needed on those?
    Daniel Huigens
    @twiss

    Oh right. This property is on SignaturePacket so maybe we should actually make Signature.packets public again?

    Yeah it's a good point, actually then I agree we could add a Signature.prototype.getCreationTime, rather than exporting packets - probably it's cleaner that way.

    along the way we realized that the signature date/expiration might have been used for that purpose.

    I see, yeah makes sense. Though when it's an essential part of the application, I think signing and checking it explicitly in the application is not a bad idea, to make it more explicit what's going on, rather than implicitly relying on the properties of OpenPGP.

    I indeed saw the issues #1137 and #1138. Is any help needed on those?

    Yes, if you feel like taking a stab at these, please feel free! Probably what's required to fix these is to:

    • Pass a date to SignaturePacket.prototype.sign and verify
    • Set signature.created in sign rather than in the constructor
    • In verify, add a check for this.isExpired
    • In createVerificationObject, that same check can then be removed
    Kevin Moutet
    @sinderw
    Sorry for the late answer, I will work on that!
    Daniel Huigens
    @twiss
    :+1: Thanks a lot! :blush: