One of Laravel's security features is Encryption. This feature creates a convenient interface for encrypting and decrypting via OpenSSL.
The documentation on the topic Encrypting A Value, explained that developers can use encryptString
function from Crypt
module likes:
1<?php
2
3namespace App\Http\Controllers;
4
5use App\Http\Controllers\Controller;
6use App\Models\User;
7use Illuminate\Http\Request;
8use Illuminate\Support\Facades\Crypt;
9
10class DigitalOceanTokenController extends Controller
11{
12 /**
13 * Store a DigitalOcean API token for the user.
14 *
15 * @param \Illuminate\Http\Request $request
16 * @return \Illuminate\Http\Response
17 */
18 public function storeSecret(Request $request)
19 {
20 $request->user()->fill([
21 'token' => Crypt::encryptString($request->token),
22 ])->save();
23 }
All the ciphertext results are encrypted with AES-256-CBC chiper. And on some occasional event, there is a requirement to decrypt the value from non-technical people who do not code.
So, I try to create laravel_decrypt. A tool written in Rust and using egui for the user interface.
egui #
Egui is an easy-to-use immediate mode GUI which can be compiled and targetted into multiple platforms (Mac, Windows, Linux, and Web), example:
1...
2impl eframe::App for MyApp {
3 fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
4 egui::CentralPanel::default().show(ctx, |ui| {
5 ui.heading("My egui Application");
6 ui.horizontal(|ui| {
7 ui.label("Your name: ");
8 ui.text_edit_singleline(&mut self.name);
9 });
10 ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
11 if ui.button("Click each year").clicked() {
12 self.age += 1;
13 }
14 ui.label(format!("Hello '{}', age {}", self.name, self.age));
15 });
16 }
17}
18...
19
Decryption #
For doing encryption aes, base64, block-modes and serde_json creates are used.
Chipertext wrapped in base64 encoding, after decoding it will output JSON object with three keys: iv
, value
, and mac
.
1pub fn parse_ciphertext(ciphertext: &str) -> Result<LaravelEncryptedData, String> {
2 let payload = match base64::decode(ciphertext) {
3 Ok(v) => v,
4 Err(_) => return Err("failed to decode base64".to_owned()),
5 };
6 match serde_json::from_slice(&payload) {
7 Ok(v) => Ok(v),
8 Err(e) => Err(e.to_string()),
9 }
10}
To convert it to plain text without authentication, we need key
, ciphertext
, and iv
.
1pub fn decrypt(key: Vec<u8>, ciphertext: Vec<u8>, iv: Vec<u8>) -> Result<String, String> {
2 let cipher = match Aes256Cbc::new_from_slices(&key, &iv) {
3 Ok(v) => v,
4 Err(e) => return Err(e.to_string()),
5 };
6 let data = match cipher.decrypt_vec(&ciphertext) {
7 Ok(v) => v,
8 Err(e) => return Err(e.to_string()),
9 };
10 Ok(String::from_utf8_lossy(&data).to_string())
11}
For full source-code, you can visit https://github.com/sakti/laravel_decrypt.