diff options
author | Florian Dold <florian@dold.me> | 2022-04-18 21:23:37 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2022-04-18 21:23:49 +0200 |
commit | 2e0b9b9cff43968a16eb9555cb6e128c979a604b (patch) | |
tree | 038e66c078e2a64acecfeff2f2c80d4128bfa35e | |
parent | 68b4d0c4de7df98190fcc07c11fa809622b27bfc (diff) |
wallet-core: age restriction crypto WIP
-rw-r--r-- | packages/anastasis-core/src/crypto.ts | 1 | ||||
-rw-r--r-- | packages/taler-util/src/nacl-fast.ts | 84 | ||||
-rw-r--r-- | packages/taler-util/src/payto.ts | 10 | ||||
-rw-r--r-- | packages/taler-util/src/talerCrypto.ts | 98 |
4 files changed, 187 insertions, 6 deletions
diff --git a/packages/anastasis-core/src/crypto.ts b/packages/anastasis-core/src/crypto.ts index 9f412c6dc..815f84c11 100644 --- a/packages/anastasis-core/src/crypto.ts +++ b/packages/anastasis-core/src/crypto.ts @@ -32,6 +32,7 @@ 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; diff --git a/packages/taler-util/src/nacl-fast.ts b/packages/taler-util/src/nacl-fast.ts index 809a1a489..82bdc7cec 100644 --- a/packages/taler-util/src/nacl-fast.ts +++ b/packages/taler-util/src/nacl-fast.ts @@ -2564,7 +2564,7 @@ function crypto_sign_keypair( return 0; } -const L = new Float64Array([ +export const L = new Float64Array([ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, ]); @@ -3045,3 +3045,85 @@ export function crypto_core_ed25519_scalar_sub( modL(o, z); return o; } + +export function crypto_edx25519_private_key_create(): Uint8Array { + const seed = new Uint8Array(32); + randombytes(seed, 32); + return crypto_edx25519_private_key_create_from_seed(seed); +} + +export function crypto_edx25519_private_key_create_from_seed( + seed: Uint8Array, +): Uint8Array { + const pk = hash(seed); + pk[0] &= 248; + pk[31] &= 127; + pk[31] |= 64; + return pk; +} + +export function crypto_edx25519_get_public(priv: Uint8Array): Uint8Array { + const pub = new Uint8Array(32); + if (0 != crypto_scalarmult_base_noclamp(pub.subarray(32), priv)) { + throw Error(); + } + return pub; +} + +export function crypto_edx25519_sign_detached( + m: Uint8Array, + skx: Uint8Array, + pkx: Uint8Array, +): Uint8Array { + const n: number = m.length; + const d = new Uint8Array(64), + h = new Uint8Array(64), + r = new Uint8Array(64); + let i, j; + const x = new Float64Array(64); + const p = [gf(), gf(), gf(), gf()]; + + for (i = 0; i < 64; i++) d[i] = skx[i]; + + const sm = new Uint8Array(n + 64); + + for (i = 0; i < n; i++) sm[64 + i] = m[i]; + for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]; + + crypto_hash(r, sm.subarray(32), n + 32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for (i = 32; i < 64; i++) sm[i] = pkx[i - 32]; + crypto_hash(h, sm, n + 64); + reduce(h); + + for (i = 0; i < 64; i++) x[i] = 0; + for (i = 0; i < 32; i++) x[i] = r[i]; + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + x[i + j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return sm.subarray(64); +} + +export function crypto_edx25519_sign_detached_verify( + msg: Uint8Array, + sig: Uint8Array, + publicKey: Uint8Array, +): boolean { + checkArrayTypes(msg, sig, publicKey); + if (sig.length !== crypto_sign_BYTES) throw new Error("bad signature size"); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error("bad public key size"); + const sm = new Uint8Array(crypto_sign_BYTES + msg.length); + const m = new Uint8Array(crypto_sign_BYTES + msg.length); + let i; + for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]; + for (i = 0; i < msg.length; i++) sm[i + crypto_sign_BYTES] = msg[i]; + return crypto_sign_open(m, sm, sm.length, publicKey) >= 0; +} diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts index 09d6856ca..dd764e42d 100644 --- a/packages/taler-util/src/payto.ts +++ b/packages/taler-util/src/payto.ts @@ -23,30 +23,30 @@ export type PaytoUri = | PaytoUriTalerBank | PaytoUriBitcoin; -interface PaytoUriGeneric { +export interface PaytoUriGeneric { targetType: string; targetPath: string; params: { [name: string]: string }; } -interface PaytoUriUnknown extends PaytoUriGeneric { +export interface PaytoUriUnknown extends PaytoUriGeneric { isKnown: false; } -interface PaytoUriIBAN extends PaytoUriGeneric { +export interface PaytoUriIBAN extends PaytoUriGeneric { isKnown: true; targetType: "iban"; iban: string; } -interface PaytoUriTalerBank extends PaytoUriGeneric { +export interface PaytoUriTalerBank extends PaytoUriGeneric { isKnown: true; targetType: "x-taler-bank"; host: string; account: string; } -interface PaytoUriBitcoin extends PaytoUriGeneric { +export interface PaytoUriBitcoin extends PaytoUriGeneric { isKnown: true; targetType: "bitcoin"; generateSegwitAddress: (r: string) => { addr1: string; addr2: string }; diff --git a/packages/taler-util/src/talerCrypto.ts b/packages/taler-util/src/talerCrypto.ts index 6bcb592e3..282d22d8b 100644 --- a/packages/taler-util/src/talerCrypto.ts +++ b/packages/taler-util/src/talerCrypto.ts @@ -583,6 +583,11 @@ export interface EcdheKeyPair { ecdhePriv: Uint8Array; } +export interface Edx25519Keypair { + edxPub: string; + edxPriv: string; +} + export function createEddsaKeyPair(): EddsaKeyPair { const eddsaPriv = nacl.randomBytes(32); const eddsaPub = eddsaGetPublic(eddsaPriv); @@ -787,3 +792,96 @@ export class SignaturePurposeBuilder { export function buildSigPS(purposeNum: number): SignaturePurposeBuilder { return new SignaturePurposeBuilder(purposeNum); } + +export type Flavor<T, FlavorT extends string> = T & { + _flavor?: `taler.${FlavorT}`; +}; + +export type FlavorP<T, FlavorT extends string, S extends number> = T & { + _flavor?: `taler.${FlavorT}`; + _size?: S; +}; + +export type OpaqueData = Flavor<string, "OpaqueData">; +export type Edx25519PublicKey = FlavorP<string, "Edx25519PublicKey", 32>; +export type Edx25519PrivateKey = FlavorP<string, "Edx25519PrivateKey", 64>; +export type Edx25519Signature = FlavorP<string, "Edx25519Signature", 64>; + +export namespace Edx25519 { + const revL = [ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, + 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, + ]; + + const L = bigint.fromArray(revL.reverse(), 256, false); + + export async function keyCreateFromSeed( + seed: OpaqueData, + ): Promise<Edx25519PrivateKey> { + return encodeCrock( + nacl.crypto_edx25519_private_key_create_from_seed(decodeCrock(seed)), + ); + } + + export async function keyCreate(): Promise<Edx25519PrivateKey> { + return encodeCrock(nacl.crypto_edx25519_private_key_create()); + } + + export async function getPublic( + priv: Edx25519PrivateKey, + ): Promise<Edx25519PublicKey> { + return encodeCrock(nacl.crypto_edx25519_get_public(decodeCrock(priv))); + } + + export function sign( + msg: OpaqueData, + key: Edx25519PrivateKey, + ): Promise<Edx25519Signature> { + throw Error("not implemented"); + } + + async function deriveFactor( + pub: Edx25519PublicKey, + seed: OpaqueData, + ): Promise<OpaqueData> { + const res = kdfKw({ + outputLength: 64, + salt: stringToBytes("edx2559-derivation"), + ikm: decodeCrock(pub), + info: decodeCrock(seed), + }); + + return encodeCrock(res); + } + + export async function privateKeyDerive( + priv: Edx25519PrivateKey, + seed: OpaqueData, + ): Promise<Edx25519PrivateKey> { + const pub = await getPublic(priv); + const privDec = decodeCrock(priv); + const privA = privDec.subarray(0, 32).reverse(); + const a = bigint.fromArray(Array.from(privA), 256, false); + + const factorBuf = await deriveFactor(pub, seed); + + const factor = bigint.fromArray(Array.from(factorBuf), 256, false); + + const aPrime = a.divide(8).multiply(factor).multiply(8); + + const bPrime = nacl.hash( + typedArrayConcat([privDec.subarray(32, 64), decodeCrock(factorBuf)]), + ); + + Uint8Array.from(aPrime.toArray(256).value) + + throw Error("not implemented"); + } + + export function publicKeyDerive( + priv: Edx25519PrivateKey, + seed: OpaqueData, + ): Promise<Edx25519PublicKey> { + throw Error("not implemented") + } +} |