C/C++ 加密解密学习记录
趁放假,去实施了一下蓄谋已久的小计划:手打实现各种密码和哈希、熟悉openssl。
代码写的稀碎,主要是学习嘛~
目前已经手打实现了:(这个项目应该还会继续维护一段时间)
HASH:
MD5、SHA1、SHA224、SHA256、SHA384、SHA512、SHA3-224、SHA3-256、SHA3-384、SHA3-512、SM3
加密解密:
通过OpenSSL实现各种密码的例子、RSA
编码:
Base64、
为了加深印象还写了一些文档记录 加密 解密的步骤,在项目目录上,想看哪个就点哪个。
这里贴一篇我记录的 SHA3 的HASH步骤:当然啦!只有步骤,原理咱不深究。
SHA3
前置知识:B 、W、L 对照表
对于SHA3家族:B固定为1600。所以 W、L也固定了。
第一步
设 需要散列的 文本为"M",M的长度为N Bit 。
需要将M 填充到 N mod r = 0;
SHA3-224: r = 1152 SHA3-256: r = 1088
SHA3-384: r = 832 SHA3-512: r = 576
填充规则:先串接 01 ,再串接 100....001。图例:
例子1:M 很短时
">例子2:M 长时
例子3:填充最少
例子4:填充最多
注意:
在计算机的实际应用中,基本单位是字节,因此填充的部分,也应该是字节。以 8Bit 为单位:
在上图中 M[0] 为最低位的 Bit,最后填补的 Bit 1 为最高位的 Bit。若以 字节的形式表示如下:
例如我需要填补 2个字节才能补足 长度 R Bit:
可以看出:我们补的字节并不是 0x60 与 0x01 ,而补的是 0x06 与 0x80 。这一部分和SHA1、SHA2、MD家族有些许区别。
若只补1个字节:
补的不是 0x61 而是 0x86。
这一部分是一个大坑。
第二步
迭代:
对上面的每一段 M 进行迭代。初始向量 S 为 长度为B的全 0 Bit串。
S 会经过多次迭代变化。经过最后一个 函数F 得到的 S 为HASH结果。
取 S 前 (224、256、384、512)Bit 即为HASH输出。
详解 迭代函数 F :
前置知识:
A[x,y,z] = S[W(5y+x)+z] ,S 即为上图的 S 。还有两个工具函数,使用代码表示:
#define A(x,y,z) (W*(5*y+x)+z)
//获得 S 的第 A(x,y,z) 个 Bit 的值(UCHAR 类型表示)
UCHAR Get_Bit(S,A(x,y,z));
//将 S 的第 A(x+1,y+1,z+1) 个 Bit 的值 赋值为 S 的第 A(x,y,z) 个 Bit 的值
VOID Set_Bit(S,A(x+1,y+1,z+1),Get_Bit(S,A(x,y,z)));
VOID SHA3_512_Data::KECCAK_P(PUCHAR S) { //这个函数就是 上述流程图中的 函数 F
for (int ir = 12 + 2 * L - Nr; ir <= 12 + 2 * L - 1; ir++) {
Rnd(S, ir);
}
}
其中:
Rnd:
θ(theat):
代码(节选):
for (int x = 0; x < 5; x++) {
for (int z = 0; z < W; z++) {
Set_Bit(C, W * x + z, Get_Bit(S, A(x, 0, z)) ^ Get_Bit(S, A(x, 1, z)) ^ Get_Bit(S, A(x, 2, z)) ^ Get_Bit(S, A(x, 3, z)) ^ Get_Bit(S, A(x, 4, z)));
}
}
for (int x = 0; x < 5; x++) {
for (int z = 0; z < W; z++) {
Set_Bit(D, W * x + z, Get_Bit(C, W * mod(x - 1, 5) + z) ^ Get_Bit(C, W * mod(x + 1, 5) + mod(z - 1, W)));
}
}
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < W; z++) {
Set_Bit(Sc, A(x, y, z), Get_Bit(D, W * x + z) ^ Get_Bit(S, A(x, y, z)));
}
}
}
ρ(rho):
代码(节选):
for (int z = 0; z < W; z++) {
Set_Bit(Sc, A(0, 0, z), Get_Bit(S, A(0, 0, z)));
}
int x = 1, y = 0;
int newx, newy;
for (int t = 0; t < 24; t++) {
for (int z = 0; z < W; z++) {
Set_Bit(Sc, A(x, y, z), Get_Bit(S, A(x, y, mod(z - ((t + 1) * (t + 2) / 2), W))));
}
newx = y%5;
newy =(2 * x + 3 * y)% 5;
x = newx;
y = newy;
}
π(pi):
代码(节选):
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < W; z++) {
j = mod(x + (3 * y), 5);
Set_Bit(Sc, A(x, y, z), Get_Bit(S, A(j,x,z)));
}
}
}
χ(chi):
代码(节选):
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < W; z++) {
Set_Bit(Sc, A(x, y, z), Get_Bit(S, A(x, y, z)) ^ ((Get_Bit(S, A(mod(x + 1, 5), y, z)) ^ 1) * Get_Bit(S, A(mod(x + 2, 5), y, z))));
}
}
}
ι(iota):
代码(节选):
memcpy(Sc, S, B / 8);
UCHAR RC[W] = { 0 };
for (int j = 0; j <= L; j++) {
int ls = pow(2, j) - 1;
RC[ls] = rc(j + 7 * Ir);
}
for (int z = 0; z < W; z++) {
Set_Bit(Sc, A(0, 0, z), Get_Bit(Sc, A(0, 0, z)) ^ RC[z]);
}
rc:
代码(节选):
UCHAR r[9] = { 1,0,0,0,0,0,0,0,0 };
if (mod(t, 255) == 0) {
return 1;
}
for (int i = 1; i <= mod(t, 255); i++) {
memcpy(&r[1], &r[0], 8);
r[0] = 0;
r[0] = r[0] ^ r[8];
r[4] = r[4] ^ r[8];
r[5] = r[5] ^ r[8];
r[6] = r[6] ^ r[8];
}
return r[0];
SHA3官方步骤:
1.
2.
3.