ZUC加密算法实现
参考资料
https://max.book118.com/html/2017/0716/122521494.shtm
一.运行结果展示
二. 程序源码
import java.util.*;
// import java.lang.*;
public class zuc {
public static void main(String[] args) {
Scanner S = new Scanner(System.in);
System.out.println("请输入十六进制128位明文:");
// String ming = S.next();
String ming = "00000000000000000000000000000000";
// 84319aa8de6915ca1f6bda6bfbd8c766
System.out.println("请输入十六进制128位密钥:");
// String k = S.next();
String k = "00000000000000000000000000000000";
// 3d4c4be96a82fdaeb58f641db17b455b
S.close();
int[] mingwen = Algorithm.DataFormat(ming);// 16
int[] key = Algorithm.DataFormat(k);// 16
int[] s = Algorithm.keyInstall(key, mingwen);// 密钥装入
System.out.println("\n明文:");
for (int i = 0; i < mingwen.length; i++) {
System.out.printf("%x ", mingwen[i]);
}
System.out.println("\n密钥:");
for (int i = 0; i < mingwen.length; i++) {
System.out.printf("%x ", key[i]);
}
System.out.println("\ns:");
for (int i = 0; i < s.length; i++) {
System.out.printf("%x ", s[i]);
}
int[] x = Algorithm.bitReconstruction(s);
int r1 = 0, r2 = 0;
int[] Wrr = Algorithm.F(x, r1, r2);
s = Algorithm.LFSRInitialisation(s, Wrr[0]);
r1 = Wrr[1];
r2 = Wrr[2];
System.out.println("\n初始化后的x,r,w,s15\n");
for (int i = 0; i < x.length; i++) {
System.out.printf("%x ", x[i]);
}
System.out.printf("%x ", r1);
System.out.printf("%x ", r2);
System.out.printf("%x ", Wrr[0]);
System.out.printf("%x ", s[15]);
// System.out.println("\n第一次线性移位后的s:\n");
// for (int i = 0; i < s.length; i++) {
// System.out.printf("%x ", s[i]);
// }
for (int i = 0; i < 31; i++) {// 初始化模式
x = Algorithm.bitReconstruction(s);
Wrr = Algorithm.F(x, r1, r2);
s = Algorithm.LFSRInitialisation(s, Wrr[0]);
r1 = Wrr[1];
r2 = Wrr[2];
// System.out.printf("\n第%d次线性移位后的s:", i);
// for (int ii = 0; ii < s.length; ii++) {
// System.out.printf("%x ", s[ii]);
// }
// System.out.printf("\n第%d次后的x,r,w,s15\n", i);
// for (int ii = 0; ii < x.length; ii++) {
// System.out.printf("%x ", x[ii]);
// }
// System.out.printf("%x ", r1);
// System.out.printf("%x ", r2);
// System.out.printf("%x ", Wrr[0]);
// System.out.printf("%x ", s[15]);
}
System.out.println("\n初始化后的s:");
for (int ii = 0; ii < s.length; ii++) {
System.out.printf("%x ", s[ii]);
}
System.out.println("\n初始化后的x,r,w,s15\n");
for (int ii = 0; ii < x.length; ii++) {
System.out.printf("%x ", x[ii]);
}
System.out.printf("%x ", r1);
System.out.printf("%x ", r2);
System.out.printf("%x ", Wrr[0]);
System.out.printf("%x ", s[15]);
// 工作模式//第一次舍弃W
int z = 0;
x = Algorithm.bitReconstruction(s);
Wrr = Algorithm.F(x, r1, r2);
s = Algorithm.LFSRWorking(s);
r1 = Wrr[1];
r2 = Wrr[2];
// 不舍弃
x = Algorithm.bitReconstruction(s);
Wrr = Algorithm.F(x, r1, r2);
z = Wrr[0] ^ x[3];
s = Algorithm.LFSRWorking(s);
r1 = Wrr[1];
r2 = Wrr[2];
System.out.printf("运行后:\nz1:%x ", z);
// 不舍弃第二次运行
x = Algorithm.bitReconstruction(s);
Wrr = Algorithm.F(x, r1, r2);
z = Wrr[0] ^ x[3];
s = Algorithm.LFSRWorking(s);
r1 = Wrr[1];
r2 = Wrr[2];
System.out.printf("第二次运行后:\nz2:%x ", z);
// int[] x = Algorithm.bitReconstruction(S);
// System.out.println("\n比特重组:");
// for (int i = 0; i < x.length; i++) {
// System.out.printf("%x ", x[i]);
// }
}
}
// 84319aa8de6915ca1f6bda6bfbd8c766
// 3d4c4be96a82fdaeb58f641db17b455b
class Algorithm {
static int[] DataFormat(String s) {// 数据格式转换,将十六进制字符串转换为数据表输出
int[] a = new int[16];
for (int i = 0; i < 16; i++) {
a[i] = Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16);
}
return a;
}
static int[] keyInstall(int[] k, int[] iv) {
int[] d = new int[16];
d[0] = Integer.parseInt("100010011010111", 2);
d[1] = Integer.parseInt("010011010111100", 2);
d[2] = Integer.parseInt("110001001101011", 2);
d[3] = Integer.parseInt("001001101011110", 2);
d[4] = Integer.parseInt("101011110001001", 2);
d[5] = Integer.parseInt("011010111100010", 2);
d[6] = Integer.parseInt("111000100110101", 2);
d[7] = Integer.parseInt("000100110101111", 2);
d[8] = Integer.parseInt("100110101111000", 2);
d[9] = Integer.parseInt("010111100010011", 2);
d[10] = Integer.parseInt("110101111000100", 2);
d[11] = Integer.parseInt("001101011110001", 2);
d[12] = Integer.parseInt("101111000100110", 2);
d[13] = Integer.parseInt("011110001001101", 2);
d[14] = Integer.parseInt("111100010011010", 2);
d[15] = Integer.parseInt("100011110101100", 2);
// System.out.println("d:");
// for (int i = 0; i < d.length; i++) {
// System.out.printf("%x ", d[i]);
// }
int[] s = new int[16];
for (int i = 0; i < 16; i++) {
s[i] = k[i] << 23 ^ d[i] << 8 ^ iv[i];
}
return s;
}
static int[] bitReconstruction(int[] s) {
int[] x = new int[4];
x[0] = ((s[15] & 0x7FFF8000) << 1) | (s[14] & 0x0000ffff);
x[1] = ((s[11] & 0x0000ffff) << 16) | ((s[9]) >>> 15);
x[2] = ((s[7] & 0x0000ffff) << 16) | ((s[5]) >>> 15);
x[3] = ((s[2] & 0x0000ffff) << 16) | ((s[0]) >>> 15);
return x;
}
static int[] F(int[] x, int r1, int r2) {
int w, w1, w2;
w = ((x[0] ^ r1) + r2) & 0xffffffff;
w1 = (r1 + x[1]) & 0xffffffff;
w2 = r2 ^ x[2];
int[] ans = new int[3];
ans[0] = w;
ans[1] = Algorithm.s(Algorithm.L1(((w1 & 0x0000ffff) << 16) ^ (w2 >>> 16)));
ans[2] = Algorithm.s(Algorithm.L2(((w2 & 0x0000ffff) << 16) ^ (w1 >>> 16)));
return ans;
}
static int L1(int in) {
return in ^ (in << 2 ^ in >>> 30) ^ (in << 10 ^ in >>> 22) ^ (in << 18 ^ in >>> 14) ^ (in << 24 ^ in >>> 8);
}
static int L2(int in) {
return in ^ (in << 8 ^ in >>> 24) ^ (in << 14 ^ in >>> 18) ^ (in << 22 ^ in >>> 10) ^ (in << 30 ^ in >>> 2);
}
static int s(int in) {
int[] S0 = { 0x3e, 0x72, 0x5b, 0x47, 0xca, 0xe0, 0x00, 0x33, 0x04, 0xd1, 0x54, 0x98, 0x09, 0xb9, 0x6d, 0xcb,
0x7b, 0x1b, 0xf9, 0x32, 0xaf, 0x9d, 0x6a, 0xa5, 0xb8, 0x2d, 0xfc, 0x1d, 0x08, 0x53, 0x03, 0x90, 0x4d,
0x4e, 0x84, 0x99, 0xe4, 0xce, 0xd9, 0x91, 0xdd, 0xb6, 0x85, 0x48, 0x8b, 0x29, 0x6e, 0xac, 0xcd, 0xc1,
0xf8, 0x1e, 0x73, 0x43, 0x69, 0xc6, 0xb5, 0xbd, 0xfd, 0x39, 0x63, 0x20, 0xd4, 0x38, 0x76, 0x7d, 0xb2,
0xa7, 0xcf, 0xed, 0x57, 0xc5, 0xf3, 0x2c, 0xbb, 0x14, 0x21, 0x06, 0x55, 0x9b, 0xe3, 0xef, 0x5e, 0x31,
0x4f, 0x7f, 0x5a, 0xa4, 0x0d, 0x82, 0x51, 0x49, 0x5f, 0xba, 0x58, 0x1c, 0x4a, 0x16, 0xd5, 0x17, 0xa8,
0x92, 0x24, 0x1f, 0x8c, 0xff, 0xd8, 0xae, 0x2e, 0x01, 0xd3, 0xad, 0x3b, 0x4b, 0xda, 0x46, 0xeb, 0xc9,
0xde, 0x9a, 0x8f, 0x87, 0xd7, 0x3a, 0x80, 0x6f, 0x2f, 0xc8, 0xb1, 0xb4, 0x37, 0xf7, 0x0a, 0x22, 0x13,
0x28, 0x7c, 0xcc, 0x3c, 0x89, 0xc7, 0xc3, 0x96, 0x56, 0x07, 0xbf, 0x7e, 0xf0, 0x0b, 0x2b, 0x97, 0x52,
0x35, 0x41, 0x79, 0x61, 0xa6, 0x4c, 0x10, 0xfe, 0xbc, 0x26, 0x95, 0x88, 0x8a, 0xb0, 0xa3, 0xfb, 0xc0,
0x18, 0x94, 0xf2, 0xe1, 0xe5, 0xe9, 0x5d, 0xd0, 0xdc, 0x11, 0x66, 0x64, 0x5c, 0xec, 0x59, 0x42, 0x75,
0x12, 0xf5, 0x74, 0x9c, 0xaa, 0x23, 0x0e, 0x86, 0xab, 0xbe, 0x2a, 0x02, 0xe7, 0x67, 0xe6, 0x44, 0xa2,
0x6c, 0xc2, 0x93, 0x9f, 0xf1, 0xf6, 0xfa, 0x36, 0xd2, 0x50, 0x68, 0x9e, 0x62, 0x71, 0x15, 0x3d, 0xd6,
0x40, 0xc4, 0xe2, 0x0f, 0x8e, 0x83, 0x77, 0x6b, 0x25, 0x05, 0x3f, 0x0c, 0x30, 0xea, 0x70, 0xb7, 0xa1,
0xe8, 0xa9, 0x65, 0x8d, 0x27, 0x1a, 0xdb, 0x81, 0xb3, 0xa0, 0xf4, 0x45, 0x7a, 0x19, 0xdf, 0xee, 0x78,
0x34, 0x60 };
int[] S1 = { 0x55, 0xc2, 0x63, 0x71, 0x3b, 0xc8, 0x47, 0x86, 0x9f, 0x3c, 0xda, 0x5b, 0x29, 0xaa, 0xfd, 0x77,
0x8c, 0xc5, 0x94, 0x0c, 0xa6, 0x1a, 0x13, 0x00, 0xe3, 0xa8, 0x16, 0x72, 0x40, 0xf9, 0xf8, 0x42, 0x44,
0x26, 0x68, 0x96, 0x81, 0xd9, 0x45, 0x3e, 0x10, 0x76, 0xc6, 0xa7, 0x8b, 0x39, 0x43, 0xe1, 0x3a, 0xb5,
0x56, 0x2a, 0xc0, 0x6d, 0xb3, 0x05, 0x22, 0x66, 0xbf, 0xdc, 0x0b, 0xfa, 0x62, 0x48, 0xdd, 0x20, 0x11,
0x06, 0x36, 0xc9, 0xc1, 0xcf, 0xf6, 0x27, 0x52, 0xbb, 0x69, 0xf5, 0xd4, 0x87, 0x7f, 0x84, 0x4c, 0xd2,
0x9c, 0x57, 0xa4, 0xbc, 0x4f, 0x9a, 0xdf, 0xfe, 0xd6, 0x8d, 0x7a, 0xeb, 0x2b, 0x53, 0xd8, 0x5c, 0xa1,
0x14, 0x17, 0xfb, 0x23, 0xd5, 0x7d, 0x30, 0x67, 0x73, 0x08, 0x09, 0xee, 0xb7, 0x70, 0x3f, 0x61, 0xb2,
0x19, 0x8e, 0x4e, 0xe5, 0x4b, 0x93, 0x8f, 0x5d, 0xdb, 0xa9, 0xad, 0xf1, 0xae, 0x2e, 0xcb, 0x0d, 0xfc,
0xf4, 0x2d, 0x46, 0x6e, 0x1d, 0x97, 0xe8, 0xd1, 0xe9, 0x4d, 0x37, 0xa5, 0x75, 0x5e, 0x83, 0x9e, 0xab,
0x82, 0x9d, 0xb9, 0x1c, 0xe0, 0xcd, 0x49, 0x89, 0x01, 0xb6, 0xbd, 0x58, 0x24, 0xa2, 0x5f, 0x38, 0x78,
0x99, 0x15, 0x90, 0x50, 0xb8, 0x95, 0xe4, 0xd0, 0x91, 0xc7, 0xce, 0xed, 0x0f, 0xb4, 0x6f, 0xa0, 0xcc,
0xf0, 0x02, 0x4a, 0x79, 0xc3, 0xde, 0xa3, 0xef, 0xea, 0x51, 0xe6, 0x6b, 0x18, 0xec, 0x1b, 0x2c, 0x80,
0xf7, 0x74, 0xe7, 0xff, 0x21, 0x5a, 0x6a, 0x54, 0x1e, 0x41, 0x31, 0x92, 0x35, 0xc4, 0x33, 0x07, 0x0a,
0xba, 0x7e, 0x0e, 0x34, 0x88, 0xb1, 0x98, 0x7c, 0xf3, 0x3d, 0x60, 0x6c, 0x7b, 0xca, 0xd3, 0x1f, 0x32,
0x65, 0x04, 0x28, 0x64, 0xbe, 0x85, 0x9b, 0x2f, 0x59, 0x8a, 0xd7, 0xb0, 0x25, 0xac, 0xaf, 0x12, 0x03,
0xe2, 0xf2 };
int[] x = new int[4];
x[0] = (in & 0xff000000) >> 24;
x[1] = (in & 0x00ff0000) >> 16;
x[2] = (in & 0x0000ff00) >> 8;
x[3] = (in & 0x000000ff);
int[] y = new int[4];
y[0] = S0[((x[0] & 0xf0) >> 4) * 16 + (x[0] & 0x0f)];
y[1] = S1[((x[1] & 0xf0) >> 4) * 16 + (x[1] & 0x0f)];
y[2] = S0[((x[2] & 0xf0) >> 4) * 16 + (x[2] & 0x0f)];
y[3] = S1[((x[3] & 0xf0) >> 4) * 16 + (x[3] & 0x0f)];
return (y[0] << 24) ^ (y[1] << 16) ^ (y[2] << 8) ^ (y[3]);
}
static int[] LFSRInitialisation(int[] s, int w) {
int f = s[0];
int v = Algorithm.mulInModule(8, s[0]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(20, s[4]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(21, s[10]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(17, s[13]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(15, s[15]);
f = Algorithm.addInModule(f, v);
int[] rets = new int[16];
f = Algorithm.addInModule(f, w >>> 1);
if (f == 0) {
f = 0x7fffffff;
}
for (int i = 0; i < 15; i++) {
rets[i] = s[i + 1];
}
rets[15] = f;
return rets;
}
static int[] LFSRWorking(int[] s) {
int f = s[0];
int v = Algorithm.mulInModule(8, s[0]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(20, s[4]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(21, s[10]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(17, s[13]);
f = Algorithm.addInModule(f, v);
v = Algorithm.mulInModule(15, s[15]);
f = Algorithm.addInModule(f, v);
int[] rets = new int[16];
if (f == 0) {
f = 0x7fffffff;
}
for (int i = 0; i < 15; i++) {
rets[i] = s[i + 1];
}
rets[15] = f;
return rets;
}
static int addInModule(int a, int b) {
int c = a + b;
return (c & 0x7fffffff) + (c >>> 31);
}
static int mulInModule(int a, int b) {// a是常量的那个
return ((b << a) | (b >>> (31 - a))) & 0x7fffffff;
}
}
// 3CA10B2157F01916902E1380ACC107BD
三.写在最后
如果想要修改测试向量, 可以在main函数中开头有相关语句, 我目前使用的是常量模式. 如果想修改成从
终端输入, 可以将常量语句换成后面被注释的语句. 具体详看代码肯定能看懂.
如果想看中间结果, 代码中的很多用于输出的注释取消掉即可, 每步的中间结果都有, 此代码系我调试完成
后注释掉的.