硬汉嵌入式论坛

 找回密码
 立即注册
查看: 265|回复: 0
收起左侧

[Lua] LUA小程序实现的AES ECB 128bit加密和解密

[复制链接]

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
123167
QQ
发表于 2026-6-8 09:00:33 | 显示全部楼层 |阅读模式




1224.png

[Lua] 纯文本查看 复制代码
-- ============================================================
-- AES-128 ECB 纯 Lua 实现
-- ============================================================

local AES = {}

-- S盒
local S_BOX = {
    0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
    0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
    0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
    0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
    0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
    0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
    0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
    0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
    0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
    0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
    0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
    0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
    0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
    0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
    0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
    0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
}

-- 逆S盒
local INV_S_BOX = {}
for i = 0, 255 do
    for j = 0, 255 do
        if S_BOX[j+1] == i then
            INV_S_BOX[i+1] = j
            break
        end
    end
end

-- 轮常数
local RCON = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36}

-- GF(2^8)乘法
local function gmul(a, b)
    local p = 0
    for i = 1, 8 do
        if (b & 1) ~= 0 then p = p ~ a end
        local hi = (a & 0x80) ~= 0
        a = (a << 1) & 0xff
        if hi then a = a ~ 0x1b end
        b = b >> 1
    end
    return p
end

-- 密钥扩展 (AES-128: 16字节密钥 → 176字节扩展密钥)
local function key_expansion(key)
    local w = {}
    for i = 0, 3 do
        w[i] = {key[4*i+1], key[4*i+2], key[4*i+3], key[4*i+4]}
    end
    for i = 4, 43 do
        local temp = {w[i-1][1], w[i-1][2], w[i-1][3], w[i-1][4]}
        if i % 4 == 0 then
            temp = {S_BOX[temp[2]+1], S_BOX[temp[3]+1], S_BOX[temp[4]+1], S_BOX[temp[1]+1]}
            temp[1] = temp[1] ~ RCON[i/4]
        end
        w[i] = {
            w[i-4][1] ~ temp[1],
            w[i-4][2] ~ temp[2],
            w[i-4][3] ~ temp[3],
            w[i-4][4] ~ temp[4]
        }
    end
    -- 展开为字节数组
    local exp_key = {}
    for i = 0, 43 do
        exp_key[4*i+1] = w[i][1]
        exp_key[4*i+2] = w[i][2]
        exp_key[4*i+3] = w[i][3]
        exp_key[4*i+4] = w[i][4]
    end
    return exp_key
end

-- 将16字节state转为4x4列主序矩阵
local function bytes_to_state(data, offset)
    local state = {}
    for r = 0, 3 do
        state[r] = {}
        for c = 0, 3 do
            state[r][c] = data[offset + c*4 + r + 1]
        end
    end
    return state
end

local function state_to_bytes(state)
    local out = {}
    for c = 0, 3 do
        for r = 0, 3 do
            out[c*4 + r + 1] = state[r][c]
        end
    end
    return out
end

-- AES加密一轮的四个操作
local function sub_bytes(state)
    for r = 0, 3 do
        for c = 0, 3 do
            state[r][c] = S_BOX[state[r][c]+1]
        end
    end
end

local function shift_rows(state)
    -- 第1行左移1,第2行左移2,第3行左移3
    local t = state[1][0]; state[1][0]=state[1][1]; state[1][1]=state[1][2]; state[1][2]=state[1][3]; state[1][3]=t
    t = state[2][0]; state[2][0]=state[2][2]; state[2][2]=t; t=state[2][1]; state[2][1]=state[2][3]; state[2][3]=t
    t = state[3][0]; state[3][0]=state[3][3]; state[3][3]=state[3][2]; state[3][2]=state[3][1]; state[3][1]=t
end

local function mix_columns(state)
    for c = 0, 3 do
        local a0,a1,a2,a3 = state[0][c], state[1][c], state[2][c], state[3][c]
        state[0][c] = gmul(2,a0) ~ gmul(3,a1) ~ a2 ~ a3
        state[1][c] = a0 ~ gmul(2,a1) ~ gmul(3,a2) ~ a3
        state[2][c] = a0 ~ a1 ~ gmul(2,a2) ~ gmul(3,a3)
        state[3][c] = gmul(3,a0) ~ a1 ~ a2 ~ gmul(2,a3)
    end
end

local function add_round_key(state, round_key, offset)
    for r = 0, 3 do
        for c = 0, 3 do
            state[r][c] = state[r][c] ~ round_key[offset + c*4 + r + 1]
        end
    end
end

-- AES-128加密单个16字节块
local function encrypt_block(plaintext, ek, offset)
    local state = bytes_to_state(plaintext, offset)
    add_round_key(state, ek, 0)
    for round = 1, 9 do
        sub_bytes(state)
        shift_rows(state)
        mix_columns(state)
        add_round_key(state, ek, round * 16)
    end
    sub_bytes(state)
    shift_rows(state)
    add_round_key(state, ek, 160)  -- 第10轮
    return state_to_bytes(state)
end

-- PKCS#7 填充
local function pkcs7_pad(data, block_size)
    local pad_len = block_size - (#data % block_size)
    if pad_len == 0 then pad_len = block_size end
    local padded = data
    for i = 1, pad_len do
        padded = padded .. string.char(pad_len)
    end
    return padded
end

-- PKCS#7 去填充
local function pkcs7_unpad(data)
    local pad_len = data:byte(#data)
    if pad_len > 0 and pad_len <= 16 then
        return data:sub(1, #data - pad_len)
    end
    return data
end

-- ============================================================
-- 公开API
-- ============================================================

-- key: 16字节字符串
-- plaintext: 明文字符串
-- 返回: 密文(二进制字符串)
function AES.encrypt_ecb(key_str, plaintext)
    assert(#key_str == 16, "AES-128 密钥必须为16字节")
    local key = {key_str:byte(1, 16)}
    local ek = key_expansion(key)
    local padded = pkcs7_pad(plaintext, 16)
    local ciphertext = ""
    for i = 1, #padded, 16 do
        local block = {padded:byte(i, i+15)}
        local enc = encrypt_block(block, ek, 0)
        for j = 1, 16 do
            ciphertext = ciphertext .. string.char(enc[j])
        end
    end
    return ciphertext
end

-- 解密(附带,方便测试)
local function inv_sub_bytes(state)
    for r = 0, 3 do
        for c = 0, 3 do
            state[r][c] = INV_S_BOX[state[r][c]+1]
        end
    end
end

local function inv_shift_rows(state)
    local t = state[1][3]; state[1][3]=state[1][2]; state[1][2]=state[1][1]; state[1][1]=state[1][0]; state[1][0]=t
    t = state[2][0]; state[2][0]=state[2][2]; state[2][2]=t; t=state[2][1]; state[2][1]=state[2][3]; state[2][3]=t
    t = state[3][3]; state[3][3]=state[3][0]; state[3][0]=state[3][1]; state[3][1]=state[3][2]; state[3][2]=t
end

local function inv_mix_columns(state)
    for c = 0, 3 do
        local a0,a1,a2,a3 = state[0][c], state[1][c], state[2][c], state[3][c]
        state[0][c] = gmul(14,a0) ~ gmul(11,a1) ~ gmul(13,a2) ~ gmul(9,a3)
        state[1][c] = gmul(9,a0)  ~ gmul(14,a1) ~ gmul(11,a2) ~ gmul(13,a3)
        state[2][c] = gmul(13,a0) ~ gmul(9,a1)  ~ gmul(14,a2) ~ gmul(11,a3)
        state[3][c] = gmul(11,a0) ~ gmul(13,a1) ~ gmul(9,a2)  ~ gmul(14,a3)
    end
end

local function decrypt_block(ciphertext, ek, offset)
    local state = bytes_to_state(ciphertext, offset)
    add_round_key(state, ek, 160)
    for round = 9, 1, -1 do
        inv_shift_rows(state)
        inv_sub_bytes(state)
        add_round_key(state, ek, round * 16)
        inv_mix_columns(state)
    end
    inv_shift_rows(state)
    inv_sub_bytes(state)
    add_round_key(state, ek, 0)
    return state_to_bytes(state)
end

function AES.decrypt_ecb(key_str, ciphertext)
    assert(#key_str == 16, "AES-128 密钥必须为16字节")
    local key = {key_str:byte(1, 16)}
    local ek = key_expansion(key)
    local plaintext = ""
    for i = 1, #ciphertext, 16 do
        local block = {ciphertext:byte(i, i+15)}
        local dec = decrypt_block(block, ek, 0)
        for j = 1, 16 do
            plaintext = plaintext .. string.char(dec[j])
        end
    end
    return pkcs7_unpad(plaintext)
end

-- ============================================================
-- 测试
-- ============================================================
-- NIST 标准测试向量
local key    = "0123456789abcdef"   -- 16字节
local pt     = "0123456789abcdef"   -- 恰好16字节(无填充)
local ct     = AES.encrypt_ecb(key, pt)
local pt2    = AES.decrypt_ecb(key, ct)

print("密钥:        " .. key)
print("明文:        " .. pt)
print("解密还原:    " .. pt2)
print("加解密一致:  " .. tostring(pt == pt2))

-- 打印密文(hex格式)
print("密文(hex): ")
for i = 1, #ct do
    io.write(string.format("%02X ", ct:byte(i)))
    if i % 16 == 0 then print() end
end


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-6-25 06:03 , Processed in 1.077389 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表