一、LED算法介绍
LED(Light Encryption Device)是一种轻量级分组密码算法,由Jian Guo等人设计,专门针对资源受限的硬件环境优化。该算法采用64位分组长度,支持64位和128位两种密钥长度,其设计灵感来源于AES,但在硬件实现上追求更小的硅片面积占用。LED标准文档的下载链接:The LED Block Cipher。
LED算法的核心结构采用了与AES相似的轮函数设计,包含四个主要操作:AddConstants(添加轮常数)、SubCells(S盒替换)、ShiftRows(行移位)和MixColumnsSerial(列混淆)。其中SubCells使用了PRESENT算法的4位S盒,提供了良好的非线性特性。MixColumnsSerial则通过一个硬件友好的MDS矩阵实现,该矩阵经过四次迭代后能达到完全扩散效果。
LED的一个显著特点是其极简的密钥调度方案——实际上它完全取消了密钥调度过程,直接重复使用原始密钥或密钥的两个部分。这种设计不仅减少了硬件实现复杂度,还使得算法在相关密钥攻击模型下也能提供可证明的安全性。通过分组操作和轮数设计,LED确保了足够的活跃S盒数量,从而抵抗差分和线性密码分析。
二、C语言实现
我们的LED算法C语言实现完整呈现了该密码算法的各个组件,通过模块化的函数设计清晰地展现了加密流程。
初始化与基本组件
实现中首先定义了LED算法所需的S盒和逆S盒,这些4位替换表是算法非线性特性的主要来源。同时预计算了GF(2⁴)有限域上的乘法表,用于后续的列混淆操作。这种查表法虽然会占用一定内存,但能显著提高运行效率,是嵌入式实现的常见优化手段。
密钥处理模块
AddKey函数实现了简单的轮密钥加操作,将64位密钥分为8个字节后,每个字节拆分为两个4位nibble与状态数组进行异或。值得注意的是,LED没有传统意义上的密钥调度算法,而是直接重复使用原始密钥,这一设计选择极大简化了实现复杂度,但也对算法的安全性证明提出了更高要求。
轮常数注入
AddConstants函数为每轮加密添加不同的常数,这些预定义的轮常数通过精心设计,确保了算法各轮之间的不对称性。实现中特别处理了状态矩阵的特定位置,使得常数添加能有效破坏可能出现的对称性攻击。轮常数的引入是预防滑动攻击等密码分析手段的重要措施。
非线性变换层
SubCells函数遍历状态矩阵的每个nibble,通过查表方式完成S盒替换。使用的4位S盒来自PRESENT算法,具有优良的密码学特性。对应的invSubCells函数则在解密过程中执行逆S盒替换,这两个函数构成了算法的核心非线性组件。
扩散操作组件
ShiftRow函数实现了类似AES的行移位操作,但针对4×4的nibble矩阵进行了调整,每行循环左移不同的偏移量。MixColumn函数则通过有限域矩阵乘法实现列混淆,使用预先计算的乘法表来优化性能。这两个扩散操作与非线性变换相互配合,确保了多轮加密后的充分混淆和扩散效果。
完整加密流程
加密函数led_encrypt_block将上述组件按特定顺序组合:初始密钥加后,进行8个大步(step)处理,每个大步包含4轮完整的加密操作。这种结构设计使得算法在硬件实现时可以获得较好的流水线效率,同时也便于进行安全性证明。
解密流程实现
解密函数led_decrypt_block采用与加密相反的步骤,使用各核心组件的逆函数。值得注意的是,轮常数的添加顺序也需要逆向处理,这体现了对称密码算法加解密对称性的特点。实现中通过调整循环顺序和调用逆函数,确保了加解密的正确互逆。
测试验证部分
提供的测试案例覆盖了全0、全1等边界情况,验证了算法实现的正确性。这些测试不仅检查了加密解密的基本功能,也验证了极端输入下的算法行为,是密码实现质量保证的重要环节。测试输出采用十六进制格式,便于人工验证结果的正确性。
#include<stdint.h>
#include<stdio.h>
static const uint8_t led_sbox[16] = {0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2};
static const uint8_t led_inv_sbox[16] = {0x5, 0xe, 0xf, 0x8, 0xc, 0x1, 0x2, 0xd, 0xb, 0x4, 0x6, 0x3, 0x0, 0x7, 0x9, 0xa};
uint8_t gmult_4bit[16][16] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
{0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x03, 0x01, 0x07, 0x05, 0x0b, 0x09, 0x0f, 0x0d},
{0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02},
{0x00, 0x04, 0x08, 0x0c, 0x03, 0x07, 0x0b, 0x0f, 0x06, 0x02, 0x0e, 0x0a, 0x05, 0x01, 0x0d, 0x09},
{0x00, 0x05, 0x0a, 0x0f, 0x07, 0x02, 0x0d, 0x08, 0x0e, 0x0b, 0x04, 0x01, 0x09, 0x0c, 0x03, 0x06},
{0x00, 0x06, 0x0c, 0x0a, 0x0b, 0x0d, 0x07, 0x01, 0x05, 0x03, 0x09, 0x0f, 0x0e, 0x08, 0x02, 0x04},
{0x00, 0x07, 0x0e, 0x09, 0x0f, 0x08, 0x01, 0x06, 0x0d, 0x0a, 0x03, 0x04, 0x02, 0x05, 0x0c, 0x0b},
{0x00, 0x08, 0x03, 0x0b, 0x06, 0x0e, 0x05, 0x0d, 0x0c, 0x04, 0x0f, 0x07, 0x0a, 0x02, 0x09, 0x01},
{0x00, 0x09, 0x01, 0x08, 0x02, 0x0b, 0x03, 0x0a, 0x04, 0x0d, 0x05, 0x0c, 0x06, 0x0f, 0x07, 0x0e},
{0x00, 0x0a, 0x07, 0x0d, 0x0e, 0x04, 0x09, 0x03, 0x0f, 0x05, 0x08, 0x02, 0x01, 0x0b, 0x06, 0x0c},
{0x00, 0x0b, 0x05, 0x0e, 0x0a, 0x01, 0x0f, 0x04, 0x07, 0x0c, 0x02, 0x09, 0x0d, 0x06, 0x08, 0x03},
{0x00, 0x0c, 0x0b, 0x07, 0x05, 0x09, 0x0e, 0x02, 0x0a, 0x06, 0x01, 0x0d, 0x0f, 0x03, 0x04, 0x08},
{0x00, 0x0d, 0x09, 0x04, 0x01, 0x0c, 0x08, 0x05, 0x02, 0x0f, 0x0b, 0x06, 0x03, 0x0e, 0x0a, 0x07},
{0x00, 0x0e, 0x0f, 0x01, 0x0d, 0x03, 0x02, 0x0c, 0x09, 0x07, 0x06, 0x08, 0x04, 0x0a, 0x0b, 0x05},
{0x00, 0x0f, 0x0d, 0x02, 0x09, 0x06, 0x04, 0x0b, 0x01, 0x0e, 0x0c, 0x03, 0x08, 0x07, 0x05, 0x0a}
};
void AddKey(uint8_t *state, const uint8_t *key) {
for (uint8_t i = 0; i < 8; i++) {
state[2 * i] ^= key[i] >> 4;
state[2 * i + 1] ^= key[i] & 0xf;
}
}
void AddConstants(uint8_t *state, uint8_t r) {
const uint8_t RC[32] = {
0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3E, 0x3D, 0x3B,
0x37, 0x2F, 0x1E, 0x3C, 0x39, 0x33, 0x27, 0x0E,
0x1D, 0x3A, 0x35, 0x2B, 0x16, 0x2C, 0x18, 0x30,
0x21, 0x02, 0x05, 0x0B, 0x17, 0x2E, 0x1C, 0x38
};
state[4] ^= 0x1;
state[8] ^= 0x2;
state[12] ^= 0x3;
uint8_t tmp = (RC[r] >> 3) & 7;
state[1] ^= tmp;
state[9] ^= tmp;
tmp = RC[r] & 7;
state[5] ^= tmp;
state[13] ^= tmp;
}
void SubCells(uint8_t *state) {
for (uint8_t i = 0; i < 16; i++) {
state[i] = led_sbox[state[i]];
}
}
void invSubCells(uint8_t *state) {
for (uint8_t i = 0; i < 16; i++) {
state[i] = led_inv_sbox[state[i]];
}
}
void ShiftRow(uint8_t *state) {
uint8_t t0, t1;
t0 = state[4];
state[4] = state[5];
state[5] = state[6];
state[6] = state[7];
state[7] = t0;
t0 = state[8];
t1 = state[9];
state[8] = state[10];
state[9] = state[11];
state[10] = t0;
state[11] = t1;
t0 = state[15];
state[15] = state[14];
state[14] = state[13];
state[13] = state[12];
state[12] = t0;
}
void invShiftRow(uint8_t *state) {
uint8_t t0, t1;
t0 = state[7];
state[7] = state[6];
state[6] = state[5];
state[5] = state[4];
state[4] = t0;
t0 = state[8];
t1 = state[9];
state[8] = state[10];
state[9] = state[11];
state[10] = t0;
state[11] = t1;
t0 = state[12];
state[12] = state[13];
state[13] = state[14];
state[14] = state[15];
state[15] = t0;
}
void MixColumn(uint8_t *state) {
uint8_t tmp[16];
for (uint8_t i = 0; i < 4; i++) {
tmp[i] = gmult_4bit[0x4][state[i]] ^ gmult_4bit[0x1][state[i + 4]] ^ gmult_4bit[0x2][state[i + 8]] ^
gmult_4bit[0x2][state[i + 12]];
tmp[i + 4] = gmult_4bit[0x8][state[i]] ^ gmult_4bit[0x6][state[i + 4]] ^ gmult_4bit[0x5][state[i + 8]] ^
gmult_4bit[0x6][state[i + 12]];
tmp[i + 8] = gmult_4bit[0xb][state[i]] ^ gmult_4bit[0xe][state[i + 4]] ^ gmult_4bit[0xa][state[i + 8]] ^
gmult_4bit[0x9][state[i + 12]];
tmp[i + 12] = gmult_4bit[0x2][state[i]] ^ gmult_4bit[0x2][state[i + 4]] ^ gmult_4bit[0xf][state[i + 8]] ^
gmult_4bit[0xb][state[i + 12]];
}
for (uint8_t i = 0; i < 16; i++) {
state[i] = tmp[i];
}
}
void invMixColumn(uint8_t *state) {
uint8_t tmp[16];
for (uint8_t i = 0; i < 4; i++) {
tmp[i] = gmult_4bit[0xc][state[i]] ^ gmult_4bit[0xc][state[i + 4]] ^ gmult_4bit[0xd][state[i + 8]] ^
gmult_4bit[0x4][state[i + 12]];
tmp[i + 4] = gmult_4bit[0x3][state[i]] ^ gmult_4bit[0x8][state[i + 4]] ^ gmult_4bit[0x4][state[i + 8]] ^
gmult_4bit[0x5][state[i + 12]];
tmp[i + 8] = gmult_4bit[0x7][state[i]] ^ gmult_4bit[0x6][state[i + 4]] ^ gmult_4bit[0x2][state[i + 8]] ^
gmult_4bit[0xe][state[i + 12]];
tmp[i + 12] = gmult_4bit[0xd][state[i]] ^ gmult_4bit[0x9][state[i + 4]] ^ gmult_4bit[0x9][state[i + 8]] ^
gmult_4bit[0xd][state[i + 12]];
}
for (uint8_t i = 0; i < 16; i++) {
state[i] = tmp[i];
}
}
void led_encrypt_block(const uint8_t *plain, uint8_t *cipher, const uint8_t *key) {
uint8_t state[16];
for (uint8_t i = 0; i < 4; i++) {
state[2 * i] = plain[3 - i] >> 4;
state[2 * i + 1] = plain[3 - i] & 0xf;
state[2 * i + 8] = plain[7 - i] >> 4;
state[2 * i + 9] = plain[7 - i] & 0xf;
}
uint8_t ikey[8];
for (int i = 0; i < 4; i++) {
ikey[i] = key[3 - i];
ikey[i + 4] = key[7 - i];
}
AddKey(state, ikey);
for (uint8_t i = 0; i < 8; i++) {
for (uint8_t j = 0; j < 4; j++) {
AddConstants(state, 4 * i + j);
SubCells(state);
ShiftRow(state);
MixColumn(state);
}
AddKey(state, ikey);
}
for (uint8_t i = 0; i < 4; i++) {
cipher[3 - i] = (state[2 * i] << 4) | (state[2 * i + 1] & 0xf);
cipher[7 - i] = (state[2 * i + 8] << 4) | (state[2 * i + 9] & 0xf);
}
}
void led_decrypt_block(const uint8_t *cipher, uint8_t *plain, const uint8_t *key) {
uint8_t state[16];
for (uint8_t i = 0; i < 4; i++) {
state[2 * i] = cipher[3 - i] >> 4;
state[2 * i + 1] = cipher[3 - i] & 0xf;
state[2 * i + 8] = cipher[7 - i] >> 4;
state[2 * i + 9] = cipher[7 - i] & 0xf;
}
uint8_t ikey[8];
for (int i = 0; i < 4; i++) {
ikey[i] = key[3 - i];
ikey[i + 4] = key[7 - i];
}
AddKey(state, ikey);
for (int i = 7; i >= 0; i--) {
for (int j = 3; j >= 0; j--) {
invMixColumn(state);
invShiftRow(state);
invSubCells(state);
AddConstants(state, 4 * i + j);
}
AddKey(state, ikey);
}
for (uint8_t i = 0; i < 4; i++) {
plain[3 - i] = (state[2 * i] << 4) | (state[2 * i + 1] & 0xf);
plain[7 - i] = (state[2 * i + 8] << 4) | (state[2 * i + 9] & 0xf);
}
}
void print_data(uint8_t *data, int data_len, const char *name) {
printf("\t%s: ", name);
for (int i = 0; i < data_len; i++) {
printf("%02x ", data[i]);
}
printf("\n");
}
void test_case1() {
printf("test case 3:\n");
uint8_t mkey[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t plain[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t cipher[8] = {0};
uint8_t decrypted_plain[8] = {0};
print_data(plain, 8, "plaintext");
print_data(mkey, 8, "mkey");
led_encrypt_block(plain, cipher, mkey);
print_data(cipher, 8, "ciphertext");
led_decrypt_block(cipher, decrypted_plain, mkey);
print_data(decrypted_plain, 8, "decrypted plaintext");
}
void test_case2() {
printf("test case 3:\n");
uint8_t mkey[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t plain[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t cipher[8] = {0};
uint8_t decrypted_plain[8] = {0};
print_data(plain, 8, "plaintext");
print_data(mkey, 8, "mkey");
led_encrypt_block(plain, cipher, mkey);
print_data(cipher, 8, "ciphertext");
led_decrypt_block(cipher, decrypted_plain, mkey);
print_data(decrypted_plain, 8, "decrypted plaintext");
}
void test_case3() {
printf("test case 3:\n");
uint8_t mkey[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t plain[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t cipher[8] = {0};
uint8_t decrypted_plain[8] = {0};
print_data(plain, 8, "plaintext");
print_data(mkey, 8, "mkey");
led_encrypt_block(plain, cipher, mkey);
print_data(cipher, 8, "ciphertext");
led_decrypt_block(cipher, decrypted_plain, mkey);
print_data(decrypted_plain, 8, "decrypted plaintext");
}
void test_case4() {
printf("test case 3:\n");
uint8_t mkey[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t plain[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t cipher[8] = {0};
uint8_t decrypted_plain[8] = {0};
print_data(plain, 8, "plaintext");
print_data(mkey, 8, "mkey");
led_encrypt_block(plain, cipher, mkey);
print_data(cipher, 8, "ciphertext");
led_decrypt_block(cipher, decrypted_plain, mkey);
print_data(decrypted_plain, 8, "decrypted plaintext");
}
int main(){
test_case1();
test_case2();
test_case3();
test_case4();
return 0;
}
三、总结
LED算法通过精简的设计在硬件效率和安全性之间取得了良好平衡。其取消密钥调度的创新设计大大减少了硬件实现面积,同时通过数学证明保证了安全性。C语言实现展示了算法各组成模块的细节,包括S盒替换、行移位、列混淆等核心操作。
该实现完整呈现了LED的加密解密流程,通过测试案例验证了正确性。在实际应用中,LED特别适合RFID标签、传感器网络等资源受限环境,其小面积实现(约1000GE左右)和低功耗特性使其在物联网安全领域具有应用潜力。