Changeset View
Standalone View
native/utils/aes-crypto-module.js
// @flow | // @flow | ||||
import { requireNativeModule } from 'expo-modules-core'; | import { requireNativeModule } from 'expo-modules-core'; | ||||
import invariant from 'invariant'; | |||||
const KEY_SIZE = 32; | const KEY_SIZE = 32; | ||||
const IV_LENGTH = 12; | |||||
const TAG_LENGTH = 16; | |||||
const AESCryptoModule: { | const AESCryptoModule: { | ||||
+generateKey: (destination: Uint8Array) => void, | +generateKey: (destination: Uint8Array) => void, | ||||
+encrypt: ( | |||||
key: Uint8Array, | |||||
data: Uint8Array, | |||||
destination: Uint8Array, | |||||
) => void, | |||||
} = requireNativeModule('AESCrypto'); | } = requireNativeModule('AESCrypto'); | ||||
export function generateKey(): Uint8Array { | export function generateKey(): Uint8Array { | ||||
const key = new Uint8Array(KEY_SIZE); | const key = new Uint8Array(KEY_SIZE); | ||||
AESCryptoModule.generateKey(key); | AESCryptoModule.generateKey(key); | ||||
return key; | return key; | ||||
} | } | ||||
export function encrypt(key: Uint8Array, data: Uint8Array): Uint8Array { | |||||
invariant(AESCryptoModule.encrypt, 'AESCrypto.encrypt is not implemented'); | |||||
const ciphertext = new Uint8Array(data.length + IV_LENGTH + TAG_LENGTH); | |||||
atul: Are we sure that this array is always going to be the right size buffer? Is it guaranteed that… | |||||
bartekAuthorUnsubmitted Done Inline ActionsAn extra check wouldn't hurt bartek: An extra check wouldn't hurt | |||||
bartekAuthorUnsubmitted Done Inline Actions
In theory, GCM mode is bit-based and can encrypt even 0 bits: https://crypto.stackexchange.com/a/40732 so this shouldn't happen. Moreover, we will always use multiples of 10KB (padding) bartek: > For example, if data.length was size 1, is there no padding added in AES.GCM.seal(...) to… | |||||
atulUnsubmitted Not Done Inline ActionsGotcha, thanks for the explanation + link with further info atul: Gotcha, thanks for the explanation + link with further info | |||||
AESCryptoModule.encrypt(key, data, ciphertext); | |||||
return ciphertext; | |||||
atulUnsubmitted Not Done Inline ActionsMentioned earlier that the encrypt/ciphertext terminology might be a bit confusing. At a minimum, I think it's confusing that just in this diff ciphertext does not always refer to "the same thing." Wonder if eg seal(...) and sealedData might be a more precise naming scheme? Since in addition to encryption there's an authentication/integrity tag involved in encrypt() and the ciphertext here contains iv and tag. atul: Mentioned earlier that the `encrypt`/`ciphertext` terminology might be a bit confusing.
At a… | |||||
bartekAuthorUnsubmitted Done Inline ActionsReplied above bartek: Replied above | |||||
} |
Are we sure that this array is always going to be the right size buffer? Is it guaranteed that the result from AESCryptoModule.encrypt(...) will strictly be equal to data.length + IV_LENGTH + TAG_LENGTH?
For example, if data.length was size 1, is there no padding added in AES.GCM.seal(...) to increase the size to the the nearest N bytes or whatever?
Might be worth adding an additional check after
to ensure that ciphertext.length == destination.length?