| NAME | NRP |
|---|---|
| Muhammad Fadhlan Ashila Harashta | 5025211168 |
| Pascal Roger Junior Tauran | 5025211072 |
| Faraihan Rafi Adityawarman | 5025211074 |
| Fauzan Ahmad Faisal | 5025211067 |
- We created a simple website that allows the user to register, login and then store their data. All these files are then encrypted before being stored.
- Before running program, please edit the env file and add
AES_KEY_KEY=9328e2bce387ed16a42f46c780fe1f64- Or you can use any key you want
-
The user is able to register themselves into the into the website providing information such as their
name,username,email,passwordasID card image. These data will be encrypted and then stored in a database. -
Once the user has registered, the website will redirect the user to the login screen where the user can enter their
emailandpasswordto log in.
-
The users data are encrypted using
AES-128-ECBthis is done usingopenssl_encrypt. -
The users ID image is also encrypted and stored in the database. This done by first converting the image to a base64 longtext using a
imageToBase64function:
public function imageToBase64($imagePath) {
try {
$imageData = file_get_contents($imagePath);
if ($imageData === false) {
throw new Exception("Failed to read the image file.");
}
$base64Encoded = base64_encode($imageData);
return $base64Encoded;
} catch (Exception $e) {
echo "An error occurred: " . $e->getMessage();
return null;
}
}- Once this is done, the
image longtextis encrypted usingAES-128-ECB,RC4, andDES. Then the one encrypted withAES-128-ECBstored in the database.
// AES Encryption for ID card
$IDAESstart = microtime(true);
$imageBase64 = openssl_encrypt($imageBase64, $cipher, $secret);
$IDAESend = microtime(true);
$IDAEStime_taken = ($IDAESend - $IDAESstart) * 1000;
echo "Time taken to encrypt ID with AES-128-ECB: " . $IDAEStime_taken . " ms";
// RC4 Encryption for ID card
$IDRC4start = microtime(true);
$imageBase64rc4 = openssl_encrypt($imageBase64, $rc4, $rc4key);
$IDRC4end = microtime(true);
$IDRC4time_taken = ($IDRC4end - $IDRC4start) * 1000;
echo "Time taken to encrypt ID with RC4: " . $IDRC4time_taken . " ms";;
// DES Encryption for ID Card
$IDDESstart = microtime(true);
$imageBase64des = openssl_encrypt($imageBase64, $des, $deskey);
$IDDESend = microtime(true);
$IDDEStime_taken = ($IDDESend - $IDDESstart) * 1000;
echo "Time taken to encrypt ID with DES-ECB: " . $IDDEStime_taken . " ms";IDAESstartrepresents the start time before the file is encrpyted andIDEASendrepresents the end time after the file is encrypted withAES-128-ECB.$IDAEStime_takenis calculated by subtractingIDAESstartfromIDAESend. It is thenmultiplied by 1000to obtain the time inms.
- As we can see, here is the comparison between the performance of the three encryption algorithms. As we can see
DESwas the fastest withRC4being second fastest andAESbeing the slowest among the three. We still chose to use AES in this case as it is the most secure among the three.
- In our encryption, it turns out that
RC4has the slowest encryption time. This occurs because PHP doesn't directly support this encryption algorithm. Because of this, we have to manually make this encryption type ourself. This is whyRC4has the slowest time in our website with average encryption time of0.209 ms, it was followed byAESwith an average encryption time of43.089 msand thenDESwith an average encryption time of0.1411 ms
- We also have measured the size of the encrypted images, in this case, the image encrypted with
RC4has the largest size with an average size of376056 bytesfollowed byAESwith an an average size250717.3333 bytesand then there isDESwith an average size of188043 bytes
- After the user logs-in, they are able to view their data by going to the
profilemenu. - Once they click it, the website will redirect them to their profile where it will pull their data from the database and decrypt it using
openssl_decryptwith the samecipherandkeyas it was encrypted. TheirID cardimage remains in base64 after the decryption as html supports displaying base64 images.
DES-ECB Encryption:
$secret = hex2bin("1B6D4B4A5254AC");;
$iv = openssl_random_pseudo_bytes(8); // Generate a random IV
$paddedName = str_pad($request->name, 8, "\0"); // Pad the name to 8 bytes if needed
$encryptedName = openssl_encrypt($paddedName, 'des-ecb', $secret, OPENSSL_RAW_DATA, $iv);
// Store the encrypted name in the database
$encryptedName = base64_encode($iv . $encryptedName);
Animals::create([
'name' => $encryptedName, // Store the encrypted name
'center_id' => $request->center_id,
'breed' => $request->breed,
'age' => $request->age,
'desc' => $request->desc,
'image' => $imageBase64
]);- First decide on the secret key for encryption
- Here, a variable $iv is defined, and it's assigned a random 8-byte value generated using the openssl_random_pseudo_bytes function. This is the Initialization Vector (IV) used for encryption
- paddedName = str_pad($request->name, 8, "\0") This line creates a variable $paddedName. It takes the name field from the $request object, and if the length of the name is less than 8 characters, it pads it with null bytes ("\0") to make it exactly 8 bytes long
- encryptedName = openssl_encrypt($paddedName, 'des-ecb', $secret, OPENSSL_RAW_DATA, $iv); This is to create variable to for the encrypted name and put the value in
- Store the encrypted name in the database
- Lastly, we put it on the table
- The user is able to upload and download the files that they have uploaded
public function download($id) {
$file = Files::find($id);
if (!$file) {
abort(404); // File not found
}
// Check if the file is a duplicate
if ($file->isDuplicate) {
// Return a view with a form to ask for the private key
return view('files.request_key', ['file' => $file]);
}
// Fetch the encrypted file content and decrypt it
$cipher = "AES-256-CBC";
$aeskey = $file->secret;
$options = 0;
$iv = $file->iv;
$decrypted_AESBase64 = openssl_decrypt($file->file_base64, $cipher, $aeskey, $options, $iv);
$fileContent = base64_decode($decrypted_AESBase64);
// Set headers for file download
$headers = [
'Content-Type' => 'application/octet-stream',
'Content-Disposition' => 'attachment; filename=' . $file->filename,
];
// Return the download response
return response()->make($fileContent, 200, $headers);
}- The user is able to view other users who are registerd to the website
- Below their profiles theres a
Request Filesbutton. Clicking on it will make a request towards therequested_userfor their files. And return a response that request has been created.
- This creates a new table
file_requestswith the parametersrequester_id,requested_idandhas_accesswhich has a default value offalse.
public function store(Request $request, User $requested)
{
$user = Auth::user();
$existingRequest = FileRequest::where('requested_id', $request->input('requested_id'))
->where('requester_id', $user->id)
->first();
if (!$existingRequest) {
$filerequest = FileRequest::create([
'requested_id' => $request->input('requested_id'),
'requester_id' => $user->id,
'has_access' => false,
]);
return redirect('/users')->with('success', 'Successfully requested files!');
} else {
return redirect('/users')->with('error', 'File request already exists!');
}
}- The user has an inbox page where the requests that they received are stored
- The requested user can click on the
Accept Requestbutton and thefile_requeststable will be updated changing thehas_accessvalue fromfalsetotrue.
- The
requested_user's files will then be duplicated and modified so that theirfileOwneris now therequester_user. During the duplication the files, the file will first be decrypted and then a newkeywill be generated to encrypt the duplicatedfiles. Once this happens the encrypted files will then be stored and the newly generatedkeywill be encrypted again by amaster keythat is stored in theenv. The newly duplicated files will also have theirisDuplicatevalue changed from false totrue, This prevents shared files to be reshared again to other users. - The
requester_userwill be notified that therequested_userhas given them access to the files via the inbox and the encrypted keyprivate_keywill also be sent to the inbox of therequester_userwhich will be used when downloading thesharedfiles.
public function update(Request $request, FileRequest $fileRequest)
{
$fileRequest->has_access = true;
$fileRequest->save();
// Fetch all files owned by the requested_id
$files = Files::where('fileOwner', $fileRequest->requested_id)->get();
// Define the cipher
$cipher = "AES-256-CBC";
$options = 0;
// Generating a new secret
$newAESkey = bin2hex(openssl_random_pseudo_bytes(16));
// $AESkeykey = bin2hex(openssl_random_pseudo_bytes(16));
$AESkeykey = env('AES_KEY_KEY');
// Duplicate each file and change the fileOwner to the requester_id
foreach ($files as $file) {
//Checks if file is a duplicate and does not duplicate if isDuplicate value is true
if(!$file->isDuplicate){
$newFile = $file->replicate();
$newFile->fileOwner = $fileRequest->requester_id;
$newFile->isDuplicate = true;
// Fetch the iv from the file
$iv = $file->iv;
// Decrypting the FileBase64
$decryptedFileBase64 = openssl_decrypt($file->file_base64, $cipher, $file->secret, $options, $iv);
// Re-encrypting the file with the new secret
$encryptedFileBase64 = openssl_encrypt($decryptedFileBase64, $cipher, $newAESkey, $options, $iv);
$encrypedAESkey = openssl_encrypt($newAESkey, $cipher, $AESkeykey, $options, $iv);
$AESkeyMessage = openssl_encrypt($encrypedAESkey, $cipher, $AESkeykey, $options, $iv);
// Storing the encrpyted file and the new secret
$newFile->file_base64 = $encryptedFileBase64;
// secret is holding the value of the encrypted encrypted key
$newFile->secret = $AESkeyMessage;
$newFile->save();
}
}
$requester = User::find($fileRequest->requester_id);
$notification = "User A has accepted your request.";
return redirect('/inbox')->with('success', 'You have accepted the file request.');
}- The
requester_useris able to download the files that have been shared to him by clicking thedownloadbutton - If the file is a
shared fileit will promt the user to enter theprivate keythat was generated when the file was shared. - After the
private keyis entered the key will be decrypted with themaster keystored in theenvand then theencrypted shared_filewill be decrypted by the decryptedprivate key. The file will then be downloaded.
public function decryptWithKey(Request $request, $id) {
$file = Files::find($id);
if (!$file) {
abort(404); // File not found
}
// Fetch the private key from the request
$privateKey = $request->input('private_key');
// Fetch the encrypted file content and decrypt it
$cipher = "AES-256-CBC";
$options = 0;
$iv = $file->iv;
$decryptedPrivateKey = openssl_decrypt($privateKey, $cipher, env('AES_KEY_KEY'), $options, $iv);
$decrypted_AESBase64 = openssl_decrypt($file->file_base64, $cipher, $decryptedPrivateKey, $options, $iv);
$fileContent = base64_decode($decrypted_AESBase64);
// Set headers for file download
$headers = [
'Content-Type' => 'application/octet-stream',
'Content-Disposition' => 'attachment; filename=' . $file->filename,
];
// Return the download response
return response()->make($fileContent, 200, $headers);
} // Generate two random prime numbers, p and q
$p = findRandomPrime(10000, 20000);
$q = findRandomPrime(10000, 20000);
// Calculate n (modulus)
$n = $p * $q;
// Calculate phi(n) (Euler's totient function)
$phiN = ($p - 1) * ($q - 1);
// Find a public exponent (e)
$e = findPublicExponent($phiN);
// Calculate private exponent (d) using the modular multiplicative inverse
$d = modInverse($e, $phiN);
// Convert keys to PEM format
$publicKeyPEM = "-----BEGIN CERTIFICATE REQUEST-----\n" .
wordwrap(base64_encode(pack('N', $e) . pack('N', $n)), 64, "\n", true) .
"\n-----END CERTIFICATE REQUEST-----\n";
$privateKeyPEM = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap(base64_encode(pack('N', $n) . pack('N', $e) . pack('N', $d)), 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----\n";
// Read the contents of the certificate, private key, and public key
$certificatePath = storage_path('app/certificates/Webhub.cer');
$certificateContent = file_get_contents($certificatePath);
// Combine the contents in the desired order
$combinedContent = $certificateContent . $privateKeyPEM . $publicKeyPEM;
// Path to the new combined certificate file in /storage/app/certificates
$newCertificatePath = storage_path("app/certificates/{$username}.crt");
// Save the combined content to the new certificate file
file_put_contents($newCertificatePath, $combinedContent);- When a new account is created, a key pair is generated.
- They key pair is in the
PEMformat. - The key pair is then combined with the
certificateand then a newcertificateis created named{$username}.crt. - It is then stored in
app/certtificates.
- In the
navbar, a new nav that leads to thesignaturepage is added. - Clicking this leads to a new page whre the user can upload a pdf and have it digitally signed.
- After the pdf is uploaded, the pdf file will be digitally signed and then the newly digitally signed pdf will be downloaded.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use PDF;
use TCPDF;
use setasign\Fpdi\Tcpdf\Fpdi;
class DigitalSignatureController extends Controller
{
public function downloadPdf(Request $request){
$cipher = "AES-256-CBC";
$options = 0;
$iv = str_repeat("0", openssl_cipher_iv_length($cipher));
$decryptedEmail = openssl_decrypt(Auth::user()->email, $cipher, Auth::user()->keyAES, $options, $iv);
$username = Auth::user()->username;
$certificate = 'file://'.base_path().'/storage/app/certificates/Webhub.crt';
// $certificate = base_path("/storage/app/certificates/{$username}.crt");
// signature information
$info = array(
'Name' => Auth::user()->username,
'Location' => 'Indonesia',
'Reason' => 'Generate Digitally Signed PDF',
'ContactInfo' => $decryptedEmail,
);
$request->validate([
'file' => 'required|file|mimes:pdf',
]);
$file = $request->file('file');
Log::info('Processing file: ' . $file->getClientOriginalName());
$pdf = new Fpdi(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->AddPage();
// Set signature
$pdf->setSignature($certificate, $certificate, 'PDFSecurity', '', 2, $info);
// Add content to the PDF
$pdf->setSourceFile($file->getRealPath());
$tplIdx = $pdf->importPage(1);
$pdf->useTemplate($tplIdx, 10, 10, 200, 200);
// Output the PDF
$pdf->Output(public_path($file->getClientOriginalName().'-digitally-signed.pdf'), 'D');
}
}














