Skip to content

Instantly share code, notes, and snippets.

@babelouest
Last active January 3, 2023 02:14
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save babelouest/9d865e69433a33d2e8a6f0a5ef9f9f1d to your computer and use it in GitHub Desktop.
Save babelouest/9d865e69433a33d2e8a6f0a5ef9f9f1d to your computer and use it in GitHub Desktop.
might be usable in a foreseen future (this was written in 2019), but hmac-secret still isn't available in the browser I know of
<!doctype html>
<html lang="en">
<head>
<!--
inspired by Mozilla Webauthn documentation: https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API
copyright: 2019 Nicolas Mora <nicolas@babelouest.org>
license: MIT
-->
<title>Hmac-Secret webauthn Extension</title>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/cbor-js-unofficial@0.1.0-a4/cbor.min.js"></script>
<!--<script type="text/javascript" src="cbor.js"></script>-->
</head>
<body>
<div>
Step 1: Create a new credential
</div>
<div>
<button type="button" id="create">New credential with Hmac-Secret extension</button>
</div>
<div id="createResult">
</div>
<hr/>
<div>
Step 2: validate assertion
</div>
<div>
salt1 (required): <input type="text" id="salt1" value="0123456789ABCDEF" maxLength="16" placeholder="16 chars" />
</div>
<div>
salt2 (optional): <input type="text" id="salt2" maxLength="16" placeholder="16 chars" />
</div>
<div>
<button type="button" id="assert">Validate assertion with Hmac-Secret extension</button>
</div>
<div id="assertResult">
</div>
</body>
</html>
<script type="text/javascript">
var credentials = [];
function str2ab(str) {
var buf = new ArrayBuffer(str.length * 2);
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function newCredential() {
var createCredentialDefaultArgs = {
publicKey: {
rp: {
name: "Acme"
},
user: {
id: new Uint8Array(16),
name: "john.p.smith@example.com",
displayName: "John P. Smith"
},
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
attestation: "direct",
timeout: 60000,
extensions: {
hmacCreateSecret: true
},
challenge: new Uint8Array([
0x8C, 0x0A, 0x26, 0xFF, 0x22, 0x91, 0xC1, 0xE9, 0xB9, 0x4E, 0x2E, 0x17, 0x1A, 0x98, 0x6A, 0x73,
0x71, 0x9D, 0x43, 0x48, 0xD5, 0xA7, 0x6A, 0x15, 0x7E, 0x38, 0x94, 0x52, 0x77, 0x97, 0x0F, 0xEF
]).buffer
}
};
console.log("credential options", createCredentialDefaultArgs);
navigator.credentials.create(createCredentialDefaultArgs)
.then((cred) => {
console.log("credential", cred);
credentials.push({
id: cred.rawId,
transports: ["usb", "nfc", "ble"],
type: "public-key"
});
var attStmt = CBOR.decode(cred.response.attestationObject);
console.log("attStmt", attStmt);
if (attStmt.authData[32] & 0x80) {
document.getElementById("createResult").innerHTML = "extension flag set";
} else {
document.getElementById("createResult").innerHTML = "extension flag not set";
}
})
.catch((err) => {
document.getElementById("createResult").innerHTML = "creation error";
console.log("creation error", err);
});
}
function newAssertion() {
var getCredentialDefaultArgs = {
publicKey: {
timeout: 60000,
allowCredentials: credentials,
challenge: new Uint8Array([
0x79, 0x50, 0x68, 0x71, 0xDA, 0xEE, 0xEE, 0xB9, 0x94, 0xC3, 0xC2, 0x15, 0x67, 0x65, 0x26, 0x22,
0xE3, 0xF3, 0xAB, 0x3B, 0x78, 0x2E, 0xD5, 0x6F, 0x81, 0x26, 0xE2, 0xA6, 0x01, 0x7D, 0x74, 0x50
]),
extensions: {
hmacGetSecret: {
salt1: str2ab(document.getElementById("salt1").value)
}
}
}
};
if (document.getElementById("salt2").value) {
getCredentialDefaultArgs.publicKey.extensions.hmacGetSecret.salt2 = str2ab(document.getElementById("salt2").value);
}
console.log("assertion option", getCredentialDefaultArgs);
navigator.credentials.get(getCredentialDefaultArgs)
.then((assertion) => {
console.log("assertion", assertion);
if (assertion.response.authenticatorData[32] & 0x80) {
document.getElementById("assertResult").innerHTML = "extension flag set";
} else {
document.getElementById("assertResult").innerHTML = "extension flag not set";
}
})
.catch((err) => {
document.getElementById("assertResult").innerHTML = "assertion error";
console.log("assertion error", err);
});
}
window.onload = function() {
document.getElementById("create").onclick = newCredential;
document.getElementById("assert").onclick = newAssertion;
};
</script>
@MrAntix
Copy link

MrAntix commented Mar 19, 2022

@0xYao
Copy link

0xYao commented Jan 2, 2023

image

Getting extension flag not set when validating the assertion, is this supposed to happen?

@babelouest
Copy link
Author

Yes, hmac-secret isn't implemented yet in any browser.

@0xYao
Copy link

0xYao commented Jan 3, 2023

Understood, so currently there is still no way to encrypt data using WebAuthn?

Or is there any way to encrypt data using the platform hardware keys (e.g. using biometrics on MacOS / Windows)

@babelouest
Copy link
Author

Understood, so currently there is still no way to encrypt data using WebAuthn?

Actually no, but just to be accurate, hmac-secret isn't per se an encryption algorithm, but a deterministic way to get a 32 or 64 bits number, using webauthn. This number can be used as an encryption key, but also as something else...

Or is there any way to encrypt data using the platform hardware keys (e.g. using biometrics on MacOS / Windows)

Not that I'm aware of, sorry...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment