proton-pmcrypto/lib/key/utils.js
larabr f12f1bc662 Linter: update to eslint v9
This eslint version brings breaking changes related to the eslint config.
eslint-airbnb-config has yet to release a compatible version with the
new format, and it generally looks unmaintained, hence we drop the dependency
in favor of the built-in recommended configs.
2025-09-22 14:16:15 +02:00

119 lines
4.8 KiB
JavaScript

import {
reformatKey as openpgp_reformatKey,
generateKey as openpgp_generateKey,
generateSessionKey as openpgp_generateSessionKey
} from '../openpgp';
import { serverTime } from '../serverTime';
import { DEFAULT_KEY_GENERATION_OFFSET } from '../constants';
import { getSymmetricKeySize, getRandomBytes } from '../crypto/utils';
import encryptMessage from '../message/encrypt';
import { SHA256 } from '../crypto/hash';
import { arrayToHexString } from '../utils';
/**
* Generate key and its revocation certificate
* @param {Object} options - same options as openpgp.generateKey
* @param {Date} [options.date] - key creation date, defaults to server time
* @param {'armored'|'binary'|'object'} [format='armored'] - format for generated `PublicKey` and `PrivateKey` data
* @returns {Promise<Object>} generated key data and armored revocation certificate in the form:
* { PrivateKey, PublicKey : String|Uint8Array|Object, revocationCertificate: String }
*/
export async function generateKey({ date = new Date(+serverTime() + DEFAULT_KEY_GENERATION_OFFSET), ...rest }) {
return openpgp_generateKey({ date, ...rest });
}
/**
* Generating a session key for the specified symmetric algorithm
* @param {'aes128'|'aes192'|'aes256'} algo Symmetric encryption algorithm name
* @returns {Uint8Array} Generated session key
* @async
*/
export async function generateSessionKeyForAlgorithm(algoName) {
const keySize = getSymmetricKeySize(algoName);
return getRandomBytes(keySize);
}
/**
* Generate a session key compatible with the given recipient keys.
* @param {OpenPGPKey} options.recipientKeys - public keys to take preferences from
* @returns {Promise<SessionKey>}
* @async
* @throws
*/
export function generateSessionKey({ recipientKeys, date = serverTime(), ...options }) {
return openpgp_generateSessionKey({ encryptionKeys: recipientKeys, date, ...options });
}
/**
* Reformat key to bind it to a new userID and generate the corresponding preferences.
* By default, the generated self-certification signatures are set to have creation time equal to the key creation time, to avoid rendering old messages unverifiable (see https://github.com/openpgpjs/openpgpjs/pull/1422).
*/
export function reformatKey({ privateKey, passphrase, date = privateKey.getCreationTime(), ...rest }) {
return openpgp_reformatKey({ privateKey, passphrase, date, ...rest });
}
/**
* Returns whether the primary key is expired, or its creation time is in the future.
* @param {OpenPGPKey} key
* @param {Date} date - date to use instead of the server time
* @returns {Promise<Boolean>}
*/
export async function isExpiredKey(key, date = serverTime()) {
const now = +date;
const expirationTime = await key.getExpirationTime(); // Always non-null for primary key expiration
return !(key.getCreationTime() <= now && now < expirationTime);
}
/**
* Returns whether the primary key is revoked.
* @param {OpenPGPKey} key
* @param {Date} date - date to use for signature verification, instead of the server time
* @returns {Boolean}
*/
export async function isRevokedKey(key, date = serverTime()) {
return key.isRevoked(null, null, date);
}
/**
* Check whether a key can successfully encrypt a message.
* This confirms that the key has encryption capabilities, it is neither expired nor revoked, and that its key material is valid.
* @param {OpenPGPKey} publicKey - key to check
* @param {Date} date - use the given date instead of the server time
* @returns {Boolean}
*/
export const canKeyEncrypt = async (publicKey, date = serverTime()) => {
try {
await encryptMessage({ textData: 'test message', encryptionKeys: publicKey, date });
return true;
} catch {
return false;
}
};
export const getSHA256Fingerprints = (key) => {
return Promise.all(
key.getKeys().map(async (keyOrSubkey) => {
const { version } = keyOrSubkey.keyPacket;
const keyFingerprintIsSHA256 = version === 5 || version === 6;
return keyFingerprintIsSHA256 ?
keyOrSubkey.getFingerprint() :
arrayToHexString(await SHA256(keyOrSubkey.keyPacket.writeForHash(version)));
})
);
};
/**
* Find the key entity that generated the given signature.
* If the signature is signed by multiple keys, only one matching key is returned.
* @param {Signature} signature
* @param {Array<Key>} keys - keys to search
* @return {Key|undefined} signing key, if found among `keys`
*/
export function getMatchingKey(signature, keys) {
const keyIDs = signature.getSigningKeyIDs();
for (const signingKeyID of keyIDs) {
// If the signing key is a subkey, we still return the full key entity
const signingKey = keys.find((key) => key.getKeys(signingKeyID).length > 0);
if (signingKey) return signingKey;
}
}