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

🐛 Buffer conversion does not work when a another Buffer implementation is used #505

Open
4 tasks done
tex0l opened this issue Nov 8, 2024 · 0 comments
Open
4 tasks done

Comments

@tex0l
Copy link
Contributor

tex0l commented Nov 8, 2024

What's happening?

Hi,
When using a different implementation of Buffer within the code, the code of RNQC fails when the underlying ArrayBuffer is larger than the view the Buffer represents.

For example, when using Buffer#slice or Buffer#subarray, it makes a shallow copy of the Buffer by creating a new view of the underlying ArrayBuffer with the appropriate byteOffset.

The issue is that when two different versions of the Buffer constructor are used, the bufferLikeToArrayBuffer function attempts to convert the input to a Buffer by reading the buffer property, which omits completely the byteOffset of the input object when applicable.

This may cause issues in real life, for example when you have to split a 64 bytes symmetric key into two sub-keys of 32 bytes (for encryption and authentication) which causes the key length to be invalid or when you have to split a ciphertext into the IV, the MAC and the AES output, which causes the IV length to be invalid.

This seems very similar to an issue I reported a few years ago: #104

Reproducible Code

import { Button, Text, View } from 'react-native'
import QuickCrypto from 'react-native-quick-crypto'
import { Buffer } from '@craftzdog/react-native-buffer'
import { Buffer as FerossBuffer } from 'buffer'

const clearText = 'test'

const testCase = (largeKey: Buffer) => {
  const key = largeKey.subarray(32) // Gets a new Uint8Array view of the ArrayBuffer store for this array
  const iv = QuickCrypto.randomBytes(16)
  const cipher = QuickCrypto.createCipheriv('aes-256-cbc', key, iv)
  const enc = Buffer.concat([ cipher.update(Buffer.from(clearText)) as unknown as Buffer, cipher.final() as unknown as Buffer ])
  const encB64 = enc.toString('base64')
  const decipher = QuickCrypto.createDecipheriv('aes-256-cbc', key, iv)
  const dec = Buffer.concat([ decipher.update(Buffer.from(encB64, 'base64')) as unknown as Buffer, decipher.final() as unknown as Buffer ])
  return dec.toString() === clearText
}

const test = () => {
  const largeKey = QuickCrypto.randomBytes(64)

  console.log('normal Buffer', testCase(largeKey))

  const largeKeyFeross = FerossBuffer.from(largeKey.toString('base64'), 'base64') // not an instance of '@craftzdog/react-native-buffer', but of 'buffer'

  console.log('Feross Buffer', testCase(largeKeyFeross as unknown as Buffer)) // This fails with 'ERROR  Error: Exception in HostFunction: Invalid Cipher key length!, js engine: hermes'
}

export default function Index() {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <Text>Edit app/index.tsx to edit this screen.</Text>
      <Button title="test" onPress={() => test()}></Button>
    </View>
  );
}

Relevant log output

ERROR  Error: Exception in HostFunction: Invalid Cipher key length!, js engine: hermes

Device

Android

QuickCrypto Version

0.7.6

Can you reproduce this issue in the QuickCrypto Example app?

Yes, I can reproduce the same issue in the Example app here

Additional information

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant