Fix OutOfMemoryError on large files
This commit is contained in:
parent
4d0dd7e5e3
commit
5da95a0c39
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020
|
||||
// Copyright (c) 2021
|
||||
// Author: Hugo Pointcheval
|
||||
|
||||
import 'dart:typed_data';
|
||||
@ -52,14 +52,23 @@ abstract class Cipher {
|
||||
///
|
||||
/// It's the result of an encryption.
|
||||
abstract class CipherText {
|
||||
/// Returns the standard algorithm name used for this ciphertext
|
||||
/// Returns the standard algorithm name used for this ciphertext.
|
||||
CipherAlgorithm get algorithm;
|
||||
|
||||
/// Returns the data of this ciphertext
|
||||
Uint8List get bytes;
|
||||
/// Returns the data of this ciphertext (in chunks).
|
||||
List<Uint8List> get bytes;
|
||||
|
||||
/// Returns the IV of this cipertext
|
||||
Uint8List get iv;
|
||||
/// Returns the IV of this cipertext (in chunks).
|
||||
List<Uint8List> get iv;
|
||||
|
||||
/// Returns the chunk number of this cipherText.
|
||||
int get size;
|
||||
|
||||
/// Returns this ciphertext in simple Byte Array format.
|
||||
Uint8List encode();
|
||||
|
||||
/// Transforms a simple Byte Array to a NativeCrypto cipherText.
|
||||
void decode(Uint8List src);
|
||||
}
|
||||
|
||||
/// Represents a pair of [BlockCipherMode] and [Padding]
|
||||
|
@ -1,8 +1,10 @@
|
||||
// Copyright (c) 2020
|
||||
// Copyright (c) 2021
|
||||
// Author: Hugo Pointcheval
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:native_crypto/native_crypto.dart';
|
||||
|
||||
import '../cipher.dart';
|
||||
import '../exceptions.dart';
|
||||
import '../key.dart';
|
||||
@ -81,9 +83,28 @@ class AESCipher implements Cipher {
|
||||
} else if (_sk == null || _sk.isEmpty) {
|
||||
throw CipherInitException('Invalid key size.');
|
||||
}
|
||||
List<Uint8List> c =
|
||||
await Platform().encrypt(data, _sk.encoded, algorithm, _params);
|
||||
return AESCipherText(c[0], c[1]);
|
||||
Uint8List dataToEncrypt;
|
||||
int maxSize = 33554432;
|
||||
AESCipherText cipherText = AESCipherText.empty();
|
||||
// If data is bigger than 32mB -> split in chunks
|
||||
if (data.length > maxSize) {
|
||||
int chunkNb = (data.length / maxSize).ceil();
|
||||
for (var i = 0; i < chunkNb; i++) {
|
||||
if (i < (chunkNb - 1)) {
|
||||
dataToEncrypt = data.sublist(i * maxSize, (i + 1) * maxSize);
|
||||
} else {
|
||||
dataToEncrypt = data.sublist(i * maxSize);
|
||||
}
|
||||
List<Uint8List> c = await Platform()
|
||||
.encrypt(dataToEncrypt, _sk.encoded, algorithm, _params);
|
||||
cipherText.append(c[0], c[1]);
|
||||
}
|
||||
} else {
|
||||
List<Uint8List> c =
|
||||
await Platform().encrypt(data, _sk.encoded, algorithm, _params);
|
||||
cipherText.append(c[0], c[1]);
|
||||
}
|
||||
return cipherText;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -96,29 +117,106 @@ class AESCipher implements Cipher {
|
||||
throw CipherInitException('Cipher not properly initialized.');
|
||||
} else if (_sk == null || _sk.isEmpty) {
|
||||
throw CipherInitException('Invalid key size.');
|
||||
} else if (cipherText.bytes.length != cipherText.iv.length) {
|
||||
throw DecryptionException(
|
||||
"This cipher text's bytes chunks length is not the same as iv chunks length");
|
||||
}
|
||||
List<Uint8List> payload = [cipherText.bytes, cipherText.iv];
|
||||
Uint8List d =
|
||||
await Platform().decrypt(payload, _sk.encoded, algorithm, _params);
|
||||
return d;
|
||||
|
||||
BytesBuilder decryptedData = BytesBuilder();
|
||||
if (cipherText.size > 1) {
|
||||
for (var i = 0; i < cipherText.size; i++) {
|
||||
List<Uint8List> payload = [cipherText.bytes[i], cipherText.iv[i]];
|
||||
Uint8List d =
|
||||
await Platform().decrypt(payload, _sk.encoded, algorithm, _params);
|
||||
decryptedData.add(d);
|
||||
}
|
||||
} else {
|
||||
List<Uint8List> payload = [cipherText.bytes[0], cipherText.iv[0]];
|
||||
Uint8List d =
|
||||
await Platform().decrypt(payload, _sk.encoded, algorithm, _params);
|
||||
decryptedData.add(d);
|
||||
}
|
||||
return decryptedData.toBytes();
|
||||
}
|
||||
}
|
||||
|
||||
class AESCipherText implements CipherText {
|
||||
Uint8List _bytes;
|
||||
Uint8List _iv;
|
||||
List<Uint8List> _bytes;
|
||||
List<Uint8List> _iv;
|
||||
|
||||
@override
|
||||
CipherAlgorithm get algorithm => CipherAlgorithm.AES;
|
||||
|
||||
@override
|
||||
Uint8List get bytes => _bytes;
|
||||
List<Uint8List> get bytes => _bytes;
|
||||
|
||||
@override
|
||||
Uint8List get iv => _iv;
|
||||
List<Uint8List> get iv => _iv;
|
||||
|
||||
@override
|
||||
int get size => _bytes.length;
|
||||
|
||||
AESCipherText(Uint8List bytes, Uint8List iv) {
|
||||
_bytes = List.from([bytes]);
|
||||
_iv = List.from([iv]);
|
||||
}
|
||||
|
||||
AESCipherText.from(List<Uint8List> bytes, List<Uint8List> iv) {
|
||||
_bytes = bytes;
|
||||
_iv = iv;
|
||||
}
|
||||
|
||||
AESCipherText.empty() {
|
||||
_bytes = <Uint8List>[];
|
||||
_iv = <Uint8List>[];
|
||||
}
|
||||
|
||||
void append(Uint8List bytes, Uint8List iv) {
|
||||
_bytes.add(bytes);
|
||||
_iv.add(iv);
|
||||
}
|
||||
|
||||
/// Returns this ciphertext in [Uint8List] format.
|
||||
///
|
||||
/// Encoding
|
||||
/// --------
|
||||
/// Uint8List encoding is : IV_1 + M_1 + IV_2 + M_2 + ... + IV_n + M_n
|
||||
///
|
||||
/// Where **IV_k** is the IV of the cipher text **M_k**
|
||||
///
|
||||
/// IV is **always** 16 bytes long, And the **M** are all max
|
||||
/// size (of 33 554 480 bytes) except the last one which is shorter than the others.
|
||||
Uint8List encode() {
|
||||
BytesBuilder builder = BytesBuilder();
|
||||
for (var i = 0; i < size; i++) {
|
||||
builder.add(_iv[i]);
|
||||
builder.add(_bytes[i]);
|
||||
}
|
||||
|
||||
return builder.toBytes();
|
||||
}
|
||||
|
||||
/// Transforms a [Uint8List] to a *NativeCrypto* cipherText.
|
||||
///
|
||||
/// Decoding
|
||||
/// --------
|
||||
/// See the list as a chain of chunks (IV and Messages)
|
||||
/// `[IV][MESSAGE][IV][MESSAGE] ... [IV][MESSA...]`
|
||||
///
|
||||
/// Chunk length is IV length + Message length = 16 + 33 554 480 bytes
|
||||
void decode(Uint8List src) {
|
||||
ByteBuffer buffer = src.buffer;
|
||||
|
||||
int chunkSize = 16 + 33554480;
|
||||
int chunkNb = (buffer.lengthInBytes / chunkSize).ceil();
|
||||
|
||||
for (var i = 0; i < chunkNb; i++) {
|
||||
_iv.add(buffer.asUint8List(i * chunkSize, 16));
|
||||
if (i < (chunkNb - 1)) {
|
||||
_bytes.add(buffer.asUint8List(16 + i * chunkSize, 33554480));
|
||||
} else {
|
||||
_bytes.add(buffer.asUint8List(16 + i * chunkSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user