首页 > 其他分享 >基于RFC3394标准的AES-128-ECB模式的密钥封装(Key Wrap)和解封(Key Unwrap)

基于RFC3394标准的AES-128-ECB模式的密钥封装(Key Wrap)和解封(Key Unwrap)

时间:2024-10-24 15:51:41浏览次数:8  
标签:ECB tciphertext CTX ctx uint8 EVP Key printf Wrap

  1. 密钥封装(Key Wrap):

    • RFC3394默认IV为0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
    • 使用AES_Encrypt函数对IV和密钥数据块进行加密,并将结果与步数异或。
    • 经过6n轮迭代后,将最终的IV和加密后的数据块复制到输出的密文中。
  2. 密钥解封(Key Unwrap):

    • 从输入的密文中提取了IV和加密的数据块。
    • 逆向执行了6n轮迭代,使用AES_Decrypt函数进行解密,并将结果与步数异或。
    • 最后将解密后的数据块复制到输出的明文中。
  3. 注意事项:

    • AES_EncryptAES_Decrypt函数中关闭了自动填充功能,因为RFC3394算法不使用填充。
    • 使用了EVP_CIPHER_CTX_newEVP_CIPHER_CTX_free来管理加密上下文。
    • 在加密和解密函数中检查了每个EVP函数调用的返回值,以确保操作成功。

 

#include <openssl/aes.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <string.h>

void AES_Encrypt(uint8_t* plaintext1, uint8_t* plaintext2, uint8_t* key)
{
    unsigned char tplaintext[16];
    unsigned char tciphertext[32];

    memset(tplaintext, 0, sizeof(tplaintext));
    memset(tciphertext, 0, sizeof(tciphertext));
    memcpy(tplaintext, plaintext1, 8);
    memcpy(tplaintext + 8, plaintext2, 8);

    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) 
    {
        printf("Error creating cipher context!\n");
        return;
    }

    //初始化加密操作
    if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL)) 
    {
        printf("Error initializing encryption!\n");
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    //不使用自动填充功能
    EVP_CIPHER_CTX_set_padding(ctx, 0);

    //执行加密操作
    int outlen;
    if (1 != EVP_EncryptUpdate(ctx, tciphertext, &outlen, tplaintext, 16)) 
    {
        printf("Error encrypting plaintext!\n");
        EVP_CIPHER_CTX_free(ctx);
        return;
    }

    //结束加密操作
    int templen;
    if (1 != EVP_EncryptFinal_ex(ctx, tciphertext + outlen, &templen)) 
    {
        printf("Error finalizing encryption!\n");
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    outlen += templen;

    printf("Ciphertext is:\n");
    for (int i = 0; i < 16; i++) 
    {
        printf("%02x", tciphertext[i]);
        if ((i+1) % 8 == 0) printf(" ");
    }
    printf("\n");

    //清理资源
    EVP_CIPHER_CTX_free(ctx);
    memcpy(plaintext1, tciphertext, 8);
    memcpy(plaintext2, tciphertext + 8, 8);
}

void AES_Decrypt(uint8_t* ciphertext1, uint8_t* ciphertext2, uint8_t* key)
{
    unsigned char tplaintext[32];
    unsigned char tciphertext[16];

    memset(tplaintext, 0, sizeof(tplaintext));
    memset(tciphertext, 0, sizeof(tciphertext));
    memcpy(tciphertext, ciphertext1, 8);
    memcpy(tciphertext + 8, ciphertext2, 8);

    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (!ctx) 
    {
        printf("Error creating cipher context!\n");
        return;
    }

    if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL)) 
    {
        printf("Error initializing decryption!\n");
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    //不使用自动填充功能
    EVP_CIPHER_CTX_set_padding(ctx, 0);

    int outlen;
    if (1 != EVP_DecryptUpdate(ctx, tplaintext, &outlen, tciphertext, 16))
    {
        printf("Error decrypting ciphertext!\n");
        EVP_CIPHER_CTX_free(ctx);
        return;
    }

    int templen;
    if (1 != EVP_DecryptFinal_ex(ctx, tciphertext + outlen, &templen)) 
    {
        printf("Error finalizing decryption!\n");
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    outlen += templen;

    printf("Plaintext is:\n");
    for (int i = 0; i < 16; i++) 
    {
        printf("%02x", tciphertext[i]);
        if ((i + 1) % 8 == 0) printf(" ");
    }
    printf("\n");

    EVP_CIPHER_CTX_free(ctx);
    memcpy(ciphertext1, tplaintext, 8);
    memcpy(ciphertext2, tplaintext + 8, 8);
}

//根据RFC3394算法进行密钥封装
void KeyWrap(uint8_t* kek, uint8_t* plaintext, int plaintext_len, uint8_t* ciphertext) 
{
    uint8_t IV[8] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
    uint8_t R[2][8]; //存储密钥数据块
    //将明文密钥数据复制到R中
    memcpy(R[0], plaintext, plaintext_len);

    //执行6n轮迭代
    for (int i = 0; i < 6 * (plaintext_len / 8); i++)
    {
        //将IV与R[0]R[1]轮流进行AES加密,并将结果与i+1异或
        AES_Encrypt(IV, R[i % 2], kek); //加密
        IV[7] ^= (uint8_t)(i + 1); //与步数异或
    }
    memcpy(ciphertext, IV, sizeof(IV));
    memcpy(ciphertext + sizeof(IV), R[0], sizeof(R));
}

void KeyUnWrap(uint8_t* kek, uint8_t* plaintext, uint8_t* ciphertext, int ciphertext_len) 
{
    uint8_t R[3][8]; //存储密钥数据块
    int plaintext_len = ciphertext_len - 8;

    //将密文数据复制到R中
    memcpy(R[0], ciphertext, ciphertext_len);

    //执行6n轮迭代
    for (int i = 6 * (plaintext_len / 8); i > 0; i--)
    {
        R[0][7] ^= (uint8_t)i; //与步数异或
        AES_Decrypt(R[0], R[(i - 1) % 2 + 1], kek); //进行ECB解密
    }
    memcpy(plaintext, R[1], plaintext_len);
}

int main() {
    uint8_t kek[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
    uint8_t plaintext[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
    uint8_t ciphertext[24];

    KeyWrap(kek, plaintext, 16, ciphertext);
    printf("Ciphertext: ");
    for (int i = 0; i < 24; ++i) {
        printf("%02X ", ciphertext[i]);
    }
    printf("\n");

    KeyUnWrap(kek, plaintext, ciphertext, 24);
    printf("Plaintext: ");
    for (int i = 0; i < 16; ++i) {
        printf("%02X ", plaintext[i]);
    }
    printf("\n");

    return 0;
}

标签:ECB,tciphertext,CTX,ctx,uint8,EVP,Key,printf,Wrap
From: https://blog.csdn.net/2201_75357739/article/details/143211060

相关文章

  • WinForm 简单实现仿WPF的WrapPanel和StackPanel
    publicinterfaceIDesiredPanel{SizeGetDesiredSize(intavailableWidth,intavaiableHeight);}publicclassStackPanel:Panel,IDesiredPanel{protectedoverridevoidOnLayout(LayoutEventArgslevent){base.OnLayout(levent);......
  • keycloak~token配置相关说明
    会话有效期在Keycloak中,"SSOSessionIdle"和"SSOSessionMax"是用于配置单点登录(SSO)会话的两个参数。这两个参数影响用户在系统中的会话过期和最大有效时间。SSOSessionIdle(单点登录会话空闲时间):定义:表示用户在系统中没有活动的时间阈值。如果用户在这段时间内没......
  • 开源图像超分ECBSR项目源码分析
    相关介绍项目GitHub地址:https://github.com/xindongzhang/ECBSR项目相关论文:https://www4.comp.polyu.edu.hk/~cslzhang/paper/MM21_ECBSR.pdf(也可以点这里下载)论文解读:Edge-orientedConvolutionBlockforReal-timeSuperResolutiononMobileDevicesWindows环境训练......
  • 最新激活Navicat 15教程,附Keygen Patch
    前言大家好,我是小徐啊。navicat是一款常用的数据库连接工具,但是它本身是需要收费的,很不方便。那么,有没有免费的方式呢?今天小徐就介绍下如何激活navicat的方式,永久激活。文末附获取方式。如何安装首先,双击navicat的安装包,开始安装,旁边的就是激活工具,待会再打开。然后,点击下一......
  • 【OpenAI】第一节(OpenAI API)获取OpenAI API KEY的两种方式,开发者必看全方面教程!
    在当今人工智能迅猛发展的时代,OpenAI的大模型为开发者提供了强大的文本生成能力。无论你是想创建聊天机器人、内容生成工具,还是其他创新应用,掌握如何获取和使用OpenAIAPIKey是你迈向成功的第一步!本文将详细介绍获取APIKey的步骤、充值方法以及如何在项目中调用API......
  • keycloak~Consent Required的使用
    ConsentRequired在keycloak中是“授权所需”,或者是“同意必需“的意思,它类似于oauth2授权时的“确认”,当你在第三方认证后,通过oauth2协议,你可以把用户相关信息返回给应用程序,而这时,用户自己需要确认一下,自己的这些信息是否可以给应用程序。为客户端配置ConsentRequired选项可......
  • 设置显示或者隐藏MasterSeeker和Total Commander主窗口的快捷键的AutoHotkey脚本2024.
    设置显示或者隐藏MasterSeeker和TotalCommander主窗口的快捷键的AutoHotkey脚本2024.10.21=========  ;========设置显示或者隐藏MasterSeeker和TotalCommander主窗口的快捷键的AutoHotkey脚本2024.10.21=========;此脚本从此行开始;D:\app\RegHotkey\RegHotkey.a......
  • KeyShot基础操作5 - 动画篇
    --本篇导航--动画界面动画类型动画时间轴导出动画一些例子注:本人目前只会简单的动画,摄像机运镜、速度曲线这些还控制不好。以下均为简单演示。动画界面KeyShot中的动画每次只能是一个动作,如果需要对同一个对象创建复杂的动画,就需要对其多次添加不同的动画效果。做......
  • DES加密,哪位大神能看看我的key_round函数为啥生成的子密钥不对啊/(ㄒoㄒ)/~~球球了
    #include<stdio.h>voidIPchange(intpt[],intIP[]){  for(inti=0;i<64;++i)  {    pt[i]=pt[IP[i]-1];  }}voidIP_1change(intct[],intIP_1[]){  for(inti=0;i<64;i++)  {    ct[i]=ct[IP_1[i]......
  • 桌面软件/exe程序软件自动化大宝剑--lackey之二次封装以及selenium模仿
    1#lackey二次封装23classlackeyAtion(object):45#初始化,有需要再加6def__init__(self):7self.lackey=lackey.Screen(0)8self.lackey.setAutoWaitTimeout(30)910#截屏需要保存路径,截图的名字11de......