From 1b63c0f35dfed317aefdda21c0dd719f5545bd12 Mon Sep 17 00:00:00 2001 From: cooper235 Date: Wed, 12 Feb 2025 12:48:53 +0530 Subject: [PATCH 1/2] Added secure password storage using flutter_secure_storage --- lib/secure_storage.dart | 89 +++++++++++++++++++++++++++++++++++++++++ pubspec.lock | 72 ++++++++++++++++----------------- pubspec.yaml | 6 +-- 3 files changed, 128 insertions(+), 39 deletions(-) create mode 100644 lib/secure_storage.dart diff --git a/lib/secure_storage.dart b/lib/secure_storage.dart new file mode 100644 index 0000000..e14eb6c --- /dev/null +++ b/lib/secure_storage.dart @@ -0,0 +1,89 @@ +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class SecureStorage { + final _storage = const FlutterSecureStorage(); + + // Store password + Future storePassword(String key, String password) async { + await _storage.write(key: key, value: password); + } + + // Retrieve password + Future getPassword(String key) async { + return await _storage.read(key: key); + } + + // Delete password + Future deletePassword(String key) async { + await _storage.delete(key: key); + } +} +import 'package:flutter/material.dart'; +import 'services/secure_storage.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: PasswordScreen(), + ); + } +} + +class PasswordScreen extends StatefulWidget { + const PasswordScreen({super.key}); + + @override + State createState() => _PasswordScreenState(); +} + +class _PasswordScreenState extends State { + final SecureStorage _secureStorage = SecureStorage(); + final TextEditingController _passwordController = TextEditingController(); + String? _retrievedPassword; + + Future _savePassword() async { + await _secureStorage.storePassword('user_password', _passwordController.text); + setState(() { + _retrievedPassword = "Password saved!"; + }); + } + + Future _loadPassword() async { + final password = await _secureStorage.getPassword('user_password'); + setState(() { + _retrievedPassword = password ?? "No password found"; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text("Secure Password Storage")), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + TextField( + controller: _passwordController, + decoration: const InputDecoration(labelText: "Enter Password"), + obscureText: true, + ), + const SizedBox(height: 10), + ElevatedButton(onPressed: _savePassword, child: const Text("Save Password")), + ElevatedButton(onPressed: _loadPassword, child: const Text("Retrieve Password")), + const SizedBox(height: 10), + Text(_retrievedPassword ?? ""), + ], + ), + ), + ); + } +} + diff --git a/pubspec.lock b/pubspec.lock index 5c3b229..d8d1b8e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -122,26 +122,26 @@ packages: dependency: transitive description: name: build_daemon - sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948" + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "4.0.4" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e" + sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.4" build_runner: dependency: transitive description: name: build_runner - sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" + sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" url: "https://pub.dev" source: hosted - version: "2.4.14" + version: "2.4.15" build_runner_core: dependency: transitive description: @@ -314,10 +314,10 @@ packages: dependency: transitive description: name: device_info_plus - sha256: e3fc9a65820fef83035af8ee8c09004a719d5d1d54e6de978fcb0d84bbeb241a + sha256: "72d146c6d7098689ff5c5f66bcf593ac11efc530095385356e131070333e64da" url: "https://pub.dev" source: hosted - version: "11.2.2" + version: "11.3.0" device_info_plus_platform_interface: dependency: transitive description: @@ -447,18 +447,18 @@ packages: dependency: "direct main" description: name: flutter_launcher_icons - sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c url: "https://pub.dev" source: hosted - version: "0.13.1" + version: "0.14.3" flutter_lints: dependency: "direct main" description: name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" flutter_native_splash: dependency: "direct main" description: @@ -537,10 +537,10 @@ packages: dependency: "direct main" description: name: fluttertoast - sha256: "8971efe7e59585e9149052e33718d84bca51e806f063d1467622b3dcb2878b6c" + sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" url: "https://pub.dev" source: hosted - version: "8.2.11" + version: "8.2.12" frontend_server_client: dependency: transitive description: @@ -569,10 +569,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: b465e99ce64ba75e61c8c0ce3d87b66d8ac07f0b35d0a7e0263fcfc10f99e836 + sha256: "04539267a740931c6d4479a10d466717ca5901c6fdfd3fcda09391bbb8ebd651" url: "https://pub.dev" source: hosted - version: "13.2.5" + version: "14.8.0" graphs: dependency: transitive description: @@ -753,10 +753,10 @@ packages: dependency: transitive description: name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.1.1" logging: dependency: transitive description: @@ -1097,10 +1097,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.0" simple_animations: dependency: "direct main" description: @@ -1222,66 +1222,66 @@ packages: dependency: "direct main" description: name: syncfusion_flutter_core - sha256: "3c1876b0a245de23de3b17a19e3106fed57d88f4fd2c8dc9bc1976705b1c31d5" + sha256: dafeebdf8673d6dd874191bf579bc17c76b4b84e09fc0e4ae5bc7e56c0c91f4b url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" syncfusion_flutter_pdf: dependency: transitive description: name: syncfusion_flutter_pdf - sha256: f89aea01d60ed11801aad5067705070b01250a909369e0d2dc5d4bd0292a9b46 + sha256: "50d8144ddc7b58b3450b4410bc8f7c456dc89d494c2270a3e294fb7ac9d7fb58" url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" syncfusion_flutter_pdfviewer: dependency: "direct main" description: name: syncfusion_flutter_pdfviewer - sha256: "792f70be12f633982a2a0fc0dba725250c425e4ac630c48fa13591e68c3b6cd5" + sha256: "171024482a426a80598fe8d46991c7a8b88dd52570057619717262e4b8439c1c" url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" syncfusion_flutter_signaturepad: dependency: transitive description: name: syncfusion_flutter_signaturepad - sha256: "447143026fa013f822abb61dc6b1c7942940043885ccb39c20bbb35a80c639fc" + sha256: "193e83e1c28207f2af20b1722e127997b135da00fffffd1bef3e8e65a25ed47e" url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" syncfusion_pdfviewer_macos: dependency: transitive description: name: syncfusion_pdfviewer_macos - sha256: bfa1371edf9ef1b0191ec8799e0d87f04149d1d1c81722a563a911c0c5c05567 + sha256: "0ade61a351b3013b992d352b408e9555bc7a54a6ded8a5117215f1376041eedc" url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" syncfusion_pdfviewer_platform_interface: dependency: transitive description: name: syncfusion_pdfviewer_platform_interface - sha256: "827b0e9d780d16c89de113f2d741de86b156f77e572966a95975a5990b89e2df" + sha256: de14eb1221036394da09885ffe6cd3cafaaeabecfe29c692735cd881cbd3c43a url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" syncfusion_pdfviewer_web: dependency: transitive description: name: syncfusion_pdfviewer_web - sha256: "310da263e447be7f4e091927b92976a9ccf2be1cb67b8d1467f426a5e68f77c3" + sha256: db54fb6da8b9a6f2c6df716ed490665396c7ce81a1e145458f409356c6b401be url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" syncfusion_pdfviewer_windows: dependency: transitive description: name: syncfusion_pdfviewer_windows - sha256: bca461aeac6e0d30980907970e15ce960aa558877196a2cdced890133eefa611 + sha256: "4ebd2ff8f250737f97fa60f2033f2b03368662c7d9f3dbe561b3c0c1df86cc3d" url: "https://pub.dev" source: hosted - version: "28.2.4" + version: "28.2.5" synchronized: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b54994a..e6316d4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,11 +35,11 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 - flutter_lints: ^4.0.0 - go_router: ^13.1.0 + flutter_lints: ^5.0.0 + go_router: ^14.8.0 flutter_native_splash: ^2.4.0 intl: ^0.19.0 - flutter_launcher_icons: ^0.13.1 + flutter_launcher_icons: ^0.14.3 simple_animations: ^5.1.0 carousel_slider: ^5.0.0 smooth_page_indicator: ^1.1.0 From ffd869b20ef04aaa4ccb867e07f8a1affa229e7d Mon Sep 17 00:00:00 2001 From: cooper235 Date: Thu, 13 Feb 2025 10:19:21 +0530 Subject: [PATCH 2/2] Added Flutter app for secure password storage --- .../gradle/wrapper/gradle-wrapper.properties | 2 +- lib/main.dart | 75 ++++++++++++++++ lib/secure_storage.dart | 89 ++++--------------- pubspec.yaml | 6 +- 4 files changed, 96 insertions(+), 76 deletions(-) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 8bc9958..7bb2df6 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip diff --git a/lib/main.dart b/lib/main.dart index be8ce3a..690aaca 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -105,3 +105,78 @@ class UhlLink extends StatelessWidget { ); } } +import 'package:flutter/material.dart'; +import 'secure_storage.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Secure Password Store', + theme: ThemeData(primarySwatch: Colors.blue), + home: PasswordScreen(), + ); + } +} + +class PasswordScreen extends StatefulWidget { + @override + _PasswordScreenState createState() => _PasswordScreenState(); +} + +class _PasswordScreenState extends State { + final TextEditingController _controller = TextEditingController(); + final SecureStorage _secureStorage = SecureStorage(); + String _retrievedPassword = "No password stored"; + + void _savePassword() async { + await _secureStorage.savePassword(_controller.text); + _controller.clear(); + setState(() { + _retrievedPassword = "Password Saved!"; + }); + } + + void _getPassword() async { + String? password = await _secureStorage.getPassword(); + setState(() { + _retrievedPassword = password ?? "No password found"; + }); + } + + void _deletePassword() async { + await _secureStorage.deletePassword(); + setState(() { + _retrievedPassword = "Password deleted!"; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text("Secure Password Store")), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + TextField( + controller: _controller, + decoration: InputDecoration(labelText: "Enter Password"), + obscureText: true, + ), + SizedBox(height: 20), + ElevatedButton(onPressed: _savePassword, child: Text("Save Password")), + ElevatedButton(onPressed: _getPassword, child: Text("Retrieve Password")), + ElevatedButton(onPressed: _deletePassword, child: Text("Delete Password")), + SizedBox(height: 20), + Text(_retrievedPassword, style: TextStyle(fontSize: 18)), + ], + ), + ), + ); + } +} diff --git a/lib/secure_storage.dart b/lib/secure_storage.dart index e14eb6c..65ca645 100644 --- a/lib/secure_storage.dart +++ b/lib/secure_storage.dart @@ -1,89 +1,30 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:crypt/crypt.dart'; class SecureStorage { - final _storage = const FlutterSecureStorage(); + final FlutterSecureStorage _storage = const FlutterSecureStorage(); - // Store password - Future storePassword(String key, String password) async { - await _storage.write(key: key, value: password); + // Hash password before saving + String hashPassword(String password) { + return Crypt.sha256(password, salt: 'random_salt').toString(); } - // Retrieve password - Future getPassword(String key) async { - return await _storage.read(key: key); + // Save password securely + Future savePassword(String password) async { + String hashedPassword = hashPassword(password); + await _storage.write(key: 'password', value: hashedPassword); } - // Delete password - Future deletePassword(String key) async { - await _storage.delete(key: key); + // Retrieve password + Future getPassword() async { + return await _storage.read(key: 'password'); } -} -import 'package:flutter/material.dart'; -import 'services/secure_storage.dart'; -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: PasswordScreen(), - ); + // Delete password + Future deletePassword() async { + await _storage.delete(key: 'password'); } } -class PasswordScreen extends StatefulWidget { - const PasswordScreen({super.key}); - @override - State createState() => _PasswordScreenState(); -} - -class _PasswordScreenState extends State { - final SecureStorage _secureStorage = SecureStorage(); - final TextEditingController _passwordController = TextEditingController(); - String? _retrievedPassword; - - Future _savePassword() async { - await _secureStorage.storePassword('user_password', _passwordController.text); - setState(() { - _retrievedPassword = "Password saved!"; - }); - } - - Future _loadPassword() async { - final password = await _secureStorage.getPassword('user_password'); - setState(() { - _retrievedPassword = password ?? "No password found"; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text("Secure Password Storage")), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - TextField( - controller: _passwordController, - decoration: const InputDecoration(labelText: "Enter Password"), - obscureText: true, - ), - const SizedBox(height: 10), - ElevatedButton(onPressed: _savePassword, child: const Text("Save Password")), - ElevatedButton(onPressed: _loadPassword, child: const Text("Retrieve Password")), - const SizedBox(height: 10), - Text(_retrievedPassword ?? ""), - ], - ), - ), - ); - } -} diff --git a/pubspec.yaml b/pubspec.yaml index e6316d4..cde1b71 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,10 @@ environment: dependencies: flutter: sdk: flutter + flutter_secure_storage: ^9.0.0 # Secure encrypted storage + crypt: ^4.0.1 # Hashing passwords + local_auth: ^2.1.6 # Optional: Biometric authentication + # The following adds the Cupertino Icons font to your application. @@ -90,7 +94,7 @@ flutter: assets: - assets/images/ - assets/pdf/ - - institute.env + - assets/institute.env - assets/cafeteria.json # - images/a_dot_ham.jpeg