-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve device transfer speed on macOS (#1275)
* add common crypto * display device transfer network speed * display transfer speed for device trasnfer * bump common crypto version * improve hmac calculate
- Loading branch information
Showing
7 changed files
with
286 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import 'dart:typed_data'; | ||
|
||
import 'package:common_crypto/common_crypto.dart' as cc; | ||
import 'package:flutter/cupertino.dart'; | ||
import 'package:pointycastle/block/aes.dart'; | ||
import 'package:pointycastle/block/modes/cbc.dart'; | ||
import 'package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart'; | ||
import 'package:pointycastle/paddings/pkcs7.dart'; | ||
import 'package:pointycastle/pointycastle.dart'; | ||
|
||
import '../platform.dart'; | ||
|
||
typedef OnCipherCallback = void Function(Uint8List data); | ||
|
||
abstract class AesCipher { | ||
factory AesCipher({ | ||
required Uint8List key, | ||
required Uint8List iv, | ||
required bool encrypt, | ||
}) { | ||
if (kPlatformIsDarwin) { | ||
return AesCipherCommonCryptoImpl(key: key, iv: iv, encrypt: encrypt); | ||
} else { | ||
return AesCipherPointyCastleImpl(key: key, iv: iv, encrypt: encrypt); | ||
} | ||
} | ||
|
||
static Uint8List _crypt({ | ||
required Uint8List key, | ||
required Uint8List iv, | ||
required Uint8List data, | ||
required bool encrypt, | ||
}) { | ||
final cipher = AesCipher(key: key, iv: iv, encrypt: encrypt); | ||
final result = <int>[]; | ||
cipher | ||
..update(data, result.addAll) | ||
..finish(result.addAll); | ||
return Uint8List.fromList(result); | ||
} | ||
|
||
static Uint8List encrypt({ | ||
required Uint8List key, | ||
required Uint8List iv, | ||
required Uint8List data, | ||
}) => | ||
_crypt(key: key, iv: iv, data: data, encrypt: true); | ||
|
||
static Uint8List decrypt({ | ||
required Uint8List key, | ||
required Uint8List iv, | ||
required Uint8List data, | ||
}) => | ||
_crypt(key: key, iv: iv, data: data, encrypt: false); | ||
|
||
void update(Uint8List data, OnCipherCallback onCipher); | ||
|
||
void finish(OnCipherCallback onCipher); | ||
} | ||
|
||
@visibleForTesting | ||
class AesCipherCommonCryptoImpl implements AesCipher { | ||
AesCipherCommonCryptoImpl({ | ||
required Uint8List key, | ||
required Uint8List iv, | ||
required bool encrypt, | ||
}) : _aesCrypto = cc.AesCryptor(key: key, iv: iv, encrypt: encrypt); | ||
|
||
final cc.AesCryptor _aesCrypto; | ||
|
||
var _disposed = false; | ||
|
||
@override | ||
void update(Uint8List data, OnCipherCallback onCipher) { | ||
if (_disposed) { | ||
throw StateError('AesCipherCommonCryptoImpl has been disposed.'); | ||
} | ||
_aesCrypto.update(data, onCipher); | ||
} | ||
|
||
@override | ||
void finish(OnCipherCallback onCipher) { | ||
if (_disposed) { | ||
throw StateError('AesCipherCommonCryptoImpl has been disposed.'); | ||
} | ||
_aesCrypto | ||
..finalize(onCipher) | ||
..dispose(); | ||
_disposed = true; | ||
} | ||
} | ||
|
||
class AesCipherPointyCastleImpl implements AesCipher { | ||
AesCipherPointyCastleImpl({ | ||
required Uint8List key, | ||
required Uint8List iv, | ||
required bool encrypt, | ||
}) : _cipher = _createAESCipher(aesKey: key, iv: iv, encrypt: encrypt); | ||
|
||
static PaddedBlockCipherImpl _createAESCipher({ | ||
required Uint8List aesKey, | ||
required Uint8List iv, | ||
required bool encrypt, | ||
}) { | ||
final cbcCipher = CBCBlockCipher(AESEngine()); | ||
return PaddedBlockCipherImpl(PKCS7Padding(), cbcCipher) | ||
..init( | ||
encrypt, | ||
PaddedBlockCipherParameters( | ||
ParametersWithIV(KeyParameter(aesKey), iv), | ||
null, | ||
), | ||
); | ||
} | ||
|
||
final PaddedBlockCipherImpl _cipher; | ||
Uint8List? _carry; | ||
List<int>? _preBytes; | ||
|
||
@override | ||
void update(Uint8List bytes, OnCipherCallback onCipher) { | ||
final toProcess = _preBytes; | ||
_preBytes = bytes; | ||
if (toProcess == null) { | ||
return; | ||
} | ||
final Uint8List data; | ||
if (_carry == null) { | ||
data = Uint8List.fromList(toProcess); | ||
} else { | ||
data = Uint8List.fromList(_carry! + toProcess); | ||
_carry = null; | ||
} | ||
final length = data.length - (data.length % 1024); | ||
if (length < data.length) { | ||
_carry = data.sublist(length); | ||
} else { | ||
_carry = null; | ||
} | ||
final encryptedData = Uint8List(length); | ||
var offset = 0; | ||
while (offset < length) { | ||
offset += _cipher.processBlock(data, offset, encryptedData, offset); | ||
} | ||
onCipher(encryptedData); | ||
} | ||
|
||
@override | ||
void finish(OnCipherCallback onCipher) { | ||
final Uint8List lastBlock; | ||
if (_carry == null) { | ||
lastBlock = Uint8List.fromList(_preBytes ?? []); | ||
} else { | ||
lastBlock = Uint8List.fromList(_carry! + _preBytes!); | ||
} | ||
final encryptedData = _cipher.process(lastBlock); | ||
onCipher(encryptedData); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import 'dart:typed_data'; | ||
|
||
import 'package:common_crypto/common_crypto.dart'; | ||
import 'package:pointycastle/digests/sha256.dart'; | ||
import 'package:pointycastle/macs/hmac.dart'; | ||
import 'package:pointycastle/pointycastle.dart'; | ||
|
||
import '../platform.dart'; | ||
|
||
Uint8List calculateHMac(Uint8List key, Uint8List data) { | ||
final calculator = HMacCalculator(key)..addBytes(data); | ||
return calculator.result; | ||
} | ||
|
||
abstract class HMacCalculator { | ||
factory HMacCalculator(Uint8List key) { | ||
if (kPlatformIsDarwin) { | ||
return _HMacCalculatorCommonCrypto(key); | ||
} | ||
return _HMacCalculatorPointyCastleImpl(key); | ||
} | ||
|
||
void addBytes(Uint8List data); | ||
|
||
Uint8List get result; | ||
} | ||
|
||
class _HMacCalculatorPointyCastleImpl implements HMacCalculator { | ||
_HMacCalculatorPointyCastleImpl(this._hMacKey) | ||
: _hmac = HMac(SHA256Digest(), 64) { | ||
_hmac.init(KeyParameter(_hMacKey)); | ||
} | ||
|
||
final Uint8List _hMacKey; | ||
final HMac _hmac; | ||
|
||
@override | ||
void addBytes(Uint8List data) { | ||
_hmac.update(data, 0, data.length); | ||
} | ||
|
||
@override | ||
Uint8List get result { | ||
final bytes = Uint8List(_hmac.macSize); | ||
final len = _hmac.doFinal(bytes, 0); | ||
return bytes.sublist(0, len); | ||
} | ||
} | ||
|
||
class _HMacCalculatorCommonCrypto implements HMacCalculator { | ||
_HMacCalculatorCommonCrypto(Uint8List key) : _hmac = HMacSha256(key); | ||
|
||
final HMacSha256 _hmac; | ||
var _isDisposed = false; | ||
|
||
@override | ||
void addBytes(Uint8List data) { | ||
if (_isDisposed) { | ||
throw StateError('HMacCalculator is disposed'); | ||
} | ||
_hmac.update(data); | ||
} | ||
|
||
@override | ||
Uint8List get result { | ||
if (_isDisposed) { | ||
throw StateError('HMacCalculator is disposed'); | ||
} | ||
final result = _hmac.finalize(); | ||
_hmac.dispose(); | ||
_isDisposed = true; | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.