密码学与图片文件隐写技术

一、问题背景

传统加密技术如同给信息穿上坚固的 “防弹衣”,而隐写术则更像是让信息 “消失” 在普通载体中,实现真正的 “隐形传输”。图片作为一种广泛使用的多媒体载体,凭借其数据量大、视觉冗余高、便于传输和存储等特点,成为了隐写术的理想选择。​

最低有效位(LSB)隐写术是一种典型的图片隐写技术。它就像一位高明的 “信息化妆师”,通过修改图像像素值的最低有效位来嵌入秘密信息。例如,对于彩色图像的 RGB 通道,每个通道用 8 位二进制表示,修改最低位 1 个比特,人眼几乎无法察觉图像视觉效果的变化,却能在不知不觉中完成信息的隐藏。​

然而,单纯的隐写术存在一个致命缺陷:一旦攻击者怀疑某张图片中藏有秘密信息,就可以通过特定技术直接提取内容,导致秘密泄露。这时,密码学的加入就像给隐写术上了一把 “双重保险锁”—— 先对秘密信息进行加密处理,再将加密后的密文嵌入图片中。这样一来,即使攻击者发现了隐藏痕迹,没有正确密钥也无法解读信息内容,大大提高了信息传输的安全性。

二、 隐写技术面临的核心安全问题

1. 隐蔽性不足:传统的图片隐写方法,如最低有效位(LSB)替换法,通过直接修改图像像素的最低有效位来嵌入信息,这种方式会显著改变图像的统计特性。攻击者可以利用卡方检验、RS分析等统计手段,通过分析图像像素值分布、高频系数特征等,识别出隐写痕迹 。例如,在大量隐写图像中,像素值的分布可能会偏离正常图像的统计规律,从而暴露隐写行为。

2. 信息完整性风险:隐写图像在传输过程中可能遭受各种形式的篡改,如恶意修改嵌入的秘密信息、对图像进行编辑处理等。如果秘密信息未经保护直接嵌入,接收方无法察觉信息是否被篡改,这可能导致重要信息泄露或决策失误。

3. 身份认证缺失:在缺乏有效身份认证机制的隐写系统中,接收方无法确认信息来源的真实性,容易遭受中间人攻击。攻击者可能伪造隐写信息,诱使接收方获取错误信息,从而造成安全隐患。

4. 密钥管理困难:隐写系统中涉及加密密钥、嵌入密钥等多种密钥,若密钥管理不善,如密钥泄露、使用弱密钥等,会导致整个隐写系统的安全防线被攻破。

而密码学中的一些技术增加了其保密性,保护其完整性,能进行身份认证等,其应用为这一问题提供了一个不错的解决方案。

三、一些加密算法的应用

1.对称加密算法

(1)AES算法:高级加密标准(AES)是目前应用最广泛的对称加密算法,支持128位、192位和256位密钥长度,具有加密速度快、安全性高的特点。在图片隐写中,首先使用AES算法对秘密信息进行加密,将明文转化为密文。然后,将密文通过合适的隐写算法嵌入图像中。例如,在基于LSB的隐写方法中,可以将AES加密后的密文逐位替换图像像素的最低有效位。由于密文具有高度的随机性,其嵌入对图像统计特性的影响较小,能够有效提高信息的保密性。

(2)3DES算法:三重数据加密标准(3DES)通过三次使用DES算法,提高了加密强度。尽管3DES的计算效率相对较低,但在对安全性要求极高的场景下仍然具有应用价值。在基于离散余弦变换(DCT)域的隐写中,可以将3DES加密后的密文嵌入图像的高频系数部分。由于高频系数对图像视觉效果影响较小,且3DES加密后的密文具有较高的安全性,能够在保证图像质量的同时,实现秘密信息的安全隐藏。

2.非对称加密算法

(1)RSA算法:RSA是一种基于数论的非对称加密算法,广泛应用于密钥交换和数字签名领域。在图片隐写系统中,RSA算法可以用于安全地交换对称加密密钥。例如,发送方和接收方可以先使用RSA算法交换AES密钥,然后使用该AES密钥对秘密信息进行加密。此外,发送方可以使用自己的RSA私钥对隐写信息进行数字签名,接收方使用发送方的公钥验证签名,从而实现信息来源的身份认证,确保信息的真实性和完整性。

(2)ECC算法:椭圆曲线密码体制(ECC)基于椭圆曲线离散对数问题,在同等安全强度下,ECC的密钥长度比RSA短,计算效率更高,适合在资源受限的环境中应用,如移动设备、物联网设备等。在图片隐写中,ECC算法可以用于快速生成数字签名,保障隐写信息的真实性。同时,ECC也可以用于密钥交换,为对称加密提供安全的密钥分发通道。

3.哈希函数与完整性保护

(1)SHA-256:安全哈希算法256(SHA-256)能够将任意长度的消息映射为256位的哈希值,具有单向性和抗碰撞性。在图片隐写中,发送方在将秘密信息加密并嵌入图像之前,先计算秘密信息的SHA-256哈希值。然后,将哈希值与加密后的密文一同嵌入图像中。接收方在提取出秘密信息后,重新计算秘密信息的哈希值,并与嵌入的哈希值进行对比。如果两个哈希值相同,则说明秘密信息在传输过程中没有被篡改,保障了信息的完整性。

(2)哈希链技术:哈希链是一种基于哈希函数的结构,适用于对一系列秘密信息进行完整性保护和溯源。在图片隐写中,发送方可以对多个秘密信息依次计算哈希值,构建哈希链。具体来说,先计算最后一个秘密信息的哈希值,然后将该哈希值与前一个秘密信息一起计算哈希值,依次类推,直至第一个秘密信息。最后,将哈希链的最后一个哈希值以及每个秘密信息和对应的哈希值(部分或全部)通过隐写算法嵌入到图片中。接收方在需要对信息进行溯源时,可以根据哈希链的计算规则,从嵌入的哈希值和秘密信息逐步验证和追溯信息的来源和完整性,有效防止信息被伪造和篡改。

4.密钥管理方案

(1)密钥生成:采用安全的伪随机数生成器(CSPRNG)生成密钥,确保密钥的随机性和不可预测性。

(2)密钥分发:使用非对称加密算法(如RSA、ECC)加密对称加密密钥,通过安全信道分发给接收方。也可以借助密钥管理中心(KMC)进行密钥的集中管理和分发。KMC可以生成密钥,并使用安全的协议(如SSL/TLS)将密钥分发给授权的用户。此外,还可以采用基于身份的密码系统(IBC),简化密钥分发过程,提高密钥管理的效率。

(3) 密钥存储:密钥应采用安全的方式存储,如使用硬件安全模块(HSM)或加密的密钥库。HSM是一种专门用于存储和处理密钥的硬件设备,具有高度的安全性,能够有效防止密钥被窃取。对于软件实现的密钥存储,应使用强加密算法对密钥进行加密存储,并设置严格的访问控制策略,限制只有授权用户能够访问密钥。

(4)密钥更新:定期更换密钥是保障密钥安全的重要措施。可以通过协商机制在发送方和接收方之间安全更新密钥。例如,使用Diffie-Hellman密钥交换算法,双方可以在不直接传输密钥的情况下,协商生成新的密钥。同时,在更新密钥时,应确保旧密钥的安全性,防止攻击者利用旧密钥破解历史加密信息。

四、以"加密-LSB隐写-哈希验证"系统为例,详细说明密码学在图片隐写中的综合应用:

对32位bmp类型的图片进行隐写

1. 加密阶段:发送方首先将秘密信息进行AES-256加密。假设秘密信息为一段文本,将其转换为二进制数据后,使用预先协商好的256位AES密钥进行加密,生成密文。

// AES-256加密/解密实现(简化版)
#define AES_BLOCK_SIZE 16
#define AES_KEY_SIZE 32

// 简单AES实现(仅为演示,实际应用需使用完整AES库)
int aes_encrypt_batch(const uint8_t* input, int length, uint8_t* output, const uint8_t* key) {
    int padded_length = ((length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
    memcpy(output, input, length);
    
    for (int i = 0; i < padded_length; i++) {
        output[i] = input[i] ^ key[i % AES_KEY_SIZE];
    }
    
    return padded_length;
}

int aes_decrypt_batch(const uint8_t* input, int length, uint8_t* output, const uint8_t* key) {
    for (int i = 0; i < length; i++) {
        output[i] = input[i] ^ key[i % AES_KEY_SIZE];
    }
    return length;
}

2. 隐写阶段:采用LSB替换法将AES密文嵌入BMP图像中。BMP图像的每个像素由RGB三个颜色通道组成,每个通道用8位二进制表示。将密文逐位替换图像像素RGB通道的最低有效位。例如,对于某个像素的红色通道值为 10101010 ,若要嵌入的密文位为 1 ,则将该红色通道值修改为 10101011 。为了提高隐蔽性,可以采用随机替换策略,避免出现规律性的替换模式。

3. 完整性保护阶段:发送方计算原始秘密信息的SHA-256哈希值,并将哈希值也嵌入图像中。可以选择在图像的特定区域(如边角部分)嵌入哈希值,以减少对图像视觉效果的影响。

// SHA-256实现(简化版)
#define SHA256_DIGEST_LENGTH 32

// 简单SHA-256实现(仅为演示,实际应用需使用完整库)
void sha256(const uint8_t* input, int length, uint8_t* digest) {
    memset(digest, 0, SHA256_DIGEST_LENGTH);
    
    for (int i = 0; i < length; i++) {
        digest[i % SHA256_DIGEST_LENGTH] ^= input[i];
    }
    
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        digest[i] = (digest[i] * 17 + 31) % 256;
    }
}

4. 接收与验证阶段:接收方在接收到隐写图像后,首先提取出嵌入的密文和哈希值。然后,使用相同的AES-256密钥对密文进行解密,得到原始秘密信息的候选内容。接着,计算解密后信息的SHA-256哈希值,并与嵌入的哈希值进行对比。如果两个哈希值相同,则说明秘密信息在传输过程中没有被篡改,接收方可以信任该信息;如果哈希值不同,则表明信息可能已被修改,接收方应拒绝接受该信息或采取相应的处理措施。

运行结果:

该运行成功的前提是在代码文件所在目录中有一个名为cover.bmp的图片

详细代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

// AES-256加密/解密实现(简化版)
#define AES_BLOCK_SIZE 16
#define AES_KEY_SIZE 32

// SHA-256实现(简化版)
#define SHA256_DIGEST_LENGTH 32

// 简单AES实现(仅为演示,实际应用需使用完整AES库)
int aes_encrypt_batch(const uint8_t* input, int length, uint8_t* output, const uint8_t* key) {
    int padded_length = ((length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
    memcpy(output, input, length);
    
    for (int i = 0; i < padded_length; i++) {
        output[i] = input[i] ^ key[i % AES_KEY_SIZE];
    }
    
    return padded_length;
}

int aes_decrypt_batch(const uint8_t* input, int length, uint8_t* output, const uint8_t* key) {
    for (int i = 0; i < length; i++) {
        output[i] = input[i] ^ key[i % AES_KEY_SIZE];
    }
    return length;
}

// 简单SHA-256实现(仅为演示,实际应用需使用完整库)
void sha256(const uint8_t* input, int length, uint8_t* digest) {
    memset(digest, 0, SHA256_DIGEST_LENGTH);
    
    for (int i = 0; i < length; i++) {
        digest[i % SHA256_DIGEST_LENGTH] ^= input[i];
    }
    
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        digest[i] = (digest[i] * 17 + 31) % 256;
    }
}

#pragma pack(push, 1)
typedef struct {
    uint16_t type;
    uint32_t size;
    uint16_t res1, res2;
    uint32_t offset;
} bmp_file_header;

typedef struct {
    uint32_t size;
    int32_t width, height;
    uint16_t planes, bit_count;
    uint32_t compression, image_size;
    int32_t xdpi, ydpi;
    uint32_t clr_used, clr_important;
} bmp_info_header;

typedef struct {
    bmp_file_header file_hdr;
    bmp_info_header info_hdr;
    uint8_t* pixels;
} bmp_image;
#pragma pack(pop)

bmp_image* load_bmp(const char* path) {
    FILE* f = fopen(path, "rb");
    if (!f) {
        printf("无法打开文件: %s\n", path);
        return NULL;
    }
    
    bmp_image* img = (bmp_image*)malloc(sizeof(bmp_image));
    if (!img) {
        fclose(f);
        return NULL;
    }
    
    fread(&img->file_hdr, sizeof(bmp_file_header), 1, f);
    fread(&img->info_hdr, sizeof(bmp_info_header), 1, f);
    
    // 支持24位和32位BMP
    if (img->file_hdr.type != 0x4D42 || (img->info_hdr.bit_count != 24 && img->info_hdr.bit_count != 32)) {
        printf("错误: 不是有效的24位或32位BMP文件\n");
        fclose(f);
        free(img);
        return NULL;
    }
    
    printf("成功检测到%d位BMP图像\n", img->info_hdr.bit_count);
    
    // 计算每行字节数(考虑4字节对齐)
    int row_size = ((img->info_hdr.width * img->info_hdr.bit_count + 31) / 32) * 4;
    int img_size = row_size * img->info_hdr.height;
    
    img->pixels = (uint8_t*)malloc(img_size);
    if (!img->pixels) {
        fclose(f);
        free(img);
        return NULL;
    }
    
    fseek(f, img->file_hdr.offset, SEEK_SET);
    fread(img->pixels, img_size, 1, f);
    fclose(f);
    
    printf("成功加载BMP图像: 宽度=%d, 高度=%d, 大小=%d字节\n", 
           img->info_hdr.width, img->info_hdr.height, img_size);
    
    return img;
}

int save_bmp(bmp_image* img, const char* path) {
    FILE* f = fopen(path, "wb");
    if (!f) {
        printf("无法创建文件: %s\n", path);
        return 0;
    }
    
    int row_size = ((img->info_hdr.width * img->info_hdr.bit_count + 31) / 32) * 4;
    int img_size = row_size * img->info_hdr.height;
    
    fwrite(&img->file_hdr, sizeof(bmp_file_header), 1, f);
    fwrite(&img->info_hdr, sizeof(bmp_info_header), 1, f);
    fwrite(img->pixels, img_size, 1, f);
    fclose(f);
    
    printf("成功保存BMP图像: %s\n", path);
    return 1;
}

void free_bmp(bmp_image* img) {
    if (img) {
        if (img->pixels) free(img->pixels);
        free(img);
    }
}

// 随机数生成器(用于随机LSB嵌入)
uint32_t seed = 12345;
uint32_t random_uint32() {
    seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
    return seed;
}

int embed_data(bmp_image* img, const uint8_t* data, int len, const uint8_t* aes_key) {
    int bytes_per_pixel = img->info_hdr.bit_count / 8;
    int row_size = ((img->info_hdr.width * img->info_hdr.bit_count + 31) / 32) * 4;
    int img_size = row_size * img->info_hdr.height;
    
    // 计算需要嵌入的总数据大小:长度(4字节) + 密文 + 哈希值
    uint8_t hash[SHA256_DIGEST_LENGTH];
    sha256(data, len, hash);
    
    uint8_t* plaintext = (uint8_t*)malloc(len + SHA256_DIGEST_LENGTH);
    memcpy(plaintext, data, len);
    memcpy(plaintext + len, hash, SHA256_DIGEST_LENGTH);
    
    int total_len = len + SHA256_DIGEST_LENGTH;
    uint8_t* encrypted = (uint8_t*)malloc(total_len + AES_BLOCK_SIZE);
    int enc_len = aes_encrypt_batch(plaintext, total_len, encrypted, aes_key);
    free(plaintext);
    
    uint8_t* to_embed = (uint8_t*)malloc(4 + enc_len);
    to_embed[0] = (total_len >> 24) & 0xFF;
    to_embed[1] = (total_len >> 16) & 0xFF;
    to_embed[2] = (total_len >> 8) & 0xFF;
    to_embed[3] = total_len & 0xFF;
    memcpy(to_embed + 4, encrypted, enc_len);
    free(encrypted);
    
    // 计算可嵌入的最大位数,跳过Alpha通道(如果存在)
    int max_bits = img->info_hdr.width * img->info_hdr.height * (bytes_per_pixel - (bytes_per_pixel == 4 ? 1 : 0));
    int total_bits = (4 + enc_len) * 8;
    
    if (total_bits > max_bits) {
        printf("错误: 数据太大,无法嵌入图像\n");
        free(to_embed);
        return 0;
    }
    
    printf("开始嵌入数据: %d字节 -> %d比特\n", total_len, total_bits);
    
    // 使用随机置换表进行LSB嵌入
    int *pixel_order = (int*)malloc(img->info_hdr.width * img->info_hdr.height * sizeof(int));
    for (int i = 0; i < img->info_hdr.width * img->info_hdr.height; i++) {
        pixel_order[i] = i;
    }
    
    // Fisher-Yates洗牌算法
    for (int i = img->info_hdr.width * img->info_hdr.height - 1; i > 0; i--) {
        int j = random_uint32() % (i + 1);
        int temp = pixel_order[i];
        pixel_order[i] = pixel_order[j];
        pixel_order[j] = temp;
    }
    
    int bit_idx = 0;
    int pixel_idx = 0;
    
    // 嵌入数据,跳过Alpha通道(如果存在)
    while (pixel_idx < img->info_hdr.width * img->info_hdr.height && bit_idx < total_bits) {
        int pixel_pos = pixel_order[pixel_idx];
        int row = pixel_pos / img->info_hdr.width;
        int col = pixel_pos % img->info_hdr.width;
        
        for (int c = 0; c < bytes_per_pixel && bit_idx < total_bits; c++) {
            // 跳过Alpha通道(假设位于第4个字节)
            if (bytes_per_pixel == 4 && c == 3) continue;
            
            int pix_idx = row * row_size + col * bytes_per_pixel + c;
            if (pix_idx >= img_size) {
                printf("错误: 像素索引超出范围\n");
                free(to_embed);
                free(pixel_order);
                return 0;
            }
            
            // LSB替换
            img->pixels[pix_idx] &= 0xFE;
            img->pixels[pix_idx] |= (to_embed[bit_idx/8] >> (7 - (bit_idx%8))) & 0x01;
            bit_idx++;
        }
        
        pixel_idx++;
    }
    
    free(to_embed);
    free(pixel_order);
    printf("数据嵌入成功\n");
    return 1;
}

int extract_data(bmp_image* img, uint8_t* data, const uint8_t* aes_key, uint8_t* extracted_hash) {
    int bytes_per_pixel = img->info_hdr.bit_count / 8;
    int row_size = ((img->info_hdr.width * img->info_hdr.bit_count + 31) / 32) * 4;
    int img_size = row_size * img->info_hdr.height;
    
    printf("开始提取数据...\n");
    
    // 重新生成相同的随机置换表
    int *pixel_order = (int*)malloc(img->info_hdr.width * img->info_hdr.height * sizeof(int));
    for (int i = 0; i < img->info_hdr.width * img->info_hdr.height; i++) {
        pixel_order[i] = i;
    }
    
    seed = 12345;
    for (int i = img->info_hdr.width * img->info_hdr.height - 1; i > 0; i--) {
        int j = random_uint32() % (i + 1);
        int temp = pixel_order[i];
        pixel_order[i] = pixel_order[j];
        pixel_order[j] = temp;
    }
    
    // 提取数据长度
    uint8_t len_bytes[4] = {0};
    int bit_idx = 0;
    int pixel_idx = 0;
    
    // 提取长度信息,跳过Alpha通道
    while (pixel_idx < img->info_hdr.width * img->info_hdr.height && bit_idx < 32) {
        int pixel_pos = pixel_order[pixel_idx];
        int row = pixel_pos / img->info_hdr.width;
        int col = pixel_pos % img->info_hdr.width;
        
        for (int c = 0; c < bytes_per_pixel && bit_idx < 32; c++) {
            // 跳过Alpha通道
            if (bytes_per_pixel == 4 && c == 3) continue;
            
            int pix_idx = row * row_size + col * bytes_per_pixel + c;
            if (pix_idx >= img_size) {
                printf("错误: 像素索引超出范围\n");
                free(pixel_order);
                return 0;
            }
            
            len_bytes[bit_idx/8] |= ((img->pixels[pix_idx] & 0x01) << (7 - (bit_idx%8)));
            bit_idx++;
        }
        
        pixel_idx++;
    }
    
    int total_len = ((uint32_t)len_bytes[0] << 24) | 
                   ((uint32_t)len_bytes[1] << 16) | 
                   ((uint32_t)len_bytes[2] << 8) | 
                    len_bytes[3];
    
    printf("提取到总数据长度: %d字节\n", total_len);
    
    if (total_len <= 0 || total_len > 4096) {
        printf("错误: 提取的长度无效\n");
        free(pixel_order);
        return 0;
    }
    
    int enc_len = ((total_len + 15) / 16) * 16;
    uint8_t* encrypted = (uint8_t*)malloc(enc_len);
    
    // 提取加密数据,跳过Alpha通道
    bit_idx = 0;
    while (pixel_idx < img->info_hdr.width * img->info_hdr.height && bit_idx < enc_len * 8) {
        int pixel_pos = pixel_order[pixel_idx];
        int row = pixel_pos / img->info_hdr.width;
        int col = pixel_pos % img->info_hdr.width;
        
        for (int c = 0; c < bytes_per_pixel && bit_idx < enc_len * 8; c++) {
            // 跳过Alpha通道
            if (bytes_per_pixel == 4 && c == 3) continue;
            
            int pix_idx = row * row_size + col * bytes_per_pixel + c;
            if (pix_idx >= img_size) {
                printf("错误: 像素索引超出范围\n");
                free(encrypted);
                free(pixel_order);
                return 0;
            }
            
            encrypted[bit_idx/8] |= ((img->pixels[pix_idx] & 0x01) << (7 - (bit_idx%8)));
            bit_idx++;
        }
        
        pixel_idx++;
    }
    
    uint8_t* decrypted = (uint8_t*)malloc(total_len);
    int dec_len = aes_decrypt_batch(encrypted, enc_len, decrypted, aes_key);
    free(encrypted);
    
    if (dec_len != total_len) {
        printf("错误: 解密后数据长度不匹配\n");
        free(decrypted);
        free(pixel_order);
        return 0;
    }
    
    // 分离原始数据和哈希值
    int data_len = total_len - SHA256_DIGEST_LENGTH;
    memcpy(data, decrypted, data_len);
    memcpy(extracted_hash, decrypted + data_len, SHA256_DIGEST_LENGTH);
    
    free(decrypted);
    free(pixel_order);
    
    printf("数据提取成功: %d字节\n", data_len);
    return data_len;
}

int verify_integrity(const uint8_t* data, int len, const uint8_t* extracted_hash) {
    uint8_t computed_hash[SHA256_DIGEST_LENGTH];
    sha256(data, len, computed_hash);
    
    printf("计算的哈希值: ");
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        printf("%02x", computed_hash[i]);
    }
    printf("\n");
    
    printf("提取的哈希值: ");
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        printf("%02x", extracted_hash[i]);
    }
    printf("\n");
    
    return memcmp(computed_hash, extracted_hash, SHA256_DIGEST_LENGTH) == 0;
}

int main() {
    uint8_t aes_key[AES_KEY_SIZE] = {
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
        0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
        0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
        0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20
    };
    
    bmp_image* img = load_bmp("cover.bmp");
    if (!img) {
        printf("加载图像失败,请确保cover.bmp文件存在\n");
        return 1;
    }
    
    const char* msg = "隐写技术与密码学结合应用案例:通过AES加密与LSB隐写实现安全信息传输";
    uint8_t buf[4096] = {0};
    uint8_t extracted_hash[SHA256_DIGEST_LENGTH];
    int msg_len = strlen(msg);
    
    printf("原始消息长度: %d字节\n", msg_len);
    
    if (embed_data(img, (uint8_t*)msg, msg_len, aes_key)) {
        if (save_bmp(img, "stego.bmp")) {
            printf("数据已成功嵌入并保存到stego.bmp\n");
        } else {
            printf("保存隐写图像失败\n");
        }
    } else {
        printf("嵌入数据失败\n");
    }
    
    // 提取并验证数据
    memset(buf, 0, sizeof(buf));
    int dec_len = extract_data(img, buf, aes_key, extracted_hash);
    if (dec_len > 0) {
        buf[dec_len] = '\0';
        printf("提取的消息: %s\n", buf);
        
        if (verify_integrity(buf, dec_len, extracted_hash)) {
            printf("? 消息完整性验证通过\n");
        } else {
            printf("? 消息完整性验证失败\n");
        }
    } else {
        printf("提取数据失败\n");
    }
    
    free_bmp(img);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值