DES加密算法介绍(含例子)
http://www.hankcs.com/security/des-algorithm-illustrated.html
DES(Data Encryption Standard)算法是世界上最常用的加密算法。在很长时间内,许多人心目中“密码生成”与DES一直是个同义词。
DES是怎么工作的?本文通过一个简单的例子来一部一部展示DES的加密流程。自动DES诞生以来,许多加密算法都采用了类似DES的手段。一旦理解了DES中的变换,你一定能够更轻松的理解这些现代加密算法中的门道。
DES处理比特,或者说二进制数字,我们知道,没四个比特构成一个十六进制数。DES加密一组64位的信息,也就是16个16进制数。为了完成加密,DES
DES秘钥获取:
我们取16进制秘钥K为:
K = 133457799BBCDFF1
我们可以得到他的二进制形式(1为0001,3为0011,依次类推,并且将没8位写成一组。这样每组的最后一位都没有被用上。)
K = 00010011 00110100 01010111 01111001 10011011 10111100 11011111 11110001
创建16个子秘钥,每个长48比特
这个64位的秘钥首先根据表格PC-1进行变换。
表PC-1
57 | 49 | 41 | 33 | 25 | 17 | 9 |
1 | 58 | 50 | 42 | 34 | 26 | 18 |
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 |
由于上表中第一个元素为57,这将使元秘钥的第57位变换为新秘钥K+的第一位。同理,元秘钥的第49位变换为新秘钥的第2位,,,元秘钥的第4位变换为新秘钥的最后一位,注意元秘钥中只有56位会进入新秘钥,上表也只有56个元素。
比如,对于原秘钥:
K = 00010011 00110100 01010111 01111001 10011011 10111100 11011111 11110001
我们将得到56位新秘钥:
K+ = 1111000 0110011 0010101 0101111 0101010 1011001 1001111 0001111
然后,我们将这个密钥拆分为左右两个部分,C0和D0,每半边都有28位。
比如,对于新密钥,我们得到:
C0 = 1111000 0110011 0010101 0101111
D0 = 0101010 1011001 1001111 0001111
对于相同定义的C0和D0,我们现在创建16个块Cn和Dn 1<=n<=16.
每一对Cn和Dn都是由前一对Cn-1和Dn-1移位而来。具体来说,对于n=1,2,3,。。。,16,在前一轮移位的结果上,进行左移操作。什么叫左移?左移指的是将除第一位外的所有为往左移一位,将第一位移动至最后一位。
这意味着,比如说,C3和D3是C2和D2移位而来的,具体来说,通过2次左移位,C16和D16则是由C15和D15通过1次左移得到的。在所有情况下,一次左移就是将所有比特往左移动一位。使的一位后的比特的位置相较于变换前成为2,3,4,,,28,1.
比如,对于原始字谜要C0和D0,我们得到:
C0 = 1111000011001100101010101111
C1 = 1110000110011001010101011111
C2 = 1100001100110010101010111111
C3 = 0000110011001010101011111111
C4 = 0011001100101010101111111100
C5 = 1100110010101010111111110000
C6 = 0011001010101011111111000011
C7 = 1100101010101111111100001100
C8 = 0010101010111111110000110011
C9 = 0101010101111111100001100110
C10 = 0101010111111110000110011001
C11 = 0101011111111000011001100101
C12 = 0101111111100001100110010101
C13 = 0111111110000110011001010101
C14 = 1111111000011001100101010101
C15 = 1111100001100110010101010111
C16 = 1111000011001100101010101111
D0 = 0101010101100110011110001111
D1 = 1010101011001100111100011110
D2 = 0101010110011001111000111101
D3 = 0101011001100111100011110101
D4 = 0101100110011110001111010101
D5 = 0110011001111000111101010101
D6 = 1001100111100011110101010101
D7 = 0110011110001111010101010110
D8 = 1001111000111101010101011001
D9 = 0011110001111010101010110011
D10 = 1111000111101010101011001100
D11 = 1100011110101010101100110011
D12 = 0001111010101010110011001111
D13 = 0111101010101011001100111100
D14 = 1110101010101100110011110001
D15 = 1010101010110011001111000111
D16 = 0101010101100110011110001111
我们现在就可以得到第n轮的新秘钥Kn(1<=n<=16)了。具体做法是,对每一对拼合后的子秘钥CnDn,按照表PC-2执行变换:
14 | 17 | 11 | 24 | 1 | 5 |
3 | 28 | 15 | 6 | 21 | 10 |
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 |
每对子秘钥有56位,但是PC-2仅仅使用其中48位。
于是,第你轮新秘钥Kn的第一位来自组合秘钥CnDn的第14位,第2位来自第17位,以此类推,知道新秘钥的第48位来自组合秘钥的第32位。
比如:
对于第一轮的组合秘钥,我们有:
C1D1 = 1110000 1100110 0101010 1011111 1010101 0110011 0011110 0011110
通过PC-2的变换后,得到:
K1 = 000110 110000 001011 101111 111111 000111 000001 110010
同理,对于其他秘钥,我们得到:
K2 = 011110 011010 111011 011001 110110 111100 100111 100101
K3 = 010101 011111 110010 001010 010000 101100 111110 011001
K4 = 011100 101010 110111 010110 110110 110011 010100 011101
K5 = 011111 001110 110000 000111 111010 110101 001110 101000
K6 = 011000 111010 010100 111110 010100 000111 101100 101111
K7 = 111011 001000 010010 110111 111101 100001 100010 111100
K8 = 111101 111000 101000 111010 110000 010011 101111 111011
K9 = 111000 001101 101111 101011 111011 011110 011110 000001
K10 = 101100 011111 001101 000111 101110 100100 011001 001111
K11 = 001000 010101 111111 010011 110111 101101 001110 000110
K12 = 011101 010111 000111 110101 100101 000110 011111 101001
K13 = 100101 111100 010111 010001 111110 101011 101001 000001
K14 = 010111 110100 001110 110111 111100 101110 011100 111010
K15 = 101111 111001 000110 001101 001111 010011 111100 001010
K16 = 110010 110011 110110 001011 000011 100001 011111 110101
关于子秘钥的话题我们就到此为止,接下来我们看信息本身。
DES是一个基于组块的加密算法,这意味着无论输入还是输出都是64位长度。也就是说DES产生了一种最多264中的变换方法。每个64位的区块被分为2个32位的部分,左半部分L和右半部分R。
比如明文,M为
M = 0123456789ABCDEF
这里的M是16进制的,将M写成二进制,我们得到一个64位的区块:
M = 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
L = 0000 0001 0010 0011 0100 0101 0110 0111
R = 1000 1001 1010 1011 1100 1101 1110 1111
M的第一位是0,最后一位是1,我们从左读到右。
对于明文M,我们计算一下初始变换IP(Initial permutation)。IP是重新变换数据M的每一位产生的。产生过程由下表决定,表格的下标对应新数据的下标,表格的数值x表示新数据的这一位来自旧数据的第x位。
比如,对M的区块,执行初始变换,得到:
M = 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
IP = 1100 1100 0000 0000 1100 1100 1111 1111 1111 0000 1010 1010 1111 0000 1010 1010
接着讲变换IP分为32位的左半边L0和右半边R0
比如,对于上例,我们得到:
L0 = 1100 1100 0000 0000 1100 1100 1111 1111
R0 = 1111 0000 1010 1010 1111 0000 1010 1010
我们接着执行16个迭代,对1<=n<=16,使用一个函数f.函数f输入两个区块,一个32位的数据块和一个48位的木曜区块Kn,输出一个32位的区块。定义+表示异或XOR。那么让n从1循环到16,我们计算:
Ln=Rn-1
Rn=Ln-1+f(Rn-1,Kn)
这样我们就得到最终区块,也就是n=16的L16R16.这个过程说白了就是,我们那前一个迭代结果的右边32位作为当前迭代的左边32位。对于当前迭代的右边32位,将它和上一个迭代的f函数的输出执行XOR运算。
比如,对于n=1,我们有:
K1 = 000110 110000 001011 101111 111111 000111 000001 110010
L1 = R0 = 1111 0000 1010 1010 1111 0000 1010 1010
R1 = L0 + f(R0,K1)
剩下就是f函数是如何工作的了,为了计算f,我们首先扩展每个Rn-1,将其从32位扩展到48位,这是通过使用一张表来重复Rn-1中的一位位来实现的。我们称这个过程为函数E。也就是说函数E(Rn-1)输入32位输出48位。
定义E为函数E的输出,将其写成8组,每组6位,这些比特是通过选择输入的某些位来产的,具体选择顺序按照如下表格实现:
32 | 1 | 2 | 3 | 4 | 5 |
4 | 5 | 6 | 7 | 8 | 9 |
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 |
也就是说E(Rn-1)开头的三个比特分别来自Rn-1的第32、1和2位。E(Rn-1)末尾的2个比特分别来自Rn-1的第32位和第1位。
比如:给定R0,我们可以计算出E(R0):
R0 = 1111 0000 1010 1010 1111 0000 1010 1010
E(R0) = 011110 100001 010101 010101 011110 100001 010101 010101
接着在f函数中,我们对输出E(Rn-1)和秘钥Kn执行XOR运算:
Kn+E(Rn-1)
比如,对K1,E(R0),我们有:
K1 = 000110 110000 001011 101111 111111 000111 000001 110010
E(R0) = 011110 100001 010101 010101 011110 100001 010101 010101
K1+E(R0) = 011000 010001 011110 111010 100001 100110 010100 100111
到这里我们还没有完成f函数的运算,我们仅仅使用一张表将Rn-1从32位扩展为48位,并且对这个结果和秘钥Kn执行了异或运算。我们现在有了48位的结果,或者说8组6比特数据。我们现在要对每组的6比特执行一些奇怪的操作:
我们将它作为一张被称为“S盒”的表格的地址。每组6比特都将给我们一个位于不同S盒中的地址。在哪个地址里存放着一个4比特的数字。这个4比特的数字将会替换掉原来的6个比特。最终结果就是,8组6比特的数据被转换为8组4比特(一共32位)的数据。
将上一步的48位的结果写成如下形式:
Kn+E(Rn-1)=B1B2B3B4B5B6B7B8
每个Bi都是一个6比特的分组,我们现在计算
S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8)
其中,Si(Bi)指的是第i个S盒的输出。
为了计算每个S函数S1,S2,,,S8,取一个6位的区块作为输入,输出一个4位的区块。决定S1的表格如下:
S1Column Number
Row | ||||||||||||||||
No. | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
0 | 14 | 4 | 13 | 1 | 2 | 15 | 11 | 8 | 3 | 10 | 6 | 12 | 5 | 9 | 0 | 7 |
1 | 0 | 15 | 7 | 4 | 14 | 2 | 13 | 1 | 10 | 6 | 12 | 11 | 9 | 5 | 3 | 8 |
2 | 4 | 1 | 14 | 8 | 13 | 6 | 2 | 11 | 15 | 12 | 9 | 7 | 3 | 10 | 5 | 0 |
3 | 15 | 12 | 8 | 2 | 4 | 9 | 1 | 7 | 5 | 11 | 3 | 14 | 10 | 0 | 6 | 13 |
如果S1是定义在这张表上的函数,B是一个6位的块,那么计算S1(B)的方法是:B的第一位和最后一位组合起来,的二进制数决定一个介于0和3之间的十进制数(或者二进制00到11之间)。设这个数为i,B的中间4位二进制数代表一个介于0到15之间的二进制数(二进制0000到1111)。设这个数为j。查表找到第i行第j列的那个数,这个是一个介于0和15之间的数,并且它是能由一个唯一的4位区块表示的。这个区块就是函数S1输入B得到的输出S1(B)。比如,对输入B=011011,第一位是0,最后一位是1,决定了行号是01,也就是十进制的1,中间4位是1101,也就是十进制的13,虽有列号是13.查表第一行第13列我们得到数字5.
这就决定了输出;5的二进制是0101,所以输出就是0101,即S1(011011)=0101。
同理,定义这8个函数S1,S2,,,S8:
14 | 4 | 13 | 1 | 2 | 15 | 11 | 8 | 3 | 10 | 6 | 12 | 5 | 9 | 0 | 7 |
0 | 15 | 7 | 4 | 14 | 2 | 13 | 1 | 10 | 6 | 12 | 11 | 9 | 5 | 3 | 8 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
例子:对弈第一轮,我们得到这8个S盒的输出:
K1+E(R0)=011000 010001 011110 111010 100001 100110 010100 100111
S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8)=0101 1100 1000 0010 1011 0101 1001 0111
函数f的最后一步就是对S盒的输出进行一个变换来产生最终值:
f=P(S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8))
变换P由如下表格定义。P输入32位数据,通过下表产生32位输出:
16 7 20 21
29 12 28 17
1 15 23 26
5 18 31 10
2 8 24 14
32 27 3 9
19 13 30 6
22 11 4 25
比如对8个S盒的输出:
S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8)=0101 1100 1000 0010 1011 0101 1001 0111
我们得到:
f=0010 0011 0100 1010 1010 1001 1011 1011
那么R1=L0+f(R0,K1)
= 1100 1100 0000 0000 1100 1100 1111 1111
+ 0010 0011 0100 1010 1010 1001 1011 1011
= 1110 1111 0100 1010 0110 0101 0100 0100
在下一轮迭代中,我们的L2=R1,这就是我们刚刚计算的结果。之后,我们必须计算R2=L1+f(R1,K2),一直完成16个迭代之后,我们有了区块L16和R16,。接着我们逆转两个区块的顺序得到一个64位的区块:
R16L16
然后,我们对其执行一个最终的IP-1,其定义如下:
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 |
也就是说,该变换的输出的第一位是输入的第40位,第二位是输入的8位,一直到将输入的第25位作为输出的最后一位。
比如,我们使用上述方法得到了第16轮的左右两个区块:
L16 = 0100 0011 0100 0010 0011 0010 0011 0100
R16 = 0000 1010 0100 1100 1101 1001 1001 0101
我们将两个区块调换位置,然后执行最终变换:
R16L16 = 00001010 01001100 11011001 10010101 01000011 01000010 00110010 00110100
IP-1 = 10000101 11101000 00010011 01010100 00001111 00001010 10110100 00000101
写成16进制得到:
85E813540F0AB405
这就是明文M=0123456789ABCDEF的密文:85E813540F0AB405
解密就是加密的反过程,执行上述步骤,只不过在那16轮迭代中,调转左右子秘钥的位置而已。
DES加密算法介绍(含例子)的更多相关文章
- 浅谈DES加密算法
一.DES加密算法介绍 1.要求密钥必须是8个字节,即64bit长度 2.因为密钥是byte[8] , 代表字符串也可以是非可见的字节,可以与Base64编码算法一起使用 3.加密.解密都需要通过字节 ...
- 在.NET Core 里使用 BouncyCastle 的DES加密算法
.NET Core上面的DES等加密算法要等到1.2 才支持,我们可是急需这个算法的支持,文章<使用 JavaScriptService 在.NET Core 里实现DES加密算法>需要用 ...
- DES加密算法实现
好久没写博客了,正好趁着实现网络工程与安全的DES算法的功夫,把代码发上来. DES的介绍可见:DES加密 原理不赘述了..实在太多,其实就是一个形式化算法,按部就班的实现就可以,只不过有些繁琐,我写 ...
- 不用搭环境的10分钟AngularJS指令简易入门01(含例子)
不用搭环境的10分钟AngularJS指令简易入门01(含例子) `#不用搭环境系列AngularJS教程01,前端新手也可以轻松入坑~阅读本文大概需要10分钟~` AngularJS的指令是一大特色 ...
- 对称密码——DES加密算法
前言 本篇博文将介绍对称密码算法中的DES密码的算法原理与代码实现(Java) DES算法原理 DES加密算法是对称加密算法(加密和解密使用同一个密钥)中的一种,DES也是分组密码,以64位为分组对明 ...
- android和.net webservice中的DES加密算法
也是看了一堆的例子,本身并不会写加密算法,好在只要会用就行了,我们把在app中使用的参数加密,然后在.net端的webservice中进行解密,本身并没有什么问题,但是android下和.net下的d ...
- DES加密算法的C++实现
<信息安全技术>这门课又在讲 DES 加密算法了,以前用纯C写过一次,这次我用 C++ 重新写了一个,写篇文章以备后用.本文介绍了 DES 算法加密的大致步骤和整体流程. 一.DES算法原 ...
- JAVA使用DES加密算法加密解密
程序中使用了.properties文件作为参数配置文档,好处是灵活配置各项参数 一旦对数据库的一些参数进行了配置,势必涉及数据库的IP,端口,用户名和密码 properties文件全是unicode编 ...
- des加密算法java&c#
项目中用到的数据加密方式是ECB模式的DES加密得到的十六进制字符串.技术支持让写一个.net版的加密算法.这里做一下记录. java版: 16进制使用的是bouncycastle. import c ...
随机推荐
- 阿里云 azkaban 发邮件的坑
azkaban : 是一个 任务调度平台 安装文档: https://azkaban.readthedocs.io/en/latest/getStarted.html 因为阿里云是禁止掉是STMP 2 ...
- 【K8S】helm chart多环境部署最佳实践-示例
Chart.yaml apiVersion: v1 appVersion: "1.0" description: A Helm chart for Kubernetes name: ...
- AQS1---走向稳定态
AQS的思想(稳定思想):即使确定了正常节点,这个节点也可能下一秒异常,即使找到了正常节点,这个节点可能只是异常status=0/-1的节点,这些都不要紧,都只是在自己旋转‘生命周期’里面和自己所看到 ...
- TreeMap源码分析1
二叉树他们都需要满足一个基本性质--即树中的任何节点的值大于它的左子节点,且小于它的右子节点.按照这个基本性质使得树的检索效率大大提高.我们知道在生成二叉树的过程是非常容易失衡的,最坏的情况就是一边倒 ...
- jquery插件实现瀑布流
jquery插件实现瀑布流<!DOCTYPE html><html lang="en"><head> <meta charset=&quo ...
- Scala Type Parameters 2
类型关系 Scala 支持在泛型类上使用型变注释,用来表示复杂类型.组合类型的子类型关系间的相关性 协变 +T,变化方向相同,通常用在生产 假设 A extends T, 对于 Clazz[+T],则 ...
- c/c++封装成python包
参考网址:https://blog.csdn.net/tiankongtiankong01/article/details/80420033 SWIG (Simplified Wrapper and ...
- Java学习:异常的概念
异常 异常概念 异常:指的是程序在执行过程中,出现的非正常的情况,最终导致JVM的非正常停止. 在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出一个异常对象.Java ...
- K8S学习笔记之k8s使用ceph实现动态持久化存储
0x00 概述 本文章介绍如何使用ceph为k8s提供动态申请pv的功能.ceph提供底层存储功能,cephfs方式支持k8s的pv的3种访问模式ReadWriteOnce,ReadOnlyMany ...
- (原创)C#操作MYSQL数据库
应用程序对数据库的操作都是只有4个:增,删,改,查. 只有”查”的操作需要使用适配器来存储查询得到的数据.其它3个操作不需要用到适配器. 不同的数据库有共同操作方法:都要建立连接对象,连接对象要有连接 ...