zoukankan      html  css  js  c++  java
  • RSA和AES加密解密过程

    RSA和AES加密解密过程

    RSA:

    非对称加密,公钥为服务提供方用来加密,私钥为请求方收到消息后用来解密,由于加密和解密时,所使用的秘钥不同,所以称之为非对称加密

    是公开密钥系统的代表;

    安全性:建立在具有大素数因子的合数,其因子分解困难这一法则之上;

    处理速度慢;

    密钥管理:加解密过程中不必网络传输保密的密钥;密钥管理优于AES算法;

    RSA加解密速度慢,不适合大量数据文件加密;

    AES:

    对称加密:需要使用随机码或者其他字符串来作为秘钥加密,同时解密也是使用相同的秘钥解密,因此称之为对称加密

    Rijndael算法是新一代的高级加密标准,运行时不需计算机有非常高的处理能力和大的内存;

    操作可以很容易的抵御时间和空间的攻击,在不同的运行环境下始终保持良好的性能;

    AES密钥长度:最长只有256bit,可用软件和硬件实现高速处理;

    密钥管理:要求在通信前对密钥进行秘密分配,解密的私钥必须通过网络传送至加密数据接收方;

    AES加密速度很快;

    AES+RSA:

    混合加密:安全性和优点都发挥出来了,是企业常用的加密方式,博主的例子,也是混合加密

    使用AES对称密码体制对传输数据加密,同时使用RSA不对称密码体制来传送AES的密钥,就可以综合发挥AES和RSA的优点同时

    避免它们缺点来实现一种新的数据加密方案


    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import net.sf.json.JSONString;
    import org.apache.commons.io.IOUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;

    import javax.crypto.*;
    import javax.crypto.spec.SecretKeySpec;
    import javax.servlet.http.HttpServletRequest;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.security.*;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;

    public class HOPoifHeadUtil {
    private static final Logger logger = LoggerFactory.getLogger(HOPoifHeadUtil.class);

    /**
    * RSA最大加密明文大小
    */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
    * RSA最大解密密文大小
    */
    private static final int MAX_DECRYPT_BLOCK = 128;

     

    /*
    * 加密
    * 1.构造密钥生成器
    * 2.根据ecnodeRules规则初始化密钥生成器
    * 3.产生密钥
    * 4.创建和初始化密码器
    * 5.内容加密
    * 6.返回字符串
    */
    public static String encodeAES(String encodeRules, String content) {
    try {
    //1.构造密钥生成器,指定为AES算法,不区分大小写
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    //2.根据ecnodeRules规则初始化密钥生成器
    //生成一个128位的随机源,根据传入的字节数组
    //防止linux下 随机生成key
    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
    secureRandom.setSeed(encodeRules.getBytes());
    keygen.init(128, secureRandom);
    //3.产生原始对称密钥
    SecretKey original_key = keygen.generateKey();
    //4.获得原始对称密钥的字节数组
    byte[] raw = original_key.getEncoded();
    //5.根据字节数组生成AES密钥
    SecretKey key = new SecretKeySpec(raw, "AES");
    //6.根据指定算法AES自成密码器
    Cipher cipher = Cipher.getInstance("AES");
    //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY
    cipher.init(Cipher.ENCRYPT_MODE, key);
    //8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
    byte[] byte_encode = content.getBytes("utf-8");
    //9.根据密码器的初始化方式--加密:将数据加密
    byte[] byte_AES = cipher.doFinal(byte_encode);
    //10.将加密后的数据转换为字符串
    //这里用Base64Encoder中会找不到包
    //解决办法:
    //在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。
    String AES_encode = new BASE64Encoder().encode(byte_AES);
    //11.将字符串返回
    return AES_encode;
    } catch (NoSuchAlgorithmException e) {
    logger.error("encodeAES.NoSuchAlgorithmException异常" , e.getMessage());
    } catch (NoSuchPaddingException e) {
    logger.error("encodeAES.NoSuchPaddingException异常" , e.getMessage());
    } catch (InvalidKeyException e) {
    logger.error("encodeAES.InvalidKeyException异常" , e.getMessage());
    } catch (IllegalBlockSizeException e) {
    logger.error("encodeAES.IllegalBlockSizeException异常" , e.getMessage());
    } catch (BadPaddingException e) {
    logger.error("encodeAES.BadPaddingException异常" , e.getMessage());
    } catch (UnsupportedEncodingException e) {
    logger.error("encodeAES.UnsupportedEncodingException异常" , e.getMessage());
    }

    //如果有错就返加nulll
    return null;
    }

    /*
    * 解密
    * 解密过程:
    * 1.同加密1-4步
    * 2.将加密后的字符串反纺成byte[]数组
    * 3.将加密内容解密
    */
    public static String deCodeAES(String encodeRules, String content) {
    try {
    //1.构造密钥生成器,指定为AES算法,不区分大小写
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    //2.根据ecnodeRules规则初始化密钥生成器
    //生成一个128位的随机源,根据传入的字节数组
    //防止linux下 随机生成key
    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
    secureRandom.setSeed(encodeRules.getBytes());
    keygen.init(128, secureRandom);
    //3.产生原始对称密钥
    SecretKey original_key = keygen.generateKey();
    //4.获得原始对称密钥的字节数组
    byte[] raw = original_key.getEncoded();
    //5.根据字节数组生成AES密钥
    SecretKey key = new SecretKeySpec(raw, "AES");
    //6.根据指定算法AES自成密码器
    Cipher cipher = Cipher.getInstance("AES");
    //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY
    cipher.init(Cipher.DECRYPT_MODE, key);
    //8.将加密并编码后的内容解码成字节数组
    byte[] byte_content = new BASE64Decoder().decodeBuffer(content);
    /*
    * 解密
    */
    byte[] byte_decode = cipher.doFinal(byte_content);
    String AES_decode = new String(byte_decode, "utf-8");
    return AES_decode;
    } catch (NoSuchAlgorithmException e) {
    logger.error("deCodeAES.NoSuchAlgorithmException异常" , e.getMessage());
    } catch (NoSuchPaddingException e) {
    logger.error("deCodeAES.NoSuchPaddingException异常" , e.getMessage());
    } catch (InvalidKeyException e) {
    logger.error("deCodeAES.InvalidKeyException异常" , e.getMessage());
    } catch (IOException e) {
    logger.error("deCodeAES.IOException异常" , e.getMessage());
    } catch (IllegalBlockSizeException e) {
    logger.error("deCodeAES.IllegalBlockSizeException" , e.getMessage());
    } catch (BadPaddingException e) {
    logger.error("deCodeAES.BadPaddingException异常" , e.getMessage());
    }

    //如果有错就返加nulll
    return null;
    }


    /**
    * 获取密钥对
    *
    * @return 密钥对
    */
    public static KeyPair getKeyPair() throws Exception {
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(2048);
    return generator.generateKeyPair();
    }

    /**
    * 获取私钥
    *
    * @param privateKey 私钥字符串
    * @return
    */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    byte[] decodedKey = org.apache.commons.codec.binary.Base64.decodeBase64(privateKey.getBytes());
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
    return keyFactory.generatePrivate(keySpec);
    }

    /**
    * 获取公钥
    *
    * @param publicKey 公钥字符串
    * @return
    */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    byte[] decodedKey = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey.getBytes());
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
    return keyFactory.generatePublic(keySpec);
    }

    /**
    * RSA加密
    *
    * @param data 待加密数据
    * @param publicKey 公钥
    * @return
    */
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    int inputLen = data.getBytes().length;
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    int offset = 0;
    byte[] cache;
    int i = 0;
    // 对数据分段加密
    while (inputLen - offset > 0) {
    if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
    cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
    } else {
    cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
    }
    out.write(cache, 0, cache.length);
    i++;
    offset = i * MAX_ENCRYPT_BLOCK;
    }
    byte[] encryptedData = out.toByteArray();
    out.close();
    // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
    // 加密后的字符串
    return new String(org.apache.commons.codec.binary.Base64.encodeBase64String(encryptedData));
    }

    /**
    * RSA解密
    *
    * @param data 待解密数据
    * @param privateKey 私钥
    * @return
    */
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] dataBytes = org.apache.commons.codec.binary.Base64.decodeBase64(data);
    int inputLen = dataBytes.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(dataBytes, offset, MAX_DECRYPT_BLOCK);
    } else {
    cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
    }
    out.write(cache, 0, cache.length);
    i++;
    offset = i * MAX_DECRYPT_BLOCK;
    }
    byte[] decryptedData = out.toByteArray();
    out.close();
    // 解密后的内容
    return new String(decryptedData, "UTF-8");
    }

    public static void main(String[] args) {
    // 获取6位随机码
    String randomCode = SmsUtil.getRandNum(6);
    try {
    // 生成密钥对
    KeyPair keyPair = getKeyPair();
    String privateKey = new String(org.apache.commons.codec.binary.Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
    String publicKey = new String(org.apache.commons.codec.binary.Base64.encodeBase64(keyPair.getPublic().getEncoded()));

    System.out.println("私钥:" + privateKey);
    System.out.println("公钥:" + publicKey);
    // RSA加密
    String data = randomCode;
    String encryptData = encrypt(data, getPublicKey(publicKey));
    System.out.println("加密后内容:" + encryptData);
    // RSA解密
    String decryptData = decrypt(encryptData, getPrivateKey(privateKey));
    System.out.println("解密后内容:" + decryptData);

    System.out.println("--------------------------加密过程:先RAS(非对称)将随机码加密,然后再用随机码(明文)AES(对称)加密-----------------------------------------");
    System.out.println("--------------------------解密过程(核心,要先拿到秘钥,即随机码):先RAS(非对称)解密获取随机码,然后再用随机码AES(对称)获取内容-----------------------------------------");

    String jsonStr = "{"switchStatus":1,"aaa":"120","bbb":"500"}";
    System.out.println("AES加密规则:" + decryptData + " 加密后的字符串为:" + encodeAES(decryptData, jsonStr));
    String encodeAES = encodeAES(decryptData, jsonStr);
    System.out.println("AES解密规则:" + decryptData + " 解密后的字符串为:" + deCodeAES(decryptData, encodeAES));

    String jsonStr2 = "{"cccc":"2"}";
    System.out.println("AES加密规则:" + decryptData + " 加密后的字符串为:" + encodeAES(decryptData, jsonStr2));
    String encodeAES2 = encodeAES(decryptData, jsonStr2);
    System.out.println("AES解密规则:" + decryptData + " 解密后的字符串为:" + deCodeAES(decryptData, encodeAES2));

    //String lastData = deCodeAES(decryptData,encodeAES);
    //PaymentLimitPO paymentLimitPO = JSON.parseObject(lastData, PaymentLimitPO.class);
    //System.out.println("JSON解析内容:" + paymentLimitPO.getSwitchStatus());
    } catch (Exception e) {
    logger.error("加密解密异常",e.getMessage());
    }
    }
    }

    总结:SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
    secureRandom.setSeed(encodeRules.getBytes());
    注释上也给出了说明,直白点的话就是window下加密解密没问题,到了linux环境下就失败。

    运行结果:

    知人者智,自知者明,胜人者有力,自胜者强。
  • 相关阅读:
    实现预定房间的功能
    实现投票,显示人数百分比的功能
    数据库包装成类
    实现微信好友列表的php代码
    几种常见的函数
    数据库查询
    用代码编辑数据库T-SQL语句
    多线程
    集合类
    一、高级查询。。。实例
  • 原文地址:https://www.cnblogs.com/nanfengxiangbei/p/14200269.html
Copyright © 2011-2022 走看看