Skip to content

Commit 3a37ed8

Browse files
authored
Merge pull request #279 from IO-Design-Team/feature/isolated-hive-checksum-cipher-fix
IsolatedHive checksum cipher fix
2 parents d57d4e5 + 082aa10 commit 3a37ed8

22 files changed

Lines changed: 394 additions & 143 deletions

hive/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 2.18.0
22

3+
- Fixes an issue with IsolatedHive encryption
34
- Automatically disables the unsafe isolate warning when running in a test
45

56
## 2.17.0

hive/lib/src/backend/js/native/backend_manager.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class BackendManager implements BackendManagerInterface {
1818
String? path,
1919
bool crashRecovery,
2020
HiveCipher? cipher,
21+
int? keyCrc,
2122
String? collection,
2223
) async {
2324
// compatibility for old store format

hive/lib/src/backend/storage_backend.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ abstract class BackendManagerInterface {
5454
String? path,
5555
bool crashRecovery,
5656
HiveCipher? cipher,
57+
int? keyCrc,
5758
String? collection,
5859
);
5960

hive/lib/src/backend/storage_backend_memory.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import 'package:hive_ce/src/box/keystore.dart';
99
/// In-memory Storage backend
1010
class StorageBackendMemory extends StorageBackend {
1111
final HiveCipher? _cipher;
12+
final int? _keyCrc;
1213

1314
final FrameHelper _frameHelper;
1415

1516
Uint8List? _bytes;
1617

1718
/// Not part of public API
18-
StorageBackendMemory(Uint8List? bytes, this._cipher)
19+
StorageBackendMemory(Uint8List? bytes, this._cipher, this._keyCrc)
1920
: _bytes = bytes,
2021
_frameHelper = FrameHelper();
2122

@@ -37,6 +38,7 @@ class StorageBackendMemory extends StorageBackend {
3738
keystore,
3839
registry,
3940
_cipher,
41+
_keyCrc,
4042
);
4143

4244
if (recoveryOffset != -1) {

hive/lib/src/backend/stub/backend_manager.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class BackendManager implements BackendManagerInterface {
1717
String? path,
1818
bool crashRecovery,
1919
HiveCipher? cipher,
20+
int? keyCrc,
2021
String? collection,
2122
) {
2223
throw UnimplementedError();

hive/lib/src/backend/vm/backend_manager.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class BackendManager implements BackendManagerInterface {
2323
String? path,
2424
bool crashRecovery,
2525
HiveCipher? cipher,
26+
int? keyCrc,
2627
String? collection,
2728
) async {
2829
if (path == null) {
@@ -45,7 +46,8 @@ class BackendManager implements BackendManagerInterface {
4546
final file = await findHiveFileAndCleanUp(name, path);
4647
final lockFile = File('$path$_delimiter$name.lock');
4748

48-
final backend = StorageBackendVm(file, lockFile, crashRecovery, cipher);
49+
final backend =
50+
StorageBackendVm(file, lockFile, crashRecovery, cipher, keyCrc);
4951
await backend.open();
5052
return backend;
5153
}

hive/lib/src/backend/vm/storage_backend_vm.dart

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,11 @@ import 'package:meta/meta.dart';
1818

1919
/// Storage backend for the Dart VM
2020
class StorageBackendVm extends StorageBackend {
21-
/// Warning for existing lock of unmatched isolation
22-
@visibleForTesting
23-
static const unmatchedIsolationWarning = '''
24-
⚠️ WARNING: HIVE MULTI-ISOLATE RISK DETECTED ⚠️
25-
26-
You are opening this box with Hive, but this box was previously opened with
27-
IsolatedHive. This can lead to DATA CORRUPTION as Hive boxes are not designed
28-
for concurrent access across isolates. Each isolate would maintain its own box
29-
cache, potentially causing data inconsistency and corruption.
30-
31-
RECOMMENDED ACTIONS:
32-
- ALWAYS use IsolatedHive to perform box operations when working with multiple
33-
isolates
34-
''';
35-
3621
final File _file;
3722
final File _lockFile;
3823
final bool _crashRecovery;
3924
final HiveCipher? _cipher;
25+
final int? _keyCrc;
4026
final FrameIoHelper _frameHelper;
4127

4228
final ReadWriteSync _sync;
@@ -73,6 +59,7 @@ RECOMMENDED ACTIONS:
7359
this._lockFile,
7460
this._crashRecovery,
7561
this._cipher,
62+
this._keyCrc,
7663
) : _frameHelper = FrameIoHelper(),
7764
_sync = ReadWriteSync();
7865

@@ -82,6 +69,7 @@ RECOMMENDED ACTIONS:
8269
this._lockFile,
8370
this._crashRecovery,
8471
this._cipher,
72+
this._keyCrc,
8573
this._frameHelper,
8674
this._sync,
8775
);
@@ -116,7 +104,7 @@ RECOMMENDED ACTIONS:
116104
props = LockProps();
117105
}
118106
if (Logger.unmatchedIsolationWarning && props.isolated && !isolated) {
119-
Logger.w(unmatchedIsolationWarning);
107+
Logger.w(HiveWarning.unmatchedIsolation);
120108
}
121109
}
122110

@@ -132,10 +120,12 @@ RECOMMENDED ACTIONS:
132120
keystore,
133121
registry,
134122
_cipher,
123+
_keyCrc,
135124
verbatim: isolated,
136125
);
137126
} else {
138-
recoveryOffset = await _frameHelper.keysFromFile(path, keystore, _cipher);
127+
recoveryOffset =
128+
await _frameHelper.keysFromFile(path, keystore, _cipher, _keyCrc);
139129
}
140130

141131
if (recoveryOffset != -1) {
@@ -158,8 +148,12 @@ RECOMMENDED ACTIONS:
158148
final bytes = await readRaf.read(frame.length!);
159149

160150
final reader = BinaryReaderImpl(bytes, registry);
161-
final readFrame =
162-
reader.readFrame(cipher: _cipher, lazy: false, verbatim: verbatim);
151+
final readFrame = reader.readFrame(
152+
cipher: _cipher,
153+
keyCrc: _keyCrc,
154+
lazy: false,
155+
verbatim: verbatim,
156+
);
163157

164158
if (readFrame == null) {
165159
throw HiveError(
@@ -177,8 +171,12 @@ RECOMMENDED ACTIONS:
177171
final writer = BinaryWriterImpl(registry);
178172

179173
for (final frame in frames) {
180-
frame.length =
181-
writer.writeFrame(frame, cipher: _cipher, verbatim: verbatim);
174+
frame.length = writer.writeFrame(
175+
frame,
176+
cipher: _cipher,
177+
keyCrc: _keyCrc,
178+
verbatim: verbatim,
179+
);
182180
}
183181

184182
try {

hive/lib/src/binary/binary_reader_impl.dart

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:hive_ce/src/crypto/crc32.dart';
77
import 'package:hive_ce/src/object/hive_list_impl.dart';
88
import 'package:hive_ce/src/registry/type_registry_impl.dart';
99
import 'package:hive_ce/src/util/extensions.dart';
10+
import 'package:hive_ce/src/util/logger.dart';
1011
import 'package:meta/meta.dart';
1112

1213
/// Not part of public API
@@ -19,6 +20,8 @@ class BinaryReaderImpl extends BinaryReader {
1920
int _bufferLimit;
2021
var _offset = 0;
2122

23+
var _crcRecomputeWarningPrinted = false;
24+
2225
/// Not part of public API
2326
BinaryReaderImpl(this._buffer, TypeRegistry typeRegistry, [int? bufferLength])
2427
: _byteData = ByteData.view(_buffer.buffer, _buffer.offsetInBytes),
@@ -259,6 +262,7 @@ class BinaryReaderImpl extends BinaryReader {
259262
/// Not part of public API
260263
Frame? readFrame({
261264
HiveCipher? cipher,
265+
int? keyCrc,
262266
bool lazy = false,
263267
int frameOffset = 0,
264268
bool verbatim = false,
@@ -274,15 +278,35 @@ class BinaryReaderImpl extends BinaryReader {
274278
if (availableBytes < frameLength - 4) return null;
275279

276280
final crc = _buffer.readUint32(_offset + frameLength - 8);
281+
final crcOffset = _offset - 4;
282+
final crcLength = frameLength - 4;
277283
final computedCrc = Crc32.compute(
278284
_buffer,
279-
offset: _offset - 4,
280-
length: frameLength - 4,
281-
crc: cipher?.calculateKeyCrc() ?? 0,
285+
offset: crcOffset,
286+
length: crcLength,
287+
crc: keyCrc ?? cipher?.calculateKeyCrc() ?? 0,
282288
);
283289

284290
// frame is corrupted or provided chiper is different
285-
if (computedCrc != crc) return null;
291+
if (computedCrc != crc) {
292+
if (keyCrc != null) {
293+
// Attempt to compute the crc without the key crc
294+
// This maintains compatibility with data written by IsolatedHive before keyCrc was introduced
295+
final computedCrc2 = Crc32.compute(
296+
_buffer,
297+
offset: crcOffset,
298+
length: crcLength,
299+
);
300+
if (computedCrc2 != crc) return null;
301+
302+
if (Logger.crcRecomputeWarning && !_crcRecomputeWarningPrinted) {
303+
Logger.w(HiveWarning.crcRecomputeNeeded);
304+
_crcRecomputeWarningPrinted = true;
305+
}
306+
} else {
307+
return null;
308+
}
309+
}
286310

287311
_limitAvailableBytes(frameLength - 8);
288312
Frame frame;

hive/lib/src/binary/binary_writer_impl.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'package:hive_ce/src/binary/frame.dart';
66
import 'package:hive_ce/src/crypto/crc32.dart';
77
import 'package:hive_ce/src/object/hive_list_impl.dart';
88
import 'package:hive_ce/src/registry/type_registry_impl.dart';
9-
import 'package:hive_ce/src/util/debug_utils.dart';
109
import 'package:hive_ce/src/util/extensions.dart';
1110
import 'package:hive_ce/src/util/logger.dart';
1211
import 'package:meta/meta.dart';
@@ -18,12 +17,6 @@ class BinaryWriterImpl extends BinaryWriter {
1817
/// The maximum integer that can be stored in a 64 bit float (2^53)
1918
static const maxInt = 9007199254740992;
2019

21-
/// Warning message printed when attempting to store an integer that is too large
22-
static const intWarning =
23-
'WARNING: Writing integer values greater than 2^53 will result in precision loss. '
24-
'This is due to Hive storing all numbers as 64 bit floats. '
25-
'Consider using a BigInt.';
26-
2720
/// The type registry to use for writing values
2821
final TypeRegistryImpl typeRegistry;
2922
var _buffer = Uint8List(_initBufferSize);
@@ -107,7 +100,9 @@ class BinaryWriterImpl extends BinaryWriter {
107100
@override
108101
void writeInt(int value) {
109102
// Web truncates values greater than 2^53 to 2^53
110-
if (kDebugMode && value >= maxInt) Logger.w(intWarning);
103+
if (Logger.bigIntWarning && value >= maxInt) {
104+
Logger.w(HiveWarning.bigInt);
105+
}
111106
writeDouble(value.toDouble());
112107
}
113108

@@ -265,7 +260,12 @@ class BinaryWriterImpl extends BinaryWriter {
265260
}
266261

267262
/// Not part of public API
268-
int writeFrame(Frame frame, {HiveCipher? cipher, bool verbatim = false}) {
263+
int writeFrame(
264+
Frame frame, {
265+
HiveCipher? cipher,
266+
int? keyCrc,
267+
bool verbatim = false,
268+
}) {
269269
final startOffset = _offset;
270270
_reserveBytes(4);
271271
_offset += 4; // reserve bytes for length
@@ -289,7 +289,7 @@ class BinaryWriterImpl extends BinaryWriter {
289289
_buffer,
290290
offset: startOffset,
291291
length: frameLength - 4,
292-
crc: cipher?.calculateKeyCrc() ?? 0,
292+
crc: keyCrc ?? cipher?.calculateKeyCrc() ?? 0,
293293
);
294294
writeUint32(crc);
295295

hive/lib/src/binary/frame_helper.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ class FrameHelper {
1111
Uint8List bytes,
1212
Keystore? keystore,
1313
TypeRegistry registry,
14-
HiveCipher? cipher, {
14+
HiveCipher? cipher,
15+
int? keyCrc, {
1516
bool verbatim = false,
1617
}) {
1718
final reader = BinaryReaderImpl(bytes, registry);
@@ -21,6 +22,7 @@ class FrameHelper {
2122

2223
final frame = reader.readFrame(
2324
cipher: cipher,
25+
keyCrc: keyCrc,
2426
lazy: false,
2527
frameOffset: frameOffset,
2628
verbatim: verbatim,

0 commit comments

Comments
 (0)