use native KDF / hash state if available

This commit is contained in:
Florian Dold 2022-12-23 12:58:26 +01:00
parent dc002f99a9
commit d98711cb51
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
7 changed files with 65 additions and 49 deletions

View File

@ -22,7 +22,7 @@
"pretty": "prettier --write src"
},
"devDependencies": {
"@types/node": "^18.8.5",
"@types/node": "^18.11.17",
"ava": "^4.3.3",
"esbuild": "^0.14.21",
"prettier": "^2.5.1",

View File

@ -16,12 +16,12 @@
import { canonicalJson } from "./helpers.js";
import { Logger } from "./logging.js";
import { kdf } from "./kdf.js";
import {
decodeCrock,
encodeCrock,
getRandomBytes,
hash,
kdf,
stringToBytes,
} from "./taler-crypto.js";

View File

@ -16,7 +16,6 @@
import * as nacl from "./nacl-fast.js";
import { sha256 } from "./sha256.js";
import { useNative } from "./taler-crypto.js";
export function sha512(data: Uint8Array): Uint8Array {
return nacl.hash(data);
@ -59,42 +58,3 @@ export function hmacSha512(key: Uint8Array, message: Uint8Array): Uint8Array {
export function hmacSha256(key: Uint8Array, message: Uint8Array): Uint8Array {
return hmac(sha256, 64, key, message);
}
export function kdf(
outputLength: number,
ikm: Uint8Array,
salt?: Uint8Array,
info?: Uint8Array,
): Uint8Array {
if (useNative && "_kdf" in globalThis) {
// @ts-ignore
return globalThis._kdf(outputLength, ikm, salt, info);
}
salt = salt ?? new Uint8Array(64);
// extract
const prk = hmacSha512(salt, ikm);
info = info ?? new Uint8Array(0);
// expand
const N = Math.ceil(outputLength / 32);
const output = new Uint8Array(N * 32);
for (let i = 0; i < N; i++) {
let buf;
if (i == 0) {
buf = new Uint8Array(info.byteLength + 1);
buf.set(info, 0);
} else {
buf = new Uint8Array(info.byteLength + 1 + 32);
for (let j = 0; j < 32; j++) {
buf[j] = output[(i - 1) * 32 + j];
}
buf.set(info, 32);
}
buf[buf.length - 1] = i + 1;
const chunk = hmacSha256(prk, buf);
output.set(chunk, i * 32);
}
return output.slice(0, outputLength);
}

View File

@ -37,8 +37,9 @@ import {
getRandomBytes,
bigintToNaclArr,
bigintFromNaclArr,
kdf,
} from "./taler-crypto.js";
import { sha512, kdf } from "./kdf.js";
import { sha512 } from "./kdf.js";
import * as nacl from "./nacl-fast.js";
import { initNodePrng } from "./prng-node.js";

View File

@ -22,7 +22,7 @@
* Imports.
*/
import * as nacl from "./nacl-fast.js";
import { kdf } from "./kdf.js";
import { hmacSha256, hmacSha512 } from "./kdf.js";
import bigint from "big-integer";
import {
CoinEnvelope,
@ -76,7 +76,10 @@ interface NativeTartLib {
keyExchangeEddsaEcdh(eddsaPriv: Uint8Array, ecdhPub: Uint8Array): Uint8Array;
rsaBlind(hmsg: Uint8Array, bks: Uint8Array, rsaPub: Uint8Array): Uint8Array;
rsaUnblind(blindSig: Uint8Array, rsaPub: Uint8Array, bks: Uint8Array): Uint8Array;
rsaVerify(hmsg: Uint8Array, rsaSig: Uint8Array, rsaPub: Uint8Array): boolean
rsaVerify(hmsg: Uint8Array, rsaSig: Uint8Array, rsaPub: Uint8Array): boolean;
hashStateInit(): any;
hashStateUpdate(st: any, data: Uint8Array): any;
hashStateFinish(st: any): Uint8Array;
}
// @ts-ignore
@ -158,6 +161,45 @@ export function encodeCrock(data: ArrayBuffer): string {
return sb;
}
export function kdf(
outputLength: number,
ikm: Uint8Array,
salt?: Uint8Array,
info?: Uint8Array,
): Uint8Array {
if (tart) {
return tart.kdf(outputLength, ikm, salt, info)
}
salt = salt ?? new Uint8Array(64);
// extract
const prk = hmacSha512(salt, ikm);
info = info ?? new Uint8Array(0);
// expand
const N = Math.ceil(outputLength / 32);
const output = new Uint8Array(N * 32);
for (let i = 0; i < N; i++) {
let buf;
if (i == 0) {
buf = new Uint8Array(info.byteLength + 1);
buf.set(info, 0);
} else {
buf = new Uint8Array(info.byteLength + 1 + 32);
for (let j = 0; j < 32; j++) {
buf[j] = output[(i - 1) * 32 + j];
}
buf.set(info, 32);
}
buf[buf.length - 1] = i + 1;
const chunk = hmacSha256(prk, buf);
output.set(chunk, i * 32);
}
return output.slice(0, outputLength);
}
/**
* HMAC-SHA512-SHA256 (see RFC 5869).
*/
@ -708,7 +750,7 @@ const logger = new Logger("talerCrypto.ts");
export function hashCoinEvInner(
coinEv: CoinEnvelope,
hashState: nacl.HashState,
hashState: TalerHashState,
): void {
const hashInputBuf = new ArrayBuffer(4);
const uint8ArrayBuf = new Uint8Array(hashInputBuf);
@ -785,7 +827,20 @@ export function eddsaVerify(
return nacl.sign_detached_verify(msg, sig, eddsaPub);
}
export function createHashContext(): nacl.HashState {
export interface TalerHashState {
update(data: Uint8Array): void;
finish(): Uint8Array;
}
export function createHashContext(): TalerHashState {
if (tart) {
const t = tart;
const st = tart.hashStateInit();
return {
finish: () => t.hashStateFinish(st),
update: (d) => t.hashStateUpdate(st, d),
}
}
return new nacl.HashState();
}

View File

@ -61,7 +61,7 @@
"dependencies": {
"@gnu-taler/idb-bridge": "workspace:*",
"@gnu-taler/taler-util": "workspace:*",
"@types/node": "^18.8.5",
"@types/node": "^18.11.17",
"axios": "^0.27.2",
"big-integer": "^1.6.51",
"fflate": "^0.7.4",

View File

@ -27,7 +27,7 @@ import { processRequestWithImpl } from "./worker-common.js";
const logger = new Logger("nodeThreadWorker.ts");
const f = url.fileURLToPath(import.meta.url);
const f = import.meta.url ? url.fileURLToPath(import.meta.url) : '__not_available__';
const workerCode = `
// Try loading the glue library for embedded