mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-06-04 13:16:42 +00:00
Support generating Curve448 and Curve25519 keys (new format)
Neither type is set as default for now, since they are not widely supported.
This commit is contained in:
parent
1509364a49
commit
24c644207d
6
openpgp.d.ts
vendored
6
openpgp.d.ts
vendored
@ -816,7 +816,7 @@ export namespace enums {
|
||||
aeadEncryptedData = 20,
|
||||
}
|
||||
|
||||
export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsa' | 'aedh' | 'aedsa';
|
||||
export type publicKeyNames = 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign' | 'elgamal' | 'dsa' | 'ecdh' | 'ecdsa' | 'eddsa' | 'ed25519Legacy' | 'aedh' | 'aedsa' | 'ed25519' | 'x25519' | 'ed448' | 'x448';
|
||||
enum publicKey {
|
||||
rsaEncryptSign = 1,
|
||||
rsaEncrypt = 2,
|
||||
@ -830,6 +830,10 @@ export namespace enums {
|
||||
eddsaLegacy = 22,
|
||||
aedh = 23,
|
||||
aedsa = 24,
|
||||
x25519 = 25,
|
||||
x448 = 26,
|
||||
ed25519 = 27,
|
||||
ed448 = 28
|
||||
}
|
||||
|
||||
enum curve {
|
||||
|
@ -36,14 +36,14 @@ ed25519.hash = bytes => sha512(bytes);
|
||||
* @returns {Promise<{ A: Uint8Array, seed: Uint8Array }>}
|
||||
*/
|
||||
export async function generate(algo) {
|
||||
const seed = getRandomBytes(getPayloadSize(algo));
|
||||
|
||||
switch (algo) {
|
||||
case enums.publicKey.ed25519: {
|
||||
const seed = getRandomBytes(getPayloadSize(algo));
|
||||
const { publicKey: A } = ed25519.sign.keyPair.fromSeed(seed);
|
||||
return { A, seed };
|
||||
}
|
||||
case enums.publicKey.ed448: {
|
||||
const seed = ed448.utils.randomPrivateKey();
|
||||
const A = ed448.getPublicKey(seed);
|
||||
return { A, seed };
|
||||
}
|
||||
|
@ -64,9 +64,9 @@ function createKey(packetlist) {
|
||||
|
||||
|
||||
/**
|
||||
* Generates a new OpenPGP key. Supports RSA and ECC keys.
|
||||
* Generates a new OpenPGP key. Supports RSA and ECC keys, as well as the newer Curve448 and Curve25519 keys.
|
||||
* By default, primary and subkeys will be of same type.
|
||||
* @param {ecc|rsa} options.type The primary key algorithm type: ECC or RSA
|
||||
* @param {ecc|rsa|curve448|curve25519} options.type The primary key algorithm type: ECC, RSA, Curve448 or Curve25519 (new format).
|
||||
* @param {String} options.curve Elliptic curve for ECC keys
|
||||
* @param {Integer} options.rsaBits Number of bits for RSA keys
|
||||
* @param {Array<String|Object>} options.userIDs User IDs as strings or objects: 'Jo Doe <info@jo.com>' or { name:'Jo Doe', email:'info@jo.com' }
|
||||
|
@ -326,7 +326,7 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
|
||||
options.sign = options.sign || false;
|
||||
|
||||
switch (options.type) {
|
||||
case 'ecc':
|
||||
case 'ecc': // NB: this case also handles legacy eddsa and x25519 keys, based on `options.curve`
|
||||
try {
|
||||
options.curve = enums.write(enums.curve, options.curve);
|
||||
} catch (e) {
|
||||
@ -341,6 +341,12 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) {
|
||||
options.algorithm = enums.publicKey.ecdh;
|
||||
}
|
||||
break;
|
||||
case 'curve25519':
|
||||
options.algorithm = options.sign ? enums.publicKey.ed25519 : enums.publicKey.x25519;
|
||||
break;
|
||||
case 'curve448':
|
||||
options.algorithm = options.sign ? enums.publicKey.ed448 : enums.publicKey.x448;
|
||||
break;
|
||||
case 'rsa':
|
||||
options.algorithm = enums.publicKey.rsaEncryptSign;
|
||||
break;
|
||||
|
@ -198,8 +198,10 @@ class PrivateKey extends PublicKey {
|
||||
|
||||
/**
|
||||
* Generates a new OpenPGP subkey, and returns a clone of the Key object with the new subkey added.
|
||||
* Supports RSA and ECC keys. Defaults to the algorithm and bit size/curve of the primary key. DSA primary keys default to RSA subkeys.
|
||||
* @param {ecc|rsa} options.type The subkey algorithm: ECC or RSA
|
||||
* Supports RSA and ECC keys, as well as the newer Curve448 and Curve25519.
|
||||
* Defaults to the algorithm and bit size/curve of the primary key. DSA primary keys default to RSA subkeys.
|
||||
* @param {ecc|rsa|curve25519|curve448} options.type The subkey algorithm: ECC, RSA, Curve448 or Curve25519 (new format).
|
||||
* Note: Curve448 and Curve25519 are not widely supported yet.
|
||||
* @param {String} options.curve (optional) Elliptic curve for ECC keys
|
||||
* @param {Integer} options.rsaBits (optional) Number of bits for RSA subkeys
|
||||
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
||||
@ -225,7 +227,7 @@ class PrivateKey extends PublicKey {
|
||||
throw new Error('Key is not decrypted');
|
||||
}
|
||||
const defaultOptions = secretKeyPacket.getAlgorithmInfo();
|
||||
defaultOptions.type = defaultOptions.curve ? 'ecc' : 'rsa'; // DSA keys default to RSA
|
||||
defaultOptions.type = getDefaultSubkeyType(defaultOptions.algorithm);
|
||||
defaultOptions.rsaBits = defaultOptions.bits || 4096;
|
||||
defaultOptions.curve = defaultOptions.curve || 'curve25519';
|
||||
options = helper.sanitizeKeyOptions(options, defaultOptions);
|
||||
@ -238,4 +240,25 @@ class PrivateKey extends PublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
function getDefaultSubkeyType(algoName) {
|
||||
const algo = enums.write(enums.publicKey, algoName);
|
||||
// NB: no encryption-only algos, since they cannot be in primary keys
|
||||
switch (algo) {
|
||||
case enums.publicKey.rsaEncrypt:
|
||||
case enums.publicKey.rsaEncryptSign:
|
||||
case enums.publicKey.rsaSign:
|
||||
case enums.publicKey.dsa:
|
||||
return 'rsa';
|
||||
case enums.publicKey.ecdsa:
|
||||
case enums.publicKey.eddsaLegacy:
|
||||
return 'ecc';
|
||||
case enums.publicKey.ed25519:
|
||||
return 'curve25519';
|
||||
case enums.publicKey.ed448:
|
||||
return 'curve448';
|
||||
default:
|
||||
throw new Error('Unsupported algorithm');
|
||||
}
|
||||
}
|
||||
|
||||
export default PrivateKey;
|
||||
|
@ -32,11 +32,13 @@ import { checkKeyRequirements } from './key/helper';
|
||||
|
||||
|
||||
/**
|
||||
* Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type.
|
||||
* Generates a new OpenPGP key pair. Supports RSA and ECC keys, as well as the newer Curve448 and Curve25519 keys.
|
||||
* By default, primary and subkeys will be of same type.
|
||||
* The generated primary key will have signing capabilities. By default, one subkey with encryption capabilities is also generated.
|
||||
* @param {Object} options
|
||||
* @param {Object|Array<Object>} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
|
||||
* @param {'ecc'|'rsa'} [options.type='ecc'] - The primary key algorithm type: ECC (default) or RSA
|
||||
* @param {'ecc'|'rsa'|'curve448'|'curve25519'} [options.type='ecc'] - The primary key algorithm type: ECC (default), RSA, Curve448 or Curve25519 (new format).
|
||||
* Note: Curve448 and Curve25519 (new format) are not widely supported yet.
|
||||
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key. If omitted or empty, the key won't be encrypted.
|
||||
* @param {Number} [options.rsaBits=4096] - Number of bits for RSA keys
|
||||
* @param {String} [options.curve='curve25519'] - Elliptic curve for ECC keys:
|
||||
|
@ -193,13 +193,13 @@ export default () => {
|
||||
});
|
||||
});
|
||||
|
||||
const curves = ['curve25519', 'p256', 'p384', 'p521', 'secp256k1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
|
||||
const curves = ['curve25519Legacy', 'p256', 'p384', 'p521', 'secp256k1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
|
||||
curves.forEach(curve => {
|
||||
describe(`ECC ${curve} parameter validation`, () => {
|
||||
let ecdsaKey;
|
||||
let ecdhKey;
|
||||
before(async () => {
|
||||
if (curve !== 'curve25519') {
|
||||
if (curve !== 'curve25519Legacy') {
|
||||
ecdsaKey = await generatePrivateKeyObject({ curve });
|
||||
ecdhKey = ecdsaKey.subkeys[0];
|
||||
} else {
|
||||
@ -247,58 +247,45 @@ export default () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ed448/X448 parameter validation', function() {
|
||||
let eddsaKey;
|
||||
let ecdhXKey;
|
||||
before(async () => {
|
||||
eddsaKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
// new EdDSA/XECDH algos
|
||||
['25519', '448'].forEach(curveID => {
|
||||
describe(`Ed${curveID}/X${curveID} parameter validation`, function() {
|
||||
let eddsaKey;
|
||||
let ecdhXKey;
|
||||
before(async () => {
|
||||
eddsaKey = await generatePrivateKeyObject({ type: `curve${curveID}` });
|
||||
ecdhXKey = eddsaKey.subkeys[0];
|
||||
});
|
||||
|
||||
xXsEZCWHXBwwtqciq6ZFU13s+dyhkWR5tOEmF1oX8OiP1B5ypfqyGVM8DkQh
|
||||
5eTIMwB1oqJCROANoyA0q2dSigAAbDA5xr74DeClPPXC4ZXJ9uzuJWKvQvE8
|
||||
x3EflhgoQCGBM7JfvH5zwdrJvPt8RKDvm0QkZzhPvnFoHnzNBHRlc3TCugQQ
|
||||
HAgAPgWCZCWHXAQLCQcICZDsN6h/ys3ppwMVCAoEFgACAQIZAQKbAwIeARYh
|
||||
BOJyE9P2eIcU2N2Ne+w3qH/KzemnAAAh1hTFCcEU77bU3YelrJTCNIOQnvt7
|
||||
Hs6yZz2053CQTOC+wHkUQLaYYBEXSNyLZxoyv+NuGTiwbuYtAOlbE2erM7Cx
|
||||
8B2Qz7M29UkFLMBUfb+yi+gTYYUWCXVQ7Um7MGjjgUG8+9p452i6f28mhRD8
|
||||
tTgNAMd5BGQlh1wavTIFgILtbzrqQCiwDGx0YcFNzu9+FZ8vK5Mmm7UEZj0a
|
||||
y7FWQtZw8tTaU6mY+RrSa52RjzkGLtQAQO++tgYqc+BnCFdCZ3ZYPRvD3mof
|
||||
ffoo3l4xmto+iyvJZbQ4wQPXttg7VjCpEfOsL9TW9Xs09aIbysKmBBgcCAAq
|
||||
BYJkJYdcCZDsN6h/ys3ppwKbDBYhBOJyE9P2eIcU2N2Ne+w3qH/KzemnAAC0
|
||||
6/eZhh/Oj2gRdab2JeFGWACGIRDKxPXsWRCXR4YrSxcvCKK6rOvsyxQsgIsJ
|
||||
JyPYkRPfmbKcseUDAEkSBLAfeizDGh7ea0GOdIMhwE/CW4f/H8ULbwi36y13
|
||||
x3oMNVaYsI9dZ588Gpi8XYy2jOtqIPQ1AA==
|
||||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||||
ecdhXKey = eddsaKey.subkeys[0];
|
||||
});
|
||||
it(`Ed${curveID} params should be valid`, async function() {
|
||||
await expect(eddsaKey.keyPacket.validate()).to.not.be.rejected;
|
||||
});
|
||||
|
||||
it('Ed448 params should be valid', async function() {
|
||||
await expect(eddsaKey.keyPacket.validate()).to.not.be.rejected;
|
||||
});
|
||||
it(`detect invalid Ed${curveID} public point`, async function() {
|
||||
const eddsaKeyPacket = await cloneKeyPacket(eddsaKey);
|
||||
const A = eddsaKeyPacket.publicParams.A;
|
||||
A[0]++;
|
||||
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
|
||||
it('detect invalid Ed448 public point', async function() {
|
||||
const eddsaKeyPacket = await cloneKeyPacket(eddsaKey);
|
||||
const A = eddsaKeyPacket.publicParams.A;
|
||||
A[0]++;
|
||||
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
const infA = new Uint8Array(A.length);
|
||||
eddsaKeyPacket.publicParams.A = infA;
|
||||
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
});
|
||||
|
||||
const infA = new Uint8Array(A.length);
|
||||
eddsaKeyPacket.publicParams.A = infA;
|
||||
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
});
|
||||
it(`X${curveID} params should be valid`, async function() {
|
||||
await expect(ecdhXKey.keyPacket.validate()).to.not.be.rejected;
|
||||
});
|
||||
|
||||
it('X448 params should be valid', async function() {
|
||||
await expect(ecdhXKey.keyPacket.validate()).to.not.be.rejected;
|
||||
});
|
||||
it(`detect invalid X${curveID} public point`, async function() {
|
||||
const ecdhXKeyPacket = await cloneKeyPacket(ecdhXKey);
|
||||
const A = ecdhXKeyPacket.publicParams.A;
|
||||
A[0]++;
|
||||
await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
|
||||
it('detect invalid x448 public point', async function() {
|
||||
const ecdhXKeyPacket = await cloneKeyPacket(ecdhXKey);
|
||||
const A = ecdhXKeyPacket.publicParams.A;
|
||||
A[0]++;
|
||||
await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
|
||||
const infA = new Uint8Array(A.length);
|
||||
ecdhXKeyPacket.publicParams.A = infA;
|
||||
await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
const infA = new Uint8Array(A.length);
|
||||
ecdhXKeyPacket.publicParams.A = infA;
|
||||
await expect(ecdhXKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2509,6 +2509,54 @@ function versionSpecificTests() {
|
||||
}
|
||||
});
|
||||
|
||||
it('Generate Ed25519 key (new format) - default subkey', async function() {
|
||||
const userID = { name: 'test', email: 'a@b.com' };
|
||||
const opt = { type: 'curve25519', userIDs: [userID], passphrase: '123', format: 'object' };
|
||||
const { privateKey: key } = await openpgp.generateKey(opt);
|
||||
expect(key.users.length).to.equal(1);
|
||||
expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
|
||||
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
|
||||
expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
|
||||
expect(key.subkeys).to.have.length(1);
|
||||
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x25519');
|
||||
});
|
||||
|
||||
it('Generate Ed25519 key (new format) - one signing subkey', async function() {
|
||||
const userID = { name: 'test', email: 'a@b.com' };
|
||||
const opt = { type: 'curve25519', userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ sign: true }] };
|
||||
const { privateKey: key } = await openpgp.generateKey(opt);
|
||||
expect(key.users.length).to.equal(1);
|
||||
expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
|
||||
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
|
||||
expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
|
||||
expect(key.subkeys).to.have.length(1);
|
||||
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ed25519');
|
||||
});
|
||||
|
||||
it('Generate Ed448 key - default subkey', async function() {
|
||||
const userID = { name: 'test', email: 'a@b.com' };
|
||||
const opt = { type: 'curve448', userIDs: [userID], passphrase: '123', format: 'object' };
|
||||
const { privateKey: key } = await openpgp.generateKey(opt);
|
||||
expect(key.users.length).to.equal(1);
|
||||
expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
|
||||
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
|
||||
expect(key.getAlgorithmInfo().algorithm).to.equal('ed448');
|
||||
expect(key.subkeys).to.have.length(1);
|
||||
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
|
||||
});
|
||||
|
||||
it('Generate Ed448 key - one signing subkey', async function() {
|
||||
const userID = { name: 'test', email: 'a@b.com' };
|
||||
const opt = { type: 'curve448', userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ sign: true }] };
|
||||
const { privateKey: key } = await openpgp.generateKey(opt);
|
||||
expect(key.users.length).to.equal(1);
|
||||
expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
|
||||
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
|
||||
expect(key.getAlgorithmInfo().algorithm).to.equal('ed448');
|
||||
expect(key.subkeys).to.have.length(1);
|
||||
expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ed448');
|
||||
});
|
||||
|
||||
it('Generate key - one signing subkey', function() {
|
||||
const userID = { name: 'test', email: 'a@b.com' };
|
||||
const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] };
|
||||
@ -4196,6 +4244,16 @@ VYGdb3eNlV8CfoEC
|
||||
expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519');
|
||||
});
|
||||
|
||||
it('Add a new default subkey to an Ed488 key', async function() {
|
||||
const userID = { name: 'test', email: 'a@b.com' };
|
||||
const opt = { type: 'curve448', userIDs: [userID], format: 'object', subkeys: [] };
|
||||
const { privateKey: key } = await openpgp.generateKey(opt);
|
||||
expect(key.subkeys).to.have.length(0);
|
||||
const newKey = await key.addSubkey();
|
||||
expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
|
||||
expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.be.undefined;
|
||||
});
|
||||
|
||||
it('Add a new default subkey to a dsa key', async function() {
|
||||
const key = await openpgp.readKey({ armoredKey: dsaPrivateKey });
|
||||
const total = key.subkeys.length;
|
||||
|
@ -4758,17 +4758,8 @@ sEj+v9LKoMTYZGMfp3qDVFLtkBE88eVmVjgJOoLhrsv7yh0PAA==
|
||||
});
|
||||
|
||||
it('sign/verify with new Ed25519 format', async function () {
|
||||
// v4 key, which we do not support generating
|
||||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
xUkEZBw5PBscroGar9fsilA0q9AX979pBhTNkGQ69vQGGW7kxRxNuABB+eAw
|
||||
JrQ9A3o1gUJg28ORTQd72+kFo87184qR97a6rRGFzQR0ZXN0wogEEBsIAD4F
|
||||
gmQcOTwECwkHCAmQT/m+Rl22Ps8DFQgKBBYAAgECGQECmwMCHgEWIQSUlOfm
|
||||
G7MWJd2909ZP+b5GXbY+zwAAVs/4pWH4l7pWcTATBavVqSATMKi4A+usp89G
|
||||
J/qaHc+qmcEpIMmPNvLQ7n4F4kEXk8Zwz+OXovVWLQ+Njl5gzooF
|
||||
=wYg1
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
` });
|
||||
const userIDs = { name: 'Alice', email: 'info@alice.com' };
|
||||
const { privateKey } = await openpgp.generateKey({ type: 'curve25519', userIDs, format: 'object' });
|
||||
const plaintext = 'plaintext';
|
||||
|
||||
const signed = await openpgp.sign({
|
||||
@ -4786,22 +4777,8 @@ J/qaHc+qmcEpIMmPNvLQ7n4F4kEXk8Zwz+OXovVWLQ+Njl5gzooF
|
||||
});
|
||||
|
||||
it('sign/verify with Ed448', async function () {
|
||||
const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
xX0GZRqLYhwAAAA5U/IaIOge/FoLzCetXKx029bdJHCz2hMFBRMuzq4msjaT
|
||||
+hLeV6puyC/PeSEfaanqTuo31vvsti2AAIttr4GDGXF4vfPzbzkWV9dT4VVs
|
||||
IU7QqLv1hzwZ+k7pHroRyXnUiYxRYHuzlg7Vw4CrAtN/8T65OMLAHgYfHAoA
|
||||
AAA9BQJlGotiIqEGAxidsHRHDsyFTw1Q7OoGEAEnRnxthKMwVBqhIL2o+HUC
|
||||
GwMCHgkCCwcDFQoIAhYAAycHAgAAAAA2KiC+Y+fhQ/48CkT9WrXTX9SCn3vH
|
||||
z43Wb++AkmpWL1HQmrJE3S4gGltezZK2E9ovagzxKxVrL14uC6hs6kJ0JIiW
|
||||
QSeMeexCTy+Gdr6j0wb4FhFNnoIu3yu2ABmZpFX/5/191YeWUryKFDAoUZmK
|
||||
gQTSOzJEvyO0ACR5L4vV3ADceOAdG8/sqhE89rTSevFXng4JAM0XVXNlckEg
|
||||
PFVzZXJBQHRlc3QudGVzdD7CwA0GExwKAAAALAUCZRqLYiKhBgMYnbB0Rw7M
|
||||
hU8NUOzqBhABJ0Z8bYSjMFQaoSC9qPh1AhkBAAAAAFw/IH72M1iyzMWhbgtw
|
||||
v0SR/XxvOIW/ZrT4Ix9236lvoOE4taL/D46CbZOjm7VAeOSfSdxt1xSKnoAL
|
||||
RsCNQ8tVPjPXclzqr6R8MbPIgBWxKcMS2eStYpBbG5qAmc+K5jdA2xcl9iW5
|
||||
bWleZ1LTah4lF6qCiD73IffADXtzw8iAMTX+0wM5N1tJUEGvgqe00ohRKiQA
|
||||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||||
const userIDs = { name: 'Alice', email: 'info@alice.com' };
|
||||
const { privateKey } = await openpgp.generateKey({ type: 'curve448', userIDs, format: 'object' });
|
||||
const plaintext = 'plaintext';
|
||||
|
||||
const signed = await openpgp.sign({
|
||||
|
Loading…
x
Reference in New Issue
Block a user