Skip to content

V5 Changelog

Daniel Huigens edited this page Mar 3, 2021 · 20 revisions

Security improvements

  • Generate ECC keys by default (#1065)
  • RSA keys can still be generated with the new type parameter of generateKey: (#1179)
    const { key } = await openpgp.generateKey({
      userIds: [{ name: 'Test', email: 'test@email' }],
      type: 'rsa'
    });
  • Newly generated RSA keys are now 4096-bits by default
  • Remove SHA-1 from default preferred hash algorithms (#1067)
  • Remove 3DES and CAST5 from default preferred symmetric algorithms (#1068)
  • … and a few smaller configuration changes

Library size reductions

  • openpgp.HKP has been moved to a separate package: openpgpjs/hkp-client
  • openpgp.WKD has been moved to a separate package: openpgpjs/wkd-client
  • openpgp.Keyring and LocalStore have been removed, because keyring handling and storage should be handled in the application, as localStorage may not meet the durability requirements of the application.
  • The built-in Web Worker and openpgp.createWorker have been removed (for the rationale, please see #1072)

High-level API changes

(Examples below)

  • Replace openpgp.key.read/readArmored with openpgp.readKey
    • openpgp.readKey now takes an options object (either { armoredKey } or { binaryKey })
    • It now only returns a single key object, rather than a { keys: [key...], err } object
    • It now throws an error if the key failed to parse or if the key block contains multiple keys
  • Add openpgp.readKeys
    • It takes an options object (either { armoredKeys } or { binaryKeys })
    • It returns an array of key objects
    • It throws if any of the keys in the key block failed to parse
  • Replace openpgp.message.read/readArmored with openpgp.readMessage, openpgp.signature.read/readArmored with openpgp.readSignature, and openpgp.cleartext.readArmored with openpgp.readCleartextMessage
    • openpgp.readMessage now takes an options object (either { armoredMessage } or { binaryMessage })
    • openpgp.readSignature now takes an options object (either { armoredSignature } or { binarySignature })
    • openpgp.readCleartextMessage now takes an options object ({ cleartextMessage })
  • Replace openpgp.message.fromText with openpgp.Message.fromText, openpgp.message.fromBinary with openpgp.Message.fromBinary, and openpgp.cleartext.fromText with openpgp.CleartextMessage.fromText
  • In openpgp.encrypt, sign, encryptSessionKey, encryptKey and decryptKey, return the result directly without wrapping it in a "results" object
  • Remove the detached option of openpgp.encrypt. You can separately call openpgp.sign({ message, privateKeys, detached: true }) instead (don't forget to remove the privateKeys option from openpgp.encrypt as well if you do so, if you don't want the message to be signed inline). However, note that storing detached signatures of plaintext data together with the encrypted data is not secure
  • Add a new openpgp.generateSessionKey function
  • Remove the returnSessionKey option of openpgp.encrypt. You can separately call openpgp.generateSessionKey({ publicKeys }) instead and call openpgp.encrypt({ sessionKey }) with the result
  • Rename all openpgp.enum.*.value_names to camelCase openpgp.enum.*.valueNames (#1093)
  • Remove openpgp.util (#1175)

Configuration changes

  • Rename all openpgp.config.option_names to camelCase openpgp.config.optionNames (#1088)
    • Rename openpgp.config.versionstring to versionString, and commentstring to commentString
  • Don't add version and comment strings to armored messages and keys by default
  • Rename openpgp.config.ignore_mdc_error to allowUnauthenticatedMessages, and add a warning in the documentation that this option is insecure
  • Remove the option to generate non-integrity-protected messages (openpgp.config.integrityProtect)
  • openpgp.config.aeadProtect now controls whether private key encryption uses AEAD; previously this was dependent on the key version, and could only be used for v5 keys
  • All top-level functions (including the new ones mentioned above) now take a config property of their options parameter
    • This can be helpful when you want to change the configuration for a single function call, rather than all OpenPGP.js function cals
    • For example, you can now generate a single V5 key as follows:
      const { key } = await openpgp.generateKey({
        userIds: [{ name: 'Test', email: 'test@email' }],
        config: { v5Keys: true }
      });
    • Config options that aren't passed still default to openpgp.config

Low-level API changes

  • Rename openpgp.packet.* to openpgp.*Packet
  • Rename openpgp.packet.Userid to openpgp.UserIDPacket
  • Rename openpgp.packet.Literal to openpgp.LiteralDataPacket
  • Rename openpgp.packet.Compressed to openpgp.CompressedDataPacket
  • Rename openpgp.packet.SymmetricallyEncrypted to openpgp.SymmetricallyEncryptedDataPacket
  • Rename openpgp.packet.SymEncryptedIntegrityProtected to openpgp.SymEncryptedIntegrityProtectedDataPacket
  • Rename openpgp.packet.SymEncryptedAEADProtected to openpgp.AEADEncryptedDataPacket

  • Rename openpgp.enums.packet.userid to openpgp.enums.packet.userID
  • Rename openpgp.enums.packet.literal to openpgp.enums.packet.literalData
  • Rename openpgp.enums.packet.compressed to openpgp.enums.packet.compressedData
  • Rename openpgp.enums.packet.symmetricallyEncrypted to openpgp.enums.packet.symmetricallyEncryptedData
  • Rename openpgp.enums.packet.symEncryptedIntegrityProtected to openpgp.enums.packet.symEncryptedIntegrityProtectedData
  • Rename openpgp.enums.packet.symEncryptedAEADProtected to openpgp.enums.packet.AEADEncryptedData

  • Rename openpgp.message.generateSessionKey to openpgp.Message.generateSessionKey
  • Rename openpgp.message.encryptSessionKey to openpgp.Message.encryptSessionKey

Examples

Parse one key (armored)

v4:

import * as openpgp from 'openpgp';
const privateKey = (await openpgp.key.readArmored(armoredKey)).keys[0];

v5:

import { readKey } from 'openpgp';
const privateKey = await readKey({ armoredKey });
Parse one or more keys (armored)

v4:

import * as openpgp from 'openpgp';
const publicKeys = (await openpgp.key.readArmored(armoredKeys)).keys;

v5:

import { readKeys } from 'openpgp';
const publicKeys = await readKeys({ armoredKeys });
Encrypt text message (armored)

v4:

import * as openpgp from 'openpgp';
const message = openpgp.message.fromText(text);
const encrypted = await openpgp.encrypt({ publicKeys, message });
console.log(encrypted.data); // String

v5:

import { Message, encrypt } from 'openpgp';
const message = Message.fromText(text);
const encrypted = await encrypt({ publicKeys, message });
console.log(encrypted); // String
Encrypt text message (unarmored)

v4:

import * as openpgp from 'openpgp';
const message = openpgp.message.fromBinary(data);
const encrypted = await openpgp.encrypt({ publicKeys, message, armor: false });
console.log(encrypted.message.packets.write()); // Uint8Array

v5:

import { Message, encrypt } from 'openpgp';
const message = Message.fromBinary(data);
const encrypted = await encrypt({ publicKeys, message, armor: false });
console.log(encrypted); // Uint8Array
Encrypt message (inspect packets)

v4:

import * as openpgp from 'openpgp';
const encrypted = await openpgp.encrypt({ publicKeys, message, armor: false });
console.log(encrypted.message.packets); // Array

v5:

import { encrypt, readMessage } from 'openpgp';
import stream from 'web-stream-tools';
const encrypted = await encrypt({ publicKeys, message, armor: false });
const message = await readMessage({ binaryMessage: encrypted });
message.packets.concat(await stream.readToEnd(message.packets.stream, _ => _)); // Optional, if you want to inspect trailing signature packets
console.log(message.packets); // Array
Sign cleartext message (armored)

v4:

import * as openpgp from 'openpgp';
const message = openpgp.cleartext.fromText(text);
const signed = await openpgp.sign({ privateKeys, message });
console.log(signed.data); // String

v5:

import { CleartextMessage, sign } from 'openpgp';
const message = CleartextMessage.fromText(text);
const signed = await sign({ privateKeys, message });
console.log(signed); // String
Sign text message (unarmored)

v4:

import * as openpgp from 'openpgp';
const message = openpgp.message.fromText(text);
const signed = await openpgp.sign({ privateKeys, message, armor: false });
console.log(signed.message.packets.write()); // Uint8Array

v5:

import { Message, sign } from 'openpgp';
const message = Message.fromText(text);
const signed = await sign({ privateKeys, message, armor: false });
console.log(signed); // Uint8Array
Detached-sign cleartext message (armored)

v4:

import * as openpgp from 'openpgp';
const message = openpgp.cleartext.fromText(text);
const signed = await openpgp.sign({ privateKeys, message, detached: true });
console.log(signed.signature); // String

v5:

import { Message, sign } from 'openpgp';
const message = Message.fromText(util.removeTrailingSpaces(text));
const signed = await sign({ privateKeys, message, detached: true });
console.log(signed); // String
Detached-sign binary message (unarmored)

v4:

import * as openpgp from 'openpgp';
const message = openpgp.message.fromText(text);
const signed = await openpgp.sign({ privateKeys, message, detached: true, armor: false });
console.log(signed.signature.packets.write()); // Uint8Array

v5:

import { Message, sign } from 'openpgp';
const message = Message.fromText(text);
const signed = await sign({ privateKeys, message, detached: true, armor: false });
console.log(signed); // Uint8Array
Verify signed text message (armored)

v4:

import * as openpgp from 'openpgp';
const message = await openpgp.message.readArmored(armor);
const verified = await openpgp.verify({ publicKeys, message });
console.log(openpgp.util.nativeEOL(openpgp.util.decode_utf8(verified.data))); // String
console.log(verified.signatures); // Array

v5:

import { readMessage, verify } from 'openpgp';
const message = await readMessage({ armoredMessage });
const verified = await verify({ publicKeys, message });
console.log(verified.data); // String
console.log(verified.signatures); // Array
Verify signed binary message (unarmored)

v4:

import * as openpgp from 'openpgp';
const message = await openpgp.message.read(binary);
const verified = await openpgp.verify({ publicKeys, message });
console.log(verified.data); // Uint8Array
console.log(verified.signatures); // Array

v5:

import { readMessage, verify } from 'openpgp';
const message = await readMessage({ binaryMessage });
const verified = await verify({ publicKeys, message, format: 'binary' });
console.log(verified.data); // Uint8Array
console.log(verified.signatures); // Array
Encrypt session keys (armored)

v4:

import * as openpgp from 'openpgp';
const encrypted = await openpgp.encryptSessionKey({ publicKeys, data, algorithm });
console.log(encrypted.message.armor()); // String

v5:

import { encryptSessionKey } from 'openpgp';
const encrypted = await encryptSessionKey({ publicKeys, data, algorithm });
console.log(encrypted); // String
Encrypt session keys (unarmored)

v4:

import * as openpgp from 'openpgp';
const encrypted = await openpgp.encryptSessionKey({ publicKeys, data, algorithm });
console.log(encrypted.message.packets.write()); // Uint8Array

v5:

import { encryptSessionKey } from 'openpgp';
const encrypted = await encryptSessionKey({ publicKeys, data, algorithm, armor: false });
console.log(encrypted); // Uint8Array
Streaming-encrypt text message on Node.js (armored)

v4:

import * as openpgp from 'openpgp';
const data = fs.createReadStream(filename, { encoding: 'utf8' });
const message = openpgp.message.fromText(data);
const encrypted = await openpgp.encrypt({ publicKeys, message });
encrypted.data.on('data', chunk => {
  console.log(openpgp.util.Uint8Array_to_str(chunk)); // String
});

v5:

import { Message, encrypt } from 'openpgp';
const data = fs.createReadStream(filename, { encoding: 'utf8' });
const message = Message.fromText(data);
const encrypted = await encrypt({ publicKeys, message });
encrypted.on('data', chunk => {
  console.log(chunk); // String
});
Streaming-encrypt binary message on Node.js (unarmored)

v4:

import * as openpgp from 'openpgp';
const data = fs.createReadStream(filename);
const message = openpgp.message.fromBinary(data);
const encrypted = await openpgp.encrypt({ publicKeys, message, armor: false });
openpgp.stream.webToNode(encrypted.message.packets.write()).pipe(targetStream);

v5:

import { Message, encrypt } from 'openpgp';
const data = fs.createReadStream(filename);
const message = Message.fromBinary(data);
const encrypted = await encrypt({ publicKeys, message, armor: false });
encrypted.pipe(targetStream);
Clone this wiki locally