Giter VIP home page Giter VIP logo

pmcrypto's Introduction

pmcrypto

v7

Changed:

  • init no longer accepts a openpgp instance: the OpenPGP.js lightweight build for browsers is always used.

  • In encryptMessage:

    • input message: options.data has been replaced by options.textData/binaryData, and options.message has been removed
    • options.data used to have trailing spaces automatically stripped. Now pass options.stripTrailingSpaces = true for the same behaviour
    • options.returnSessionKey has been removed, now separately generate a session key using e.g. generateSessionKey and pass it via options.sessionKey.
    • options.publicKeys has been renamed to options.encryptionKeys, options.privateKeys to options.signingKeys.
    • options.armor has been replaced by options.format taking 'armored'|'binary'|'object', where armor: false corresponds to format: 'object' (but it is recommended to use 'binary' or 'armored' instead).
    • output message: result.message is always returned for encrypted data (result.data has been removed)
  • In decryptMessage:

    • options.privateKeys has been renamed to options.decryptionKeys, options.publicKeys to options.verificationKeys.
    • errors has been renamed to verificationErrors
    • if the message is signed, and verificationKeys are given but none corresponds to the original signing key, a verification error is returned (previously, this didn't return any errors).
  • In signMessage:

    • input message: options.data has been replaced by options.textData/binaryData, and options.message has been removed
    • options.data used to automatically create a cleartext message. For the same behaviour, if detached = true, now pass textData with stripTrailingSpaces. The equivalent for detached = false (namely CleartextMessage signing) is not implemented (unused).
    • options.privateKeys has been renamed to options.signingKeys.
    • options.armor has been replaced by options.format taking 'armored'|'binary'|'object', where armor: false corresponds to format: 'object' (but it is recommended to use 'binary' or 'armored' instead).
  • In verifyMessage:

    • options.publicKeys has been renamed to options.verificationKeys.
    • pass options.stripTrailingSpaces: true if the message could contain trailing whitespaces on any line and it was signed by passing options.data in previous versions.
    • as in decryptMessage, if verificationKeys are given but none matches the original, a verification error is returned (previously, this didn't return any errors).
  • generateSessionKey now takes recipient public keys in input and generates a session key compatible with their key preferences. The former function, which generates a key for a given symmetric algo was renamed generateSessionKeyForAlgorithm.

Replaced:

  • getMessage, getSignature, getCleartextMessage, getKey(s): use the corresponding read* functions instead, which take named inputs to preserve type info (e.g. readMessage({ armoredMessage }))
  • decryptPrivateKey, encryptPrivateKey: these performed both parsing/serialization and decryption/encryption. Now, separately parse a binary/armored key using readPrivateKey and then pass the result to decryptKey or encryptKey. These function still do not modify the original privateKey instance.

Added

  • readPrivateKey(s): similar to readKey(s) but expect and return a PrivateKey instance
  • generateSessionKeyForAlgorithm: same as generateSessionKey for v6

Removed:

  • createMessage, createCleartextMessage: serialized data is now taken as input directly by sign/verify/encryptMessage as options.text/binaryData
  • decryptMIMEMessage (unused)
  • keyCheck and keyInfo (unused)
  • snake_case aliases for base64 utils (e.g. encode_base64)
  • createWorker : OpenPGP.js no longer includes a worker. For performance reasons, apps are encouraged to create their own workers.

Usage

pmcrypto must be initialized using the init function, to apply changes to the underlying OpenPGP.js configuration.

import { init } from 'pmcrypto';

init();

Examples

Encrypt/sign and decrypt/verify string or binary data using keys

Encrypt/sign and decrypt/verify string or binary data using keys

To parse and decrypt the keys

const recipientPublicKey = await readKey({ armoredKey: '...' }); // or `binaryKey`
const senderPrivateKey = await decryptKey({
  privateKey: await readPrivateKey({ armoredKey: '...' }),
  passphrase: 'personal key passphrase'
});

To encrypt and sign:

const { 
  message: armoredMessage,
  encryptedSignature: armoredEncryptedSignature
} = await encryptMessage({
  textData: 'text data to encrypt', // or `binaryData` for Uint8Arrays
  encryptionKeys: recipientPublicKey, // and/or `passwords`
  signingKeys: senderPrivateKey,
  detached: true,
  format: 'armored' // or 'binary' to output a binary message and signature
});

// share `armoredMessage`

To decrypt and verify (non-streamed input):

// load the required keys
const senderPublicKey = await readKey(...);
const recipientPrivateKey = await decryptKey(...);

const { data: decryptedData, verified } = await decryptMessage({
  message: await readMessage({ armoredMessage }), // or `binaryMessage`
  encryptedSignature: await readMessage({ armoredMessage: armoredEncryptedSignature })
  decryptionKeys: recipientPrivateKey // and/or 'passwords'
  verificationKeys: senderPublicKey
});

For streamed inputs: to encrypt (and/or sign), pass the stream to textData or binaryData based on the streamed data type. Similarly, to decrypt and verify, the input options are the same as the non-streaming case. However, if armoredMessage (or binaryMessage) is a stream, the decryption result needs to be handled differently:

// explicitly loading stream polyfills for legacy browsers is required since v7.2.2
if (!globalThis.TransformStream) {
  await import('web-streams-polyfill/es6');
}

const { data: dataStream, verified: verifiedPromise } = await decryptMessage({
  message: await readMessage({ armoredMessage: streamedArmoredMessage }),
  ... // other options
});

// you need to read `dataStream` before resolving `verifiedPromise`, even if you do not need the decrypted data
const decryptedData = await readToEnd(dataStream);
const verificationStatus = await verified;
Encrypt/decrypt using the session key

Encrypt/decrypt using the session key directly

In v6, encryptMessage would return the generated session key if options.returnSessionKey: true was given. This option is no longer supported. Instead:

// First generate the session key
const sessionKey = await generateSessionKey({ recipientKeys: recipientPublicKey });

// Then encrypt the data with it
const { message: armoredMessage } = await encryptMessage({
  textData: 'text data to encrypt', // or `binaryData` for Uint8Arrays
  sessionKey,
  encryptionKeys: recipientPublicKey, // and/or `passwords`, used to encrypt the session key
  signingKeys: senderPrivateKey,
});

To decrypt, you can again provide the session key directly:

// Then encrypt the data with it
const { data } = await decryptMessage({
  message: await readMessage({ armoredMessage }),
  sessionKeys: sessionKey,
  verificationKeys: senderPublicKey,
});

You can also encrypt the session key on its own:

const armoredEncryptedSessionKey = await encryptSessionKey({
  sessionKey,
  encryptionKeys, // and/or passwords
  format: 'armored'
});

// And decrypt it with:
const sessionKey = await decryptSessionKey({
  message: await readMessage({ armoredMessage: armoredEncryptedSessionKey }),
  decryptionsKeys // and/or passwords
});

Testing

Headless Chrome (or Chromium), Firefox and Webkit are used for the tests. To install any missing browsers automatically, you can run npx playwright install --with-deps <chromium|firefox|webkit>. Alternatively, you can install them manually as you normally would on your platform. If you'd like to test on a subset of browsers, use e.g. npm test -- --browsers ChromeHeadless,FirefoxHeadless.

pmcrypto's People

Contributors

bafs avatar cronosh avatar dependabot[bot] avatar dhoko avatar econdepe avatar epokk avatar gscoon avatar horejsek avatar kaylukas avatar kylekatarnls avatar larabr avatar lkpch avatar mandragorian avatar mmso avatar sanjanarajan avatar swiip avatar twiss avatar valentinbonneaud avatar vincaslt avatar wussler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pmcrypto's Issues

Refactor (and consider moving) base64 and utf8 utils

We should review if these utils are needed in the library, otherwise move them over to the clients monorepo.

Regardless, the following refactoring should be done:

  • Remove the binary string variants encodeUtf8 and decodeUtf8
  • Accept/return Uint8Arrays for base64 encoding/decoding
  • Remove encodeUtf8Base64 and decodeUtf8Base64 (they can just chain two functions)

decodeBase64 (or base64ToBytes/Array) should return a Uint8Array, and then utf8BytesToString should take a Uint8Array and return a string, so that utf8BytesToString ∘ base64ToBytes == decodeUtf8Base64.

And then if binary strings are needed in some cases, binaryStringToArray / arrayToBinaryString can be used.

`binaryStringToArray` and `arrayToBinaryString` encoding

The encoding/decoding of binaryStringToArray/arrayToBinaryString is problematic for unicode chars.

encoding result
pmc.binaryStringToArray('aéこん') Uint8Array(4) [97, 233, 83, 147]
new TextEncoder('utf-8').encode('aéこん') Uint8Array(9) [97, 195, 169, 227, 129, 147, 227, 130, 147]
decoding result
pmc.arrayToBinaryString([97, 233, 83, 147]) aéS (not the expected result; aéこん)
  • str2ab('aéこん') gives an ArrayBuffer of
    • Int8Array(8) [97, 0, -23, 0, 83, 48, -109, 48]
    • Int16Array(4) [97, 233, 12371, 12435]
    • Int32Array(2) [15269985, 814952531]
    • Uint8Array(8) [97, 0, 233, 0, 83, 48, 147, 48]

Ref:

Verifying encrypted streaming data with signature fails

const { data } = await decryptMessage({
    message: openpgp.message.read(stream),
    signature: getSignature(decryptedSignature),
    sessionKeys: keys.sessionKeys,
    publicKeys: keys.privateKey.toPublic(),
    streaming: 'web',
    format: 'binary',
});

Code like this will fail with Cannot convert undefined or null to object because of

function isCanonicalTextSignature({ packets }) {
return Object.values(packets).some(({ signatureType = false }) => signatureType === CANONICAL_TEXT);
}

This function is passed a Promise of signature (because of streaming decryption), so packets resolves to undefined.

This function should possibly accept and return a promise. There are three scenarios which I can think of in which it must work:

  • streaming decryption + known signature (like original example)
  • streaming decryption + inlined signature (promise is required in that case)
  • non-streaming decryption + signature

Ecc curve types in keyInfo

We want to be able to display the curve type in the FE, so people can check if they are using nist curves etcetera.

So I would like to have some parameter in keyinfo that describes the curve type.

keyinfo / openpgp fails on a ecc key

It can't request the bitsize of a key.
cf:

TypeError: this.params[0].byteLength is not a function
    at i.getBitSize (openpgp.min.js:2)
    at vendor.js:80215
    at <anonymous>

Boundary delimiters with special characters

There is an issue where boundary delimiters with regex characters does not get parsed, e.g.

=-=rzmb8HM+ZkeNcG=-=

because the current parser creates a regexp of the delimiter.

Tests: incorrect line references reported on error

In tests, the line references given on error are off, due to two separate issues:

  • since webpack does not emit source map files for TS, a custom plugin should be set: codymikol/karma-webpack#109 (comment)
  • even with the above fix, karma-webpack v5 has a bug that breaks the source map referencing: codymikol/karma-webpack#493. The proposed temporary solution (set splitChunks: false) does not work for us, because chunking is needed in the tests to load the mailparses and openpgp.js. Their next karma-webpack release will hopefully fix the problem.

Replace `keyCheck` and simplify `keyInfo`

  • keyCheck should be removed since it is not used in our apps, and it is strongly coupled with keyInfo. The checks it does should be re-implemented in a different function (e.g. named checkPersonalKey), taking an OpenPGPKey in input, instead of a custom object. It should check key strength requirements through the function(s) implemented in #121 , as well as binding signature validity, whether the key can encrypt etc (same checks as API).
  • keyInfo should be removed, or simplified to not include key checks. It is currently used in apps to collect minimal key metadata.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.