wallet: use native crypto if available
This commit is contained in:
parent
265e7a7137
commit
d040c3b861
@ -29,6 +29,7 @@ export {
|
|||||||
secretbox,
|
secretbox,
|
||||||
secretbox_open,
|
secretbox_open,
|
||||||
crypto_sign_keyPair_fromSeed,
|
crypto_sign_keyPair_fromSeed,
|
||||||
|
setPRNG,
|
||||||
} from "./nacl-fast.js";
|
} from "./nacl-fast.js";
|
||||||
export { RequestThrottler } from "./RequestThrottler.js";
|
export { RequestThrottler } from "./RequestThrottler.js";
|
||||||
export * from "./CancellationToken.js";
|
export * from "./CancellationToken.js";
|
||||||
|
@ -59,18 +59,6 @@ export function hmacSha256(key: Uint8Array, message: Uint8Array): Uint8Array {
|
|||||||
return hmac(sha256, 64, key, message);
|
return hmac(sha256, 64, key, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* HMAC-SHA512-SHA256 (see RFC 5869).
|
|
||||||
*/
|
|
||||||
export function kdfKw(args: {
|
|
||||||
outputLength: number;
|
|
||||||
ikm: Uint8Array;
|
|
||||||
salt?: Uint8Array;
|
|
||||||
info?: Uint8Array;
|
|
||||||
}) {
|
|
||||||
return kdf(args.outputLength, args.ikm, args.salt, args.info);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kdf(
|
export function kdf(
|
||||||
outputLength: number,
|
outputLength: number,
|
||||||
ikm: Uint8Array,
|
ikm: Uint8Array,
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import * as nacl from "./nacl-fast.js";
|
import * as nacl from "./nacl-fast.js";
|
||||||
import { kdf, kdfKw } from "./kdf.js";
|
import { kdf } from "./kdf.js";
|
||||||
import bigint from "big-integer";
|
import bigint from "big-integer";
|
||||||
import {
|
import {
|
||||||
CoinEnvelope,
|
CoinEnvelope,
|
||||||
@ -55,6 +55,8 @@ export function getRandomBytesF<T extends number, N extends string>(
|
|||||||
return nacl.randomBytes(n);
|
return nacl.randomBytes(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useNative = true;
|
||||||
|
|
||||||
const encTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
const encTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
||||||
|
|
||||||
class EncodingError extends Error {
|
class EncodingError extends Error {
|
||||||
@ -99,6 +101,10 @@ function getValue(chr: string): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function encodeCrock(data: ArrayBuffer): string {
|
export function encodeCrock(data: ArrayBuffer): string {
|
||||||
|
if (useNative && "_encodeCrock" in globalThis) {
|
||||||
|
// @ts-ignore
|
||||||
|
return globalThis._encodeCrock(data);
|
||||||
|
}
|
||||||
const dataBytes = new Uint8Array(data);
|
const dataBytes = new Uint8Array(data);
|
||||||
let sb = "";
|
let sb = "";
|
||||||
const size = data.byteLength;
|
const size = data.byteLength;
|
||||||
@ -123,7 +129,23 @@ export function encodeCrock(data: ArrayBuffer): string {
|
|||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HMAC-SHA512-SHA256 (see RFC 5869).
|
||||||
|
*/
|
||||||
|
export function kdfKw(args: {
|
||||||
|
outputLength: number;
|
||||||
|
ikm: Uint8Array;
|
||||||
|
salt?: Uint8Array;
|
||||||
|
info?: Uint8Array;
|
||||||
|
}) {
|
||||||
|
return kdf(args.outputLength, args.ikm, args.salt, args.info);
|
||||||
|
}
|
||||||
|
|
||||||
export function decodeCrock(encoded: string): Uint8Array {
|
export function decodeCrock(encoded: string): Uint8Array {
|
||||||
|
if (useNative && "_decodeCrock" in globalThis) {
|
||||||
|
// @ts-ignore
|
||||||
|
return globalThis._decodeCrock(encoded);
|
||||||
|
}
|
||||||
const size = encoded.length;
|
const size = encoded.length;
|
||||||
let bitpos = 0;
|
let bitpos = 0;
|
||||||
let bitbuf = 0;
|
let bitbuf = 0;
|
||||||
@ -152,6 +174,10 @@ export function decodeCrock(encoded: string): Uint8Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function eddsaGetPublic(eddsaPriv: Uint8Array): Uint8Array {
|
export function eddsaGetPublic(eddsaPriv: Uint8Array): Uint8Array {
|
||||||
|
if (useNative && "_eddsaGetPublic" in globalThis) {
|
||||||
|
// @ts-ignore
|
||||||
|
return globalThis._eddsaGetPublic(eddsaPriv);
|
||||||
|
}
|
||||||
const pair = nacl.crypto_sign_keyPair_fromSeed(eddsaPriv);
|
const pair = nacl.crypto_sign_keyPair_fromSeed(eddsaPriv);
|
||||||
return pair.publicKey;
|
return pair.publicKey;
|
||||||
}
|
}
|
||||||
@ -164,13 +190,13 @@ export function keyExchangeEddsaEcdhe(
|
|||||||
eddsaPriv: Uint8Array,
|
eddsaPriv: Uint8Array,
|
||||||
ecdhePub: Uint8Array,
|
ecdhePub: Uint8Array,
|
||||||
): Uint8Array {
|
): Uint8Array {
|
||||||
const ph = nacl.hash(eddsaPriv);
|
const ph = hash(eddsaPriv);
|
||||||
const a = new Uint8Array(32);
|
const a = new Uint8Array(32);
|
||||||
for (let i = 0; i < 32; i++) {
|
for (let i = 0; i < 32; i++) {
|
||||||
a[i] = ph[i];
|
a[i] = ph[i];
|
||||||
}
|
}
|
||||||
const x = nacl.scalarMult(a, ecdhePub);
|
const x = nacl.scalarMult(a, ecdhePub);
|
||||||
return nacl.hash(x);
|
return hash(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function keyExchangeEcdheEddsa(
|
export function keyExchangeEcdheEddsa(
|
||||||
@ -179,7 +205,7 @@ export function keyExchangeEcdheEddsa(
|
|||||||
): Uint8Array {
|
): Uint8Array {
|
||||||
const curve25519Pub = nacl.sign_ed25519_pk_to_curve25519(eddsaPub);
|
const curve25519Pub = nacl.sign_ed25519_pk_to_curve25519(eddsaPub);
|
||||||
const x = nacl.scalarMult(ecdhePriv, curve25519Pub);
|
const x = nacl.scalarMult(ecdhePriv, curve25519Pub);
|
||||||
return nacl.hash(x);
|
return hash(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RsaPub {
|
interface RsaPub {
|
||||||
@ -477,7 +503,7 @@ function csFDH(
|
|||||||
const L = bigint.fromArray(lMod, 256, false);
|
const L = bigint.fromArray(lMod, 256, false);
|
||||||
|
|
||||||
const info = stringToBytes("Curve25519FDH");
|
const info = stringToBytes("Curve25519FDH");
|
||||||
const preshash = nacl.hash(typedArrayConcat([rPub, hm]));
|
const preshash = hash(typedArrayConcat([rPub, hm]));
|
||||||
return csKdfMod(L, preshash, csPub, info).reverse();
|
return csKdfMod(L, preshash, csPub, info).reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,6 +634,10 @@ export function createEcdheKeyPair(): EcdheKeyPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hash(d: Uint8Array): Uint8Array {
|
export function hash(d: Uint8Array): Uint8Array {
|
||||||
|
if (useNative && "_hash" in globalThis) {
|
||||||
|
// @ts-ignore
|
||||||
|
return globalThis._hash(d);
|
||||||
|
}
|
||||||
return nacl.hash(d);
|
return nacl.hash(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +646,7 @@ export function hash(d: Uint8Array): Uint8Array {
|
|||||||
* to 32 bytes.
|
* to 32 bytes.
|
||||||
*/
|
*/
|
||||||
export function hashTruncate32(d: Uint8Array): Uint8Array {
|
export function hashTruncate32(d: Uint8Array): Uint8Array {
|
||||||
const sha512HashCode = nacl.hash(d);
|
const sha512HashCode = hash(d);
|
||||||
return sha512HashCode.subarray(0, 32);
|
return sha512HashCode.subarray(0, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,7 +703,7 @@ export function hashDenomPub(pub: DenominationPubKey): Uint8Array {
|
|||||||
dv.setUint32(0, pub.age_mask ?? 0);
|
dv.setUint32(0, pub.age_mask ?? 0);
|
||||||
dv.setUint32(4, DenomKeyType.toIntTag(pub.cipher));
|
dv.setUint32(4, DenomKeyType.toIntTag(pub.cipher));
|
||||||
uint8ArrayBuf.set(pubBuf, 8);
|
uint8ArrayBuf.set(pubBuf, 8);
|
||||||
return nacl.hash(uint8ArrayBuf);
|
return hash(uint8ArrayBuf);
|
||||||
} else if (pub.cipher === DenomKeyType.ClauseSchnorr) {
|
} else if (pub.cipher === DenomKeyType.ClauseSchnorr) {
|
||||||
const pubBuf = decodeCrock(pub.cs_public_key);
|
const pubBuf = decodeCrock(pub.cs_public_key);
|
||||||
const hashInputBuf = new ArrayBuffer(pubBuf.length + 4 + 4);
|
const hashInputBuf = new ArrayBuffer(pubBuf.length + 4 + 4);
|
||||||
@ -682,7 +712,7 @@ export function hashDenomPub(pub: DenominationPubKey): Uint8Array {
|
|||||||
dv.setUint32(0, pub.age_mask ?? 0);
|
dv.setUint32(0, pub.age_mask ?? 0);
|
||||||
dv.setUint32(4, DenomKeyType.toIntTag(pub.cipher));
|
dv.setUint32(4, DenomKeyType.toIntTag(pub.cipher));
|
||||||
uint8ArrayBuf.set(pubBuf, 8);
|
uint8ArrayBuf.set(pubBuf, 8);
|
||||||
return nacl.hash(uint8ArrayBuf);
|
return hash(uint8ArrayBuf);
|
||||||
} else {
|
} else {
|
||||||
throw Error(
|
throw Error(
|
||||||
`unsupported cipher (${
|
`unsupported cipher (${
|
||||||
@ -693,6 +723,10 @@ export function hashDenomPub(pub: DenominationPubKey): Uint8Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function eddsaSign(msg: Uint8Array, eddsaPriv: Uint8Array): Uint8Array {
|
export function eddsaSign(msg: Uint8Array, eddsaPriv: Uint8Array): Uint8Array {
|
||||||
|
if (useNative && "_eddsaSign" in globalThis) {
|
||||||
|
// @ts-ignore
|
||||||
|
return globalThis._eddsaSign(msg, eddsaPriv);
|
||||||
|
}
|
||||||
const pair = nacl.crypto_sign_keyPair_fromSeed(eddsaPriv);
|
const pair = nacl.crypto_sign_keyPair_fromSeed(eddsaPriv);
|
||||||
return nacl.sign_detached(msg, pair.secretKey);
|
return nacl.sign_detached(msg, pair.secretKey);
|
||||||
}
|
}
|
||||||
@ -702,6 +736,10 @@ export function eddsaVerify(
|
|||||||
sig: Uint8Array,
|
sig: Uint8Array,
|
||||||
eddsaPub: Uint8Array,
|
eddsaPub: Uint8Array,
|
||||||
): boolean {
|
): boolean {
|
||||||
|
if (useNative && "_eddsaVerify" in globalThis) {
|
||||||
|
// @ts-ignore
|
||||||
|
return globalThis._eddsaVerify(msg, sig, eddsaPub);
|
||||||
|
}
|
||||||
return nacl.sign_detached_verify(msg, sig, eddsaPub);
|
return nacl.sign_detached_verify(msg, sig, eddsaPub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ import {
|
|||||||
j2s,
|
j2s,
|
||||||
Logger,
|
Logger,
|
||||||
setGlobalLogLevelFromString,
|
setGlobalLogLevelFromString,
|
||||||
|
setPRNG,
|
||||||
WalletNotification,
|
WalletNotification,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { BridgeIDBFactory } from "@gnu-taler/idb-bridge";
|
import { BridgeIDBFactory } from "@gnu-taler/idb-bridge";
|
||||||
@ -54,6 +55,16 @@ import * as _qjsOsImp from "os";
|
|||||||
const textDecoder = new TextDecoder();
|
const textDecoder = new TextDecoder();
|
||||||
const textEncoder = new TextEncoder();
|
const textEncoder = new TextEncoder();
|
||||||
|
|
||||||
|
setGlobalLogLevelFromString("trace");
|
||||||
|
|
||||||
|
setPRNG(function (x: Uint8Array, n: number) {
|
||||||
|
// @ts-ignore
|
||||||
|
const va = globalThis._randomBytes(n);
|
||||||
|
const v = new Uint8Array(va);
|
||||||
|
for (let i = 0; i < n; i++) x[i] = v[i];
|
||||||
|
for (let i = 0; i < v.length; i++) v[i] = 0;
|
||||||
|
});
|
||||||
|
|
||||||
export interface QjsHttpResp {
|
export interface QjsHttpResp {
|
||||||
status: number;
|
status: number;
|
||||||
data: ArrayBuffer;
|
data: ArrayBuffer;
|
||||||
@ -126,8 +137,6 @@ export class NativeHttpLib implements HttpRequestLibrary {
|
|||||||
data = new ArrayBuffer(0);
|
data = new ArrayBuffer(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(`data type ${data?.constructor.name}`);
|
|
||||||
console.log(`data: ${j2s(data)}`);
|
|
||||||
const res = qjsOs.fetchHttp(url, {
|
const res = qjsOs.fetchHttp(url, {
|
||||||
method,
|
method,
|
||||||
data,
|
data,
|
||||||
|
Loading…
Reference in New Issue
Block a user