@@ -2483,7 +2483,12 @@ gboolean bd_crypto_luks_reencrypt (const gchar *device, BDCryptoLUKSReencryptPar
24832483 paramsReencrypt .luks2 = & paramsLuks2 ;
24842484
24852485 paramsLuks2 .sector_size = params -> sector_size ;
2486- paramsLuks2 .pbkdf = get_pbkdf_params (params -> pbkdf , error );
2486+ if (params -> pbkdf == NULL ) {
2487+ paramsLuks2 .pbkdf = crypt_get_pbkdf_default (CRYPT_LUKS2 );
2488+ } else {
2489+ paramsLuks2 .pbkdf = get_pbkdf_params (params -> pbkdf , error );
2490+ }
2491+
24872492 if (paramsLuks2 .pbkdf == NULL ) {
24882493 /* get info to log */
24892494 if (params -> pbkdf != NULL && params -> pbkdf -> type != NULL ) {
@@ -2530,6 +2535,226 @@ gboolean bd_crypto_luks_reencrypt (const gchar *device, BDCryptoLUKSReencryptPar
25302535 return TRUE;
25312536}
25322537
2538+ /**
2539+ * bd_crypto_luks_encrypt:
2540+ * @device: device to encrypt. Either an active device name for online encryption, or a block device for offline encryption.
2541+ * Must match the @params's "offline" parameter
2542+ * @params: encryption parameters
2543+ * @context: key slot context to unlock @device. The newly created keyslot will use the same context
2544+ * @prog_func: (scope call) (nullable): progress function. Also used to possibly stop encryption
2545+ * @error: (out) (optional): place to store error (if any)
2546+ *
2547+ * Encrypts @device. In contrast to %bd_crypto_luks_format, possible existent data on @device is not destroyed,
2548+ * but encrypted, i.e., is usable after activating device.
2549+ *
2550+ * Important: you need to ensure that there is enough free (unallocated) space on @device for a LUKS header (recomended 16 to 32 MiB).
2551+ *
2552+ * Returns: true, if the encryption was successful or gracefully stopped with @prog_func.
2553+ * false, if an error occurred.
2554+ *
2555+ * Supported @context types for this function: passphrase
2556+ *
2557+ * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_MODIFY
2558+ */
2559+ gboolean bd_crypto_luks_encrypt (const gchar * device , BDCryptoLUKSReencryptParams * params , BDCryptoKeyslotContext * context , BDCryptoLUKSReencryptProgFunc prog_func , GError * * error ) {
2560+ struct crypt_device * cd = NULL ;
2561+ struct crypt_params_reencrypt paramsReencrypt = {};
2562+ struct crypt_params_luks2 paramsLuks2 = {};
2563+ struct reencryption_progress_struct usrptr ;
2564+
2565+ guint key_size = params -> key_size / 8 ; /* convert bits to bytes */
2566+ const gchar * HEADER_FILENAME_TEMPLATE = "libblockdev-crypto-luks-encrypt-XXXXXX" ;
2567+ gchar * header_file_path = NULL ;
2568+ int allocated_keyslot ;
2569+ gint ret , fd = 0 ;
2570+ guint64 progress_id = 0 ;
2571+ gchar * msg = NULL ;
2572+ GError * l_error = NULL ;
2573+
2574+ msg = g_strdup_printf ("Started encryption of LUKS device '%s'" , device );
2575+ progress_id = bd_utils_report_started (msg );
2576+ g_free (msg );
2577+
2578+ if (context -> type != BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE ) {
2579+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_INVALID_CONTEXT ,
2580+ "Only the 'passphrase' context type is supported for LUKS encrypt." );
2581+ bd_utils_report_finished (progress_id , l_error -> message );
2582+ g_propagate_error (error , l_error );
2583+ crypt_free (cd );
2584+ return FALSE;
2585+ }
2586+
2587+ fd = g_file_open_tmp (HEADER_FILENAME_TEMPLATE , & header_file_path , & l_error );
2588+ if (fd == -1 ) {
2589+ g_set_error (error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_REENCRYPT_FAILED ,
2590+ "Failed to create temporary header file: %s" , l_error -> message );
2591+ bd_utils_report_finished (progress_id , (* error )-> message );
2592+ g_free (header_file_path );
2593+ crypt_free (cd );
2594+ return FALSE;
2595+ }
2596+
2597+ ret = posix_fallocate (fd , 0 , 4096 );
2598+ close (fd );
2599+ if (ret != 0 ) {
2600+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_REENCRYPT_FAILED ,
2601+ "Failed to allocate enough space for temporary header file." );
2602+ bd_utils_report_finished (progress_id , l_error -> message );
2603+ g_propagate_error (error , l_error );
2604+ unlink (header_file_path );
2605+ g_free (header_file_path );
2606+ crypt_free (cd );
2607+ return FALSE;
2608+ }
2609+
2610+ ret = crypt_init (& cd , header_file_path );
2611+ if (ret < 0 ) {
2612+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_DEVICE ,
2613+ "Failed to initialize device with detached header: %s" , strerror_l (- ret , c_locale ));
2614+ bd_utils_report_finished (progress_id , l_error -> message );
2615+ g_propagate_error (error , l_error );
2616+ unlink (header_file_path );
2617+ g_free (header_file_path );
2618+ return FALSE;
2619+ }
2620+
2621+ paramsLuks2 .data_device = device ;
2622+ paramsLuks2 .sector_size = params -> sector_size ;
2623+ paramsLuks2 .pbkdf = get_pbkdf_params (params -> pbkdf , error );
2624+
2625+ crypt_set_data_offset (cd , 16 MiB / SECTOR_SIZE );
2626+ ret = crypt_format (cd , CRYPT_LUKS2 , params -> cipher , params -> cipher_mode , NULL , NULL , key_size , & paramsLuks2 );
2627+ if (ret < 0 ) {
2628+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_REENCRYPT_FAILED ,
2629+ "Failed to format a header file: %s" , strerror_l (- ret , c_locale ));
2630+ bd_utils_report_finished (progress_id , l_error -> message );
2631+ g_propagate_error (error , l_error );
2632+ unlink (header_file_path );
2633+ g_free (header_file_path );
2634+ crypt_free (cd );
2635+ return FALSE;
2636+ }
2637+
2638+ ret = crypt_keyslot_add_by_key (cd ,
2639+ CRYPT_ANY_SLOT ,
2640+ NULL ,
2641+ key_size ,
2642+ (const char * ) context -> u .passphrase .pass_data ,
2643+ context -> u .passphrase .data_len ,
2644+ 0 );
2645+ if (ret < 0 ) {
2646+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_ADD_KEY ,
2647+ "Failed to add key: %s" , strerror_l (- ret , c_locale ));
2648+ bd_utils_report_finished (progress_id , l_error -> message );
2649+ g_propagate_error (error , l_error );
2650+ unlink (header_file_path );
2651+ g_free (header_file_path );
2652+ crypt_free (cd );
2653+ return FALSE;
2654+ }
2655+ allocated_keyslot = ret ;
2656+ bd_utils_report_progress (progress_id , 10 , "Added new keyslot" );
2657+
2658+ paramsReencrypt .mode = CRYPT_REENCRYPT_ENCRYPT ;
2659+ paramsReencrypt .direction = CRYPT_REENCRYPT_BACKWARD ;
2660+ paramsReencrypt .resilience = params -> resilience ;
2661+ paramsReencrypt .hash = params -> hash ;
2662+ paramsReencrypt .data_shift = 16 MiB / SECTOR_SIZE ;
2663+ paramsReencrypt .max_hotzone_size = params -> max_hotzone_size ;
2664+ paramsReencrypt .device_size = 0 ;
2665+ paramsReencrypt .flags = CRYPT_REENCRYPT_INITIALIZE_ONLY ;
2666+ paramsReencrypt .flags |= CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT ;
2667+ paramsReencrypt .luks2 = & paramsLuks2 ;
2668+
2669+ /* Initialize reencryption */
2670+ ret = crypt_reencrypt_init_by_passphrase (cd ,
2671+ params -> offline ? NULL : device ,
2672+ (const char * ) context -> u .passphrase .pass_data ,
2673+ context -> u .passphrase .data_len ,
2674+ CRYPT_ANY_SLOT ,
2675+ allocated_keyslot ,
2676+ params -> cipher ,
2677+ params -> cipher_mode ,
2678+ & paramsReencrypt );
2679+ if (ret < 0 ) {
2680+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_REENCRYPT_FAILED ,
2681+ "Failed to initialize encryption: %s" , strerror_l (- ret , c_locale ));
2682+ bd_utils_report_finished (progress_id , l_error -> message );
2683+ g_propagate_error (error , l_error );
2684+ unlink (header_file_path );
2685+ g_free (header_file_path );
2686+ crypt_free (cd );
2687+ return FALSE;
2688+ }
2689+
2690+ /* Set header from temporary file to disk */
2691+ /* 1/2: Re-init without detached header */
2692+ crypt_free (cd );
2693+ cd = NULL ;
2694+ ret = crypt_init (& cd , device );
2695+ if (ret < 0 ) {
2696+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_DEVICE ,
2697+ "Failed to re-initialize device: %s" , strerror_l (- ret , c_locale ));
2698+ bd_utils_report_finished (progress_id , l_error -> message );
2699+ g_propagate_error (error , l_error );
2700+ unlink (header_file_path );
2701+ g_free (header_file_path );
2702+ return FALSE;
2703+ }
2704+
2705+ /* 2/2: Set header */
2706+ ret = crypt_header_restore (cd , CRYPT_LUKS2 , header_file_path );
2707+ unlink (header_file_path );
2708+ g_free (header_file_path );
2709+ if (ret < 0 ) {
2710+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_DEVICE ,
2711+ "Failed to re-initialize device: %s" , strerror_l (- ret , c_locale ));
2712+ bd_utils_report_finished (progress_id , l_error -> message );
2713+ g_propagate_error (error , l_error );
2714+ crypt_free (cd );
2715+ return FALSE;
2716+ }
2717+
2718+ paramsReencrypt .flags &= ~CRYPT_REENCRYPT_INITIALIZE_ONLY ;
2719+ paramsReencrypt .flags |= CRYPT_REENCRYPT_RESUME_ONLY ;
2720+
2721+ ret = crypt_reencrypt_init_by_passphrase (cd ,
2722+ params -> offline ? NULL : device ,
2723+ (const char * ) context -> u .passphrase .pass_data ,
2724+ context -> u .passphrase .data_len ,
2725+ CRYPT_ANY_SLOT ,
2726+ allocated_keyslot ,
2727+ params -> cipher ,
2728+ params -> cipher_mode ,
2729+ & paramsReencrypt );
2730+ if (ret < 0 ) {
2731+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_REENCRYPT_FAILED ,
2732+ "Failed to re-initialize encryption: %s" , strerror_l (- ret , c_locale ));
2733+ bd_utils_report_finished (progress_id , l_error -> message );
2734+ g_propagate_error (error , l_error );
2735+ crypt_free (cd );
2736+ return FALSE;
2737+ }
2738+
2739+ /* marshal to usrptr */
2740+ usrptr .progress_id = progress_id ;
2741+ usrptr .usr_func = prog_func ;
2742+
2743+ ret = crypt_reencrypt_run (cd , reencryption_progress , & usrptr );
2744+ if (ret != 0 ) {
2745+ g_set_error (& l_error , BD_CRYPTO_ERROR , BD_CRYPTO_ERROR_REENCRYPT_FAILED ,
2746+ "Reencryption failed: %s" , strerror_l (- ret , c_locale ));
2747+ bd_utils_report_finished (progress_id , l_error -> message );
2748+ g_propagate_error (error , l_error );
2749+ crypt_free (cd );
2750+ return FALSE;
2751+ }
2752+
2753+ crypt_free (cd );
2754+ bd_utils_report_finished (progress_id , "Completed." );
2755+ return TRUE;
2756+ }
2757+
25332758/**
25342759 * bd_crypto_luks_reencrypt_status:
25352760 * @device: an active device name or a block device
0 commit comments