-
-
Notifications
You must be signed in to change notification settings - Fork 259
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
Feat: TrezorHostProtocol #13542
base: develop
Are you sure you want to change the base?
Feat: TrezorHostProtocol #13542
Conversation
const iv1 = getIvFromNonce(recvNonce); // should be 1 | ||
|
||
const hostStaticKeys = getCurve25519KeyPair(Buffer.alloc(32).fill(9)); | ||
const hostEphemeralKeys = getCurve25519KeyPair(Buffer.alloc(32).fill(1)); |
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.
This looks suspicious. The host ephemeral key pair should be generated randomly before the HandshakeInitiationReq
is sent, since its public part is contained in the message.
const iv0 = getIvFromNonce(sendNonce); // should be 0 | ||
const iv1 = getIvFromNonce(recvNonce); // should be 1 | ||
|
||
const hostStaticKeys = getCurve25519KeyPair(Buffer.alloc(32).fill(9)); |
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.
The host static key should be generated randomly once and kept constant for all invocations of the protocol.
// const credentials = knownCredentials.find(c => { | ||
// const isPaired = findKnownPairingCredentials(knownCredentials[0], trezorEphemeralPubkey); | ||
// }) | ||
const hostTempKeys = hostStaticKeys || getCurve25519KeyPair(Buffer.alloc(32).fill(9)); |
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.
The bytes inside getcurve25519KeyPair
should be 0900000000000000000000000000000000000000000000000000000000000000
instead of 0909090909090909090909090909090909090909090909090909090909090909
.
function conditionalSwap(a: bigint, b: bigint, condition: boolean): [bigint, bigint] { | ||
const mask = condition ? -1n : 0n; | ||
const newA = (a & ~mask) | (b & mask); | ||
const newB = (a & mask) | (b & ~mask); | ||
|
||
return [newA, newB]; |
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.
I'm not sure if it makes sense to try to make this function run in constant time in TypeScript.
If so, then the line const mask = condition ? -1n : 0n;
is likely not constant time since it probably uses a conditional branch.
if not so, then the function can be defined as return condition ? [b, a] : [a, b];
.
function conditionalMove(first: bigint, second: bigint, condition: boolean): bigint { | ||
const trueMask = condition ? -1n : 0n; | ||
const falseMask = ~trueMask; | ||
|
||
return (first & falseMask) | (second & trueMask); | ||
} |
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.
I'm not sure if it makes sense to try to make this function run in constant time in TypeScript.
If so, then the line const trueMask = condition ? -1n : 0n;
is likely not constant time since it probably uses a conditional branch.
if not so, then the function can be defined as return condition ? second : first;
.
if (!isPaired) { | ||
if (PAIRING_METHODS.includes(2)) { | ||
const createCodeEntryChallenge = await call('ThpCodeEntryChallenge', { | ||
challenge: Buffer.alloc(32).fill(1), |
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.
This should be generated randomly.
const { secret } = codeEntry.payload.message; | ||
const sha = sha256(Buffer.from(secret, 'hex')); | ||
|
||
console.warn('secret compare with commitment', sha.compare(handshakeCommitment)); |
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.
You should return an error if the hashes don't match.
await new Promise(resolve => setTimeout(resolve, 1000)); | ||
|
||
const debugState = await call('DebugLinkGetState', {}); | ||
const { thp_pairing_code_entry_code, thp_pairing_secret } = |
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.
code_qr_code
and code_nfc_unidirectional
should be transmitted from Trezor to Host instead of thp_pairing_secret
.
if (pairingReq.payload.message.commitment) { | ||
handshakeCommitment = Buffer.from(pairingReq.payload.message.commitment, 'hex'); | ||
} |
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.
This should be done only if code entry was a pairing method advertised in protocol parameters.
const sha = sha256(Buffer.from(secret, 'hex')); | ||
|
||
console.warn('secret compare with commitment', sha.compare(handshakeCommitment)); | ||
|
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.
You should check that code = SHA-256(h || secret || challenge || PairingMethod_CodeEntry) % 1000000.
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.
Similarly for nfcPairing
and qrCodePairing
.
b621c58
to
8bd0e9b
Compare
3a87b56
to
db8ab69
Compare
b2da7e9
to
5ef1e08
Compare
6c0b109
to
bb1c4da
Compare
|
||
it('AESGCM encode/decode', () => { | ||
const key = Buffer.from( | ||
'ccbf529fc8dd4662d4d1d1fa66368b8758c0b6673a1bb9d532d95ca607cbf729', |
Check failure
Code scanning / CodeQL
Hard-coded credentials Critical test
key
import { aesgcm } from '../../src/protocol-thp/crypto/aesgcm'; | ||
import { curve25519, getCurve25519KeyPair } from '../../src/protocol-thp/crypto/curve25519'; | ||
|
||
const PROTOCOL_NAME = Buffer.from('Noise_XX_25519_AESGCM_SHA256', 'ascii'); |
Check failure
Code scanning / CodeQL
Hard-coded credentials Critical test
key
757a81f
to
8451c81
Compare
26daf9d
to
a0a7f06
Compare
// const cmd = this.device.getCommands(); | ||
// const response = await cmd.typedCall('ResetDevice', 'Success', this.params); | ||
console.log('----> running reset function!'); | ||
const response = await this.device.transport.call({ | ||
session: this.device.transportSession!, | ||
name: 'LoadDevice', | ||
data: { | ||
pin: '', | ||
label: 'THP device', | ||
passphrase_protection: true, | ||
mnemonics: ['all all all all all all all all all all all all'], | ||
skip_checksum: true, | ||
}, | ||
protocol: this.device.protocol, | ||
protocolState: this.device.protocolState, | ||
}); |
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.
this can be now dropped. TrezorConnect.loadDevice should be available
Co-authored-by: Ondřej Vejpustek <[email protected]> following: trezor/trezor-firmware#3435
a0a7f06
to
fa7ff3b
Compare
🚀 Expo preview is ready!
|
let newSessionId = 0; | ||
// TODO: what if known.length >= 255? | ||
while (!newSessionId || knownSessions.includes(newSessionId.toString())) { | ||
newSessionId = getWeakRandomInt(1, 256); |
Check failure
Code scanning / CodeQL
Insecure randomness High
Math.random()
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI about 18 hours ago
To fix the problem, we need to replace the use of getWeakRandomInt
with a function that generates cryptographically secure random integers. We can use the crypto
module available in Node.js to achieve this. Specifically, we can use crypto.randomInt
to generate a secure random integer within a specified range.
- Replace the call to
getWeakRandomInt
with a new function that usescrypto.randomInt
to generate a secure random integer. - Ensure that the new function is imported and used correctly in the relevant parts of the code.
-
Copy modified lines R1-R2 -
Copy modified line R14
@@ -1 +1,3 @@ | ||
import { randomInt } from 'crypto'; | ||
|
||
/** | ||
@@ -11,3 +13,3 @@ | ||
|
||
return Math.floor(Math.random() * (max - min) + min); | ||
return randomInt(min, max); | ||
}; |
heavy draft