Java 加密算法(二)

个人博客:haichenyi.com。感谢关注

补充知识点:

密钥: 加密方用公钥,解密方用私钥

重要的事情强调六遍:

不用自己写加密算法

不用自己写加密算法

不用自己写加密算法

不用自己写加密算法

不用自己写加密算法

不用自己写加密算法

Cipher类

  Android有专门用来加密的工具类Cipher类,他里面封装了几种常用的加密算法,本篇介绍两种AES,RSA。

用法

分三步:以AES举例说明

  /**
   * 加密方式:AES
   * 工作模式:ECB,CBC,CTR,OFB,CFB
   * 填充模式:PKCS5Padding,PKCS7Padding,ZEROPadding等等
   */
String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";//AES是加密方式 CBC是工作模式 PKCS5Padding是填充模式


//第一步:获取对象
Cipher cipher = Cipher.getInstance(String transformation);//传 CBC_PKCS5_PADDING


//第二步:设置初始化参数
    /**
     * 第一个参数:传类型,是加密Cipher.ENCRYPT_MODE,还是解密Cipher.DECRYPT_MODE
     * 第二个参数:传密钥key,我们这里传的是SecretKeySpec,它实现SecretKey,SecretKey实现Key接口。
     *             SecretKeySpec keySpec = new SecretKeySpec(raw, AES);//第一个参数传密钥byte数组,第二个参数传加密类型也就是"AES"字符串即可
     * 第三个参数:传偏移量AlgorithmParameterSpec,我们这里传的IvParameterSpec,他实现AlgorithmParameterSpec接口,iv偏移量传默认的16个0的字节数组
     *              new IvParameterSpec(new byte[cipher.getBlockSize()]),这里是传的默认的16个0的byte数组,也是常用的方式
     */
cipher.init(int opmode, Key key, AlgorithmParameterSpec params)


第三步:加密。传需要加密的字符串的byte数组
cipher.doFinal(byte[] input)

经过以上三步:AES加密就算完成了,加密之后就需要解密,辣么,怎么解密呢?

    草鸡简单,第二步初始化的时候,第一个参数传解密即可,其他都是一样的。

对称加密

概念

出自百度百科

  需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。对称性加密也称为密钥加密。

  所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则,规定如何进行加密和解密。

  因此,加密的安全性不仅取决于加密算法本身,密钥管理的安全性更是重要。因为加密和解密都使用同一个密钥,如何把密钥安全地传递到解密者手上就成了必须要解决的问题。

  说了这么多废话,要我说,就一句话公钥,私钥 相同 的加密方式称之为对称加密

用法——AES

  申明:我这里并不是说对称加密就只有AES这一种方式,相反,对称加密有很多种,我这里只讲我用到的对称加密中的一种方式——AES


  private static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";//AES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
  private static final String AES = "AES";//AES 加密
  private static final String SHA1PRNG = "SHA1PRNG";// SHA1PRNG 强随机种子算法, 要区别4.2以上版本的调用方法

/**
   * 随机生成密钥,传同一个字符串,每次都生成的不一样
   * @param seed 一般传用户的密码
   * @return 返回密钥的byte数组
   * @throws Exception 异常
   */
  private static byte[] getRawKey(String seed) throws Exception {
    SecureRandom sr = null;
    // 在4.2以上版本中,SecureRandom获取方式发生了改变
    if (android.os.Build.VERSION.SDK_INT >= 17) {
      sr = SecureRandom.getInstance(SHA1PRNG, "Crypto");
    } else {
      sr = SecureRandom.getInstance("SHA1PRNG"); // 获得一个随机数,传入的参数为默认方式。
    }
    sr.setSeed(seed.getBytes());  // 设置一个种子,这个种子一般是用户设定的密码。也可以是其它某个固定的字符串
    KeyGenerator keyGen = KeyGenerator.getInstance("AES");  // 获得一个key生成器(AES加密模式)
    //AES中128位密钥版本有10个加密循环,192比特密钥版本有12个加密循环,256比特密钥版本则有14个加密循环。
    keyGen.init(128, sr);      // 设置密匙长度128位
    SecretKey key = keyGen.generateKey();  // 获得密匙
    return key.getEncoded();
  }


  /**
   * 加密过程
   * @param raw 密钥的数组
   * @param clear 需要加密的byte数组
   * @return 加密后的byte数组
   * @throws Exception 异常
   */
  private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    SecretKeySpec keySpec = new SecretKeySpec(raw, AES);
    Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
    //iv偏移量传默认的16个0的字节数组
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
    return cipher.doFinal(clear);
  }


  /*
   * 解密
   */
  private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec keySpec = new SecretKeySpec(raw, AES);
    Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
    cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
    return cipher.doFinal(encrypted);
  }

  上面给的三个方法,一个获取密钥,一个加密,一个解密,注释写的很清楚,我就不用再讲了,转16进制的方法,我前一篇讲加密的时候就给出来了,不知道的可以去前一篇看一下,我下面给出调用方式和结果截图

   try {
          byte[] rawKey = getRawKey(key);
          Log.v("wz", rawKey.length + "");
          String s = bytesToHexFun1(rawKey);
          Log.v("wz","密钥16进制-->"+s);
          byte[] encrypt = encrypt(rawKey, data.getBytes());
          String after = Base64.encodeToString(encrypt, Base64.NO_WRAP);
          Log.v("wz","加密后-->"+after);
          byte[] decode = Base64.decode(after, Base64.NO_WRAP);
          byte[] before = decrypt(rawKey, decode);
          Log.v("wz","解密后-->"+new String(before));
        } catch (Exception e) {
          e.printStackTrace();
        }

结果:

非对称加密

概念

出自百度百科

  1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是“公开密钥系统”。

  与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

  说了这么多废话,要我说,就一句话公钥,私钥 不相同 的加密方式称之为对称加密

用法——RSA

  申明:我这里并不是说非对称加密就只有RSA这一种方式,相反,对非称加密有很多种,我这里只讲我用到的非对称加密中的一种方式——RSA

  辣么,成对公钥,私钥怎么来呢?难道我们自己去写吗?你要是会写,那你很棒棒哦,反正我不会(爱咋咋),我是在线生成公钥,私钥对。用法跟上面讲的AES是类似的:

/**
   * 我们之前拿到的是公钥,我们还要把公钥转成Key
   * 因为cipher.init()初始化的时候,第二个参数需要传Key类型的,并不是String
   * 获取Key,我这里返回的是PublicKey,它实现的Key接口
   * @param pubKey 生成的公钥
   * @return 最后需要的key
   * @throws Exception 异常
   */
  public static PublicKey loadPublicKey(String pubKey) throws Exception {
    byte[] buffer = Base64.decode(pubKey, Base64.DEFAULT);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
    return keyFactory.generatePublic(keySpec);
  }

  /**
   * 加密
   * @param data 需要加密的数据
   * @param publicKey key
   * @return 返回加密后的byte,需要转成字符串
   * @throws Exception 异常
   */
  private static byte[] encryptRSA(String data,PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE,publicKey);
    return cipher.doFinal(data.getBytes());
  }

  /**
   * 解密(我们需要注意的是,我们解密的是私钥加密的数据,不能解密公钥加密的数据)
   * @param data 需要解密的数据
   * @param publicKey key
   * @return 返回解密后的数组
   * @throws Exception 异常
   */
  private static byte[] decryptRSA(String data,PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE,publicKey);
    return cipher.doFinal(data.getBytes());
  }

  这里,注释说的很清楚,看懂了前面的AES,辣么,这个RSA应该不是问题。

猜你喜欢

转载自blog.csdn.net/qq_27634797/article/details/79499922