对称密码
密码编码学分为:对称密码学,非对称密码学,密码协议。
对称加密方案也称为对称密钥(Symmetric-key)、秘密密钥(secret-key)、和单密钥(Single-key)算法,对称加密分为:分组密码和序列密码
对称加密算法的加密密钥和解密密钥是完全相同的,第一,加密算法必须足够强,第二,加密的安全性依赖于密钥的秘密性,而非算法的保密性。
假设用对称加密算法检验注册码,正确的方法是吧用户输入的注册码作为加密算法或解密算法的密钥,这样,解密者想要找到一个正确的注册码,只能穷举。但如果在检查注册码是,将用户的输入的采用做算法的输入输出,则无论是使用加密算法还是解密,解密者都可以利用调试器在内存中找到所用的密钥中,从而将算法求逆,写出注册机。
常见的对称分组加密有DES,IDEA,AES,BlowFish,TowFish,TEA,RC4等等,以下介绍几例
分组加密
分组加密叫块加密,
分组密码有五种工作体制:1.电码本模式(Electronic Codebook Book (ECB));2.密码分组链接模式(Cipher Block Chaining (CBC));3.计算器模式(Counter (CTR));4.密码反馈模式(Cipher FeedBack (CFB));5.输出反馈模式(Output FeedBack (OFB))。
序列加密
IDEA
密钥长度128bit,分组长度64bit,由James Massey与来学嘉设计,在1991年首次提出。
现在IDEA被认为是不安全的加密算法
加密步骤
1.生成子密钥
IDEA共有52个16位子密钥,该密钥由输入的128位密钥生成
- 输入的128位被分为8个16位分组,并直接作为前8个子密钥使用
- 128位密钥循环左移25位,生成的128位密钥被分成8个16位的分组,作为接下来的8个密钥
- 重复上一步,直至52个子密钥全部生成
IDEA算法的加密过程
分析IDEAKeyGenMe
使用FindCrypt查看 加密为RIPEMD160和SHA1和SHA1加密一样啊
TEA
TEA算法是分组密码,分组长度为64位,密钥长度为128位,采用Feistel网络。
加密过程
| #include <stdint.h>
 void encrypt (uint32_t v[2], const uint32_t k[4]) {
 uint32_t v0=v[0], v1=v[1], sum=0, i;
 uint32_t delta=0x9E3779B9;
 uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
 for (i=0; i<32; i++) {
 sum += delta;
 v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
 v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
 }
 v[0]=v0; v[1]=v1;
 }
 
 | 
其中特征常量delta是由黄金分割点得来的,delta = 0x9E377989。TEA的变体XTEA和XXTEA都用到了这个常量,但是加密过程不同,在识别算法时需要注意。
在加密轮数方面,作者推荐的加密轮数是64轮,即循环32次,也可以采用其他加密轮数,比如32轮或者128轮,在分析的时候也需要注意。
DES
密钥长64位,56位参与运算,8位校验(每八位的第八位)
现在DES被认为是不安全的
当n个64位明文数据参与运算经过DES处理,
加密方法
IP初始置换 –》16轮迭代 –》IP-1逆置换
将64位化为两部分L0和R0(都是32位)
R1=L0^f(R0,K1)
以下对上述过程解释:
IP置换:ip置换,ip的表将对应位置的原始数据
16轮迭代分为F轮函数和异或,F轮函数分为:1.E扩展,2.异或,3.S盒,4.P置换
1.E扩展:右32bit转化为48位
S盒压缩处理:分为8个6bit的字符,将6位压缩为4位输出   48-》32(根据一个6进4出的S盒 )
P置换和ip置换差不多
P置换后要和L0进行异或得到R0
逆置换和ip置换差不多
AES
明文固定长度128位,密钥长度可以是128,192,256位
AES成为最流行的算法之一,已有破解方法
加密方法
明文 –> 初始变换 –> 9轮循环运算 –> 1轮最终轮 –>  密文
循环运算:1.字节代换,2.行位移,3.列混合,4.轮密钥加;最终轮无3
下面对上面的加密过程进行解释;
1.初始变换:将明文划为16字节(4*4矩阵),和密钥进行异或
2.1字节代换:矩阵在S盒中找到相应的位置进行代换
2.2行位移:第一行位置不变,第二行向左位移1位,第三行向左位移2位,向左位移3位
2.3列混合:将输入的 (4*4) 矩阵左乘一个 4*4给定的矩阵
| 正矩阵(好像一般是这个)2|3|1|1
 1|2|3|1
 1|1|2|3
 3|1|1|2
 
 | 
2.4轮密钥加:将结果和子密钥进行异或
子密钥如何得到呢?初始密钥经过密钥扩展可得到10个子密钥
密钥扩展:设有个密钥为4*4的矩阵W,i为列数
1.如果说i不是4的倍数,W[i]=W[i-1]^W[i-4]
2.如果是i的倍数,W[i]=W[i-4]^T(W[i-1])
T函数包含:字循环,字节代换和轮常量异或
字循环:将i-1列的第一个放在最后一个
字节代换:将循环结果查看S盒进行代换
轮常量异或:轮常量是给定的,将前两步得到的结果和轮常量进行异或即可
其中,矩阵元素的乘法和加法都是定义在基于GF(2^8)上的二元运算,并不是通常意义上的乘法和加法。这里涉及到一些信息安全上的数学知识,不过不懂这些知识也行。其实这种二元运算的加法等价于两个字节的异或,乘法则复杂一点。对于一个8位的二进制数来说,使用域上的乘法乘以(00000010)等价于左移1位(低位补0)后,再根据情况同(00011011)进行异或运算,设S1 = (a7 a6 a5 a4 a3 a2 a1 a0),刚0x02 * S1如下图所示:

也就是说,如果a7为1,则进行异或运算,否则不进行。
类似地,乘以(00000100)可以拆分成两次乘以(00000010)的运算:

乘以(0000 0011)可以拆分成先分别乘以(0000 0001)和(0000 0010),再将两个乘积异或:

因此,我们只需要实现乘以2的函数,其他数值的乘法都可以通过组合来实现。
解密方法
对称加密加解密使用一套算法,只是用逆变换取代原来的变换。
算法实现
AES有五种加密模式(CBC、ECB、CTR、OCF、CFB),以下算法为ECB
AES加密函数中,首先进行密钥扩展,然后把128位长度的字符串读进一个4*4的整数数组中,这个数组就是状态矩阵。例如,pArray[0][0] = S0,pArray[1][0] = S1, pArray[0][1] = S4。这个读取过程是通过 convertToIntArray()函数来实现的。每个轮操作的函数都对pArray进行修改,也就是对状态矩阵进行混淆。在执行完10轮加密后,会把pArray转换回字符串,再存入明文p的字符数组中,所以,在加密完后,明文p的字符串中的字符就是加密后的字符了。这个转换过程是通过convertArrayToStr()函数来实现的。
| 
 
 
 
 void aes(char *p, int plen, char *key){
 int keylen = strlen(key);
 if(plen == 0 || plen % 16 != 0) {
 printf("明文字符长度必须为16的倍数!\n");
 exit(0);
 }
 if(!checkKeyLen(keylen)) {
 printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
 exit(0);
 }
 extendKey(key);
 int pArray[4][4];
 for(int k = 0; k < plen; k += 16) {
 convertToIntArray(p + k, pArray);
 addRoundKey(pArray, 0);
 for(int i = 1; i < 10; i++){
 subBytes(pArray);
 shiftRows(pArray);
 mixColumns(pArray);
 addRoundKey(pArray, i);
 }
 
 subBytes(pArray);
 shiftRows(pArray);
 addRoundKey(pArray, 10);
 convertArrayToStr(pArray, p + k);
 }
 }
 
 | 
密钥扩展
| static int w[44];
 
 static void extendKey(char *key) {
 for(int i = 0; i < 4; i++)
 w[i] = getWordFromStr(key + i * 4);
 for(int i = 4, j = 0; i < 44; i++) {
 if( i % 4 == 0) {
 w[i] = w[i - 4] ^ T(w[i - 1], j);
 j++;
 }else {
 w[i] = w[i - 4] ^ w[i - 1];
 }
 }
 }
 
 | 
T函数实现
| static const int Rcon[10] = { 0x01000000, 0x02000000,
 0x04000000, 0x08000000,
 0x10000000, 0x20000000,
 0x40000000, 0x80000000,
 0x1b000000, 0x36000000 };
 
 static int T(int num, int round) {
 int numArray[4];
 splitIntToArray(num, numArray);
 leftLoop4int(numArray, 1);
 
 for(int i = 0; i < 4; i++)
 numArray[i] = getNumFromSBox(numArray[i]);
 
 int result = mergeArrayToInt(numArray);
 return result ^ Rcon[round];
 }
 
 | 
代码代换
| static int getNumFromSBox(int index) {
 int row = getLeft4Bit(index);
 int col = getRight4Bit(index);
 return S[row][col];
 }
 
 static void subBytes(int array[4][4]){
 for(int i = 0; i < 4; i++)
 for(int j = 0; j < 4; j++)
 array[i][j] = getNumFromSBox(array[i][j]);
 }
 
 | 
行移位
| static void leftLoop4int(int array[4], int step) {
 int temp[4];
 for(int i = 0; i < 4; i++)
 temp[i] = array[i];
 
 int index = step % 4 == 0 ? 0 : step % 4;
 for(int i = 0; i < 4; i++){
 array[i] = temp[index];
 index++;
 index = index % 4;
 }
 }
 
 static void shiftRows(int array[4][4]) {
 int rowTwo[4], rowThree[4], rowFour[4];
 
 for(int i = 0; i < 4; i++) {
 rowTwo[i] = array[1][i];
 rowThree[i] = array[2][i];
 rowFour[i] = array[3][i];
 }
 
 leftLoop4int(rowTwo, 1);
 leftLoop4int(rowThree, 2);
 leftLoop4int(rowFour, 3);
 
 for(int i = 0; i < 4; i++) {
 array[1][i] = rowTwo[i];
 array[2][i] = rowThree[i];
 array[3][i] = rowFour[i];
 }
 }
 
 | 
列混合
| 
 
 static const int colM[4][4] = { 2, 3, 1, 1,
 1, 2, 3, 1,
 1, 1, 2, 3,
 3, 1, 1, 2 };
 
 static int GFMul2(int s) {
 int result = s << 1;
 int a7 = result & 0x00000100;
 
 if(a7 != 0) {
 result = result & 0x000000ff;
 result = result ^ 0x1b;
 }
 
 return result;
 }
 
 static int GFMul3(int s) {
 return GFMul2(s) ^ s;
 }
 
 
 
 
 static int GFMul(int n, int s) {
 int result;
 
 if(n == 1)
 result = s;
 else if(n == 2)
 result = GFMul2(s);
 else if(n == 3)
 result = GFMul3(s);
 else if(n == 0x9)
 result = GFMul9(s);
 else if(n == 0xb)
 result = GFMul11(s);
 else if(n == 0xd)
 result = GFMul13(s);
 else if(n == 0xe)
 result = GFMul14(s);
 
 return result;
 }
 
 
 
 static void mixColumns(int array[4][4]) {
 
 int tempArray[4][4];
 
 for(int i = 0; i < 4; i++)
 for(int j = 0; j < 4; j++)
 tempArray[i][j] = array[i][j];
 
 for(int i = 0; i < 4; i++)
 for(int j = 0; j < 4; j++){
 array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j])
 ^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);
 }
 }
 
 | 
轮密钥加
| 
 
 
 static void addRoundKey(int array[4][4], int round) {
 int warray[4];
 for(int i = 0; i < 4; i++) {
 
 splitIntToArray(w[ round * 4 + i], warray);
 
 for(int j = 0; j < 4; j++) {
 array[j][i] = array[j][i] ^ warray[j];
 }
 }
 }
 
 | 
AES解密
| 
 
 
 
 void deAes(char *c, int clen, char *key) {
 int keylen = strlen(key);
 if(clen == 0 || clen % 16 != 0) {
 printf("密文字符长度必须为16的倍数!现在的长度为%d\n",clen);
 exit(0);
 }
 if(!checkKeyLen(keylen)) {
 printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
 exit(0);
 }
 extendKey(key);
 int cArray[4][4];
 for(int k = 0; k < clen; k += 16) {
 convertToIntArray(c + k, cArray);
 addRoundKey(cArray, 10);
 int wArray[4][4];
 for(int i = 9; i >= 1; i--) {
 deSubBytes(cArray);
 deShiftRows(cArray);
 deMixColumns(cArray);
 getArrayFrom4W(i, wArray);
 deMixColumns(wArray);
 addRoundTowArray(cArray, wArray);
 }
 deSubBytes(cArray);
 deShiftRows(cArray);
 addRoundKey(cArray, 0);
 convertArrayToStr(cArray, c + k);
 }
 }
 
 | 
参考链接
《加密与解密》 作者段钢  6.2对称加密算法
hash加密
AES加密
AES的五种加密模式