五、m序列
1、线性反馈移位寄存器的多项式表示
(1)在上一节中已经使用了递推公式描述LFSR,但这种形式不便于分析序列的周期、线性复杂度等性质,而多项式是数学里分析线性递推关系的"利器",它能把递推关系转化为多项式运算,直接关联到密码学关心的核心指标。
(2)延迟算子与LFSR一元多项式表示:
(3)生成函数的定义及定理:
①生成函数的定义:
②定理1:
③定理2:
④定理3:
2、m序列产生的条件
(1)不可约多项式与本原多项式:
①不可约多项式:
②本原多项式:
(2)m序列产生的必要条件:
(3)m序列产生的充要条件:
(4)m序列举例:
3、m序列的伪随机性
4、m序列的安全性
(1)已知m序列,推算相应的反馈多项式方法:
(2)解方程方法举例:
①例1:
②例2:
(3)线性反馈移位寄存器综合解:
①设计或求解LSFR时,主要考虑以下两个问题:
1\]如何利用级数尽可能短的LFSR产生周期大、随机性能良好的序列。这是从密钥生成角度考虑,用最小的代价产生尽可能好的、参与密码变换的序列。
\[2\]当已知一个长为N的序列时,如何构造一个级数尽可能小的LFSR来产生它。这是从密码分析角度来考虑,花费最小的代价,用线性方法重构密钥序列。
②线性综合解:

③LFSR综合问题:

④Berlekamp-Massey算法:





## 六、非线性序列
### 1、Geffe序列生成器
(1)Geffe序列生成器的结构:
Geffe序列生成器由3个LFSR组成,其中LFSR2作为控制生成器使用,如下图所示
当LFSR2输出1时,LFSR2与LFSR1相连接
当LFSR2输出0时,LFSR2与LFSR3相连接

(2)Geffe序列生成器的工作逻辑:

(3)Geffe序列生成器的C语言实现:
```cpp
#include
#include
#include
// 定义LFSR结构体
typedef struct {
uint32_t state; // 寄存器状态(最高位为抽头位)
uint32_t mask; // 抽头掩码(反馈多项式中抽头位对应1)
uint32_t poly; // 反馈多项式(仅用于初始化掩码)
int width; // 寄存器位宽
} LFSR;
// 初始化LFSR:设置状态和抽头掩码(根据多项式)
void lfsr_init(LFSR *lfsr, uint32_t seed, uint32_t polynomial, int width) {
lfsr->state = seed & ((1ULL << width) - 1); // 限制在width位内
if (lfsr->state == 0) lfsr->state = 1; // 避免全0状态
lfsr->poly = polynomial;
lfsr->width = width;
// 构建掩码:多项式中所有非零项对应的位数(抽头位置)
lfsr->mask = 0;
for (int i = 0; i < width; i++) {
if (polynomial & (1 << i)) {
lfsr->mask |= (1 << i);
}
}
}
// 时钟一次:计算反馈位,移位,返回输出位(移出的最高位)
uint8_t lfsr_clock(LFSR *lfsr) {
// 计算反馈位:所有抽头位的异或(计算掩码内的位)
uint32_t feedback = 0;
uint32_t masked = lfsr->state & lfsr->mask;
// 快速奇偶校验(计算所有位的异或)
feedback = masked ^ (masked >> 16);
feedback ^= feedback >> 8;
feedback ^= feedback >> 4;
feedback ^= feedback >> 2;
feedback ^= feedback >> 1;
feedback &= 1;
// 输出位为移出的最高位(第width-1位)
uint8_t output = (lfsr->state >> (lfsr->width - 1)) & 1;
// 左移一位,将反馈位放入最低位
lfsr->state = ((lfsr->state << 1) & ((1ULL << lfsr->width) - 1)) | feedback;
return output;
}
// 生成一个比特的Geffe输出
uint8_t geffe_bit(LFSR *lfsr1, LFSR *lfsr2, LFSR *lfsr3) {
uint8_t b1 = lfsr_clock(lfsr1);
uint8_t b2 = lfsr_clock(lfsr2);
uint8_t b3 = lfsr_clock(lfsr3);
// 若b3=1,输出b1;否则输出b2
return b3 ? b1 : b2;
}
// 生成一个密钥字节(8个连续比特)
uint8_t geffe_byte(LFSR *lfsr1, LFSR *lfsr2, LFSR *lfsr3) {
uint8_t byte = 0;
for (int i = 0; i < 8; i++) {
byte = (byte << 1) | geffe_bit(lfsr1, lfsr2, lfsr3);
}
return byte;
}
// 加密函数:数据与Geffe生成的密钥流异或(原地操作)
void geffe_encrypt(uint8_t *data, size_t len,
uint32_t seed1, uint32_t seed2, uint32_t seed3) {
LFSR lfsr1, lfsr2, lfsr3;
// 使用三个不同本原多项式(长度分别为 13, 15, 17)
// 多项式以二进制表示:x^13 + x^4 + x^3 + x + 1 -> 0x201B (bit13=1, bit4=1, bit3=1, bit1=1)
lfsr_init(&lfsr1, seed1, (1 << 13) | (1 << 4) | (1 << 3) | (1 << 1) | 1, 13);
lfsr_init(&lfsr2, seed2, (1 << 15) | (1 << 1) | 1, 15); // x^15 + x + 1
lfsr_init(&lfsr3, seed3, (1 << 17) | (1 << 3) | 1, 17); // x^17 + x^3 + 1
for (size_t i = 0; i < len; i++) {
uint8_t keystream = geffe_byte(&lfsr1, &lfsr2, &lfsr3);
data[i] ^= keystream;
}
}
// 解密函数(与加密相同,因为异或对称)
void geffe_decrypt(uint8_t *data, size_t len,
uint32_t seed1, uint32_t seed2, uint32_t seed3) {
geffe_encrypt(data, len, seed1, seed2, seed3);
}
// 辅助函数:打印十六进制
void print_hex(const uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) {
printf("%02X ", data[i]);
}
printf("\n");
}
int main() {
// 明文示例
uint8_t plaintext[] = "Geffe sequence generator example!";
size_t len = strlen((char*)plaintext);
// 三个种子(密钥),不能为0,且应小于各自LFSR的最大周期
uint32_t seed1 = 0x1A2B; // 13位,小于8192
uint32_t seed2 = 0x3C4D; // 15位,小于32768
uint32_t seed3 = 0x5E6F; // 17位,小于131072
printf("原始明文: %s\n", plaintext);
printf("明文(HEX): ");
print_hex(plaintext, len);
// 加密
geffe_encrypt(plaintext, len, seed1, seed2, seed3);
printf("密文(HEX): ");
print_hex(plaintext, len);
// 解密(使用相同种子)
geffe_decrypt(plaintext, len, seed1, seed2, seed3);
printf("解密后明文: %s\n", plaintext);
return 0;
}
```
### 2、J-K触发器与Pless生成器
(1)J-K触发器的结构:

(2)利用1个J-K触发器构成的非线性序列生成器:

(3)利用1个J-K触发器构成的非线性序列生成器的弱点:

(4)Pless生成器的结构:
Pless生成器由8个LFSR、4个J-K触发器和1个循环计数器构成,由循环计数器进行选通控制,如图所示

(5)Pless生成器的C语言实现:
```cpp
#include
#include
#include
#include
// ---------- 1. LFSR 结构体及实现 ----------
typedef struct {
uint32_t state;
uint32_t poly;
uint8_t width;
} LFSR;
void lfsr_init(LFSR *lfsr, uint32_t seed, uint32_t poly, uint8_t width) {
lfsr->state = seed & ((1UL << width) - 1);
if (lfsr->state == 0 && width < 32) lfsr->state = 1;
lfsr->poly = poly;
lfsr->width = width;
}
uint8_t lfsr_clock(LFSR *lfsr) {
uint8_t fb_bit = 0;
for (uint8_t i = 0; i < lfsr->width; i++) {
if ((lfsr->poly >> i) & 1) {
fb_bit ^= (lfsr->state >> i) & 1;
}
}
uint8_t output_bit = (lfsr->state >> (lfsr->width - 1)) & 1;
lfsr->state = ((lfsr->state << 1) & ((1UL << lfsr->width) - 1)) | fb_bit;
return output_bit;
}
// ---------- 2. JK 触发器结构体及实现 ----------
typedef struct {
uint8_t q; // 当前输出状态
} JK_FlipFlop;
void jk_init(JK_FlipFlop *jk, uint8_t init_q) {
jk->q = init_q; // 初始化为 0 或 1
}
uint8_t jk_clock(JK_FlipFlop *jk, uint8_t j, uint8_t k) {
uint8_t next_q;
if (j == 0 && k == 0) {
next_q = jk->q; // 保持当前状态
}
else if (j == 0 && k == 1) {
next_q = 0; // 复位 (Reset)
}
else if (j == 1 && k == 0) {
next_q = 1; // 置位 (Set)
}
else { // (j == 1 && k == 1)
next_q = 1 ^ jk->q; // 翻转 (Toggle)
}
jk->q = next_q;
return jk->q;
}
// ---------- 3. Pless 生成器 ----------
#define NUM_LFSR_PAIRS 4
typedef struct {
LFSR lfsr_j;
LFSR lfsr_k;
JK_FlipFlop jk;
} PlessUnit;
typedef struct {
PlessUnit units[NUM_LFSR_PAIRS];
uint8_t counter; // 循环计数器 (0 到 NUM_LFSR_PAIRS-1)
} PlessGenerator;
// 初始化Pless生成器
void pless_init(PlessGenerator *pg, const uint32_t seeds_J[4], const uint32_t seeds_K[4]) {
// 8个LFSR的多项式和位宽(示例参数,可按需调整)
const uint32_t polys_J[NUM_LFSR_PAIRS] = { 0x8003, 0x801B, 0x8021, 0x803D }; // x^15 + x + 1, 等等
const uint32_t polys_K[NUM_LFSR_PAIRS] = { 0x8049, 0x8065, 0x808F, 0x8020 }; // 不同多项式
const uint8_t width_J[NUM_LFSR_PAIRS] = { 15, 15, 15, 15 };
const uint8_t width_K[NUM_LFSR_PAIRS] = { 15, 15, 15, 15 };
for (int i = 0; i < NUM_LFSR_PAIRS; i++) {
lfsr_init(&pg->units[i].lfsr_j, seeds_J[i], polys_J[i], width_J[i]);
lfsr_init(&pg->units[i].lfsr_k, seeds_K[i], polys_K[i], width_K[i]);
jk_init(&pg->units[i].jk, 0);
}
pg->counter = 0;
}
// 产生1位密钥流 -> Pless生成器的一个时钟
uint8_t pless_clock(PlessGenerator *pg) {
// 1. 从循环计数器中选择当前的单元
uint8_t idx = pg->counter;
PlessUnit *unit = &pg->units[idx];
// 2. 驱动选中的两个LFSR各前进1步,产生JK触发器的J和K输入
uint8_t j_in = lfsr_clock(&unit->lfsr_j);
uint8_t k_in = lfsr_clock(&unit->lfsr_k);
// 3. JK触发器产生输出
uint8_t out_bit = jk_clock(&unit->jk, j_in, k_in);
// 4. 循环计数器前进到下一个单元
pg->counter = (pg->counter + 1) % NUM_LFSR_PAIRS;
return out_bit;
}
// ---------- 4. 加密/解密接口 ----------
void pless_encrypt(uint8_t *data, size_t len, const uint32_t seeds_J[4], const uint32_t seeds_K[4]) {
PlessGenerator pg;
pless_init(&pg, seeds_J, seeds_K);
for (size_t i = 0; i < len; i++) {
uint8_t keystream_byte = 0;
for (int bit = 0; bit < 8; bit++) {
keystream_byte = (keystream_byte << 1) | pless_clock(&pg);
}
data[i] ^= keystream_byte;
}
}
// 异或对称性,解密函数与加密相同
void pless_decrypt(uint8_t *data, size_t len, const uint32_t seeds_J[4], const uint32_t seeds_K[4]) {
pless_encrypt(data, len, seeds_J, seeds_K);
}
// ---------- 5. 主函数演示 ----------
void print_hex(uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) printf("%02X ", data[i]);
printf("\n");
}
int main() {
uint32_t seeds_J[4] = { 0x1234, 0x5678, 0x9ABC, 0xDEF0 };
uint32_t seeds_K[4] = { 0x1357, 0x2468, 0x9BDF, 0xACE0 };
char plaintext[] = "Pless generator example!";
size_t len = strlen(plaintext);
uint8_t *data = (uint8_t*)malloc(len);
memcpy(data, plaintext, len);
printf("原始明文: %s\n", plaintext);
printf("明文(HEX): "); print_hex(data, len);
pless_encrypt(data, len, seeds_J, seeds_K);
printf("密文(HEX): "); print_hex(data, len);
pless_decrypt(data, len, seeds_J, seeds_K);
printf("解密后明文: %s\n", data);
free(data);
return 0;
}
```
### 3、钟控序列生成器
(1)钟控序列生成器的结构:
钟控序列最基本的模型是用一个LFSR控制另外一个LFSR的移位时钟脉冲,如下图所示,这是一个最简单的钟控序列生成器(停走生成器),下面也以此结构对钟控序列生成器进行介绍


(2)钟控序列的周期:


(3)钟控序列的线性复杂度:

(4)钟控序列生成器的C语言实现:
```cpp
#include
#include
#include
#include
// ========== LFSR 结构体 ==========
typedef struct {
uint32_t state; // 当前状态(最高位为输出位)
uint32_t mask; // 抽头掩码(反馈多项式对应的位)
int width; // 寄存器宽度
} LFSR;
// 初始化LFSR:根据种子和抽头掩码(种子不能为0)
void lfsr_init(LFSR *lfsr, uint32_t seed, uint32_t tap_mask, int width) {
lfsr->state = seed & ((1UL << width) - 1);
if (lfsr->state == 0) lfsr->state = 1; // 避免全0死锁
lfsr->mask = tap_mask;
lfsr->width = width;
}
// LFSR时钟一次,返回输出位(移出的最高位)
uint8_t lfsr_clock(LFSR *lfsr) {
// 计算反馈位:抽头位的异或
uint32_t fb = 0;
uint32_t masked = lfsr->state & lfsr->mask;
// 快速奇偶校验
fb = masked ^ (masked >> 16);
fb ^= fb >> 8;
fb ^= fb >> 4;
fb ^= fb >> 2;
fb ^= fb >> 1;
fb &= 1;
uint8_t out = (lfsr->state >> (lfsr->width - 1)) & 1;
lfsr->state = ((lfsr->state << 1) & ((1UL << lfsr->width) - 1)) | fb;
return out;
}
// ========== 停走生成器结构体 ==========
typedef struct {
LFSR control; // 控制LFSR(决定目标时钟)
LFSR target; // 目标LFSR(输出序列)
} StopGoGen;
// 初始化停走生成器
void stopgo_init(StopGoGen *gen,
uint32_t ctrl_seed, uint32_t ctrl_mask, int ctrl_width,
uint32_t targ_seed, uint32_t targ_mask, int targ_width) {
lfsr_init(&gen->control, ctrl_seed, ctrl_mask, ctrl_width);
lfsr_init(&gen->target, targ_seed, targ_mask, targ_width);
}
// 产生一个输出比特(停走机制)
uint8_t stopgo_bit(StopGoGen *gen) {
// 控制LFSR始终时钟
uint8_t ctrl_out = lfsr_clock(&gen->control);
// 如果控制输出为1,则目标LFSR时钟一次;否则目标不时钟
if (ctrl_out == 1) {
lfsr_clock(&gen->target); // 注意:这里只时钟,丢弃其输出(也可以保存输出)
}
// 目标LFSR的当前输出作为最终输出(即每次调用都返回目标寄存器的当前最高位)
// 注意:目标可能没时钟,所以输出与前一次相同。
return (gen->target.state >> (gen->target.width - 1)) & 1;
}
// 产生一个密钥字节(收集8个输出比特)
uint8_t stopgo_byte(StopGoGen *gen) {
uint8_t byte = 0;
for (int i = 0; i < 8; i++) {
byte = (byte << 1) | stopgo_bit(gen);
}
return byte;
}
// ========== 流密码加解密接口 ==========
void stopgo_encrypt(uint8_t *data, size_t len,
uint32_t ctrl_seed, uint32_t ctrl_mask, int ctrl_width,
uint32_t targ_seed, uint32_t targ_mask, int targ_width) {
StopGoGen gen;
stopgo_init(&gen, ctrl_seed, ctrl_mask, ctrl_width,
targ_seed, targ_mask, targ_width);
for (size_t i = 0; i < len; i++) {
uint8_t ks = stopgo_byte(&gen);
data[i] ^= ks;
}
}
void stopgo_decrypt(uint8_t *data, size_t len,
uint32_t ctrl_seed, uint32_t ctrl_mask, int ctrl_width,
uint32_t targ_seed, uint32_t targ_mask, int targ_width) {
// 流密码加解密相同
stopgo_encrypt(data, len, ctrl_seed, ctrl_mask, ctrl_width,
targ_seed, targ_mask, targ_width);
}
// ========== 辅助函数 ==========
void print_hex(const uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) {
printf("%02X ", data[i]);
}
printf("\n");
}
// ========== 主函数演示 ==========
int main() {
// 选择两个LFSR的参数(可使用本原多项式对应的抽头掩码)
// 控制LFSR: 宽度13,抽头掩码 x^13 + x^4 + x^3 + x + 1 对应位: 13,4,3,1,0
// 掩码 = (1<<12) | (1<<3) | (1<<2) | (1<<0) ? 注意:通常宽度13,最高位索引12
// 为简单,使用常见15级LFSR: x^15 + x + 1 掩码 = (1<<14) | (1<<0) 实际抽头位14和0
// 控制LFSR宽度15,掩码0x8001 (位14和位0)
// 目标LFSR宽度17,掩码 x^17 + x^3 + 1 -> 位16和位2和位0 => 0x20005
uint32_t ctrl_mask = (1 << 14) | 1; // 15级,抽头14和0
int ctrl_width = 15;
uint32_t targ_mask = (1 << 16) | (1 << 2) | 1; // 17级,抽头16,2,0
int targ_width = 17;
// 种子不能全0
uint32_t ctrl_seed = 0x2A3F; // 15位内
uint32_t targ_seed = 0x1A5B7; // 17位内
// 测试明文
char text[] = "Stop-and-Go clock-controlled generator!";
size_t len = strlen(text);
uint8_t *data = (uint8_t*)malloc(len);
memcpy(data, text, len);
printf("原始明文: %s\n", text);
printf("明文(HEX): ");
print_hex(data, len);
// 加密
stopgo_encrypt(data, len, ctrl_seed, ctrl_mask, ctrl_width,
targ_seed, targ_mask, targ_width);
printf("密文(HEX): ");
print_hex(data, len);
// 解密
stopgo_decrypt(data, len, ctrl_seed, ctrl_mask, ctrl_width,
targ_seed, targ_mask, targ_width);
printf("解密后明文: %s\n", data);
free(data);
return 0;
}
```
## 七、A5流密码算法
### 1、A5流密码算法介绍
(1)A5/1是GSM移动通信中用于语音通话加密的流密码,它的核心是用三个线性反馈移位寄存器(LFSR),通过钟控停走的方式生成密钥流,再和明文/密文做逐位异或完成加解密。

需要说明的是,A5/1算法中,LFSR的移位方式是左移方式,各寄存器的编号从第0级编号到第n-1级
(2)基本密钥与会话密钥:

(3)明文处理与加密方式:
①A5/1算法将通话的明文数据按每帧228bit分为若干帧,然后进行逐帧加密,每帧的处理方式相同且独立。

②加密方式:

(4)算法初始化:
初始化就是利用一次通话的会话密钥k和帧序号设定三个线性移位寄存器的起点,也即初始状态
首先将三个LFSR的初始状态设置为全零,然后将64bit的会话密钥k从低位到高位依次移入三个寄存器,每一位密钥bit,同时与三个寄存器的反馈抽头输出异或,结果作为寄存器的输入,三个寄存器都移位64次,完成会话密钥的注入
然后将22bit的帧序号从低位到高位,依次移入三个寄存器,每一位帧序号bit,与三个寄存器的反馈抽头输出异或,作为输入,三个寄存器都移位22次,完成帧序号的注入(对不同的帧设置不同的帧序号,保证对每帧以不同的起点生成密钥流,尽可能地避免密钥重用)
此时,三个寄存器的状态已经混合了会话密钥和帧号,每帧的状态都不同
### 2、A5流密码算法的基本原理
(1)密钥流生成与加解密:

(2)加密过程:
三个LFSR以钟控方式连续动作100次,但不输出密钥流
然后三个LFSR以钟控方式连续动作114次,在每次动作后,三个LFSR都将最高位寄存器中的值输出,这三个bit的异或就是当前时刻输出的1bit密钥
然后连续动作114步,共输出114bit密钥流,用于对用户手机到基站传送的114bit数据的加密
(3)解密过程:
三个LFSR以钟控方式连续动作100次,但不输出密钥流
然后三个LFSR以钟控方式连续动作114次,在每次动作后,三个LFSR都将最高级寄存器中的值输出,这三个bit的模2和就是当前时刻输出的1bit密钥流
然后连续动作114步,共输出114bit密钥流,这114bit用于对基站到用户手机传送的114bit数据的解密
### 3、A5流密码算法的弱点
(1)移位寄存器,太短容易遭受穷举攻击。
A5/1算法把主密钥作为算法中三个寄存器的初始值,长度为64bit,如果利用已知明文攻击,只需要知道其中两个寄存器的初始值,就可以计算出另一个寄存器的初始值,这只需要240步就可以得出寄存器LFSR-1和LFSR-2的结构
(2)事实上,A5/1加密算法中存在严重的安全问题。
利用GSM通信加密中的两个安全漏洞,可以通过离线迭代计算生成一个彩虹表,它包含有密钥和其相对应的输出密码,这个彩虹表的大小为984GB,得到了彩虹表之后,安全专家就可以在短短的九秒内确定用于加密通信数据的密钥