精华内容
下载资源
问答
  • http://www.hankcs.com/security/des-algorithm-illustrated.html DES(Data Encryption Standard)算法是世界上常用...本文通过一个简单例子来一部一部展示DES的加密流程。自动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

    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执行变换:

    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位,这些比特是通过选择输入的某些位来产的,具体选择顺序按照如下表格实现:

    E BIT-SELECTION TABLE
    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:

    S1
    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

     

     

    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

    例子:对弈第一轮,我们得到这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  45  13  53  21  61  29 
    36  44  12  52  20  60  28 
    35  43  11  51  19  59  27 
    34  42  10  50  18  58  26 
    33  41  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轮迭代中,调转左右子秘钥的位置而已。

    转载于:https://www.cnblogs.com/LoganChen/p/11432092.html

    展开全文
  • 这是在课堂上讲解的一个例子最简单的对称算法DES关于该算法的一些说明,有兴趣的朋友可以参考下面的链接http://baike.baidu.com/view/7510.htm static void Main(string[] args) { DES des = DES.Create...
    这是在课堂上讲解的一个例子,最简单的对称算法,DES
    关于该算法的一些说明,有兴趣的朋友可以参考下面的链接
    http://baike.baidu.com/view/7510.htm
     
     
        static void Main(string[] args)
        {
            DES des = DES.Create();
            des.Key = Convert.FromBase64String("12345678910=");
            des.IV = Convert.FromBase64String("12345678910=");
            //DES的算法密钥和向量必须是12位,而且最后一位必须的=
            //而且必须用FromBase64String的方式获取
    
            string original = "Hello,world";
            byte[] data = EncryptText(original, des.Key, des.IV);//加密
            string result = DecryptText(data, des.Key, des.IV);//解密
    
            Console.WriteLine(result);
            Console.Read();
    
    
        }
    
        private static string DecryptText(byte[] data, byte[] key, byte[] iv)
        {
            MemoryStream ms = new MemoryStream(data);
            DES des = DES.Create();
            CryptoStream stream = new CryptoStream(ms, des.CreateDecryptor(key, iv), CryptoStreamMode.Read);
            byte[] from = new byte[data.Length];
            stream.Read(from, 0, from.Length);
    
            return Encoding.ASCII.GetString(from);
    
        }
    
        private static byte[] EncryptText(string original, byte[] key, byte[] iv)
        {
            MemoryStream ms = new MemoryStream();//用来接收密文的内存流
            DES des = DES.Create();
            CryptoStream stream = new CryptoStream(ms, des.CreateEncryptor(key, iv), CryptoStreamMode.Write);
            //创建加密流
    
            byte[] to = Encoding.ASCII.GetBytes(original);//获取输入的字符串的字节
            stream.Write(to, 0, to.Length);//写入加密流
            stream.FlushFinalBlock();//写入内存流,并清空缓冲区
            byte[] ret = ms.ToArray();
            stream.Close();
            ms.Close();
    
            return ret;
    
        }

    转载于:https://www.cnblogs.com/chenxizhang/archive/2010/03/22/1691876.html

    展开全文
  • DES数据加密

    2013-06-07 15:29:12
    幸运的是,在所有的加密算法最简单的一种就是“置换表”算法,这种算法也能很好达到加密的需要。每一个数据段(总是一个字节)对应着“置换表”中的一个偏移量,偏移量所对应的值就输出成为加密后的文件。加密...
  • 比如你想记录自己的日常生活,记在自己电脑上怕遗失,记在网上又怕被黑客攻击而泄露,所以这时你需要这个简单有效的加密方式,不增加内容的长度,看上去也跟别的日志没有区别,要看的时候,自己输入密码看就是,如果...
  • 对称加密的例子如另一篇文章中的DES加解密、3DES加解密。 这里要介绍的是非对称加解密中,应用广泛的一种:RSA。 RSA简介 RSA的由来,你可以简单的百度到,它是由三位大神在1978年提出的一种高安全性的算法。 ...

    对称与非对称加解密,最主要区别在于:对称加密,加解密的密钥是一致的;非对称加密,加解密的密钥是不一致的;

    对称加密的例子如另一篇文章中的DES加解密、3DES加解密。

    这里要介绍的是非对称加解密中,应用最广泛的一种:RSA。

    RSA简介

    RSA的由来,你可以简单的百度到,它是由三位大神在1978年提出的一种高安全性的算法。

    具体可看百度百科:RSA

    在使用中,主要有三个步骤:RSA公私密钥对生成、加密、解密。

    RSA中涉及概念的明晰

    1、RSA公私密钥对,是哪里来的?
    2、RSA比较容易让初接触者搞混的是,它是怎么加密、怎么解密,为什么要这么干?
    3、RSA的数字签名是几个意思?
    4、数字签名和RSA加解密要一起用吗?
    我们一一来解答下这几个问题:
    1)、RSA的公私密钥对,可以由一个类生成:KeyPairGenerator。看字面意思就知道这是密钥对生成的意思。具体如何生成,后续介绍;
    2)、RSA的加密、解密:RSA有两种形式的加解密。
              No.1:假如有待加密数据Data,那么可以用公钥加密Data,得到加密后的数据encryptData。这个时候,可以用私钥解密这个encryptData;
              No.2:假如有待加密数据Data,那么可以用私钥加密Data,得到加密后的数据encryptData。这个时候,可以用公钥解密这个encryptData;
    3)、RSA的数字签名,简单来说,就是私钥加密、公钥解密的一个过程。数字签名,包含签名、验证。你用私钥加密,这就是个签名过程,你用公钥解密,就是个验证过程。
             数字签名的作用,是保证数据的真实性和完整性。
    4)、数字签名和RSA的加解密不一定要一起使用,它们实际是独立的。

    RSA加解密实例解析

    对于上面提出的RSA的问题和解答,我们接着用实例来加以说明。

    RSA公私密钥对的生成

    /**
    	 * 生成公私密钥对
    	 * @throws NoSuchAlgorithmException
    	 * @throws IOException
    	 */
    	public static void generateKeys() throws NoSuchAlgorithmException, IOException {
    		 /** RSA算法要求有一个可信任的随机数源 */
    		SecureRandom secureRandom=new SecureRandom();
    		 /** 为RSA算法创建一个KeyPairGenerator对象 */
    		KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(TAG);
    		/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
    		keyPairGenerator.initialize(1024, secureRandom);
    		/** 生成密匙对 */
    		KeyPair keyPair=keyPairGenerator.generateKeyPair();
    		/** 得到公钥 */
    		java.security.Key publicKey=keyPair.getPublic();
    		/** 得到私钥 */
    		java.security.Key privateKey=keyPair.getPrivate();
    		
    		//对象流形式写入公钥
    		ObjectOutputStream outputStream=new ObjectOutputStream(new FileOutputStream(PUBLCIKEY));
    	    outputStream.writeObject(publicKey);
    	    outputStream.flush();
    	    outputStream.close();
    	    //对象流形式写入私钥
    	    ObjectOutputStream outputStream1=new ObjectOutputStream(new FileOutputStream(PRIVATEKEY));
    	    outputStream1.writeObject(privateKey);
    	    outputStream1.flush();
    	    outputStream1.close();
    	}
    以上函数,每一行基本都添加了说明。
    (1)用KeyPairGenerator生成一个公私密钥对(使用时,需要获取一个对象,这里的TAG=RSA);
    (2)生成的过程中我们需要一个随机数源、初始化时需要一个大小限制(这里设置为1024,可在512-65536之间浮动,希望数字没记错);
    (3)密钥对生成后,我们用对象流形式保存公私密钥对。为什么用对象流形式保存,因为后续使用起来,你会感觉更方便。

    RSA公钥加密,私钥解密

    这是最常用到的模式。为什么这么使用,因为在RSA的密钥分配中,你是将私钥自己保留着,而将公钥公开。私钥具有唯一性,只有自己知道。公钥是广泛分布的,可以认为大家都知道的。
    当你想让其他人给你发送一条加密数据的时候,你首先把公钥给他,他用公钥加密数据,并把公钥加密后的数据发送给你。你这就可以用私钥来解密了。而如果其他人拿到他发送的数据,是没有办法解密的,因为私钥只在你手中。
    这就保证了数据不会被外人解析。
    具体的实现代码:
    /**
    	 * 公钥加密
    	 * @param str  待加密数据
    	 * @return        加密后的数据
    	 * @throws ClassNotFoundException
    	 * @throws IOException
    	 * @throws NoSuchAlgorithmException
    	 * @throws NoSuchPaddingException
    	 * @throws InvalidKeyException
    	 * @throws IllegalBlockSizeException
    	 * @throws BadPaddingException
    	 */
    	public static byte[] encrypt(String str) throws ClassNotFoundException, IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
    	{
    		ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(PUBLCIKEY));
    		java.security.Key publicKey2= (java.security.Key)objectInputStream.readObject();
    		objectInputStream.close();
    		 /** 得到Cipher对象来实现对源数据的RSA加密 */
    		Cipher cipher=Cipher.getInstance(TAG);
    		cipher.init(Cipher.ENCRYPT_MODE, publicKey2);
    		
    
    		byte[] encryptedData=str.getBytes();
    		int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密  doFinal
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedDatas = out.toByteArray();
            out.close();
            
    		return encryptedDatas;
    	}
    	
    	/**
    	 * 私钥解密
    	 * @param encryString 公钥加密后的数据
    	 * @return                    解密后数据
    	 * @throws FileNotFoundException
    	 * @throws IOException
    	 * @throws ClassNotFoundException
    	 * @throws InvalidKeyException
    	 * @throws NoSuchAlgorithmException
    	 * @throws NoSuchPaddingException
    	 * @throws IllegalBlockSizeException
    	 * @throws BadPaddingException
    	 */
    	public static byte[] decrypt(byte[] encryString) throws FileNotFoundException, IOException, ClassNotFoundException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException
    	{
    		ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(PRIVATEKEY));
    		java.security.Key privatekey= (java.security.Key)objectInputStream.readObject();
    		objectInputStream.close();
    		
    		Cipher cipher=Cipher.getInstance(TAG);
    		cipher.init(Cipher.DECRYPT_MODE, privatekey);
    		
    		
    		byte[] decryptedData=encryString;
    		int inputLen = decryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(decryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(decryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedDatas = out.toByteArray();
            out.close();
    		
    	    return decryptedDatas;
    	}

    这是代码中的公钥加密、私钥解密的写法。
    其实,仔细看这两段代码,你可以看到:
    (1)它们的重点都在Cipher这个类,所不同的是加密和解密的初始化是不一样的。ENCRYPT_MODE,加密;DECRYPT_MODE,解密;
    (2)加解密的重点可以归纳为:Cipher获取对象(Cipher.getInstance(TAG))、Cipher初始化(cipher.init)、Cipher加解密(cipher.doFinal);
    (3)为什么我要对数据进行分段加解密:因为当你加密的字符串超过117或者解密数据超过128时,会出现错误,如:Data must not be longer than 128 bytes 。
    通过以上的操作,你其实已经可以做一个测试实验了。生成一对公私密钥对,然后用公钥加密,私钥解密。你会发现,结果如你所想。

    RSA私钥加密,公钥解密

    我们通过公钥加密,私钥解密,已经实现了。那么,我们反过来用吗,用私钥加密,公钥解密?
    答案是可以的。
    模式和以前类似,我们贴两段代码来see see:
    /**
    	 * 获取私钥加密后的数据
    	 * @param data   待加密数据
    	 * @return  私钥加密后的数据
    	 * @throws IOException
    	 * @throws ClassNotFoundException
    	 * @throws NoSuchAlgorithmException
    	 * @throws NoSuchPaddingException
    	 * @throws InvalidKeyException
    	 * @throws IllegalBlockSizeException
    	 * @throws BadPaddingException
    	 */
    	public static byte[] encryptByPrivateKey(String data) throws IOException, ClassNotFoundException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
    	{
    		ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(PRIVATEKEY));
    		java.security.Key privatekey= (java.security.Key)objectInputStream.readObject();
    		objectInputStream.close();
    		 /** 得到Cipher对象来实现对源数据的RSA加密 */
    		Cipher cipher=Cipher.getInstance(TAG);
    		cipher.init(Cipher.ENCRYPT_MODE, privatekey);
    		
    
    		byte[] encryptedData=data.getBytes();
    		int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密  doFinal
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedDatas = out.toByteArray();
            out.close();
            
    		return encryptedDatas;
    	}
    	
    	/**
    	 * 用公钥解密数据
    	 * @param encryptData  加密后的数据
    	 * @return                      公钥解密后的数据
    	 * @throws NoSuchPaddingException 
    	 * @throws NoSuchAlgorithmException 
    	 * @throws IOException 
    	 * @throws InvalidKeyException 
    	 * @throws ClassNotFoundException 
    	 * @throws BadPaddingException 
    	 * @throws IllegalBlockSizeException 
    	 */
    	public static byte[] decryptByPublicKey(byte[] encryptedData) throws NoSuchAlgorithmException, NoSuchPaddingException, IOException, InvalidKeyException, ClassNotFoundException, IllegalBlockSizeException, BadPaddingException
    	{
    		ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(PUBLCIKEY));
    		java.security.Key publicKey2= (java.security.Key)objectInputStream.readObject();
    		objectInputStream.close();
    		
    		Cipher cipher=Cipher.getInstance(TAG);
    		cipher.init(Cipher.DECRYPT_MODE, publicKey2);
    		
    		int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密  doFinal
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedDatas = out.toByteArray();
            out.close();
            
    		return decryptedDatas;
    		
    	}
    	
    你会发现,私钥加密、公钥解密的写法和上面的公钥加密、私钥解密没什么大的区别,只是换了个顺序而已。你也可以解密出正确的数据。
    那这就出现了两个担忧:
    (1)公钥是公开的!你用私钥加密后,发出的数据,如果有保密性要求,这么做是无法保密的,所有知道公钥的人,都可以解密你的数据;
    (2)解密了你的数据的人,有可能篡改你的数据。
    因此,这个过程是有风险的。你的数据保密性和真实完整性得不到保障。
    所以,一般情况下,如果你要保障你的数据保密性不会用这样的形式来。而是用公钥加密,私钥解密。
    那如果要保证通讯双方数据的保密性,你要怎么做?

    那这个私钥加密、公钥解密是用来干嘛的呢?数据的真实性、完整性如何得到保障呢?
    这就需要后面要说的数字签名来解决和应用了。

    数字签名

    数字签名,目的其实与传统签名意义相差不大。它主要是为了证明,数据的真实性以及完整性。在传统签名中,你在一个刷卡单上签字,说明这个是得到你授权的真实交易。数字签名,是在数据的角度做了这个操作,保障数据是真实的。通过数据签名的验证,可以保障数据是没有被篡改和真实性。
    那如何做这个数字签名呢?
    我们分两个步骤来:

    签名

    首先,你要签名。
    签名,首先你要准备几个参数:你拥有的私钥,这个是代表这数据是你的;待签名的数据;
    /**
    	 * 数字签名
    	 * @param str  加密过的数据
    	 * @return       私钥对信息生成数字签名
    	 * @throws NoSuchAlgorithmException
    	 * @throws InvalidKeySpecException
    	 * @throws SignatureException
    	 * @throws InvalidKeyException
    	 * @throws IOException 
    	 * @throws FileNotFoundException 
    	 * @throws ClassNotFoundException 
    	 */
    	public static byte[] sign(byte[] encryptData) throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, InvalidKeyException, FileNotFoundException, IOException, ClassNotFoundException
    	{
    		ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(PRIVATEKEY));
    		PrivateKey privatekey3= (PrivateKey)objectInputStream.readObject();
    		objectInputStream.close();
    		/*
    		PKCS8EncodedKeySpec pkcs8EncodedKeySpec=new PKCS8EncodedKeySpec(privatekey2.getEncoded());
    		KeyFactory keyFactory=KeyFactory.getInstance(TAG);
    		PrivateKey pKey=keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    		*/
    		Signature signature=Signature.getInstance(SIGNATURE_ALGORITHM);
    		signature.initSign(privatekey3);
    		signature.update(encryptData);
    		byte[] result= signature.sign();
    		return result;
    	}
    代码分为两块:获取到私钥,用私钥初始化,加载想要签名的数据,最后返回签名数据。
    那要如何验证呢?

    验证

    验证,你也需要提供几个参数:公钥、想要验证签名的数据、签名数据
    我们也先看代码:
    /**
    	 * 数字签名正确性验证
    	 * @param encryptData  加密后的数据
    	 * @param sign              数字签名
    	 * @param publicKey      公钥
    	 * @return                      数字签名验签结果(true or false)
    	 * @throws SignatureException
    	 * @throws NoSuchAlgorithmException
    	 * @throws InvalidKeySpecException
    	 * @throws InvalidKeyException
    	 * @throws IOException 
    	 * @throws FileNotFoundException 
    	 * @throws ClassNotFoundException 
    	 */
    	public static boolean verifySign(byte[] encryptData,byte[] sign) throws SignatureException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, FileNotFoundException, IOException, ClassNotFoundException
    	{
    		
    		ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(PUBLCIKEY));
    		PublicKey publicKey2= (PublicKey)objectInputStream.readObject();
    		objectInputStream.close();
    		/*
    		X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKey2.getEncoded());
    		KeyFactory keyFactory=KeyFactory.getInstance(TAG);
    		PublicKey publicKey3= keyFactory.generatePublic(keySpec);
    		*/
    		Signature signature=Signature.getInstance(SIGNATURE_ALGORITHM);
    		signature.initVerify(publicKey2);
    		signature.update(encryptData);
    		return signature.verify(sign);
    	}
    这里代码也分为两块:获取到公钥、签名验证。
    签名验证中,首先你用公钥初始化验证的类,然后加载想要验证的数据,最后用verify方法(参数是签名数据)来验证结果。这里返回的是true或者false;

    运行效果

    我们调用以上的方法,看看实际运行效果:
     String baseString="你是RSA吗?";
             System.out.println("原始字符串为:"+baseString);
             
    		generateKeys();
            System.out.println("公私秘钥对生成成功...");
    
            System.out.println("公钥加密,私钥解密流程开始...");
    		byte[] encryptByte=encrypt(baseString);
    		System.out.println("加密后的密文为:"+new String( encryptByte));
            String decryptString=new String(decrypt(encryptByte));
    		System.out.println("解密后的明文为:"+decryptString);
    		System.out.println("公钥加密,私钥解密流程结束...\r\n");
    		
    		 System.out.println("私钥加密,公钥解密流程开始...");
    		 byte[] privateEncryptData=encryptByPrivateKey(baseString);
    		 System.out.println("私钥加密后的数据为:"+new String(privateEncryptData));
    		 byte[] publicDecryptData=decryptByPublicKey(privateEncryptData);
    		 System.out.println("公钥解密-(私钥加密后的数据)为:"+new String(publicDecryptData));
    		 System.out.println("私钥加密,公钥解密流程结束...\r\n");
    
    
    		 System.out.println("数字签名流程开始...");
    		 byte[] signresult= sign(privateEncryptData);
    		 System.out.println("数字签名为:"+new String(signresult));
             boolean temp=verifySign(privateEncryptData, signresult);
             System.out.println("数字签名验签结果为:"+temp);
             System.out.println("数字签名流程结束...");

    运行效果:



    以上,就是文章主要讲的RSA加解密和数字签名的介绍。
    在这个过程中,有几个要注意的地方:

    注意点

    1、Data must not be longer than 128 bytes 。这个就是上面提到的,加解密的长度限制问题。在做加解密时,要控制好待加密、待解密数据长度的控制,不要超过范围。用分段法解决该问题。

    2、Data must start with zero。这个是你在byte[]型转String型,然后再转回byte[]型过程中,可能出现的编码问题。最好的办法是,只在显示的时候用String型,其他时候,数据传输等,用byte[]型即可。


    源码

    这里附上源码地址:

    http://download.csdn.net/detail/yangzhaomuma/9387355

    展开全文
  • java源码包---java 源码 大量 实例

    千次下载 热门讨论 2013-04-18 23:15:26
     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...
  • java源码包2

    千次下载 热门讨论 2013-04-20 11:28:17
     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 ...
  • java源码包3

    千次下载 热门讨论 2013-04-20 11:30:13
     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 ...
  • java源码包4

    千次下载 热门讨论 2013-04-20 11:31:44
     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 ...
  • 2个目标文件 摘要:Java源码,文件操作,TCP,服务器 Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。...
  • 2个目标文件 摘要:Java源码,文件操作,TCP,服务器 Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。...
  • 2个目标文件 摘要:Java源码,文件操作,TCP,服务器 Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...
  • 计算机网络(第四版+潘爱民)

    千次下载 热门讨论 2011-10-09 12:41:20
    6.1.4 套接字程序设计的例子:一个Internet文件服务器 6.2 传输协议的要素 6.2.1 编 址 6.2.2 建立连接 6.2.3 释放连接 6.2.4 流控制和缓冲 6.2.5 多路复用 6.2.6 崩溃恢复 6.3 一个简单的传输协议 6.3.1 服务原语...
  • vc++ 应用源码包_1

    热门讨论 2012-09-15 14:22:12
    DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM应用---遍历...
  • vc++ 应用源码包_2

    热门讨论 2012-09-15 14:27:40
    DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM应用---遍历...
  • vc++ 应用源码包_6

    热门讨论 2012-09-15 14:59:46
    DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM应用---遍历...
  • vc++ 应用源码包_5

    热门讨论 2012-09-15 14:45:16
    DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM应用---遍历...
  • asp.net知识库

    2015-06-18 08:45:45
    一个XSLT的简单例子 XSLXSLT板主题整理 xsl入门的好文章 新手学习XSL的好东西 XSL语法介绍 XSL学习心得 - 调用属性值 XSLT与XML转换的详细介绍 功能应用 读写搜索 基础教程 RSS Web2.0时代,RSS你会用了吗?(技术...
  • vc++ 应用源码包_4

    热门讨论 2012-09-15 14:38:35
    DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM应用---遍历...
  • vc++ 应用源码包_3

    热门讨论 2012-09-15 14:33:15
    DES加密算法源代码 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 DirectShow开发指南源码 directUI_D DirectUI界面库 DOM应用---遍历...
  • vc++ 开发实例源码包

    2014-12-16 11:25:17
    DES加密算法源代码 如题。 Detected memory leaks 检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 如题。 DirectShow开发指南源码 如题。 directUI_D DirectUI界面...
  • part.of.speech.des.path=http://localhost:8080/word_web/resources/part_of_speech_des.txt #二元模型 bigram.path=http://localhost:8080/word_web/resources/bigram.txt #三元模型 trigram.path=...
  •  《Visual Basic开发实战1200例》分为I、II两卷共计1200个例子,包括了开发中各个方面常用的实例,是目前市场上实例全面的开发类图书;书中实例来源于多位工程师的多年积累,具有很强的实用性。 本书是第II卷...
  •  《Visual Basic开发实战1200例》分为I、II两卷共计1200个例子,包括了开发中各个方面常用的实例,是目前市场上实例全面的开发类图书;书中实例来源于多位工程师的多年积累,具有很强的实用性。 本书是第II卷...

空空如也

空空如也

1 2
收藏数 29
精华内容 11
关键字:

des算法最简单例子