diff options
Diffstat (limited to 'packages/anastasis-core/src/crypto.ts')
-rw-r--r-- | packages/anastasis-core/src/crypto.ts | 107 |
1 files changed, 81 insertions, 26 deletions
diff --git a/packages/anastasis-core/src/crypto.ts b/packages/anastasis-core/src/crypto.ts index da8338636..8bc004e95 100644 --- a/packages/anastasis-core/src/crypto.ts +++ b/packages/anastasis-core/src/crypto.ts @@ -1,22 +1,38 @@ +/* + This file is part of GNU Anastasis + (C) 2021-2022 Anastasis SARL + + GNU Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + import { - bytesToString, canonicalJson, decodeCrock, encodeCrock, getRandomBytes, - kdf, kdfKw, secretbox, crypto_sign_keyPair_fromSeed, stringToBytes, secretbox_open, + hash, + bytesToString, + hashArgon2id, } from "@gnu-taler/taler-util"; -import { gzipSync } from "fflate"; -import { argon2id } from "hash-wasm"; export type Flavor<T, FlavorT extends string> = T & { _flavor?: `anastasis.${FlavorT}`; }; + export type FlavorP<T, FlavorT extends string, S extends number> = T & { _flavor?: `anastasis.${FlavorT}`; _size?: S; @@ -55,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); } @@ -111,6 +125,46 @@ export async function decryptRecoveryDocument( return anastasisDecrypt(asOpaque(userId), recoveryDocData, "erd"); } +export interface PolicyMetadata { + secret_name: string; + policy_hash: string; +} + +export async function encryptPolicyMetadata( + userId: UserIdentifier, + metadata: PolicyMetadata, +): Promise<OpaqueData> { + const metadataBytes = typedArrayConcat([ + decodeCrock(metadata.policy_hash), + stringToBytes(metadata.secret_name), + ]); + const nonce = encodeCrock(getRandomBytes(nonceSize)); + return anastasisEncrypt( + nonce, + asOpaque(userId), + encodeCrock(metadataBytes), + "rmd", + ); +} + +export async function decryptPolicyMetadata( + userId: UserIdentifier, + metadataEnc: OpaqueData, +): Promise<PolicyMetadata> { + // @ts-ignore + console.log("metadataEnc", metadataEnc); + const plain = await anastasisDecrypt(asOpaque(userId), metadataEnc, "rmd"); + // @ts-ignore + console.log("plain:", plain); + const metadataBytes = decodeCrock(plain); + const policyHash = encodeCrock(metadataBytes.slice(0, 64)); + const secretName = bytesToString(metadataBytes.slice(64)); + return { + policy_hash: policyHash, + secret_name: secretName, + }; +} + export function typedArrayConcat(chunks: Uint8Array[]): Uint8Array { let payloadLen = 0; for (const c of chunks) { @@ -175,11 +229,11 @@ async function anastasisDecrypt( const nonceBuf = ctBuf.slice(0, nonceSize); const enc = ctBuf.slice(nonceSize); const key = await deriveKey(keySeed, encodeCrock(nonceBuf), salt); - const cipherText = secretbox_open(enc, nonceBuf, key); - if (!cipherText) { + const clearText = secretbox_open(enc, nonceBuf, key); + if (!clearText) { throw Error("could not decrypt"); } - return encodeCrock(cipherText); + return encodeCrock(clearText); } export const asOpaque = (x: string): OpaqueData => x; @@ -248,7 +302,6 @@ export async function coreSecretRecover(args: { args.encryptedMasterKey, "emk", ); - console.log("recovered master key", masterKey); return await anastasisDecrypt(masterKey, args.encryptedCoreSecret, "cse"); } @@ -283,20 +336,22 @@ export async function coreSecretEncrypt( }; } +export async function pinAnswerHash(pin: number): Promise<SecureAnswerHash> { + return encodeCrock(hash(stringToBytes(pin.toString()))); +} + export async function secureAnswerHash( answer: string, 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), |