93 lines
3.0 KiB
Dart
93 lines
3.0 KiB
Dart
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:crypton/crypton.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:marianum_mobile/push/push_decryptor.dart';
|
|
import 'package:pointycastle/export.dart' as pc;
|
|
|
|
/// Encrypts [plain] with [publicKey] using OAEP (SHA-1), mirroring Nextcloud's
|
|
/// default padding.
|
|
String _encryptOaep(RSAPublicKey publicKey, String plain) {
|
|
final cipher = pc.OAEPEncoding(pc.RSAEngine())
|
|
..init(
|
|
true,
|
|
pc.PublicKeyParameter<pc.RSAPublicKey>(publicKey.asPointyCastle),
|
|
);
|
|
final out = cipher.process(Uint8List.fromList(utf8.encode(plain)));
|
|
return base64.encode(out);
|
|
}
|
|
|
|
/// Signs the encrypted bytes with the server private key (SHA512withRSA).
|
|
String _sign(RSAPrivateKey serverPrivate, String subjectBase64) {
|
|
final signature = serverPrivate.createSHA512Signature(
|
|
Uint8List.fromList(base64.decode(subjectBase64)),
|
|
);
|
|
return base64.encode(signature);
|
|
}
|
|
|
|
void main() {
|
|
final device = RSAKeypair.fromRandom();
|
|
final server = RSAKeypair.fromRandom();
|
|
|
|
const subjectJson =
|
|
'{"app":"spreed","subject":"Max: Hallo","type":"chat","id":"abc123","nid":42}';
|
|
|
|
group('PushDecryptor', () {
|
|
test('decrypts an OAEP-encrypted subject', () {
|
|
final encrypted = _encryptOaep(device.publicKey, subjectJson);
|
|
final decryptor = PushDecryptor(
|
|
devicePrivateKey: device.privateKey,
|
|
serverPublicKey: server.publicKey,
|
|
);
|
|
|
|
expect(
|
|
decryptor.verify(encrypted, _sign(server.privateKey, encrypted)),
|
|
isTrue,
|
|
);
|
|
|
|
final subject = decryptor.decrypt(encrypted);
|
|
expect(subject, isNotNull);
|
|
expect(subject!.app, 'spreed');
|
|
expect(subject.isTalk, isTrue);
|
|
expect(subject.id, 'abc123');
|
|
expect(subject.nid, 42);
|
|
});
|
|
|
|
test('decrypts a PKCS1-encrypted subject (fallback)', () {
|
|
// crypton's encrypt uses PKCS#1 v1.5.
|
|
final encrypted = device.publicKey.encrypt(subjectJson);
|
|
final subject = PushDecryptor(
|
|
devicePrivateKey: device.privateKey,
|
|
).decrypt(encrypted);
|
|
expect(subject, isNotNull);
|
|
expect(subject!.subject, 'Max: Hallo');
|
|
});
|
|
|
|
test('rejects a signature made with the wrong key', () {
|
|
final encrypted = _encryptOaep(device.publicKey, subjectJson);
|
|
final wrong = RSAKeypair.fromRandom();
|
|
final decryptor = PushDecryptor(
|
|
devicePrivateKey: device.privateKey,
|
|
serverPublicKey: server.publicKey,
|
|
);
|
|
expect(
|
|
decryptor.verify(encrypted, _sign(wrong.privateKey, encrypted)),
|
|
isFalse,
|
|
);
|
|
});
|
|
|
|
test('parses delete-multiple subjects', () {
|
|
const deleteJson = '{"delete-multiple":true,"nids":[1,2,3]}';
|
|
final encrypted = _encryptOaep(device.publicKey, deleteJson);
|
|
final subject = PushDecryptor(
|
|
devicePrivateKey: device.privateKey,
|
|
).decrypt(encrypted);
|
|
expect(subject, isNotNull);
|
|
expect(subject!.deleteMultiple, isTrue);
|
|
expect(subject.isAnyDelete, isTrue);
|
|
expect(subject.nids, [1, 2, 3]);
|
|
});
|
|
});
|
|
}
|