Skip to content
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

fix: also compress key on iOS when fallback secure environment is used #18

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,42 @@ export async function generateKeypair(id: string, biometricsBacked = true): Prom

export async function getPublicBytesForKeyId(keyId: string): Promise<Uint8Array> {
const publicBytes = await getSecureEnvironment().getPublicBytesForKeyId(keyId)
let uncompressedKey = publicBytes
let key = publicBytes

if (Platform.OS === 'android' && publicBytes.length > 65) {
if (key.length > 65) {
// Try to parse it from the ASN.1 SPKI format
const spki = AsnParser.parse(publicBytes, SubjectPublicKeyInfo)
uncompressedKey = new Uint8Array(spki.subjectPublicKey)
key = new Uint8Array(spki.subjectPublicKey)
}

if (Platform.OS === 'android') {
if (uncompressedKey.length !== 65 || uncompressedKey[0] !== 0x04) {
throw new Error('Invalid uncompressed key format')
}
if (key.length === 65 && key[0] !== 0x04) {
throw new Error('Invalid uncompressed key prefix')
}

if (key.length === 65) {
// Extract the X and Y coordinates
const x = uncompressedKey.slice(1, 33) // bytes 1 to 32 (X coordinate)
const y = uncompressedKey.slice(33, 65) // bytes 33 to 64 (Y coordinate)

const x = key.slice(1, 33) // bytes 1 to 32 (X coordinate)
const y = key.slice(33, 65) // bytes 33 to 64 (Y coordinate)
// Determine the parity of the Y coordinate
const prefix = y[y.length - 1] % 2 === 0 ? 0x02 : 0x03

// Return the compressed key (prefix + X coordinate)
const compressedKey = new Uint8Array(33)
compressedKey[0] = prefix
compressedKey.set(x, 1)
return compressedKey
key = compressedKey
}

if (key.length === 33 && key[0] !== 0x03 && key[0] !== 0x02) {
throw new Error('Invalid compressed key prefix')
}

if (key.length !== 33) {
throw new Error(
`After attempting key compression, the key has an invalid length. Expected: '33', Received: '${key.length}'`
)
}

return publicBytes
return key
}

export async function sign(keyId: string, message: Uint8Array, biometricsBacked = true): Promise<Uint8Array> {
Expand Down