Skip to content

Commit

Permalink
Merge pull request #1081 from near/ONB-13
Browse files Browse the repository at this point in the history
Minor bug fix on biometric-ed25519 package [ONB-13]
  • Loading branch information
andy-haynes authored Mar 23, 2023
2 parents ec8932e + ea99125 commit 232e35e
Show file tree
Hide file tree
Showing 5 changed files with 744 additions and 20 deletions.
4 changes: 2 additions & 2 deletions packages/biometric-ed25519/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@near-js/biometric-ed25519",
"description": "JavaScript library to handle webauthn and biometric keys",
"version": "0.0.2",
"version": "0.0.3",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": {
Expand All @@ -11,10 +11,10 @@
"author": "Pagoda",
"license": "ISC",
"dependencies": {
"@aws-crypto/sha256-js": "^4.0.0",
"@hexagon/base64": "^1.1.26",
"asn1-parser": "^1.1.8",
"buffer": "^6.0.3",
"crypto": "^1.0.1",
"elliptic": "^6.5.4",
"fido2-lib": "3.3.4",
"near-api-js": "workspace:*"
Expand Down
23 changes: 16 additions & 7 deletions packages/biometric-ed25519/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import base64 from "@hexagon/base64";
import { eddsa as EDDSA } from "elliptic";
import { createHash } from "crypto";
import { Sha256 } from "@aws-crypto/sha256-js";
import { Buffer } from "buffer";
import asn1 from "asn1-parser";
import { KeyPair } from "near-api-js";
Expand Down Expand Up @@ -50,9 +50,11 @@ export const createKey = async (username: string): Promise<KeyPair> => {
const publicKey = result.authnrData.get("credentialPublicKeyPem");
const publicKeyBytes = get64BytePublicKeyFromPEM(publicKey);
const ed = new EDDSA("ed25519");
const key = ed.keyFromSecret(createHash('sha256').update(Buffer.from(publicKeyBytes)).digest());
const edSha256 = new Sha256();
edSha256.update(Buffer.from(publicKeyBytes));
const key = ed.keyFromSecret(await edSha256.digest());
return KeyPair.fromString(base_encode(new Uint8Array(Buffer.concat([key.getSecret(), Buffer.from(key.getPublic())]))));
});
})
};

// Ecrecover returns two possible public keys for a given signature
Expand All @@ -77,16 +79,23 @@ export const getKeys = async (username: string): Promise<[KeyPair, KeyPair]> =>
//@ts-ignore
const parser = asn1?.ASN1?.parse || window?.ASN1?.parse;
const rAndS = parser(new Uint8Array(signature));
const clientDataJSONHash = createHash('sha256').update(
const clientDataSha256 = new Sha256();
clientDataSha256.update(
Buffer.from(new Uint8Array(base64.toArrayBuffer(getAssertionResponse.response.clientDataJSON, true)))
).digest();
);
const clientDataJSONHash = await clientDataSha256.digest();
const AuthenticatiorDataJSONHash = Buffer.from(new Uint8Array(base64.toArrayBuffer(getAssertionResponse.response.authenticatorData, true)))
const authenticatorAndClientDataJSONHash = Buffer.concat([AuthenticatiorDataJSONHash, clientDataJSONHash]);

const correctPKs = recoverPublicKey(rAndS.children[0].value, rAndS.children[1].value, authenticatorAndClientDataJSONHash, 0);
const ed = new EDDSA("ed25519");
const firstED = ed.keyFromSecret(createHash('sha256').update(correctPKs[0]).digest());
const secondED = ed.keyFromSecret(createHash('sha256').update(correctPKs[1]).digest());
const firstEdSha256 = new Sha256();
firstEdSha256.update(Buffer.from(correctPKs[0]));
const secondEdSha256 = new Sha256();
secondEdSha256.update(Buffer.from(correctPKs[1]));

const firstED = ed.keyFromSecret(await firstEdSha256.digest());
const secondED = ed.keyFromSecret(await secondEdSha256.digest());
const firstKeyPair = KeyPair.fromString(base_encode(new Uint8Array(Buffer.concat([firstED.getSecret(), Buffer.from(firstED.getPublic())]))));
const secondKeyPair = KeyPair.fromString(base_encode(new Uint8Array(Buffer.concat([secondED.getSecret(), Buffer.from(secondED.getPublic())]))));
return [firstKeyPair, secondKeyPair];
Expand Down
8 changes: 5 additions & 3 deletions packages/biometric-ed25519/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import base64 from "@hexagon/base64";
import { ec as EC } from "elliptic";
import { createHash } from "crypto";
import { Sha256 } from "@aws-crypto/sha256-js";
import { PublicKey } from "near-api-js/lib/utils";

const USER_NAME_MAX_LENGTH = 25;
Expand Down Expand Up @@ -86,14 +86,16 @@ export const publicKeyCredentialToJSON = (pubKeyCred) => {
return pubKeyCred;
};

export const recoverPublicKey = (r, s, message, recovery) => {
export const recoverPublicKey = async (r, s, message, recovery) => {
const ec = new EC("p256");
const sigObj = { r, s };

if (recovery !== 0 && recovery !== 1) {
throw new Error('Invalid recovery parameter');
}
const h = createHash('sha256').update(message).digest();
const hash = new Sha256();
hash.update(message);
const h = await hash.digest();
let Q, P;
try {
Q = ec.recoverPubKey(h, sigObj, 0);
Expand Down
Loading

0 comments on commit 232e35e

Please sign in to comment.