Skip to content

Commit

Permalink
Keys and encryption (PalisadoesFoundation#2027)
Browse files Browse the repository at this point in the history
* add crypto package and password encryption

* add doc for Encryptor class

* merge with develop

* add key generation

* write docs and suppress some warnings

* fix formatting of lib/views/pre_auth_screens/login.dart
  • Loading branch information
literalEval authored and palisadian committed Jan 10, 2024
1 parent e77331b commit 821d587
Show file tree
Hide file tree
Showing 20 changed files with 204 additions and 53 deletions.
1 change: 1 addition & 0 deletions lib/apptheme.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
// import 'package:flutter_screenutil/flutter_screenutil.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/router.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_good_doc_comments
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:talawa/constants/routing_constants.dart';
Expand Down
125 changes: 125 additions & 0 deletions lib/utils/encryptor.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import 'dart:convert';
import 'dart:typed_data';

import 'package:crypto/crypto.dart';
import 'package:hive/hive.dart';
import 'package:pointycastle/asymmetric/oaep.dart';
import 'package:pointycastle/asymmetric/rsa.dart';
import 'package:pointycastle/pointycastle.dart';
import 'package:pointycastle/random/fortuna_random.dart';

/// Handles all of the encryption tasks in the codebase.
class Encryptor {
Expand All @@ -22,4 +29,122 @@ class Encryptor {
if (!shouldEncrypt) return data;
return sha256.convert(utf8.encode(data)).toString();
}

/// Generates RSA Key Pairs (Public/Private).
///
/// Should be called only during app's first initialization,
/// and any future usage should be done by getting the keys
/// from the local storage.
///
/// **params**:
/// None
///
/// **returns**:
/// * `AsymmetricKeyPair<PublicKey, PrivateKey>`: The generated
/// public and private keys.
AsymmetricKeyPair<PublicKey, PrivateKey> generateRSAKeyPair() {
final keyGen = RSAKeyGeneratorParameters(BigInt.parse('65537'), 2048, 64);
final secureRandom = FortunaRandom();
final random = SecureRandom('Fortuna')
..seed(secureRandom as CipherParameters);
final keyGenParams = ParametersWithRandom(keyGen, random);

final keyGenerator = KeyGenerator('RSA');
keyGenerator.init(keyGenParams);

return keyGenerator.generateKeyPair();
}

/// Saves the generated key pair to local storage.
///
/// Any future usage of the keys must be initiated from here.
///
/// **params**:
/// * `keyPair`: [AsymmetricKeyPair] to save.
///
/// **returns**:
/// * `Future<void>`: None
Future<void> saveKeyPair(
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair,
) async {
// TODO: Implement secure storage here

await Hive.openBox<AsymmetricKeyPair<PublicKey, PrivateKey>>('user_keys');
final keysBox = await Hive.openBox('user_keys');

keysBox.put('key_pair', keyPair);
}

/// Loads secret keys from the Hive db.
///
/// **params**:
/// None
///
/// **returns**:
/// * `Future<AsymmetricKeyPair<PublicKey, PrivateKey>>`: The public and
/// private key pair
Future<AsymmetricKeyPair<PublicKey, PrivateKey>> loadKeyPair() async {
await Hive.openBox<AsymmetricKeyPair<PublicKey, PrivateKey>>('user_keys');
final keysBox = await Hive.openBox('user_keys');

return (await keysBox.get('key_pair'))
as AsymmetricKeyPair<PublicKey, PrivateKey>;
}

/// Encrypts the given string data with Recipient's Public Key.
///
/// **params**:
/// * `data`: The string to encrypt
/// * `recipientPublicKey`: Key to be used to encrypt. Recipient's public
/// key in our case.
///
/// **returns**:
/// * `String`: Encrypted string
String assymetricEncryptString(String data, RSAPublicKey recipientPublicKey) {
final cipher = OAEPEncoding(RSAEngine())
..init(true, PublicKeyParameter<RSAPublicKey>(recipientPublicKey));

final encryptedBytes = cipher.process(Uint8List.fromList(data.codeUnits));
return base64Encode(encryptedBytes);
}

/// Encrypts the given string data with user's Private Key.
///
/// **params**:
/// * `data`: The string to decrypt
/// * `privateKey`: Key to be used to decrypt. User's private key in our case.
///
/// **returns**:
/// * `String`: Decrypted string
String assymetricDecryptString(String data, RSAPrivateKey privateKey) {
final cipher = OAEPEncoding(RSAEngine())
..init(false, PrivateKeyParameter<RSAPrivateKey>(privateKey));

final decryptedBytes = cipher.process(base64Decode(data));
return String.fromCharCodes(decryptedBytes);
}

/// Helper function to decrypt the message.
///
/// Internally uses the [loadKeyPair] function to get private key and
/// [assymetricDecryptString] to decrypt the given message.
///
/// **params**:
/// * `message`: Message object containing a field named [encryptedMessage]
/// which is supposed to contained user's message in encrypted format.
///
/// **returns**:
/// * `Future<void>`: None
/// TODO: Use this somewhere
Future<void> receiveMessage(Map<String, dynamic> message) async {
final privateKey = (await loadKeyPair()).privateKey;

final encryptedMessage = message['encryptedMessage'] as String;
final decryptedMessage = assymetricDecryptString(
encryptedMessage,
privateKey as RSAPrivateKey,
);

print('Decrypted Message: $decryptedMessage');
}
}
1 change: 1 addition & 0 deletions lib/view_model/access_request_view_model.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc
import 'package:flutter/cupertino.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:talawa/constants/routing_constants.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_good_doc_comments, talawa_api_doc
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/views/after_auth_screens/feed/organization_feed.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc
import 'package:flutter/material.dart';
import 'package:talawa/view_model/after_auth_view_models/feed_view_models/organization_feed_view_model.dart';
import 'package:talawa/view_model/main_screen_view_model.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_good_doc_comments, talawa_api_doc
import 'package:flutter/material.dart';
import 'package:talawa/apptheme.dart';
import 'package:talawa/models/organization/org_info.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc, talawa_good_doc_comments
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:talawa/enums/enums.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/views/after_auth_screens/profile/profile_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc
import 'package:contained_tab_bar_view/contained_tab_bar_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_braintree/flutter_braintree.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/views/pre_auth_screens/login.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:talawa/widgets/raised_round_edge_button.dart';
import 'package:talawa/widgets/rich_text.dart';

/// This is the login widget.
///
/// There are two input fiels. The first one takes in the email and
/// the second one takes in the password of the user.
/// There is also a "Forgot Password" text button, which directs to
Expand Down
1 change: 1 addition & 0 deletions lib/widgets/custom_avatar.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_good_doc_comments, talawa_api_doc
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/widgets/custom_list_tile.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_good_doc_comments, talawa_api_doc
import 'package:flutter/material.dart';
import 'package:talawa/enums/enums.dart';
import 'package:talawa/models/options/options.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/widgets/post_container.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc
import 'package:flutter/material.dart';
import 'package:visibility_detector/visibility_detector.dart';

Expand Down
1 change: 1 addition & 0 deletions lib/widgets/post_detailed_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_good_doc_comments, talawa_api_doc
import 'package:flutter/material.dart';
import 'package:talawa/utils/app_localization.dart';

Expand Down
1 change: 1 addition & 0 deletions lib/widgets/post_list_widget.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc
import 'package:flutter/material.dart';
import 'package:talawa/models/post/post_model.dart';
import 'package:talawa/widgets/post_widget.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/widgets/post_widget.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: talawa_api_doc
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:talawa/models/post/post_model.dart';
Expand Down
34 changes: 21 additions & 13 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "405666cd3cf0ee0a48d21ec67e65406aad2c726d9fa58840d3375e7bdcd32a07"
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
url: "https://pub.dev"
source: hosted
version: "60.0.0"
version: "61.0.0"
_flutterfire_internals:
dependency: transitive
description:
Expand All @@ -21,10 +21,10 @@ packages:
dependency: transitive
description:
name: analyzer
sha256: "1952250bd005bacb895a01bf1b4dc00e3ba1c526cf47dca54dfe24979c65f5b3"
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
url: "https://pub.dev"
source: hosted
version: "5.12.0"
version: "5.13.0"
analyzer_plugin:
dependency: transitive
description:
Expand Down Expand Up @@ -266,7 +266,7 @@ packages:
source: hosted
version: "0.3.3+4"
crypto:
dependency: transitive
dependency: "direct main"
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
Expand Down Expand Up @@ -301,26 +301,26 @@ packages:
dependency: "direct dev"
description:
name: custom_lint
sha256: "3ce36c04d30c60cde295588c6185b3f9800e6c18f6670a7ffdb3d5eab39bb942"
sha256: "837821e4619c167fd5a547b03bb2fc6be7e65b800ec75528848429705c31ceba"
url: "https://pub.dev"
source: hosted
version: "0.4.0"
version: "0.5.3"
custom_lint_builder:
dependency: transitive
description:
name: custom_lint_builder
sha256: "73d09c9848e9f6d5c3e0a1809eac841a8d7ea123d0849feefa040e1ad60b6d06"
sha256: "3537d50202568994a6f42b1f2953aed6292fc5ecf83e45237af73f64aff2be72"
url: "https://pub.dev"
source: hosted
version: "0.4.0"
version: "0.5.3"
custom_lint_core:
dependency: transitive
description:
name: custom_lint_core
sha256: "9170d9db2daf774aa2251a3bc98e4ba903c7702ab07aa438bc83bd3c9a0de57f"
sha256: "3bdebdd52a42b4d6e5be9cd833ad1ecfbbc23e1020ca537060e54085497aea9c"
url: "https://pub.dev"
source: hosted
version: "0.4.0"
version: "0.5.3"
dart_style:
dependency: transitive
description:
Expand Down Expand Up @@ -1261,6 +1261,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.6"
pointycastle:
dependency: "direct main"
description:
name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.7.3"
pool:
dependency: transitive
description:
Expand Down Expand Up @@ -1813,10 +1821,10 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.0"
web:
dependency: transitive
description:
Expand Down
4 changes: 3 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies:
connectivity_plus: ^4.0.2
contained_tab_bar_view: ^0.8.0

crypto: ^3.0.3
cupertino_icons: ^1.0.3
currency_picker: ^2.0.16

Expand Down Expand Up @@ -58,14 +59,15 @@ dependencies:
http: ^1.1.0
image_cropper: ^5.0.0

intl: ^0.18.0
image_picker: ^1.0.4
intl: ^0.18.0
json_annotation: ^4.7.0
mockito: ^5.4.2
network_image_mock: ^2.1.1
path_provider: ^2.1.1
permission_handler: ^11.0.0
plugin_platform_interface: ^2.1.6
pointycastle: ^3.7.3
provider: ^6.0.3
qr_code_scanner: ^1.0.0
qr_flutter: 4.0.0
Expand Down
Loading

0 comments on commit 821d587

Please sign in to comment.