1.ECB模式详解

转自:https://blog.csdn.net/sunqiujing/article/details/75066924

DES参考这篇博文:写的好

https://blog.csdn.net/qq_27570955/article/details/52442092

ECB模式(电子密码本模式)

在ECB模式中,将明文分组加密之后的结果直接作为密文分组,缺点是会容易攻击,因为明文相同的密文相同

目录

  1. 1概念
  2. 2ECB模式的优缺点

概念

ECB(Electronic Codebook,电码本)模式是分组密码的一种最基本的工作模式。在该模式下,待处理信息被分为大小合适的分组,然后分别对每一分组独立进行加密或解密处理。如下图所示:
我们可以将其理解为是一个巨大的"明文分组→密文分组"的对应表

ECB模式的优缺点

编辑

ECB模式作为一种基本工作模式,具有操作简单,易于实现的特点。同时由于其分组的独立性,利于实现并行处理,并且能很好地防止误差传播。

另一方面由于所有分组的加密方式一致,明文中的重复内容会在密文中有所体现,因此难以抵抗统计分析攻击。

因此,ECB模式一般只适用于小数据量的字符信息的安全性保护,例如密钥保护。

ECB模式优点:

1. 简单

2. 有利于并行计算

3. 误差不会被传送

ECB模式缺点:

1. 不能隐藏明文的模式

2. 可能对明文进行主动攻击

对ECB模式的攻击,截图来源自图解密码技术一书:

ECB模式的加密:

#include <STRING.H>#define IN
#define OUT//假设加密分组为4字节一组/**************************************************************************
*功  能:    加密算法 (与Key异或)
*参  数:    lpszData        当前明文分组数据
*           lpszKey         Key
*           lpszDeData      加密后的结果
*
*返回值:
**************************************************************************/
void Encrypt(IN const char *lpszData, IN const char *lpszKey, OUT char *lpszEnData)
{int i = 0;for (i = 0; i < 4; i++){lpszEnData[i] = lpszData[i] ^ lpszKey[i];}
}/**************************************************************************
*功  能:    解密算法 (再次异或还原明文)
*参  数:    lpszData        当前密文分组数据
*           lpszKey         Key
*           lpszDeData      解密后的结果
*
*返回值:
**************************************************************************/
void Decrypt(IN const char *lpszData, IN const char *lpszKey, OUT char *lpszDeData)
{int i = 0;for (i = 0; i < 4; i++){lpszDeData[i] = lpszData[i] ^ lpszKey[i];}
}int main(int argc, char* argv[])
{char *lpszData = "Hello World!";char szEnData[16] = {0};char szDeData[16] = {0};char *lpszKey = "1234";int i = 0;printf("原始数据: %s\r\n", lpszData);while (true){if (strlen(lpszData + i) == 0){break;}Encrypt(lpszData + i, lpszKey, szEnData + i);i += 4;}printf("加密后数据: %s\r\n", szEnData);i = 0;while (true){if (strlen(szEnData + i) == 0){break;}Decrypt(szEnData + i, lpszKey, szDeData + i);i += 4;}printf("解密后数据: %s\r\n", szDeData);return 0;
}

原数据: Hello World!

加密后: yW_X^d[C^W

解密后: Hello World!

2.密码算法详解——DES

0 DES简介

  在20世纪60年代后期,IBM公司成立了一个由Horst Feistel负责的计算机密码学研究项目。1971年设计出密码算法LUCIFER后,该项目宣告结束。LUCIFER被卖给了伦敦的Lloyd公司,用在同样由IBM公司开发的现金发放系统上。LUCIFER是分组长度为64位、密钥长度为128位、具有Feistel结构的分组密码算法。因为LUCIFER非常成功,IBM决定开发一个适合于芯片实现的商业密码产品。这一次由Walter Tuchman和Carl Meyer牵头,参与者不仅有IBM公司的研究人员,而且还有美国国家安全局(NSA)的技术顾问。这次努力的结果是给出了LUCIFER的一个修订版,它的抗密码分析能力更强,而且密钥长度减小为56位。

  1973年,美国国家标准局(NBS)征求美国国家密码标准方案时,IBM将Tuchman-Meyer方案提交给NBS,它是所有应征方案中最好的一个,所以1977年NBS将它采纳为数据加密标准,即DES。

  以上内容直接来自与参考文献[1],参考文献[2]给出了更加详细的一些介绍,有兴趣可以阅读。

1 Feistel

  分组密码常用的结构有SP、Feistel[3]、Lai-Massey、MISTY等,其中Feistel结构的使用较为普遍,不仅DES用到了,后续的很多经典算法中都有涉及,故在此先对其进行介绍。

1.1 Feistel介绍

  Feistel是以发明者Horst Feistel的名字命名的。加解密的原理如右图1,左边表示的加密过程,右边表示解密过程。

  在每一轮加密过程中,明文被分成左右两部分。

  加密和解密公式如下:

  不同的是,在加密过程中,轮数和轮密钥从小开始递增;解密时正好相反,从最大开始递减。

  从图中可以看出,加密最后一轮的操作与前面的有所不同,最后一轮得到的两个部分没有交换,之所以这样是为了保持解密的流程和加密一致,这样在硬件设计时可以使用相同的结构,进而减少硬件面积。

  但是对于Feistel结构最本质的特点到底是什么,我也一直不太明白,比较浅显的一点认识就是:每一轮只有一半的比特位参与计算,另外一半直接作为下一轮的输入。

1.2 一个简单的例子

  假设明文为(L0,R0),一共有两轮计算,每轮的密钥分别为k0、k1,加解密的流程如图2。

2 算法流程

  DES算法原理如右图,相关参数如下: 

  • 明文分组长度:64 bits
  • 密钥长度:64 bits
  • 轮数:16轮

  整个操作可以分为3部分:

  • 初始置换和逆初始置换:这是一对可逆操作,一组数字经过初始置换(或逆初始置换)后,再经过逆初始置换(或初始置换)即可恢复原来的值;
  • 每轮的加解密操作:64位明文和48为密钥经过一定的操作,输出64位密文;
  • 轮密钥计算:64位初始密钥经过置换、循环移位等得到16轮的密钥,每轮密钥长度为48位。

  接下来分别对这三种核心操作进行介绍。

2.1 初始置换与逆初始置换

  置换的操作如下表1、表2,将一个64位的输入通过各位的提到得到一个新的64位输出。观察可以发现x = IP-1 ( IP(x) ) = IP ( IP-1(x) )。  

  需要注意的一点是,图中的索引值从1开始(下文中的数字也类似),有些资料中是从0开始的,如果从零开始,则所有的数字减1即可。

2.2 每轮的操作

  每一轮的流程如图4,从图中可以看出DES用到了Feistel结构。F即为图中虚线框的内容。

图4 轮操作流程

  每一轮主要涉及3中操作:

  • 扩展/置换:将32位输入扩展成48位输出,如表3;
  • S盒:将48位输入分成8组分别作为8个S盒的输入,每组6位,最高位和最低位作为行索引,中间4位作为列索引,得到一个值x(0<=x<=15),表示为二进制即为4位,8个S盒的输出和在一起正好32位。表4是S1的数值;
  • 置换:对32位输入进行位的变化,输出仍为32位,如表5。

2.3 轮密钥扩展

  从图1和图4中可以得出,密钥扩展流程可以表示如下:

    1) 64位初始密钥P进行置换选择1,得到56位输出K;

    2) 将K循环左移一定位数,再进行置换选择2得到48位输出k1(即第一轮的密钥);

    3) 循环步骤2),直至得到16轮的密钥(k1、k2、……、k16);

    4) 结束。

  置换选择1、置换选择2和左移次数的值分别如表6、表7、表8。

 

3 其它密码算法

  近期介绍了DES、AES和Simon3种密码算法,他们都属于分组密码算法,后续有时间再介绍其它分组密码算法、流密码算法、杂凑函数(Hash算法)等。读者有兴趣可以参考《密码学与网络安全——原理与实践》以及网上相关资料,算法原理基本都差不多。

4 参考资料

[1] William Stallings著;王张宜等译. 密码编码学与网络安全——原理与实践(第五版)[M]. 北京:电子工业出版社,2012.1.

[2] http://en.wikipedia.org/wiki/Data_Encryption_Standard

[3] http://en.wikipedia.org/wiki/Feistel_cipher

[4] https://github.com/tarequeh/DES

DES代码

#include<memory.h>
#include "DES.h"
#include<stdio.h>
char szKeys[16][48];//存储16组48bit密钥
char szCipherText[64];//存储64位密文
char szplaintText[64];//存储64位明文
char szCiphertextInBytes[8];//储存8位密文
char szPlaintextInBytes[8];//储存8位明文字符串
char szCiphertextInBinary[65]; //储存二进制密文(64个Bits)
char szCiphertextInHex[17]; //储存十六进制密文,最后一位存'\0'// permuted choice table (PC1)
const static char PC1_Table[56] = {//64位密钥去掉8,16,24...等8位奇偶位,对PC1_Table进行置换,密钥A=0--27,57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,  //B=28--56 [注:数字为数组下标]10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
};
// permuted choice key (PC2)
const static char PC2_Table[48] = {//A,B俩个28bit的密钥进行i次迭代后,组合成56bit密钥,对PC2_Table进行置换,14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,//生成子密钥,子密钥与进行i次迭代的数据进行位异或操作23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};
// number left rotations of pc1
const static char Shift_Table[16] = { //第i次迭代次数1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};
// initial permutation (IP)
const static char IP_Table[64] = {//明文数据对此表进行置换,得到新的64bit数据58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,57, 49, 41, 33, 25, 17,  9, 1, 59, 51, 43, 35, 27, 19, 11, 3,61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};
// expansion operation matrix (E)
const static char E_Table[48] = {//把IP_Table置换过的明文数据分为left,right两部分,left不变,right对E_Table进行扩展,成48bit32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,//然后与i次迭代生成的子密钥进行位异或操作,得到新的right数据8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1
};
// The (in)famous S-boxes
const static char S_Box[8][4][16] = {//把新的到的right48bit数据压缩成32bit,1.把48bit数据分割成8个6bit数据,// S1                                                                 2.把6bit的数据第1位和第6位组合位此表纵坐标,2-5位横坐标,得到相关值14,  4,    13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,     //  3.把数据转为4bit  S[i]对应i次迭代的数据0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,        //  4.最终得到32bit数据4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,// S2 15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,// S3 10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,// S4 7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,// S5 2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,// S6 12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,// S7 4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,// S8 13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};
// 32-bit permutation function P used on the output of the S-boxes
const static char P_Table[32] = {//将得到的32bit right数据按P_Table进行置换,得到新数据right16, 7, 20, 21, 29, 12, 28, 17, 1,  15, 23, 26, 5,  18, 31, 10,//将right与left进行位异或操作,结果赋值给right2,  8, 24, 14, 32, 27, 3,  9,  19, 13, 30, 6,  22, 11, 4,  25 //将本次的原始right值赋值给left
};                                                  //得到的left和right进行下一次迭代操作
// final permutation IP^-1
const static char IPR_Table[64] = {//将left和right结合,按IPR_Table表进行置换,结果为最终的加密数据40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41,  9, 49, 17, 57, 25
};extern "C" void initialization()
{memset(szKeys, 0, 16 * 48);memset(szCipherText, 0, 64);memset(szplaintText, 0, 64);memset(szCiphertextInBytes, 0, 8);memset(szPlaintextInBytes, 0, 8);memset(szCiphertextInBinary, 0, 65);memset(szCiphertextInHex, 0, 17);}
extern "C" char *DES_GetszCiphertextInBytes()
{return szCiphertextInBytes;
}
extern "C" char *DES_GetszPlaintextInBytes()
{return szPlaintextInBytes;
}
extern "C" void DES_InitializeKey(char* srcBytes)
{char sz_64key[64] = { 0 };char sz_56key[56] = { 0 };DES_Bytes2Bits(srcBytes, sz_64key, 64);for (int i = 0; i < 56; i++)    //置换64位密钥为56位{sz_56key[i] = sz_64key[PC1_Table[i]-1];}DES_CreateSubKey(sz_56key);
}extern "C" void DES_CreateSubKey(char* sz_56key)
{int i, j;char sz_leftKey[28] = { 0 };char sz_rightKey[28] = { 0 };char sz_tempL[28] = { 0 };char sz_tempR[28] = { 0 };char sz_temp56[56] = { 0 };memcpy(sz_leftKey, sz_56key, 28);memcpy(sz_rightKey, sz_56key+28, 28);for (i = 0; i < 16; i++){memcpy(sz_tempL, sz_leftKey + Shift_Table[i], 28 - Shift_Table[i]); //移位操作memcpy(sz_tempL + 28 - Shift_Table[i], sz_leftKey, Shift_Table[i]);memcpy(sz_tempR, sz_rightKey + Shift_Table[i], 28 - Shift_Table[i]);//移位操作memcpy(sz_tempR + 28 - Shift_Table[i], sz_rightKey, Shift_Table[i]);memcpy(sz_temp56, sz_tempL, 28);memcpy(sz_temp56+28, sz_tempR, 28);for (j = 0; j < 48; j++){szKeys[i][j] = sz_temp56[PC2_Table[j]-1];  //生成16组48位的子密钥}memcpy(sz_leftKey, sz_tempL, 28);memcpy(sz_rightKey, sz_tempR, 28);}
}
extern "C" void DES_EncryptData(char* _srcBytes) //加密8位字符串
{int i = 0,j=0;char sz_srcBits[64] = { 0 };char sz_shiftIP[64] = { 0 };char sz_srcL[32] = { 0 };char sz_srcR[32] = { 0 };char sz_resultBits[64] = { 0 };DES_Bytes2Bits(_srcBytes, sz_srcBits, 64);  for (i = 0; i < 64; i++){sz_shiftIP[i] = sz_srcBits[IP_Table[i]-1];  //64位明文置换}memcpy(sz_srcL, sz_shiftIP, 32);memcpy(sz_srcR, sz_shiftIP + 32, 32);for (i = 0; i<16; i++)    //16次迭代操作{DES_FunctionF(sz_srcL, sz_srcR, i);}memcpy(sz_resultBits, sz_srcR, 32);  //组合left、rightmemcpy(sz_resultBits + 32, sz_srcL, 32);for (j = 0; j<64; j++){szCipherText[j] = sz_resultBits[IPR_Table[j] - 1];   //进行逆置换}DES_Bits2Bytes(szCiphertextInBytes, szCipherText, 64);
}
extern "C" void DES_FunctionF(char* sz_srcL, char* sz_srcR, unsigned int iKey)
{int i = 0;char sz_P32[32] = { 0 };char sz_R[32] = { 0 };char sz_48R[48] = { 0 };char sz_key[48] = { 0 };char sz_xor[48] = { 0 };char compressData32[32] = { 0 };for (i = 0; i < 48; i++)  //right 扩展{sz_48R[i] = sz_srcR[E_Table[i]-1];}memcpy(sz_key, szKeys[iKey], 48);DES_XOR(sz_48R, sz_key, 48, sz_xor); //扩展后的right与子密钥进行异或操作DES_CompressFunc(sz_xor, compressData32);//异或结果进行压缩成32bitfor (i = 0; i<32; i++){sz_P32[i] = compressData32[P_Table[i] - 1]; // 压缩后的数据进行置换}DES_XOR(sz_P32, sz_srcL, 32, sz_R);  //置换后的right与left数据进行异或memcpy(sz_srcL, sz_srcR, 32);    //传入的初始right赋值给left作为下次的leftmemcpy(sz_srcR, sz_R, 32);//左右异或生成的right的值作为下次运算的right}
extern "C" void DES_XOR(char* szParam1, char* szParam2, unsigned int uiParamLength, char* szReturnValueBuffer)//异或操作
{unsigned int i = 0;for (i = 0; i<uiParamLength; i++){szReturnValueBuffer[i] = szParam1[i] ^ szParam2[i];}
}
extern "C" void DES_CompressFunc(char* _src48, char* _dst32)//压缩数据
{char tempBit[8][6] = { 0 };char dest4bit[4] = { 0 };int i = 0, X = 0, Y = 0, j = 0;for (i = 0; i<8; i++){memcpy(tempBit[i], _src48 + i * 6, 6);X = (tempBit[i][0] << 1 )+ (tempBit[i][5]);Y = 0;for (j = 1; j<5; j++){Y += tempBit[i][j] << (4 - j);}DES_Int2Bits(S_Box[i][X][Y], dest4bit);memcpy(_dst32 + i * 4, dest4bit, 4);}
}
extern "C" void DES_Bytes2Bits(char *srcBytes, char* dstBits, unsigned int sizeBits)
{unsigned int i = 0;for (i = 0; i < sizeBits; i++)dstBits[i] = ((srcBytes[i >> 3] << (i & 7)) & 128) >> 7;
}extern "C" void DES_Bits2Bytes(char *dstBytes, char* srcBits, unsigned int sizeBits)
{unsigned int i = 0;memset(dstBytes, 0, sizeBits >> 3);for (i = 0; i < sizeBits; i++)dstBytes[i >> 3] |= (srcBits[i] << (7 - (i & 7)));
}extern "C" void DES_Int2Bits(unsigned int _src, char* dstBits)
{unsigned int i = 0;for (i = 0; i < 4; i++)dstBits[i] = ((_src << i) & 8) >> 3;
}extern "C" void DES_Bits2Hex(char *dstHex, char* srcBits, unsigned int sizeBits)
{unsigned int i = 0, j = 0;memset(dstHex, 0, sizeBits >> 2);for (i = 0; i < sizeBits; i++) //convert to int 0-15dstHex[i >> 2] += (srcBits[i] << (3 - (i & 3)));for (j = 0; j < (sizeBits >> 2); j++)  dstHex[j] += dstHex[j] > 9 ? 55 : 48; //convert to char '0'-'F'
}extern "C" void DES_Hex2Bits(char *srcHex, char* dstBits, unsigned int sizeBits)
{unsigned int i = 0, j = 0;memset(dstBits, 0, sizeBits);for (i = 0; i < (sizeBits >> 2); i++)srcHex[i] -= srcHex[i] > 64 ? 55 : 48; //convert to char int 0-15for (j = 0; j < sizeBits; j++)dstBits[j] = ((srcHex[j >> 2] << (j & 3)) & 15) >> 3;}
extern "C" void DES_DecryptData(char* _srcBytes) //解密8位字符串
{int i = 0, j = 0;char sz_srcBits[64] = { 0 };char sz_shiftIP[64] = { 0 };char sz_srcL[32] = { 0 };char sz_srcR[32] = { 0 };char sz_resultBits[64] = { 0 };DES_Bytes2Bits(_srcBytes, sz_srcBits, 64);for (i = 0; i < 64; i++){sz_shiftIP[i] = sz_srcBits[IP_Table[i] - 1];  }memcpy(sz_srcR, sz_shiftIP, 32);memcpy(sz_srcL, sz_shiftIP + 32, 32);for (i = 0; i<16; i++)    {DES_FunctionF(sz_srcR, sz_srcL, 15 - i);}memcpy(sz_resultBits, sz_srcL, 32);  memcpy(sz_resultBits + 32, sz_srcR, 32);for (j = 0; j<64; j++){szplaintText[j] = sz_resultBits[IPR_Table[j] - 1];   }DES_Bits2Bytes(szPlaintextInBytes, szplaintText, 64);
}

IoT:电子密本ECB和DES模式详解相关推荐

  1. getinstance方法详解_二、设计模式总览及工厂模式详解

    二.架构师内功心法之设计模式 2.架构师内功心法之设计模式 2.1.课程目标 1.通过对本章内容的学习,了解设计模式的由来. 2.介绍设计模式能帮我们解决哪些问题. 3.剖析工厂模式的历史由来及应用场 ...

  2. Spotify敏捷模式详解三部曲第二篇:研发过程

    本文转自:Scrum 中文网 引言 在本系列文章的第一篇,我们介绍了Spotify的敏捷研发团队,以及它独特的组织架构.Spotify的研发团队采用的是一种非常独特的组织架构,如下图所示: 整个研发组 ...

  3. Spotify敏捷模式详解三部曲第一篇:研发团队

    本文转自:Scrum中文网 引言 2018年4月,来自北欧瑞典的音乐流媒体公司.百亿美元独角兽Spotify创造了历史,它成为了当代上市公司当中,第一家通过"直接上市"的方式在美国 ...

  4. Docker(十四):Docker:网络模式详解

    Docker作为目前最火的轻量级容器技术,牛逼的功能,如Docker的镜像管理,不足的地方网络方面. Docker自身的4种网络工作方式,和一些自定义网络模式 安装Docker时,它会自动创建三个网络 ...

  5. linux apache两种工作模式详解

    apache两种工作模式详解 刚接触这两个配置时很迷糊,全部开启或全部注释没有几多变化.今天搜索到这么一篇讲得还不错的文章,看了几篇,还是不能完全记住,做一个收藏. 空闲子进程:是指没有正在处理请求的 ...

  6. cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...

  7. STM32开发 -- 低功耗模式详解(2)

    如需转载请注明出处:https://juyou.blog.csdn.net/article/details/98631012 上一篇文章 STM32开发 – 低功耗模式详解(1) 简单的总结了一下低功 ...

  8. 【Tools】VMware虚拟机三种网络模式详解和操作

    00. 目录 文章目录 00. 目录 01. VMware虚拟机三种网络模式 02. Bridged(桥接模式) 03. NAT(地址转换模式) 04. Host-Only(仅主机模式) 05. 参考 ...

  9. Activity的启动模式详解

    Activity的启动模式详解 Activity有四种载入模式:standard(默认), singleTop, singleTask和 singleInstance. (1).standard(默认 ...

最新文章

  1. Integer的自动缓存
  2. SpringBoot第十七篇:上传文件
  3. 献给那些怀揣IT梦想的北漂一族
  4. python【蓝桥杯vip练习题库】ADV-9 递归倒置字符数组
  5. Java String,StringBuilder和StringBuffer的区别 StringBuilder StringBuffer String
  6. python rq asyncio_Python 的异步 IO:Asyncio 简介
  7. MyBatis-Plus 高级功能 —— 实现逻辑删除
  8. 目前区块链项目的生态系统:一共七大类
  9. Taro+react开发(41)封装组件2
  10. 中国制造特斯拉亮相 中文车尾标亮了!网友:好抠吗?
  11. CUDA中的复数定义、开内存空间以及运算
  12. 中国半导体蚀刻设备行业市场供需与战略研究报告
  13. 智能优化算法:蜻蜓优化算法-附代码
  14. 使用Nodejs 批量下载文件, 甘特图 gantt-schedule-timeline-calendar 免费
  15. GD32F130之DMA
  16. 智课雅思短语---三、unshakable duty
  17. 初中三年级数学可以用计算机吗,不到3分钟,这份初中数学攻略被家长和学生疯狂转发!太实用了!...
  18. Facebook 开源微光效果 Shimmer
  19. 最新面试必看的 数据库 知识大总结
  20. h5网站建设设计解决方案

热门文章

  1. Android开发学习之路-LruCache使用和源码分析
  2. Android——RelativeLayout(相对布局)
  3. 请问spfa+stack 和spfa+queue 是什么原理
  4. 华为牛人在华为工作十年的感悟!--总结[华为的10年工作]
  5. eclipse + mapxtreme 代码示例1
  6. 推模式下dataset1下显示的是...未找到项目... 问题的解决
  7. yum提示“Cannot retrieve metalink for repository: epel/x86_64” 解决方法
  8. Cisco——DHCPv6小实验
  9. CentOS下ELK基于ElastAlert实现日志的微信报警
  10. 安装zabbix4.0