Chiffrement des fichiers
Pour chiffrer & déchiffrer des fichiers, on peut utiliser :
- les méthodes
encryptFile
etdecryptFile
du SDK, ou ; - les méthodes
encryptFile
etdecryptFile
d'uneEncryptionSession
.
Pour l'utilisation des méthodes EncryptionSession#encryptFile
et EncryptionSession#decryptFile
, il faut se référer à la section dédiée du guide sur les EncryptionSession
.
Format d'un fichier chiffré
Un fichier chiffré avec Seald est constitué de deux parties :
- un en-tête contenant l'identifiant de l'
EncryptionSession
; - le résultat du chiffrement avec la clé de l'
EncryptionSession
d'un tar contenant le fichier à chiffrer.
Ainsi le fichier chiffré est légèrement plus volumineux que le fichier original, d'environ 2 kB.
Description des fonctions
encryptFile
La méthode encryptFile
a 4 arguments : clearFile
, filename
, recipients
et opts
.
Elle retourne un Promise
qui se résout en le même type qu'utilisé pour clearFile
.
clearFile
: le fichier à chiffrer
encryptFile
supporte plusieurs types pour clearFile
et retourne le résultat avec le même type :
string
;Buffer
;Blob
dans le navigateur uniquement ;ReadableStream
des Web StreamsReadable
des Streams Node.JS).
Des exemples d'utilisation avec ces différents types sont disponibles à la fin de cette page.
filename
: le nom du fichier
Il s'agit d'un String
qui est utilisé pour :
- être la
metadata
par défaut de l'EncryptionSession
qui sera créée ; - être enregistré comme nom du fichier à chiffrer dans le tar décrit ci-dessus.
TIP
Le filename
n'est pas disponible lors du déchiffrement, cela fera l'objet d'une mise à jour.
recipients
: les utilisateurs autorisés à déchiffrer
Il s'agit d'un objet décrivant les utilisateurs autorisés à déchiffrer :
sealdIds
: un tableau contenant des identifiants Seald des utilisateurs autorisés à déchiffrer. Ceci est la méthode recommandée pour lister les utilisateurs autorisés.connectors
: un tableau contenant des connecteurs référençant des utilisateurs dans votre application, tels que déclarés lors de la génération des identités.userIds
: un tableau contenant des identifiants utilisateurs dans votre application tels que déclarés lors de la génération des identités. Cette option est dépréciée. Il est déconseillé de l'utiliser dans du nouveau code.
TIP
Il est possible de chiffrer pour un connector
qui n'est pas encore assigné à une identité Seald si opts.allowUnregisteredUsers
est à true
.
Dans ce cas, il ne s'agit pas de chiffrement de bout-en-bout : la clé de chiffrement en clair est mise en séquestre sur les serveurs de Seald le temps qu'une identité Seald soit créée et associée à ce connector
.
opts
: options
Il s'agit d'un objet avec plusieurs propriétés optionnelles. Trois d'entre elles sont particulièrement intéressantes (pour avoir la liste complète, consultez la référence) :
fileSize
: taille du fichier à chiffrer, nécessaire pour une utilisation avec les typesReadableStream
andReadable
.metadata
:metadata
de l'EncryptionSession
qui sera créée (la valeur defilename
par défaut).encryptForSelf
: si vous chiffrez pour un groupe dont l'utilisateur fait partie, vous pouvez mettre cette option àfalse
afin de ne pas chiffrer directement pour ses propres identités. L'utilisateur pourra toujours déchiffrer la donnée grâce à son appartenance au groupe. Ceci peut vous permettre d'améliorer la performance du chiffrement.
decryptFile
La méthode decryptFile
a un seul argument : encryptedFile
, le fichier à déchiffrer.
decryptFile
supporte les mêmes types pour encryptedFile
qu'encryptFile
pour clearFile
.
Elle retourne une Promise
qui se résout en un Object
qui a les propriétés suivantes :
data
: le fichier déchiffré, est du même type que celui utilisé pourencryptedFile
;type
: un des types suivants'string'
,'buffer'
,'node-stream'
,'blob'
,'readable-stream'
;filename
: le nom du fichier original ;size
: la taille du fichier en octets ;sessionId
: l'identifiant de l'EncryptionSession
.
Exemples
Avec des String
La signature la plus simple pour chiffrer un fichier est un String
:
const encryptedString = await seald.encryptFile(
'Secret file content',
'SecretFile.txt',
{ sealdIds: [mySealdId, user2SealdId] }
)
Dans ce cas, le type de sortie sera un String
encodé en base64 du fichier chiffré. Il sera alors possible de le déchiffrer de la façon suivante :
const {
data, // 'Secret file content'
type, // 'string'
size, // 19
sessionId, // the encryption session ID
filename // 'SecretFile.txt'
} = await seald.decryptFile(encryptedString)
console.log(data) // This will log 'Secret file content'
info
Le contenu de clearFile
est interprété comme étant de l'UTF-8.
TIP
S'il ne s'agit que de textes à chiffrer, il est recommandé d'utiliser l'autre format de chiffrement : encryptMessage
/ decryptMessage
qui est beaucoup plus léger.
WARNING
La sortie de encryptFile
utilisée avec un String
est environ 33% plus lourde que le fichier original à cause de l'encodage base64.
Avec des Buffer
Le SDK peut utiliser des Buffer
au sens de Node.js (qui sont polyfillés hors environnement Node.js) :
const encryptedBuffer = await seald.encryptFile(
Buffer.from('Secret file content', 'utf8'),
'SecretFile.txt',
{ sealdIds: [mySealdId, user2SealdId] }
)
Dans ce cas, le type de sortie sera un Buffer
. Il sera alors possible de le déchiffrer de la façon suivante :
const {
data, // An instance of Buffer containing the clear text data
type, // 'buffer'
size, // 19
sessionId, // the encryption session ID
filename // 'SecretFile.txt'
} = await seald.decryptFile(encryptedBuffer)
console.log(data.toString('utf8')) // This will log 'Secret file content'
Avec des Blob
Dans un navigateur, le SDK peut utiliser des Blob
:
const encryptedBlob = await seald.encryptFile(
new Blob(['Secret file content']),
'SecretFile.txt',
{ sealdIds: [mySealdId, user2SealdId] }
)
Dans ce cas, le type de sortie sera un Blob
. Il sera alors possible de le déchiffrer de la façon suivante :
const {
data, // An instance of Blob containing the clear text data
type, // 'blob'
size, // 19
sessionId, // the encryption session ID
filename // 'SecretFile.txt'
} = await seald.decryptFile(encryptedBlob)
console.log(await data.text()) // This will log 'Secret file content'
TIP
Les fichiers obtenus au travers de champs <input type="file">
sont de type File
qui hérite de Blob
. Il sont donc traités de la même façon par le SDK.
Le Blob
déchiffré n'a pas de Blob#type
défini, mais il peut être déduit de l'extension du fichier (en utilisant le paquet mime-types
par exemple).
Vous pouvez également recréer une instance de File
en utilisant son constructeur à partir du Blob
déchiffré et du filename
(et éventuellement du type mime déduit).
WARNING
React-Native n'implémentant pas les méthodes Blob#arrayBuffer
ou Blob#stream
pourtant standards, il n'est pas possible d'utiliser le type Blob
dans un environnement React-Native. Il faut utiliser un autre type (comme les Buffer
en utilisant un polyfill ou les String
).
Avec des ReadableStream
Dans un navigateur, le SDK peut utiliser des ReadableStream
. Par exemple, avec la méthode Blob#stream
:
WARNING
Dans ce mode, il faut passer à la fonction encryptFile
la taille du fichier en clair via le paramètre options.fileSize
.
const blob = new Blob(['Secret file content'])
const encryptedReadableStream = await seald.encryptFile(
blob.stream(),
'SecretFile.txt',
{ sealdIds: [mySealdId, user2SealdId] },
{ fileSize: blob.size }
)
Dans ce cas, le type de sortie sera un ReadableStream
. Il sera alors possible de le déchiffrer de la façon suivante :
const {
data, // An instance of ReadableStream which will stream the clear text data
type, // 'readable-stream'
size, // 19
sessionId, // the encryption session ID
filename // 'SecretFile.txt'
} = await sealdSession.decryptFile(encryptedReadableStream)
let result = ''
const reader = data.getReader()
while (true) {
const read = await reader.read()
if (read.done) break
else result += read.value
}
console.log(result) // This will log 'Secret file content'
Streamer un envoi de fichier
Hormis sur Chrome depuis la version 95, il n'est pas possible d'utiliser fetch
avec un ReadableStream
comme corps de requête.
Pour contourner, une solution consiste à découper côté client le fichier chiffré en chunks de 5Mo par exemple, de les envoyer individuellement au serveur, et le serveur aura la charge de reconstituer les différents chunks dans l'ordre.
Avec des streams Readable
de Node.js
Le SDK peut utiliser des streams Readable
de Node.js. Dans un navigateur, cela fonctionne également en utilisant un polyfill. Par exemple, pour lire & chiffrer un fichier puis l'écrire :
WARNING
Dans ce mode, il faut passer à la fonction encryptFile
la taille du fichier en clair via le paramètre options.fileSize
.
const { createReadStream, createWriteStream, promises: fsPromises } = require('fs')
const { stat } = fsPromises
const inputFile = './path/to/fileToEncrypt'
const outputFile = './path/to/encryptedFile'
const readable = createReadStream(inputFile)
const writable = createWriteStream(outputFile)
const encryptedStream = await seald.encryptFile(
readable,
'SecretFile.txt',
{ sealdIds: [mySealdId, user2SealdId] },
{ fileSize: (await stat(inputFile)).size }
)
encryptedStream
.on('error', () => { console.error('errored') })
.pipe(writable)
.on('error', () => { console.error('errored') })
.on('end', () => { console.log('finished') })
Il sera alors possible de le déchiffrer de la façon suivante :
const { createReadStream, createWriteStream, promises: fsPromises } = require('fs')
const { stat } = fsPromises
const inputFile = './path/to/encryptedFile'
const outputFile = './path/to/decryptedFile'
const readable = createReadStream(inputFile)
const writable = createWriteStream(outputFile)
const {
data, // An instance of Readable which will stream the clear text data
type, // 'node-stream'
size, // 19
sessionId, // the encryption session ID
filename // 'SecretFile.txt'
} = await seald.decryptFile(readable)
data
.on('error', () => { console.error('errored') })
.pipe(writable)
.on('error', () => { console.error('errored') })
.on('end', () => { console.log('finished') })
Sur React-Native
La lecture de fichiers sur React-Native s'effectue en général avec le paquet react-native-fs
, ou avec expo-file-system
.
Dans ces deux cas, la lecture d'un fichier binaire rend un string base64.
Afin de chiffrer les données brutes du fichier, et non son encodage base64, il faut le convertir dans un format binaire, par exemple un Buffer
.
import RNFS from 'react-native-fs'
import { Buffer } from '@craftzdog/react-native-buffer'
const inputStringB64 = await RNFS.readFile(inputFilePath, 'base64')
const inputBuffer = Buffer.from(inputStringB64, 'base64') // Convertit le base64 avant de chiffrer
const encryptedBuffer = await seald.encryptFile(
inputBuffer,
'fileToEncrypt',
{ sealdIds: [mySealdId, user2SealdId] }
)
import * as FileSystem from 'expo-file-system'
import { Buffer } from '@craftzdog/react-native-buffer'
const inputStringB64 = await FileSystem.readAsStringAsync(
inputFilePath,
{ encoding: FileSystem.EncodingType.Base64 }
)
const inputBuffer = Buffer.from(inputStringB64, 'base64') // Convertit le base64 avant de chiffrer
const encryptedBuffer = await seald.encryptFile(
inputBuffer,
'fileToEncrypt',
{ sealdIds: [mySealdId, user2SealdId] }
)
De même, pour déchiffrer un fichier chiffré depuis le système de fichier, il faudra également décoder le base64 de la même manière.