Java安全编程笔记【2】------数据内容的保护---加密和解密。

加密是保护重要数据以及程序之间进行秘密通信的重要方法,随着加密的广泛应用,已发展成为一门单独的学科:密码( Cryptography )。密码学这一单词来自希腊语 Kryptus (隐藏)和 Gr á phein (写),可见通过加密将信息隐藏起来是密码学的重要内容。 Java 中提供了常用的加密和解密算法,该部分将介绍如何使用这些已有的算法。

该部分主要内容:

1. 通过编写凯撒密码了解加密和解密的基本过程

2. 创建对称密钥,使用对称密钥进行加密和解密

3. 创建非对称密钥,使用非对称密钥进行加密和解密

4. 使用密钥协定分发密钥

2.1 一个简单的加密和解密程序——凯撒密码

说明:

凯撒密码是罗马扩张时期朱利斯• 凯撒( Julius Caesar )创造的,用于加密通过信使传递的作战命令。它将字母表中的字母移动一定位置而实现加密。例如如果向右移动 2 位,则字母 A 将变为 C ,字母 B 将变为 D ,字母 X 变成 Z ,字母 Y 则变为 A ,字母 Z 变为 B

因此,假如有个明文字符串“ Hello ”用这种方法加密的话,将变为密文:“ Jgnnq ”。而如果要解密,则只要将字母向相反方向移动同样位数即可。如密文“ Jgnnq ”每个字母左移两位变为“ Hello ”。这里,移动的位数“ 2 ”是加密和解密所用的密钥。本实例通过 Java 实现了这一过程,由此可以了解与加密和解密相关的概念。

编程思路:

首先获取要加密的内容以及密钥,凯撒密码的密钥即字符移动的位数。由于凯撒密码器的移位是针对字符的,因此需要将待加密的内容中每个字符取出,然后针对每个字符分别加以移位。

//文件 Caesar.java

public class Caesar

{//凯撒密码 ,移动的位数 2就是加密和解密所用的密钥 !!

   public static void main(String args[]) throws Exception{

        String s=args[0];//读取要加密的字符串 (明文 )

        int key=Integer.parseInt(args[1]);//读取密钥 (移动的位数 ,负数表示向左移动,正数表示向右移动 )

        String es="";

        for(int i=0;i<s.length( );i++)

        {//取出字符串中每个字符

           char c=s.charAt(i);

            if(c>='a' && c<='z')

           {//对每个字符进行移位,是小写字母

              c+=key%26;//移动 key%26

              if(c<'a') c+=26;//向左越界

              if(c>'z') c-=26;//向右越界

        }

           else if(c>='A' && c<='Z')

           {//大写字母

              c+=key%26;

               if(c<'A') c+=26;

              if(c>'Z') c-=26;

           }

           es+=c;

       }

       System.out.println(es);//输出密文

   }

}

该程序既可用于加密又可用于解密。

编译: javac Caesar.java

只要执行:

java Caesar 明文(要加密的字符串) 密钥(移动的位数)

即可加密。在密钥前面加上负号,将运行

java Caesar 明文(要加密的字符串) - 密钥(移动的位数)即可解密。

如为了加密字符串“ Hello World! ”,可随意取一个密钥如 4 ,运行:

java Caesar "Hello World!" 4

将输出“ Lipps Asvph! ”。这里“ Hello World! ”是明文,“ Lipps Asvph! ”是密文。如果密钥大于 26 ,程序中移位前会和 26 取模而将其调整到 26 以下。因此运行:

java Caesar "Hello World!" 30

同样将输出“ Lipps Asvph! ”。

为了将密文“ Lipps Asvph! ”解密,需要知道加密该密文所用的密钥 4 ,这样,执行:

java Caesar "Lipps Asvph!" -4

将得到明文“ Hello World! ”。

如果密钥和加密时所用的不同,则解密时将得到无意义的输出,如运行

java Caesar "Lipps Asvph!" –3

程序将输出“ Ifmmp Xpsme! ”。这样,只有知道密钥才能得到原来的密文。

2.2 对称密钥的生成和保存

上节的凯撒密码是很脆弱的,密钥总共只有 26 个,攻击者得到密文后即使不知道密钥,也可一个一个地试过去,最多试 26 次就可以得到明文。现代密码算法的过程要复杂得多,其中一类和凯撒密码类似,加密和解密使用相同的密钥,称为对称密钥算法;另一类则在加密时使用一种密钥,在解密时使用另一种密钥,称为非对称密钥算法。这些算法的密钥也不再是简单的整数,而是很长的二进制数。这样,一个 56 位的密钥有 2^(56)( 72,057,594,037,927,936 )个不同的可能取值,这需要耗费超级计算机约一天的时间尝试每一个密钥。当密钥长度达到 128 位,则密钥数量达到 2^(128) 个,需要的时间增加到 272 倍,约 1.29 × 1019 年。 Java 中已经提供了常用的加密算法,我们不需要了解算法的细节而可以直接使用这些算法实现加密。各种算法所用的密钥各有不同,本节将学习 Java 中创建对称密钥的方法。

2.2.1 对称密钥的生成及以对象序列化方式保存

实例说明

本实例给出 Java 中创建对称密钥的步骤,并通过对象序列化方式保存在文件中。

编程思路:

1 ) 获取密钥生成器

KeyGenerator kg=KeyGenerator.getInstance("DESede");

分析: Java KeyGenerator 类中提供了创建对称密钥的方法。 Java 中的类一般使用 new 操作符通过构造器创建对象,但 KeyGenerator 类不是这样,它预定义了一个静态方法 getInstance( ),通过它获得 KeyGenerator 类型的对象。这种类成为工厂类或工厂。方法 getInstance( )的参数为字符串类型,指定加密算法的名称。可以是“ Blowfish 、“ DES”、“ DESede”、“ HmacMD5”或“ HmacSHA1”等。这些算法都可以实现加密,这里我们不关心这些算法的细节,只要知道其使用上的特点即可。其中“ DES”是目前最常用的对称加密算法,但安全性较差。针对 DES 安全性的改进产生了能满足当前安全需要的 TripleDES 算法,即“ DESede”。“ Blowfish”的密钥长度可达 448 位,安全性很好。“ AES”是一种替代 DES 算法的新算法,可提供很好的安全性。

2 ) 初始化密钥生成器

kg.init(168);

分析:该步骤一般指定密钥的长度。如果该步骤省略的话,会根据算法自动使用默认的密钥长度。指定长度时,若第一步密钥生成器使用的是“ DES”算法,则密钥长度必须是 56 位;若是“ DESede”,则可以是 112 168 位,其中 112 位有效;若是“ AES”,可以是 128, 192 256 位;若是“ Blowfish”,则可以是 32 448 之间可以被 8 整除

的数;“ HmacMD5”和“ HmacSHA1”默认的密钥长度都是 64 个字节。

3 ) 生成密钥

SecretKey k=kg.generateKey( );

分析:使用第一步获得的 KeyGenerator 类型的对象中 generateKey( )方法可以获得密钥。其类型为 SecretKey 类型,可用于以后的加密和解密。

4 ) 通过对象序列化方式将密钥保存在文件中

FileOutputStream f=new FileOutputStream("key1.dat");

ObjectOutputStream b=new ObjectOutputStream(f);

b.writeObject(k);

分析: ObjectOutputStream 类中提供的 writeObject 方法可以将对象序列化,以流的方式进行处理。这里将文件输出流作为参数传递给 ObjectOutputStream 类的构造器,这样创建好的密钥将保存在文件 key1.data 中。

//文件: Skey_DES.java

import java.io.*;

import javax.crypto.*;

public class Skey_DES

{//对称密钥的生成,并通过对象序列化方式保存在文件中

    public static void main(String args[]) throws Exception

   {

            KeyGenerator kg=KeyGenerator.getInstance("DESede");//创建密钥生成器

            kg.init(168);//初始化密钥生成器

            SecretKey k=kg.generateKey( );//生成密钥

            //通过对象序列化方式将密钥保存在文件中

            FileOutputStream  f=new FileOutputStream("key1.dat");

            ObjectOutputStream b=new  ObjectOutputStream(f);

             b.writeObject(k);

      }

}

编译 javac Skey_DES.java  运行 java Skey_DES ,在当前目录下将生成文件 key1.dat ,其中包含的密钥可以用于使

Triple DES 算法的加密和解密。

2.2.2 以字节保存对称密钥

实例说明

2.2.1 小节的实例将密钥通过对象序列化方式保存在文件中,在文件中保存的是对象,本实例以另一种方式保存在文件中,即以字节保存在文件中。

编程思路:

Java 中所有的密钥类都有一个 getEncoded( ) 方法,通过它可以从密钥对象中获取主要编码格式,其返回值是字节数组。其主要步骤为:

1 ) 获取密钥

FileInputStream f=new FileInputStream("key1.dat");

ObjectInputStream b=new ObjectInputStream(f);

Key k=(Key)b.readObject( );

分析:该步骤与 2.2.1 小节的第 4 步是相对应的, 2.2.1 小节的第 4 步将密钥对象以对象流的方式存入文件,而这一步则将文件中保存的对象读取出来以便使用。首先创建文件输入流,然后将其作为参数传递给对象输入流,最后执行对象输入流的 readObject( )方法读取密钥对象。由于 readObject( )返回的是 Object 类型,因此需要强制转换成 Key 类型。这里使用的是已有的密钥,也可以不使用这里的三行代码,而使用 2.1.1 小节中的前三步的代码生成新的密钥再继续下面的步骤。

2 ) 获取主要编码格式

byte[ ] kb=k.getEncoded( );

分析:执行 SecretKey 类型的对象 k getEncoded( )方法,返回的编码放在 byte类型的数组中。

3 ) 保存密钥编码格式

FileOutputStream f2=new FileOutputStream("keykb1.dat");

f2.write(kb);

分析:先创建文件输出流对象,在其参数中指定文件名,如 keykb1.dat。然后执行文件输出流的 write( )方法将第 2 步中得到的字节数组中的内容写入文件。

//文件: Skey_kb.java

import java.io.*;

import java.security.*;

 

public class Skey_kb

{// 以字节方式保存密钥。程序中在保存了密钥编码后,又使用循环语句将字节数组中的内容

  // 打印出来。这样就可以较为直观地看到密钥编码的内容了。

   public static void main(String args[]) throws Exception

   {

          FileInputStream f=new FileInputStream("key1.dat");// 首先获取密钥

          ObjectInputStream b=new ObjectInputStream(f);

          Key k=(Key)b.readObject( );

        byte[ ] kb=k.getEncoded( );// 获取主要编码格式

        // 保存密钥编码格式

        FileOutputStream  f2=new FileOutputStream("keykb1.dat");

             f2.write(kb);

        // 打印密钥编码中的内容

        for(int i=0;i<kb.length;i++)

        {

             System.out.print(kb[i]+",");

        }

   }

}

程序中在保存了密钥编码后,又使用循环语句将字节数组中的内容打印出来。这样可以较为直观地看到密钥编码的内容。

运行程序:

编译: javac Skey_kb.java  输入 java Skey_kb 运行程序,在程序的当前目录中将产生文件名为 keykb1.dat 的文件,屏幕输出如下:

11,-105,-119,50,4,-105,16,38,-14,-111,21,-95,70,-15,76,-74,67,-88,59,-71,55,-125,104,42,

此即程序中创建的密钥的编码内容,如果用文本编辑器打开 keykb1.dat ,看到的不是上面的数字而是类似下面的字符:

2 ?& 驊  馤禖 ?? *

这是因为 keykb1.dat 是一个二进制文件,存放的是任意二进制数。读者运行时肯定结果和上面会有所不同,实际上 2.2.1 小节的程序每次运行时生成的密钥都不会相同,这就保证了密钥的唯一性。作为对称密钥,只要保证若加密某段文字用的是某个密钥,则解密这段密文时用同样的密钥即可。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值