The challenge is based on two components:
The code was not stripped to help with understanding and checking the manual.
Here is the source code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include <sys/ptrace.h>
#include "vbx.h"
#include "utils.h"
const int N = 8;
const uint8_t secret[] = {0x1e, 0xcb, 0x87, 0xc1, 0xb4, 0x76, 0x70, 0xb9, 0x99, 0xad, 0xdf, 0x84, 0x1e, 0x62, 0x25, 0x66, 0x38, 0x50, 0x72, 0xe3, 0xf1, 0x5f, 0x6c, 0x00, 0x0c, 0xef, 0xaf, 0x94, 0xc6, 0x03, 0xc4, 0xb1, 0x7f, 0x96, 0x18, 0xb3, 0x7f, 0x94, 0x54, 0x0a, 0xc7, 0xf8, 0xc2, 0xf1, 0x19, 0xe5, 0xda, 0xbf, 0xd7, 0x8f, 0xce, 0xbb, 0x0e, 0x7d, 0xe8, 0xdd, 0xc2, 0xca, 0x29, 0xcb, 0xc1, 0x23, 0x03, 0x66};
struct RNG {
unsigned int seed;
};
unsigned int gen(struct RNG* rng) {
rng->seed = rng->seed * 110515245 + 114514;
return (unsigned int)(rng->seed/65536) % 32768;
}
uint8_t* init(int N, char* key) {
uint8_t *arr = (uint8_t*) malloc((N*N) * sizeof(uint8_t));
for(int i = 0; i < N*N; i++) {
arr[i] = (uint8_t) key[i];
}
return arr;
}
int manipulate(vbx_ubyte_t *v_dst, vbx_ubyte_t *v_src, const int N) {
vbx_set_vl(1, N, N);
vbx_set_2D(N * sizeof(vbx_ubyte_t), sizeof(vbx_ubyte_t), 0);
vbx_set_3D(sizeof(vbx_ubyte_t), N * sizeof(vbx_ubyte_t), 0);
vbx(VVBU, VMOV, v_dst, v_src, 0);
return 1;
}
int enc(uint8_t *keys, uint8_t* input) {
for (int i = 0; i < N; i++) {
uint8_t *pt = input + i * N;
enc2(pt, keys);
// pt should match secret[i*N:i*N+N]
if (memcmp(pt, secret + i * N, N) != 0) {
return 0;
}
}
return 1;
}
int main() {
printf("+------+. \n");
printf("|`. | `. \n");
printf("| `+--+---+ \n");
printf("| | | | \n");
printf("+---+--+. | \n");
printf(" `. | `.| \n");
printf(" `+------+ \n");
#if VBX_SIMULATOR==1
vbxsim_init(512, 16384, 256, 6, 5, 4, 0, 0);
#endif
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) exit(1);
char command[65];
printf("Enter the command to unlock the Matrix...\n> ");
scanf("%64s", command);
if (strlen(command) != 0x40 || strncmp(command, "SEKAI{", 6) != 0 || command[63] != '}') {
printf("Incorrect command format. You cannot unlock the Matrix. :(\n");
exit(1);
}
uint8_t *A = init(N, command);
static const int num_elements = N * N;
// Allocate vectors in scratchpad
vbx_ubyte_t* v_A = vbx_sp_malloc(num_elements * sizeof(vbx_ubyte_t));
vbx_ubyte_t* v_B = vbx_sp_malloc(num_elements * sizeof(vbx_ubyte_t));
vbx_ubyte_t* v_C = vbx_sp_malloc(num_elements * sizeof(vbx_ubyte_t));
vbx_ubyte_t* v_D = vbx_sp_malloc(num_elements * sizeof(vbx_ubyte_t));
vbx_ubyte_t* v_O = vbx_sp_malloc(num_elements * sizeof(vbx_ubyte_t));
if (v_A == NULL || v_B == NULL || v_C == NULL || v_D == NULL || v_O == NULL) {
printf("Unknown error while launching the Matrix.\n");
exit(1);
}
vbx_dma_to_vector(v_A, A, num_elements * sizeof(vbx_ubyte_t));
vbx_sync();
vbx_set_vl(num_elements);
vbx(VSBU, VXOR, v_A, v_A, 0x13);
vbx(SVBU, VMOV, v_B, 2, 0);
vbx(VSBU, VSLT, v_D, v_A, 97);
vbx(VVBU, VSUB, v_B, v_B, v_D);
vbx(VVBU, VMUL, v_C, v_A, v_B);
manipulate(v_O, v_C, N);
uint8_t* output = (uint8_t*) malloc(num_elements * sizeof(uint8_t));
vbx_dma_to_host(output, v_O, num_elements * sizeof(vbx_ubyte_t));
vbx_sync();
printf("Command accepted. Generating your Single-use Key...\n");
printf("Using RNG to make it completely random.");
sleep(2);
struct RNG rng = {0xdeadbeef};
uint8_t key[16];
for (int i = 0; i < 16; i++) {
while (1) {
key[i] = (uint8_t) gen(&rng) % 256;
if (key[i] >= 33 && key[i] <= 126) {
break;
}
}
}
uint8_t keys[SEKAI_BLOCK_SIZE/16*SEKAI_R2];
ks2(key, keys);
printf("\nVerifying your identity...\n");
if (enc(keys, output)) {
printf("Access granted. Enjoy the Matrix Flag.\n");
} else {
printf("Access denied. You cannot unlock the Matrix. :(\n");
}
vbx_sp_free();
return 0;
}
Flag: SEKAI{y4y_u_p4ss3d_ScR4TcHp4D_t35t_w1th_V3ct0rB10x_4nd_51M0N_xD}