Encrypted messaging app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
3.5 KiB

  1. import 'dart:convert';
  2. import 'dart:typed_data';
  3. import 'package:pointycastle/export.dart';
  4. import '/utils/encryption/aes_helper.dart';
  5. import '/utils/encryption/crypto_utils.dart';
  6. // TODO: Find good place for this to live
  7. Friend findFriendByFriendId(List<Friend> friends, String id) {
  8. for (var friend in friends) {
  9. if (friend.friendId == id) {
  10. return friend;
  11. }
  12. }
  13. // Or return `null`.
  14. throw ArgumentError.value(id, 'id', 'No element with that id');
  15. }
  16. class Friend {
  17. String id;
  18. String userId;
  19. String username;
  20. String friendId;
  21. String friendSymmetricKey;
  22. RSAPublicKey publicKey;
  23. DateTime? acceptedAt;
  24. bool? selected;
  25. Friend({
  26. required this.id,
  27. required this.userId,
  28. required this.username,
  29. required this.friendId,
  30. required this.friendSymmetricKey,
  31. required this.publicKey,
  32. required this.acceptedAt,
  33. this.selected,
  34. });
  35. factory Friend.fromJson(Map<String, dynamic> json, RSAPrivateKey privKey) {
  36. Uint8List idDecrypted = CryptoUtils.rsaDecrypt(
  37. base64.decode(json['friend_id']),
  38. privKey,
  39. );
  40. Uint8List username = CryptoUtils.rsaDecrypt(
  41. base64.decode(json['friend_username']),
  42. privKey,
  43. );
  44. Uint8List symmetricKeyDecrypted = CryptoUtils.rsaDecrypt(
  45. base64.decode(json['symmetric_key']),
  46. privKey,
  47. );
  48. String publicKeyString = AesHelper.aesDecrypt(
  49. symmetricKeyDecrypted,
  50. base64.decode(json['asymmetric_public_key'])
  51. );
  52. RSAPublicKey publicKey = CryptoUtils.rsaPublicKeyFromPem(publicKeyString);
  53. return Friend(
  54. id: json['id'],
  55. userId: json['user_id'],
  56. username: String.fromCharCodes(username),
  57. friendId: String.fromCharCodes(idDecrypted),
  58. friendSymmetricKey: base64.encode(symmetricKeyDecrypted),
  59. publicKey: publicKey,
  60. acceptedAt: json['accepted_at']['Valid'] ?
  61. DateTime.parse(json['accepted_at']['Time']) :
  62. null,
  63. );
  64. }
  65. Map<String, dynamic> payloadJson() {
  66. Uint8List friendIdEncrypted = CryptoUtils.rsaEncrypt(
  67. Uint8List.fromList(friendId.codeUnits),
  68. publicKey,
  69. );
  70. Uint8List usernameEncrypted = CryptoUtils.rsaEncrypt(
  71. Uint8List.fromList(username.codeUnits),
  72. publicKey,
  73. );
  74. Uint8List symmetricKeyEncrypted = CryptoUtils.rsaEncrypt(
  75. Uint8List.fromList(
  76. base64.decode(friendSymmetricKey),
  77. ),
  78. publicKey,
  79. );
  80. var publicKeyEncrypted = AesHelper.aesEncrypt(
  81. base64.decode(friendSymmetricKey),
  82. Uint8List.fromList(CryptoUtils.encodeRSAPublicKeyToPem(publicKey).codeUnits),
  83. );
  84. return {
  85. 'id': id,
  86. 'user_id': userId,
  87. 'friend_id': base64.encode(friendIdEncrypted),
  88. 'friend_username': base64.encode(usernameEncrypted),
  89. 'symmetric_key': base64.encode(symmetricKeyEncrypted),
  90. 'asymmetric_public_key': publicKeyEncrypted,
  91. 'accepted_at': null,
  92. };
  93. }
  94. String publicKeyPem() {
  95. return CryptoUtils.encodeRSAPublicKeyToPem(publicKey);
  96. }
  97. Map<String, dynamic> toMap() {
  98. return {
  99. 'id': id,
  100. 'user_id': userId,
  101. 'username': username,
  102. 'friend_id': friendId,
  103. 'symmetric_key': base64.encode(friendSymmetricKey.codeUnits),
  104. 'asymmetric_public_key': publicKeyPem(),
  105. 'accepted_at': acceptedAt?.toIso8601String(),
  106. };
  107. }
  108. @override
  109. String toString() {
  110. return '''
  111. id: $id
  112. userId: $userId
  113. username: $username
  114. friendId: $friendId
  115. accepted_at: $acceptedAt''';
  116. }
  117. }