diff --git a/lib/encryption/ssss.dart b/lib/encryption/ssss.dart index d24cdefa..5fd2e562 100644 --- a/lib/encryption/ssss.dart +++ b/lib/encryption/ssss.dart @@ -142,6 +142,24 @@ class SSSS { OLM_RECOVERY_KEY_PREFIX.length + SSSS_KEY_LENGTH)); } + static String encodeRecoveryKey(Uint8List recoveryKey) { + final keyToEncode = []; + for (final b in OLM_RECOVERY_KEY_PREFIX) { + keyToEncode.add(b); + } + keyToEncode.addAll(recoveryKey); + var parity = 0; + for (final b in keyToEncode) { + parity ^= b; + } + keyToEncode.add(parity); + // base58-encode and add a space every four chars + return base58 + .encode(keyToEncode) + .replaceAllMapped(RegExp(r'.{4}'), (s) => '${s.group(0)} ') + .trim(); + } + static Uint8List keyFromPassphrase(String passphrase, PassphraseInfo info) { if (info.algorithm != AlgorithmTypes.pbkdf2) { throw Exception('Unknown algorithm'); @@ -596,6 +614,9 @@ class OpenSSSS { bool get isUnlocked => privateKey != null; + String get recoveryKey => + isUnlocked ? SSSS.encodeRecoveryKey(privateKey) : null; + Future unlock( {String passphrase, String recoveryKey, String keyOrPassphrase}) async { if (keyOrPassphrase != null) { diff --git a/test/encryption/ssss_test.dart b/test/encryption/ssss_test.dart index 96d83f34..12541af3 100644 --- a/test/encryption/ssss_test.dart +++ b/test/encryption/ssss_test.dart @@ -112,6 +112,17 @@ void main() { expect(await handle.getStored('best animal'), 'foxies'); }); + test('encode / decode recovery key', () async { + final key = Uint8List.fromList(SecureRandom(32).bytes); + final encoded = SSSS.encodeRecoveryKey(key); + final decoded = SSSS.decodeRecoveryKey(encoded); + expect(key, decoded); + + final handle = client.encryption.ssss.open(); + await handle.unlock(recoveryKey: SSSS_KEY); + expect(handle.recoveryKey, SSSS_KEY); + }); + test('cache', () async { final handle = client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);