-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add base58check decoding to recovery iframe #18
Merged
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
18.18.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,13 @@ git clone [email protected]:tkhq/frames.git | |
cd frames/ | ||
``` | ||
|
||
Install dependencies | ||
Install Node: | ||
```sh | ||
nvm use | ||
``` | ||
(the command above installs the version specified in `.nvmrc`, but any Node version >= v18 should do) | ||
|
||
Install dependencies: | ||
```sh | ||
cd recovery && npm install | ||
cd export && npm install | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -249,7 +249,7 @@ <h2>Message log</h2> | |
} | ||
|
||
/** | ||
* Encodes a buffer into base64url | ||
* Decodes a base64-encoded string into a buffer | ||
* @param {string} s | ||
* @return {Uint8Array} | ||
*/ | ||
|
@@ -262,6 +262,64 @@ <h2>Message log</h2> | |
return bytes; | ||
} | ||
|
||
/** | ||
* Decodes a base58check-encoded string into a buffer | ||
* This function throws an error when the string is too small, doesn't have the proper checksum, or contains invalid characters. | ||
* Inspired by https://gist.github.com/diafygi/90a3e80ca1c2793220e5/ | ||
* @param {string} s | ||
* @return {Uint8Array} | ||
*/ | ||
async function base58checkDecode(s) { | ||
if (s.length < 5) { | ||
throw new Error(`cannot base58-decode a string of length < 5 (found length ${s.length})`) | ||
} | ||
|
||
// See https://en.bitcoin.it/wiki/Base58Check_encoding | ||
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | ||
var decoded = BigInt(0); | ||
var decodedBytes = []; | ||
var result = []; | ||
for (var i = 0; i < s.length; i++) { | ||
if (alphabet.indexOf(s[i]) === -1) { | ||
throw new Error(`cannot base58-decode: ${s[i]} isn't a valid character`) | ||
} | ||
var carry = alphabet.indexOf(s[i]); | ||
|
||
// If the current base58 digit is 0, append a 0 byte. | ||
// "result.length == i" can only happen if we have not seen non-zero bytes so far | ||
r-n-o marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (carry == 0 && result.length === i) { | ||
result.push(0); | ||
} | ||
|
||
var j = 0; | ||
while (j < decodedBytes.length || carry > 0) { | ||
var currentByte = decodedBytes[j]; | ||
// shift the current byte 58 units and add the carry amount (or just add the carry amount if this is a new byte) | ||
currentByte = currentByte ? currentByte * 58 + carry : carry; | ||
emostov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// find the new carry amount (1-byte shift of current byte value) | ||
carry = currentByte >> 8; | ||
// reset the current byte to the remainder (the carry amount will pass on the overflow) | ||
decodedBytes[j] = currentByte % 256; | ||
j++ | ||
} | ||
} | ||
|
||
result = result.concat(decodedBytes.reverse()); | ||
|
||
var foundChecksum = result.slice(result.length - 4) | ||
|
||
var msg = result.slice(0, result.length - 4) | ||
var checksum1 = await crypto.subtle.digest("SHA-256", new Uint8Array(msg)) | ||
var checksum2 = await crypto.subtle.digest("SHA-256", new Uint8Array(checksum1)) | ||
var computedChecksum = Array.from(new Uint8Array(checksum2)).slice(0, 4); | ||
|
||
if (computedChecksum.toString() != foundChecksum.toString()) { | ||
throw new Error(`checksums do not match: computed ${computedChecksum} but found ${foundChecksum}`) | ||
} | ||
|
||
return new Uint8Array(msg); | ||
} | ||
|
||
/** | ||
* `SubtleCrypto.sign(...)` outputs signature in IEEE P1363 format: | ||
* - https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#ecdsa | ||
|
@@ -764,6 +822,7 @@ <h2>Message log</h2> | |
logMessage, | ||
base64urlEncode, | ||
base64urlDecode, | ||
base58checkDecode, | ||
bigIntToHex, | ||
stringToBase64urlString, | ||
uint8arrayToHexString, | ||
|
@@ -854,7 +913,26 @@ <h2>Message log</h2> | |
* @param {string} bundle | ||
*/ | ||
var onInjectBundle = async function(bundle) { | ||
var bundleBytes = TKHQ.base64urlDecode(bundle); | ||
if ( | ||
// Non-alphanumerical characters in base64url: - and _. These aren't in base58. | ||
bundle.indexOf("-") === -1 && bundle.indexOf("_") === -1 | ||
// Uppercase o (O), uppercase i (I), lowercase L (l), and 0 aren't in the character set either. | ||
&& bundle.indexOf("O") === -1 && bundle.indexOf("I") === -1 && bundle.indexOf("l") === -1 && bundle.indexOf("0") === -1 | ||
) { | ||
// If none of these characters are in the bundle we assume it's a base58check-encoded string | ||
// This isn't perfect: there's a small chance that a base64url-encoded string doesn't have any of these characters by chance! | ||
// But we accept this risk given this branching is only here to support our transition to base58check. | ||
// I hear you'd like to quantify this risk? Let's do it. | ||
// Assuming random bytes in our bundle and a bundle length of 33 (public key, compressed) + 48 (encrypted cred) = 81 bytes. | ||
// The odds of a byte being in the overlap set between base58 and base64url is 58/64=0.90625. | ||
// Which means the odds of a 81 bytes string being in the overlap character set for its entire length is... | ||
// ... 0.90625^81 = 0.0003444209703 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice |
||
// Are you convinced that this is good enough? I am :) | ||
var bundleBytes = await TKHQ.base58checkDecode(bundle); | ||
} else { | ||
var bundleBytes = TKHQ.base64urlDecode(bundle); | ||
} | ||
|
||
if (bundleBytes.byteLength <= 33) { | ||
throw new Error("bundle size " + bundleBytes.byteLength + " is too low. Expecting a compressed public key (33 bytes) and an encrypted credential") | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏