WIP: initial work for Anastasis in qtart

This commit is contained in:
Iván Ávalos 2023-06-30 17:52:24 -06:00
parent 0b60602833
commit ef51ba983f
No known key found for this signature in database
GPG Key ID: AC47C0E4F348CE33
7 changed files with 92 additions and 28 deletions

View File

@ -23,7 +23,6 @@
"dependencies": {
"@gnu-taler/taler-util": "workspace:*",
"fflate": "^0.7.4",
"hash-wasm": "^4.9.0",
"tslib": "^2.5.3"
},
"ava": {

View File

@ -26,8 +26,8 @@ import {
secretbox_open,
hash,
bytesToString,
hashArgon2id,
} from "@gnu-taler/taler-util";
import { argon2id } from "hash-wasm";
export type Flavor<T, FlavorT extends string> = T & {
_flavor?: `anastasis.${FlavorT}`;
@ -71,15 +71,13 @@ export async function userIdentifierDerive(
): Promise<UserIdentifier> {
const canonIdData = canonicalJson(idData);
const hashInput = stringToBytes(canonIdData);
const result = await argon2id({
hashLength: 64,
iterations: 3,
memorySize: 1024 /* kibibytes */,
parallelism: 1,
password: hashInput,
salt: decodeCrock(serverSalt),
outputType: "binary",
});
const result = await hashArgon2id(
hashInput, // password
decodeCrock(serverSalt), // salt
3, // iterations
1024, // memoryLimit (kibibytes)
64, // hashLength
);
return encodeCrock(result);
}
@ -343,15 +341,13 @@ export async function secureAnswerHash(
truthUuid: TruthUuid,
questionSalt: TruthSalt,
): Promise<SecureAnswerHash> {
const powResult = await argon2id({
hashLength: 64,
iterations: 3,
memorySize: 1024 /* kibibytes */,
parallelism: 1,
password: stringToBytes(answer),
salt: decodeCrock(questionSalt),
outputType: "binary",
});
const powResult = await hashArgon2id(
stringToBytes(answer), // password
decodeCrock(questionSalt), // salt
3, // iterations
1024, // memorySize (kibibytes)
64, // hashLength
);
const kdfResult = kdfKw({
outputLength: 64,
salt: decodeCrock(truthUuid),

View File

@ -69,11 +69,12 @@
"big-integer": "^1.6.51",
"fflate": "^0.7.4",
"jed": "^1.1.1",
"tslib": "^2.5.3"
"tslib": "^2.5.3",
"hash-wasm": "^4.9.0"
},
"ava": {
"files": [
"lib/**/*test.js"
]
}
}
}

View File

@ -24,6 +24,7 @@
import * as nacl from "./nacl-fast.js";
import { hmacSha256, hmacSha512 } from "./kdf.js";
import bigint from "big-integer";
import { argon2id } from "hash-wasm";
import {
CoinEnvelope,
CoinPublicKeyString,
@ -69,6 +70,13 @@ interface NativeTartLib {
encodeCrock(buf: Uint8Array | ArrayBuffer): string;
decodeCrock(str: string): Uint8Array;
hash(buf: Uint8Array): Uint8Array;
hashArgon2id(
password: Uint8Array,
salt: Uint8Array,
iterations: number,
memorySize: number,
hashLength: number,
): Uint8Array;
eddsaGetPublic(buf: Uint8Array): Uint8Array;
ecdheGetPublic(buf: Uint8Array): Uint8Array;
eddsaSign(msg: Uint8Array, priv: Uint8Array): Uint8Array;
@ -253,6 +261,33 @@ export function decodeCrock(encoded: string): Uint8Array {
return out;
}
export async function hashArgon2id(
password: Uint8Array,
salt: Uint8Array,
iterations: number,
memorySize: number,
hashLength: number,
): Promise<Uint8Array> {
if (tart) {
return tart.hashArgon2id(
password,
salt,
iterations,
memorySize,
hashLength,
);
}
return await argon2id({
password: password,
salt: salt,
iterations: iterations,
memorySize: memorySize,
hashLength: hashLength,
parallelism: 1,
outputType: "binary",
});
}
export function eddsaGetPublic(eddsaPriv: Uint8Array): Uint8Array {
if (tart) {
return tart.eddsaGetPublic(eddsaPriv);

View File

@ -36,6 +36,7 @@
"@gnu-taler/idb-bridge": "workspace:*",
"@gnu-taler/taler-util": "workspace:*",
"@gnu-taler/taler-wallet-core": "workspace:*",
"@gnu-taler/anastasis-core": "workspace:*",
"tslib": "^2.5.3"
}
}
}

View File

@ -41,6 +41,10 @@ import {
Wallet,
WalletApiOperation,
} from "@gnu-taler/taler-wallet-core";
import {
reduceAction,
ReducerState,
} from "@gnu-taler/anastasis-core";
setGlobalLogLevelFromString("trace");
@ -169,6 +173,25 @@ class NativeWalletMessageHandler {
}
}
/**
* Handle an Anastasis request from the native app.
*/
async function handleAnastasisRequest(
state: ReducerState,
action: string,
id: string,
args: any,
): Promise<CoreApiResponse> {
// For now, this will return "success" even if the wrapped Anastasis
// response is a ReducerStateError.
return {
type: "response",
id,
operation: "anastasis",
result: await reduceAction(state, action, args),
};
}
export function installNativeWalletListener(): void {
setGlobalLogLevelFromString("trace");
const handler = new NativeWalletMessageHandler();
@ -190,7 +213,13 @@ export function installNativeWalletListener(): void {
let respMsg: CoreApiResponse;
try {
respMsg = await handler.handleMessage(operation, id, msg.args ?? {});
if (msg.operation === "anastasis") {
// TODO: do some input validation here
let req = msg.args ?? {};
respMsg = await handleAnastasisRequest(req.state, req.action, id, req.args ?? {});
} else {
respMsg = await handler.handleMessage(operation, id, msg.args ?? {});
}
} catch (e) {
respMsg = {
type: "error",

View File

@ -1,4 +1,4 @@
lockfileVersion: '6.1'
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
@ -120,9 +120,6 @@ importers:
fflate:
specifier: ^0.7.4
version: 0.7.4
hash-wasm:
specifier: ^4.9.0
version: 4.9.0
tslib:
specifier: ^2.5.3
version: 2.5.3
@ -581,6 +578,9 @@ importers:
fflate:
specifier: ^0.7.4
version: 0.7.4
hash-wasm:
specifier: ^4.9.0
version: 4.9.0
jed:
specifier: ^1.1.1
version: 1.1.1
@ -716,6 +716,9 @@ importers:
packages/taler-wallet-embedded:
dependencies:
'@gnu-taler/anastasis-core':
specifier: workspace:*
version: link:../anastasis-core
'@gnu-taler/idb-bridge':
specifier: workspace:*
version: link:../idb-bridge