| 
         
     
     | 
     | 
    
  
    | 
    JAVA加密算法的实现用例 | 
   
  
     | 
   
  
     | 
   
  
    | 
     作者:未知  来源:月光软件站  加入时间:2005-5-13 月光软件站  | 
   
  
    对象 参数 algorithm 如:"DSA"
  public final void initSign(PrivateKey privateKey) throws InvalidKeyException 用指定的私钥初始化 参数:privateKey 所进行签名时用的私钥
  public final void update(byte data) throws SignatureException public final void update(byte[] data) throws SignatureException public final void update(byte[] data, int off, int len) throws SignatureException 添加要签名的信息
  public final byte[] sign() throws SignatureException 返回签名的数组,前提是initSign和update
  public final void initVerify(PublicKey publicKey) throws InvalidKeyException 用指定的公钥初始化 参数:publicKey 验证时用的公钥
  public final boolean verify(byte[] signature) throws SignatureException 验证签名是否有效,前提是已经initVerify初始化 参数: signature 签名数组
   */  import java.security.*;  import java.security.spec.*; public class testdsa {   public static void main(String[] args) throws java.security.NoSuchAlgorithmException,java.lang.Exception {         testdsa my=new testdsa();         my.run();   }   public void run()   {
    //数字签名生成密钥   //第一步生成密钥对,如果已经生成过,本过程就可以跳过,对用户来讲myprikey.dat要保存在本地   //而mypubkey.dat给发布给其它用户    if ((new java.io.File("myprikey.dat")).exists()==false) {        if (generatekey()==false) {            System.out.println("生成密钥对败");            return;           };         } //第二步,此用户 //从文件中读入私钥,对一个字符串进行签名后保存在一个文件(myinfo.dat)中 //并且再把myinfo.dat发送出去 //为了方便数字签名也放进了myifno.dat文件中,当然也可分别发送   try {   java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));   PrivateKey myprikey=(PrivateKey)in.readObject();   in.close();
   // java.security.spec.X509EncodedKeySpec pubX509=new java.security.spec.X509EncodedKeySpec(bX509);
   //java.security.spec.X509EncodedKeySpec pubkeyEncode=java.security.spec.X509EncodedKeySpec   String myinfo="这是我的信息";    //要签名的信息   //用私钥对信息生成数字签名   java.security.Signature signet=java.security.Signature.getInstance("DSA");   signet.initSign(myprikey);   signet.update(myinfo.getBytes());   byte[] signed=signet.sign();  //对信息的数字签名   System.out.println("signed(签名内容)="+byte2hex(signed));  //把信息和数字签名保存在一个文件中   java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat"));   out.writeObject(myinfo);   out.writeObject(signed);   out.close();   System.out.println("签名并生成文件成功");   }   catch (java.lang.Exception e) {     e.printStackTrace();     System.out.println("签名并生成文件失败");   };
    //第三步   //其他人通过公共方式得到此户的公钥和文件   //其他人用此户的公钥,对文件进行检查,如果成功说明是此用户发布的信息.   //   try {
     java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));    PublicKey pubkey=(PublicKey)in.readObject();    in.close();    System.out.println(pubkey.getFormat());
     in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));    String info=(String)in.readObject();    byte[] signed=(byte[])in.readObject();    in.close();
    java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");   signetcheck.initVerify(pubkey);   signetcheck.update(info.getBytes());   if (signetcheck.verify(signed)) {   System.out.println("info="+info);    System.out.println("签名正常");   }   else  System.out.println("非签名正常");   }   catch (java.lang.Exception e) {e.printStackTrace();};
 
    }
    //生成一对文件myprikey.dat和mypubkey.dat---私钥和公钥,   //公钥要用户发送(文件,网络等方法)给其它用户,私钥保存在本地   public boolean generatekey()   {     try {   java.security.KeyPairGenerator  keygen=java.security.KeyPairGenerator.getInstance("DSA");  // SecureRandom secrand=new SecureRandom();  // secrand.setSeed("tttt".getBytes()); //初始化随机产生器  // keygen.initialize(576,secrand);     //初始化密钥生成器   keygen.initialize(512);   KeyPair keys=keygen.genKeyPair(); //  KeyPair keys=keygen.generateKeyPair(); //生成密钥组   PublicKey pubkey=keys.getPublic();   PrivateKey prikey=keys.getPrivate();
    java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat"));   out.writeObject(prikey);   out.close();   System.out.println("写入对象 prikeys ok");   out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));    out.writeObject(pubkey);    out.close();    System.out.println("写入对象 pubkeys ok");    System.out.println("生成密钥对成功");    return true;   }   catch (java.lang.Exception e) {    e.printStackTrace();    System.out.println("生成密钥对失败");    return false;    };
    }
    public String byte2hex(byte[] b)     {      String hs="";      String stmp="";      for (int n=0;n<b.length;n++)       {        stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));        if (stmp.length()==1) hs=hs+"0"+stmp;        else hs=hs+stmp;        if (n<b.length-1)  hs=hs+":";       }      return hs.toUpperCase();     }
  }
   
 
 
  2.4. DESede/DES对称算法 首先生成密钥,并保存(这里并没的保存的代码,可参考DSA中的方法)
  KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);
 
  SecretKey deskey = keygen.generateKey();
  用密钥加密明文(myinfo),生成密文(cipherByte)
  Cipher c1 = Cipher.getInstance(Algorithm);
  c1.init(Cipher.ENCRYPT_MODE,deskey);
  byte[] cipherByte=c1.doFinal(myinfo.getBytes());
  传送密文和密钥,本文没有相应代码可参考DSA
  .............
  用密钥解密密文
  c1 = Cipher.getInstance(Algorithm);
  c1.init(Cipher.DECRYPT_MODE,deskey);
  byte[] clearByte=c1.doFinal(cipherByte);
  相对来说对称密钥的使用是很简单的,对于JCE来讲支技DES,DESede,Blowfish三种加密术
  对于密钥的保存各传送可使用对象流或者用二进制编码,相关参考代码如下
     SecretKey deskey = keygen.generateKey();    byte[] desEncode=deskey.getEncoded();    javax.crypto.spec.SecretKeySpec destmp=new javax.crypto.spec.SecretKeySpec(desEncode,Algorithm);    SecretKey mydeskey=destmp;
   
 
 
  相关API
  KeyGenerator 在DSA中已经说明,在添加JCE后在instance进可以如下参数
  DES,DESede,Blowfish,HmacMD5,HmacSHA1
  javax.crypto.Cipher 加/解密器
  public static final Cipher getInstance(java.lang.String transformation)                                 throws java.security.NoSuchAlgorithmException,                                        NoSuchPaddingException
   
 
 
  返回一个指定方法的Cipher对象
  参数:transformation 方法名(可用 DES,DESede,Blowfish)
  public final void init(int opmode, java.security.Key key) throws java.security.InvalidKeyException
 
  用指定的密钥和模式初始化Cipher对象
  参数:opmode 方式(ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE)
  key 密钥
  public final byte[] doFinal(byte[] input)                      throws java.lang.IllegalStateException,                             IllegalBlockSizeException,                             BadPaddingException
 
   
 
  对input内的串,进行编码处理,返回处理后二进制串,是返回解密文还是加解文由init时的opmode决定
 
  注意:本方法的执行前如果有update,是对updat和本次input全部处理,否则是本inout的内容
  /* 安全程序 DESede/DES测试 */ import java.security.*; import javax.crypto.*; public class testdes { public static void main(String[] args){     testdes my=new testdes();     my.run();   } public  void run() { //添加新安全算法,如果用JCE就要把它添加进去  Security.addProvider(new com.sun.crypto.provider.SunJCE()); String Algorithm="DES"; //定义 加密算法,可用 DES,DESede,Blowfish String myinfo="要加密的信息";    try {    //生成密钥    KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);    SecretKey deskey = keygen.generateKey();
     //加密    System.out.println("加密前的二进串:"+byte2hex(myinfo.getBytes()));    System.out.println("加密前的信息:"+myinfo);    Cipher c1 = Cipher.getInstance(Algorithm);    c1.init(Cipher.ENCRYPT_MODE,deskey);    byte[] cipherByte=c1.doFinal(myinfo.getBytes());     System.out.println("加密后的二进串:"+byte2hex(cipherByte));    //解密    c1 = Cipher.getInstance(Algorithm);    c1.init(Cipher.DECRYPT_MODE,deskey);    byte[] clearByte=c1.doFinal(cipherByte);    System.out.println("解密后的二进串:"+byte2hex(clearByte));    System.out.println("解密后的信息:"+(new String(clearByte)));
    }    catch (java.security.NoSuchAlgorithmException e1) {e1.printStackTrace();}    catch (javax.crypto.NoSuchPaddingException e2) {e2.printStackTrace();}    catch (java.lang.Exception e3) {e3.printStackTrace();}   }  public String byte2hex(byte[] b) //二行制转字符串     {      String hs="";      String stmp="";      for (int n=0;n<b.length;n++)       {        stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));        if (stmp.length()==1) hs=hs+"0"+stmp;        else hs=hs+stmp;        if (n<b.length-1)  hs=hs+":";       }      return hs.toUpperCase();     }
  }
   
 
 
  2.5. Diffie-Hellman密钥一致协议 公开密钥密码体制的奠基人Diffie和Hellman所提出的 "指数密钥一致协议"(Exponential Key Agreement Protocol),该协议不要求别的安全性先决条件,允许两名用户在公开媒体上交换信息以生成"一致"的,可以共享的密钥。在JCE的中实现用户alice生成DH类型的密钥对,如果长度用1024生成的时间请,推荐第一次生成后保存DHParameterSpec,以便下次使用直接初始化.使其速度加快
  System.out.println("ALICE: 产生 DH 对 ..."); KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");  aliceKpairGen.initialize(512); KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
   
 
 
  alice生成公钥发送组bob
  byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
   
 
 
  bob从alice发送来的公钥中读出DH密钥对的初始参数生成bob的DH密钥对
  注意这一步一定要做,要保证每个用户用相同的初始参数生成的
     DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();     KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");     bobKpairGen.initialize(dhParamSpec);     KeyPair bobKpair = bobKpairGen.generateKeyPair();
   
 
 
  bob根据alice的公钥生成本地的DES密钥
     KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");     bobKeyAgree.init(bobKpair.getPrivate());     bobKeyAgree.doPhase(alicePubKey, true);     SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");
   
 
 
  bob已经生成了他的DES密钥,他现把他的公钥发给alice,
        byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
   
 
 
  alice根据bob的公钥生成本地的DES密钥
         ,,,,,,解码     KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");     aliceKeyAgree.init(aliceKpair.getPrivate());     aliceKeyAgree.doPhase(bobPubKey, true);     SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");
   
 
 
  bob和alice能过这个过程就生成了相同的DES密钥,在这种基础就可进行安全能信
  常用API
  java.security.KeyPairGenerator 密钥生成器类 public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException 以指定的算法返回一个KeyPairGenerator 对象 参数: algorithm 算法名.如:原来是DSA,现在添加了 DiffieHellman(DH)
  public void initialize(int keysize) 以指定的长度初始化KeyPairGenerator对象,如果没有初始化系统以1024长度默认设置 参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数 注意:如果用1024生长的时间很长,最好生成一次后就保存,下次就不用生成了
  public void initialize(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException 以指定参数初始化
  javax.crypto.interfaces.DHPublicKey public DHParameterSpec getParams() 返回 java.security.KeyFactory
  public static KeyFactory getInstance(String algorithm) throws NoSuchAlgorithmException 以指定的算法返回一个KeyFactory 参数: algorithm 算法名:DSH,DH
  public final PublicKey generatePublic(KeySpec keySpec) throws InvalidKeySpecException 根据指定的key说明,返回一个PublicKey对象
  java.security.spec.X509EncodedKeySpec public X509EncodedKeySpec(byte[] encodedKey) 根据指定的二进制编码的字串生成一个key的说明 参数:encodedKey 二进制编码的字串(一般能过PublicKey.getEncoded()生成) javax.crypto.KeyAgreement 密码一至类
  public static final KeyAgreement getInstance(java.lang.String algorithm) throws java.security.NoSuchAlgorithmException 返回一个指定算法的KeyAgreement对象 参数:algorithm 算法名,现在只能是DiffieHellman(DH)
  public final void init(java.security.Key key) throws java.security.InvalidKeyException 用指定的私钥初始化 参数:key 一个私钥
  public final java.security.Key doPhase(java.security.Key key, boolean lastPhase) throws java.security.InvalidKeyException, java.lang.IllegalStateException 用指定的公钥进行定位,lastPhase确定这是否是最后一个公钥,对于两个用户的 情况下就可以多次定次,最后确定 参数:key 公钥 lastPhase 是否最后公钥
  public final SecretKey generateSecret(java.lang.String algorithm) throws java.lang.IllegalStateException, java.security.NoSuchAlgorithmException, java.security.InvalidKeyException 根据指定的算法生成密钥 参数:algorithm 加密算法(可用 DES,DESede,Blowfish)
  */ import java.io.*; import java.math.BigInteger; import java.security.*; import java.security.spec.*; import java.security.interfaces.*; import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; import com.sun.crypto.provider.SunJCE;
  public class testDHKey {
 
      public static void main(String argv[]) {     try {         testDHKey my= new testDHKey();         my.run();     } catch (Exception e) {         System.err.println(e);
      }     }
      private void run() throws Exception {         Security.addProvider(new com.sun.crypto.provider.SunJCE());
      System.out.println("ALICE: 产生 DH 对 ...");     KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");         aliceKpairGen.initialize(512);     KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); //生成时间长
          // 张三(Alice)生成公共密钥 alicePubKeyEnc 并发送给李四(Bob) ,         //比如用文件方式,socket.....     byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
         //bob接收到alice的编码后的公钥,将其解码     KeyFactory bobKeyFac = KeyFactory.getInstance("DH");     X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec  (alicePubKeyEnc);     PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec);         System.out.println("alice公钥bob解码成功");      // bob必须用相同的参数初始化的他的DH KEY对,所以要从Alice发给他的公开密钥,          //中读出参数,再用这个参数初始化他的 DH key对
           //从alicePubKye中取alice初始化时用的参数     DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();     KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");     bobKpairGen.initialize(dhParamSpec);     KeyPair bobKpair = bobKpairGen.generateKeyPair();         System.out.println("BOB: 生成 DH key 对成功");     KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");     bobKeyAgree.init(bobKpair.getPrivate());         System.out.println("BOB: 初始化本地key成功");         //李四(bob) 生成本地的密钥 bobDesKey     bobKeyAgree.doPhase(alicePubKey, true);     SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");     System.out.println("BOB: 用alice的公钥定位本地key,生成本地DES密钥成功");         // Bob生成公共密钥 bobPubKeyEnc 并发送给Alice,         //比如用文件方式,socket.....,使其生成本地密钥     byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();         System.out.println("BOB向ALICE发送公钥");
           // alice接收到 bobPubKeyEnc后生成bobPubKey          // 再进行定位,使aliceKeyAgree定位在bobPubKey     KeyFactory aliceKeyFac = KeyFactory.getInstance("DH");     x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);     PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);        System.out.println("ALICE接收BOB公钥并解码成功"); ;     KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");     aliceKeyAgree.init(aliceKpair.getPrivate());         System.out.println("ALICE: 初始化本地key成功");
      aliceKeyAgree.doPhase(bobPubKey, true);         // 张三(alice) 生成本地的密钥 aliceDesKey     SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");         System.out.println("ALICE: 用bob的公钥定位本地key,并生成本地DES密钥");
          if (aliceDesKey.equals(bobDesKey)) System.out.println("张三和李四的密钥相同");        //现在张三和李四的本地的deskey是相同的所以,完全可以进行发送加密,接收后解密,达到        //安全通道的的目的
          /*          * bob用bobDesKey密钥加密信息          */     Cipher bobCipher = Cipher.getInstance("DES");     bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey);         String bobinfo= "这是李四的机密信息";         System.out.println("李四加密前原文:"+bobinfo);     byte[] cleartext =bobinfo.getBytes();     byte[] ciphertext = bobCipher.doFinal(cleartext);
          /*          * alice用aliceDesKey密钥解密          */     Cipher aliceCipher = Cipher.getInstance("DES");     aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey);     byte[] recovered = aliceCipher.doFinal(ciphertext);         System.out.println("alice解密bob的信息:"+(new String(recovered)));     if (!java.util.Arrays.equals(cleartext, recovered))         throw new Exception("解密后与原文信息不同");     System.out.println("解密后相同");
      }
  }
   
 
 
  第3章小结 在加密术中生成密钥对时,密钥对的当然是越长越好,但费时也越多,请从中从实际出发选取合适的长度,大部分例码中的密钥是每次运行就从新生成,在实际的情况中是生成后在一段时间保存在文件中,再次运行直接从文件中读入,从而加快速度。当然定时更新和加强密钥保管的安全性也是必须的。 
 
  | 
   
  
     | 
   
  
     相关文章:相关软件:  | 
   
   
      |