Refactor: s2k module to Typescrip

This commit is contained in:
Julia Krüger 2023-12-06 18:21:21 +01:00
parent e92b44bc84
commit 48bd1a06f0
No known key found for this signature in database
GPG Key ID: B8738B09D5E94DEB
6 changed files with 32 additions and 22 deletions

View File

@ -17,7 +17,7 @@
import * as stream from '@openpgp/web-stream-tools'; import * as stream from '@openpgp/web-stream-tools';
import { armor, unarmor } from './encoding/armor'; import { armor, unarmor } from './encoding/armor';
import { Argon2OutOfMemoryError } from './type/s2k'; import { Argon2OutOfMemoryError } from './type/s2k/index.ts';
import defaultConfig from './config'; import defaultConfig from './config';
import crypto from './crypto'; import crypto from './crypto';
import enums from './enums'; import enums from './enums';

View File

@ -16,7 +16,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import PublicKeyPacket from './public_key'; import PublicKeyPacket from './public_key';
import { newS2KFromConfig, newS2KFromType } from '../type/s2k'; import { newS2KFromConfig, newS2KFromType } from '../type/s2k/index.ts';
import crypto from '../crypto'; import crypto from '../crypto';
import enums from '../enums'; import enums from '../enums';
import util from '../util'; import util from '../util';

View File

@ -15,7 +15,7 @@
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import { newS2KFromConfig, newS2KFromType } from '../type/s2k'; import { newS2KFromConfig, newS2KFromType } from '../type/s2k/index.ts';
import defaultConfig from '../config'; import defaultConfig from '../config';
import crypto from '../crypto'; import crypto from '../crypto';
import computeHKDF from '../crypto/hkdf'; import computeHKDF from '../crypto/hkdf';

View File

@ -8,7 +8,7 @@ const ARGON2_VERSION = 0x13;
const ARGON2_SALT_SIZE = 16; const ARGON2_SALT_SIZE = 16;
export class Argon2OutOfMemoryError extends Error { export class Argon2OutOfMemoryError extends Error {
constructor(...params) { constructor(...params: string[]) {
super(...params); super(...params);
if (Error.captureStackTrace) { if (Error.captureStackTrace) {
@ -20,16 +20,22 @@ export class Argon2OutOfMemoryError extends Error {
} }
// cache argon wasm module // cache argon wasm module
let loadArgonWasmModule; let loadArgonWasmModule: Function;
let argon2Promise; let argon2Promise: Promise<Function>;
// reload wasm module above this treshold, to deallocated used memory // reload wasm module above this treshold, to deallocated used memory
const ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = 2 << 19; const ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = 2 << 19;
class Argon2S2K { class Argon2S2K {
type: string;
salt: Uint8Array | null;
t: number;
p: number;
encodedM: number;
/** /**
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
*/ */
constructor(config = defaultConfig) { constructor(config = defaultConfig) {
const { passes, parallelism, memoryExponent } = config.s2kArgon2Params; const { passes, parallelism, memoryExponent } = config.s2kArgon2Params;
this.type = 'argon2'; this.type = 'argon2';
@ -52,7 +58,7 @@ class Argon2S2K {
* @param {Uint8Array} bytes - Payload of argon2 string-to-key specifier * @param {Uint8Array} bytes - Payload of argon2 string-to-key specifier
* @returns {Integer} Actual length of the object. * @returns {Integer} Actual length of the object.
*/ */
read(bytes) { read(bytes: Uint8Array) {
let i = 0; let i = 0;
this.salt = bytes.subarray(i, i + 16); this.salt = bytes.subarray(i, i + 16);
@ -69,7 +75,7 @@ class Argon2S2K {
* Serializes s2k information * Serializes s2k information
* @returns {Uint8Array} Binary representation of s2k. * @returns {Uint8Array} Binary representation of s2k.
*/ */
write() { write(): Uint8Array {
const arr = [ const arr = [
new Uint8Array([enums.write(enums.s2k, this.type)]), new Uint8Array([enums.write(enums.s2k, this.type)]),
this.salt, this.salt,
@ -87,7 +93,7 @@ class Argon2S2K {
* @throws {Argon2OutOfMemoryError|Errors} * @throws {Argon2OutOfMemoryError|Errors}
* @async * @async
*/ */
async produceKey(passphrase, keySize) { async produceKey(passphrase: string, keySize: number): Promise<Uint8Array> {
const decodedM = 2 << (this.encodedM - 1); const decodedM = 2 << (this.encodedM - 1);
try { try {
@ -120,7 +126,7 @@ class Argon2S2K {
} }
return hash; return hash;
} catch (e) { } catch (e) {
if (e.message && ( if (e instanceof Error && e.message && (
e.message.includes('Unable to grow instance memory') || // Chrome e.message.includes('Unable to grow instance memory') || // Chrome
e.message.includes('failed to grow memory') || // Firefox e.message.includes('failed to grow memory') || // Firefox
e.message.includes('WebAssembly.Memory.grow') || // Safari e.message.includes('WebAssembly.Memory.grow') || // Safari

View File

@ -34,10 +34,14 @@ import { UnsupportedError } from '../../packet/packet';
import util from '../../util'; import util from '../../util';
class GenericS2K { class GenericS2K {
algorithm: number;
type: string;
c: number;
salt: Uint8Array | null;
/** /**
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
*/ */
constructor(s2kType, config = defaultConfig) { constructor(s2kType: number, config = defaultConfig) {
/** /**
* Hash function identifier, or 0 for gnu-dummy keys * Hash function identifier, or 0 for gnu-dummy keys
* @type {module:enums.hash | 0} * @type {module:enums.hash | 0}
@ -76,7 +80,7 @@ class GenericS2K {
* @param {Uint8Array} bytes - Payload of string-to-key specifier * @param {Uint8Array} bytes - Payload of string-to-key specifier
* @returns {Integer} Actual length of the object. * @returns {Integer} Actual length of the object.
*/ */
read(bytes) { read(bytes: Uint8Array): Number {
let i = 0; let i = 0;
this.algorithm = bytes[i++]; this.algorithm = bytes[i++];
@ -123,7 +127,7 @@ class GenericS2K {
* Serializes s2k information * Serializes s2k information
* @returns {Uint8Array} Binary representation of s2k. * @returns {Uint8Array} Binary representation of s2k.
*/ */
write() { write(): Uint8Array {
if (this.type === 'gnu-dummy') { if (this.type === 'gnu-dummy') {
return new Uint8Array([101, 0, ...util.stringToUint8Array('GNU'), 1]); return new Uint8Array([101, 0, ...util.stringToUint8Array('GNU'), 1]);
} }
@ -133,10 +137,10 @@ class GenericS2K {
case 'simple': case 'simple':
break; break;
case 'salted': case 'salted':
arr.push(this.salt); this.salt && arr.push(this.salt);
break; break;
case 'iterated': case 'iterated':
arr.push(this.salt); this.salt &&arr.push(this.salt);
arr.push(new Uint8Array([this.c])); arr.push(new Uint8Array([this.c]));
break; break;
case 'gnu': case 'gnu':
@ -156,8 +160,8 @@ class GenericS2K {
* hashAlgorithm hash length * hashAlgorithm hash length
* @async * @async
*/ */
async produceKey(passphrase, numBytes) { async produceKey(passphrase: string, numBytes: number): Promise<Uint8Array> {
passphrase = util.encodeUTF8(passphrase); const encodedPassphrase = util.encodeUTF8(passphrase);
const arr = []; const arr = [];
let rlength = 0; let rlength = 0;
@ -167,13 +171,13 @@ class GenericS2K {
let toHash; let toHash;
switch (this.type) { switch (this.type) {
case 'simple': case 'simple':
toHash = util.concatUint8Array([new Uint8Array(prefixlen), passphrase]); toHash = util.concatUint8Array([new Uint8Array(prefixlen), encodedPassphrase]);
break; break;
case 'salted': case 'salted':
toHash = util.concatUint8Array([new Uint8Array(prefixlen), this.salt, passphrase]); toHash = util.concatUint8Array([new Uint8Array(prefixlen), this.salt, encodedPassphrase]);
break; break;
case 'iterated': { case 'iterated': {
const data = util.concatUint8Array([this.salt, passphrase]); const data = util.concatUint8Array([this.salt, encodedPassphrase]);
let datalen = data.length; let datalen = data.length;
const count = Math.max(this.getCount(), datalen); const count = Math.max(this.getCount(), datalen);
toHash = new Uint8Array(prefixlen + count); toHash = new Uint8Array(prefixlen + count);

View File

@ -13,7 +13,7 @@ const allowedS2KTypesForEncryption = new Set([enums.s2k.argon2, enums.s2k.iterat
* @returns {Object} New s2k object * @returns {Object} New s2k object
* @throws {Error} for unknown or unsupported types * @throws {Error} for unknown or unsupported types
*/ */
export function newS2KFromType(type, config = defaultConfig) { export function newS2KFromType (type: number, config = defaultConfig): Argon2S2K | GenericS2K {
switch (type) { switch (type) {
case enums.s2k.argon2: case enums.s2k.argon2:
return new Argon2S2K(config); return new Argon2S2K(config);
@ -33,7 +33,7 @@ export function newS2KFromType(type, config = defaultConfig) {
* @returns {Object} New s2k object * @returns {Object} New s2k object
* @throws {Error} for unknown or unsupported types * @throws {Error} for unknown or unsupported types
*/ */
export function newS2KFromConfig(config) { export function newS2KFromConfig(config = defaultConfig) {
const { s2kType } = config; const { s2kType } = config;
if (!allowedS2KTypesForEncryption.has(s2kType)) { if (!allowedS2KTypesForEncryption.has(s2kType)) {