IoT:电子密本ECB和DES模式详解
1.ECB模式详解
转自:https://blog.csdn.net/sunqiujing/article/details/75066924
DES参考这篇博文:写的好
https://blog.csdn.net/qq_27570955/article/details/52442092
ECB模式(电子密码本模式)
在ECB模式中,将明文分组加密之后的结果直接作为密文分组,缺点是会容易攻击,因为明文相同的密文相同
目录
- 1概念
- 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模式详解相关推荐
- getinstance方法详解_二、设计模式总览及工厂模式详解
二.架构师内功心法之设计模式 2.架构师内功心法之设计模式 2.1.课程目标 1.通过对本章内容的学习,了解设计模式的由来. 2.介绍设计模式能帮我们解决哪些问题. 3.剖析工厂模式的历史由来及应用场 ...
- Spotify敏捷模式详解三部曲第二篇:研发过程
本文转自:Scrum 中文网 引言 在本系列文章的第一篇,我们介绍了Spotify的敏捷研发团队,以及它独特的组织架构.Spotify的研发团队采用的是一种非常独特的组织架构,如下图所示: 整个研发组 ...
- Spotify敏捷模式详解三部曲第一篇:研发团队
本文转自:Scrum中文网 引言 2018年4月,来自北欧瑞典的音乐流媒体公司.百亿美元独角兽Spotify创造了历史,它成为了当代上市公司当中,第一家通过"直接上市"的方式在美国 ...
- Docker(十四):Docker:网络模式详解
Docker作为目前最火的轻量级容器技术,牛逼的功能,如Docker的镜像管理,不足的地方网络方面. Docker自身的4种网络工作方式,和一些自定义网络模式 安装Docker时,它会自动创建三个网络 ...
- linux apache两种工作模式详解
apache两种工作模式详解 刚接触这两个配置时很迷糊,全部开启或全部注释没有几多变化.今天搜索到这么一篇讲得还不错的文章,看了几篇,还是不能完全记住,做一个收藏. 空闲子进程:是指没有正在处理请求的 ...
- cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战
1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...
- STM32开发 -- 低功耗模式详解(2)
如需转载请注明出处:https://juyou.blog.csdn.net/article/details/98631012 上一篇文章 STM32开发 – 低功耗模式详解(1) 简单的总结了一下低功 ...
- 【Tools】VMware虚拟机三种网络模式详解和操作
00. 目录 文章目录 00. 目录 01. VMware虚拟机三种网络模式 02. Bridged(桥接模式) 03. NAT(地址转换模式) 04. Host-Only(仅主机模式) 05. 参考 ...
- Activity的启动模式详解
Activity的启动模式详解 Activity有四种载入模式:standard(默认), singleTop, singleTask和 singleInstance. (1).standard(默认 ...
最新文章
- Integer的自动缓存
- SpringBoot第十七篇:上传文件
- 献给那些怀揣IT梦想的北漂一族
- python【蓝桥杯vip练习题库】ADV-9 递归倒置字符数组
- Java String,StringBuilder和StringBuffer的区别 StringBuilder StringBuffer String
- python rq asyncio_Python 的异步 IO:Asyncio 简介
- MyBatis-Plus 高级功能 —— 实现逻辑删除
- 目前区块链项目的生态系统:一共七大类
- Taro+react开发(41)封装组件2
- 中国制造特斯拉亮相 中文车尾标亮了!网友:好抠吗?
- CUDA中的复数定义、开内存空间以及运算
- 中国半导体蚀刻设备行业市场供需与战略研究报告
- 智能优化算法:蜻蜓优化算法-附代码
- 使用Nodejs 批量下载文件, 甘特图 gantt-schedule-timeline-calendar 免费
- GD32F130之DMA
- 智课雅思短语---三、unshakable duty
- 初中三年级数学可以用计算机吗,不到3分钟,这份初中数学攻略被家长和学生疯狂转发!太实用了!...
- Facebook 开源微光效果 Shimmer
- 最新面试必看的 数据库 知识大总结
- h5网站建设设计解决方案
热门文章
- Android开发学习之路-LruCache使用和源码分析
- Android——RelativeLayout(相对布局)
- 请问spfa+stack 和spfa+queue 是什么原理
- 华为牛人在华为工作十年的感悟!--总结[华为的10年工作]
- eclipse + mapxtreme 代码示例1
- 推模式下dataset1下显示的是...未找到项目... 问题的解决
- yum提示“Cannot retrieve metalink for repository: epel/x86_64” 解决方法
- Cisco——DHCPv6小实验
- CentOS下ELK基于ElastAlert实现日志的微信报警
- 安装zabbix4.0