Merge branch 'soru/export-key-as-string' into 'main'

feat: Add a way to string-encode a recovery key

Closes #140

See merge request famedly/famedlysdk!634
This commit is contained in:
Krille Fear 2021-02-03 10:50:23 +00:00
commit 3e7ce2fe13
2 changed files with 32 additions and 0 deletions

View File

@ -142,6 +142,24 @@ class SSSS {
OLM_RECOVERY_KEY_PREFIX.length + SSSS_KEY_LENGTH)); OLM_RECOVERY_KEY_PREFIX.length + SSSS_KEY_LENGTH));
} }
static String encodeRecoveryKey(Uint8List recoveryKey) {
final keyToEncode = <int>[];
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) { static Uint8List keyFromPassphrase(String passphrase, PassphraseInfo info) {
if (info.algorithm != AlgorithmTypes.pbkdf2) { if (info.algorithm != AlgorithmTypes.pbkdf2) {
throw Exception('Unknown algorithm'); throw Exception('Unknown algorithm');
@ -596,6 +614,9 @@ class OpenSSSS {
bool get isUnlocked => privateKey != null; bool get isUnlocked => privateKey != null;
String get recoveryKey =>
isUnlocked ? SSSS.encodeRecoveryKey(privateKey) : null;
Future<void> unlock( Future<void> unlock(
{String passphrase, String recoveryKey, String keyOrPassphrase}) async { {String passphrase, String recoveryKey, String keyOrPassphrase}) async {
if (keyOrPassphrase != null) { if (keyOrPassphrase != null) {

View File

@ -112,6 +112,17 @@ void main() {
expect(await handle.getStored('best animal'), 'foxies'); 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 { test('cache', () async {
final handle = final handle =
client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning); client.encryption.ssss.open(EventTypes.CrossSigningSelfSigning);