diff --git a/live_exam_os/.gitignore b/live_exam_os/.gitignore
index 13e2528deaca3ca35d47df372b92142538ebc354..906aca118331bd80348ac667bd0d215a2e74d2b3 100644
--- a/live_exam_os/.gitignore
+++ b/live_exam_os/.gitignore
@@ -2,3 +2,5 @@
 .env*
 cache/
 config/02-customisation/etc/NetworkManager/system-connections/wifi.nmconnection
+tools/unlocker-advanced.c
+config/03-post_install/7000-unlocker-advanced.sh*
diff --git a/live_exam_os/Dockerfile b/live_exam_os/Dockerfile
index 398bd7aef684d19bcfd54adc86c29412fbf81e21..3ca37d879e9fc4eea6e6a5fc44b2fbdf4a23b693 100644
--- a/live_exam_os/Dockerfile
+++ b/live_exam_os/Dockerfile
@@ -1,22 +1,50 @@
-ARG DEBIAN_FRONTEND=noninteractive
 FROM ubuntu:22.04
 
 ENV archive=go1.22.6.linux-amd64.tar.gz
 ENV PATH=$PATH:/usr/local/go/bin
 
-RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y gcc pkg-config git wget make ca-certificates libglfw3-dev libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev upx-ucl curl cryptsetup squashfs-tools fakechroot debootstrap xorriso mtools dosfstools gnutls-bin
+RUN apt-get update && \
+    DEBIAN_FRONTEND=noninteractive \
+    apt-get install -y gcc \
+    pkg-config \
+    git \
+    wget \
+    make \
+    ca-certificates \
+    libglfw3-dev \
+    libxcursor-dev \
+    libxinerama-dev \
+    libxi-dev \
+    libxxf86vm-dev \
+    upx-ucl \
+    curl \
+    cryptsetup \
+    squashfs-tools \
+    fakechroot \
+    debootstrap \
+    xorriso \
+    mtools \
+    dosfstools \
+    gnutls-bin \
+    build-essential \
+    unzip \
+    libykpers-1-dev \
+    libyubikey-dev \
+    libcryptsetup-dev \
+    libssl-dev \
+    && apt-get clean
+
 
 RUN git clone https://github.com/limine-bootloader/limine.git --branch=v8.x-binary --depth=1 /opt/limine && \
     cd /opt/limine && \
     make && \
     cp /opt/limine/limine /bin/
 
-RUN git config --global --add safe.directory /data
-
-RUN wget https://go.dev/dl/$archive && tar -C /usr/local -xzf $archive
 
 # This part is used to compile the dependencies so that you don't have to do it every time you run the build.sh script (it saves around 2.5 minutes).
 WORKDIR /nexus
+RUN wget https://go.dev/dl/$archive && tar -C /usr/local -xzf $archive
+RUN git config --global --add safe.directory /nexus
 
 COPY src src
 COPY Makefile .
@@ -24,3 +52,9 @@ COPY config config
 
 RUN cd config/certs && ./gen-cert.sh ca.info nexus-server.info /nexus/certs
 RUN make build_nexus-exam SERVER='127.0.0.1:1077' CERT='certs/ca-cert.pem' EXAM_USER='user' EXAM_PWD='pwd'
+
+WORKDIR /tigress
+
+COPY live_exam_os/tigress_4.0.10-1_all.deb.zip .
+RUN unzip tigress_4.0.10-1_all.deb.zip
+RUN dpkg --force-architecture -i tigress_4.0.10-1_all.deb
diff --git a/live_exam_os/config/01-packages_install/packages b/live_exam_os/config/01-packages_install/packages
index 6c3320c7dae5fd3d96e9e5a95803dc668f5f89d8..b309e6bf1972ab2c41aaf0df637bf7410f4bd2b0 100644
--- a/live_exam_os/config/01-packages_install/packages
+++ b/live_exam_os/config/01-packages_install/packages
@@ -9,7 +9,6 @@ xserver-xorg
 xserver-xorg-input-libinput
 xinit
 xfce4
-xfce4-terminal
 systemd
 policykit-1
 adwaita-icon-theme
@@ -21,6 +20,9 @@ iptables
 ufw
 rfkill
 wpasupplicant
-yubikey-personalization
 shim-signed
 grub-efi-amd64-signed
+build-essential
+libykpers-1-dev
+libyubikey-dev
+libcryptsetup-dev
diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/unlock b/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/unlock
new file mode 100755
index 0000000000000000000000000000000000000000..ddeed75ff61bf34da4324ab5d62fde44adb260ab
--- /dev/null
+++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/unlock
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set -e
+. /usr/share/initramfs-tools/hook-functions
+
+copy_exec /etc/unlock_luks /scripts/unlock_luks
+copy_exec /lib/x86_64-linux-gnu/libykpers-1.so.* /lib/x86_64-linux-gnu/
diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/yubikey b/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/yubikey
deleted file mode 100755
index 56bc51daadf1fc546c5fe94971d80ff726269b81..0000000000000000000000000000000000000000
--- a/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/yubikey
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-set -e
-. /usr/share/initramfs-tools/hook-functions
-
-copy_exec /usr/bin/ykchalresp /bin/ykchalresp
-copy_exec /etc/challenge /scripts/challenge
diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus
index 0b2fb417d630e16180f7c963a2c7799148150921..3eba82c00cda688fb2317dd715b455b5f389991d 100755
--- a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus
+++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus
@@ -24,23 +24,4 @@ if [ ! $exit_code -eq 0 ]; then
   mount_and_switch /cdrom/squash.rootfs
 fi
 
-
-echo "Waiting for Yubikey."
-while true; do
-  output=$(ykchalresp -2 -i /scripts/challenge 2>&1)
-
-  exit_code=$?
-  
-  if read -t 1 -n 1 input && [ "$input" = "p" ]; then
-    echo ""
-    decrypt_with_passphrase /cdrom/squash.rootfs
-    continue
-  fi
-  
-  if [ "$exit_code" -eq 1 ]; then
-      sleep 1
-      continue
-  fi
-
-  decrypt_with_challenge /cdrom/squash.rootfs $output
-done
+decrypt_mount_and_switch
diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe
index d5ed66b68011bbaca5bb671575cb23810de655dd..8077c0256a8e965791c21d0f7f104a1cccc28660 100755
--- a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe
+++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe
@@ -17,21 +17,4 @@ if [ ! $exit_code -eq 0 ]; then
   mount_and_switch $SQUASH_FILE
 fi
 
-echo "Waiting for Yubikey"
-while true; do
-  output=$(ykchalresp -2 -i /scripts/challenge 2>&1)
-  exit_code=$?
-  
-  if read -t 1 -n 1 input && [ "$input" = "p" ]; then
-    echo ""
-    decrypt_with_passphrase $SQUASH_FILE
-    continue
-  fi
-  
-  if [ "$exit_code" -eq 1 ]; then
-      sleep 1
-      continue
-  fi
-  
-  decrypt_with_challenge $SQUASH_FILE $output
-done
+decrypt_mount_and_switch
diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools
index 1f712517796be800b1827df64942f854a0c7cc2e..64b8fa003087c62d436364323d5c4dc129a2cdad 100755
--- a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools
+++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools
@@ -14,6 +14,27 @@ mount_and_switch() {
   exec switch_root /newroot /sbin/init
 }
 
+decrypt_mount_and_switch() {
+  echo "Waiting for Yubikey."
+  while true; do
+    output=$(/scripts/unlock_luks)
+    exit_code=$?
+
+    if read -t 1 -n 1 input && [ "$input" = "p" ]; then
+      echo ""
+      decrypt_with_passphrase /cdrom/squash.rootfs
+      continue
+    fi
+
+    if [ "$exit_code" -eq 1 ]; then
+        sleep 1
+        continue
+    fi
+
+    mount_and_switch /dev/mapper/data
+  done
+}
+
 decrypt_with_passphrase() {
   SQUASHFS_LUKS=$1
   cryptsetup open $1 data
@@ -26,18 +47,6 @@ decrypt_with_passphrase() {
   echo "Wrong passphrase"
 }
 
-decrypt_with_challenge() {
-  SQUASHFS_LUKS=$1
-  echo -n "$2" | cryptsetup open $SQUASHFS_LUKS data
-  exit_code=$?
-
-  if [ "$exit_code" -eq 0 ]; then
-    mount_and_switch /dev/mapper/data
-  fi
-
-  echo "Decryption error, possibly wrong Yubikey"
-}
-
 mount_fs() {
   SQUASHFS_PATH=$1
   mkdir -p /newroot/{home, run, tmp, var/log, var/tmp} /rw_home /squash
@@ -63,7 +72,6 @@ mount_fs() {
   mount --bind /rw_home /newroot/home
 }
 
-
 find_active_interface() {
     for iface in $(ls /sys/class/net); do
         if [ "$iface" = "lo" ]; then
diff --git a/live_exam_os/config/03-post_install/5000-push_challenge.sh b/live_exam_os/config/03-post_install/5000-push_challenge.sh
deleted file mode 100755
index 27bfbe6a91dddc542aee97f2085613a06b442769..0000000000000000000000000000000000000000
--- a/live_exam_os/config/03-post_install/5000-push_challenge.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#/bin/bash
-
-. tools/functions.sh
-
- echo " [Adding challenge file...]"
- echo "$CHALLENGE" > $ROOTFS_DIR/etc/challenge
diff --git a/live_exam_os/config/03-post_install/7000-unlocker.sh b/live_exam_os/config/03-post_install/7000-unlocker.sh
new file mode 100755
index 0000000000000000000000000000000000000000..628fdb15a260c4ca594a46aaf1ee92bb1bf3aafe
--- /dev/null
+++ b/live_exam_os/config/03-post_install/7000-unlocker.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+. tools/functions.sh
+
+echo " [Compile unlocker...]"
+
+sed "s/DUMMY_CHALLENGE/$CHALLENGE/g" tools/unlocker.c > /tmp/unlocker.c
+run_command gcc -o /tmp/unlock_luks /tmp/unlocker.c -I/usr/include/ykpers-1 -lykpers-1 -lyubikey -lcryptsetup
+run_command strip /tmp/unlock_luks
+run_command cp /tmp/unlock_luks $ROOTFS_DIR/etc/unlock_luks
diff --git a/live_exam_os/config/03-post_install/8000-initramfs.sh b/live_exam_os/config/03-post_install/8000-initramfs.sh
index 0c5e737be3e3460f5b3b1e5caad49651fab51610..3db26efb3da8cabba3fc687c7d753e06173fcbd3 100755
--- a/live_exam_os/config/03-post_install/8000-initramfs.sh
+++ b/live_exam_os/config/03-post_install/8000-initramfs.sh
@@ -4,4 +4,3 @@
 
 echo " [Update initramfs...]"
 run_command_chroot update-initramfs -u
-check_exit_code $? "Error during initramfs generation"
diff --git a/live_exam_os/tigress_4.0.10-1_all.deb.zip b/live_exam_os/tigress_4.0.10-1_all.deb.zip
new file mode 100644
index 0000000000000000000000000000000000000000..3a4c6a2e6a9f57d6a0f9d32d6906c1041766c476
Binary files /dev/null and b/live_exam_os/tigress_4.0.10-1_all.deb.zip differ
diff --git a/live_exam_os/tools/functions.sh b/live_exam_os/tools/functions.sh
index 1b6745a8455ee0b8d1604255e71c1f0a5229041a..717963aaf2592d354677ba71057faa008158b150 100755
--- a/live_exam_os/tools/functions.sh
+++ b/live_exam_os/tools/functions.sh
@@ -77,3 +77,20 @@ check_dependencies() {
     exit 1
   fi
 }
+
+find_latest_library() {
+  local library_name=$1
+
+  local library_files
+  library_files=$(find /$ROOTFS_DIR -name "$library_name" 2>/dev/null)
+
+  if [ -z "$library_files" ]; then
+    echo "No version available of $library_name."
+    return 1
+  fi
+
+  local latest_library
+  latest_library=$(echo "$library_files" | sort -r | head -n 1)
+
+  realpath "$latest_library"
+}
diff --git a/live_exam_os/tools/unlocker.c b/live_exam_os/tools/unlocker.c
new file mode 100644
index 0000000000000000000000000000000000000000..8af2605fd18e217b3c1c6418162c324cc80a40ac
--- /dev/null
+++ b/live_exam_os/tools/unlocker.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ykpers-1/ykpers.h>
+#include <yubikey.h>
+#include <libcryptsetup.h>
+
+#define LUKS_DEVICE "/cdrom/squash.rootfs"
+#define LUKS_NAME "data"
+
+int unlock_luks(const char *device, const char *name, const char *key, size_t key_size) {
+  struct crypt_device *cd;
+
+  if (crypt_init(&cd, device) < 0) {
+    fprintf(stderr, "Error: Cannot initialize cryptsetup\n");
+    return -1;
+  }
+
+  if (crypt_load(cd, CRYPT_LUKS2, NULL) < 0) {
+    fprintf(stderr, "Error: Cannot load LUKS header\n");
+    crypt_free(cd);
+    return -1;
+  }
+
+  if (crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, key, strlen(key), CRYPT_ACTIVATE_ALLOW_DISCARDS) < 0) {
+    fprintf(stderr, "Error: Cannot decrypt device\n");
+    crypt_free(cd);
+    return -1;
+  }
+
+  crypt_free(cd);
+  return 0;
+}
+
+int main() {
+  YK_KEY *yk = NULL;
+  unsigned char response[64];
+  unsigned int response_len = sizeof(response);
+  char *hex_response = malloc(41);
+  unsigned char challenge[64] = "DUMMY_CHALLENGE\n";
+
+  if (!hex_response) {
+    fprintf(stderr, "Error: Failed memory allocation\n");
+    free(hex_response);
+    return 1;
+  }
+
+  if (!yk_init()) {
+    fprintf(stderr, "Error: Cannot initialize libykpers\n");
+    free(hex_response);
+    return 1;
+  }
+
+  yk = yk_open_first_key();
+  if (!yk) {
+    yk_release();
+    free(hex_response);
+    return 1;
+  }
+
+  if (!yk_challenge_response(yk, SLOT_CHAL_HMAC1, YK_FLAG_MAYBLOCK, sizeof(challenge), challenge, response_len, response)) {
+    fprintf(stderr, "Error: challenge-response issue\n");
+    yk_close_key(yk);
+    yk_release();
+    free(hex_response);
+    return 1;
+  }
+
+  for (int i = 0; i < 20; i++) {
+    sprintf(hex_response + (i * 2), "%02x", response[i]);
+  }
+  hex_response[40] = '\0';
+
+  yk_close_key(yk);
+  yk_release();
+
+  if (unlock_luks(LUKS_DEVICE, LUKS_NAME, hex_response, strlen(hex_response)) != 0) {
+    fprintf(stderr, "Error: Cannot decrypt device\n");
+    return 1;
+  }
+
+  free(hex_response);
+  return 0;
+}