欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

摘要(MD5\SHA1\MAC)、对称加密(DES\AES)、非对称加密(DSA\RSA)签名在JAVA中应用

程序员文章站 2024-03-20 11:51:10
...

引言:去年阅读了《JAVA加密与解密的艺术》草草总结了一些概念,实际在JAVA里的代码应用迟迟没有记录、更新、总结。今天重新梳理一下,温故一下应用知识。

本文主要介绍内容:
1、JAVA安全领域的组成部分
2、摘要、对称加密、非对称加密的区别
3、具体实现代码

JAVA安全领域的组成部分

Java安全领域总共分为四个部分:

  • JCA(Java加密体系结构):基本的加密框架,如证书、数字签名、消息摘要、**对产生器。
  • JCE(Java加密扩展包):在JCA的基础上进行拓展,提供了各种加密算法、消息摘要算法和**管理等功能。包括DES\AES\RSA\DSA等等算法,都是由JCE来提供的,JCE的实现主要在javax.cryptpo包(及其子包)中。
  • JSSE(Java安全套接字扩展包):提供了基于SSL(安全套接字层)的加密功能。在网络的传输过程中,信息会经过多个主机(很可能其中一台被窃听),最终传送给接受者,这是不安全的。这种确保网络通信安全的服务就是由JSSE来提供的。
  • JAAS(Java鉴别与安全服务):提供了在Java平台上进行用户身份鉴别的功能。

JAC和JCE是Java平台提供用于安全和加密服务的两组API。它们不执行任何算法,他们只是连接应用和实际算法实现程序的一直接口。软件开发商可以根据JCE接口将各种算法实现后,打包成一个Provider(安全提供者),动态地加载到Java运行环境。下面展示一下如何查看JDK自带的一些提供者以及其提供的算法。

public void provider() {
        for (Provider provider : Security.getProviders()) {
            System.out.println(provider);
            for (Map.Entry<Object, Object> entry : provider.entrySet()) {
                System.out.println("\t" + entry.getValue());
            }
        }
    }

摘要(MD5\SHA1\MAC)、对称加密(DES\AES)、非对称加密(DSA\RSA)签名在JAVA中应用

Java安全体系安全不仅支持来自Sun官方的提供者,同时也可以配置第三方安全提供者以扩展相应的算法实现。

安全提供者实现了两个抽象的概念:引擎和算法。引擎可以理解为操作,如加密、解密等。算法则定义了如何操作如何执行,如一个算法可以理解为引擎的具体实现。当然,一个算法可以有多种实现方式,这就意味着同一个算法可以和多个引擎具有不同的实现。

摘要、对称加密、非对称加密的区别

  • 摘要:采用单向加密算法,比如MD5\SHA\MAC等,这是一种数据完整性的加密,这种单向加密一般我们称为摘要,而不是纯意义上的加密。防止数据在传输过程中被篡改,因为摘要不可逆的,比较常见的场景,某会员系统里,会员密码信息都是通过摘要入库的,验证密码是否一致,也是通过对比摘要,这保护了用户密码的安全性。

  • 对称加密:对称加密*要求加密与解密使用同一个共享**,解密是加密的逆运算,由于双方共享同一个**,就要求必须在通信前商定该**,并妥善保管。我们在网络中传输**时,往往为了**的安全性,再对**进行一次非对称加密。对称加密有两种方式,一种是基于固定**的加密与解密,另一种是基于随机源**的加密与解密。这两种方式在后面均会以代码形式讲解。常用的一些对称加密如DES\AES\三重DES等。从底层加密原理角度,

  • 非对称加密:非对称加密*的加***和解***不同,一个公开,称为公钥;一个保密,称为私钥。因此,通信双方都有一对自己的公私钥,私钥自己保管好,公钥提供给对方。非对称加密一般有两种
    其一,进行数据认证(鉴权)服务校验,即对发送数据方是否是我们所期望的那个做验证。私钥加签,公钥验签。
    其二,对数据进行加密,公钥加密,私钥解密。由于非对称加密算法的低效,所以各密码机构主张对称加 密算法和非对称加密算法结合,用对称加密算法加密内容,用非对称加密算法加密对称算法的**。在算法设计上,非对称加密算法对待加密数据长度要求极为苛刻。比如,RSA算法要求待加密数据长度不得超过53个字节。所以,非对称加密主要用于交换对称加密的秘***,而非数据内容上的加密。

常用的一些非对称加密如DSA\RSA\ECDSA等。

具体实现代码

1、摘要实现

public void messageDigest() throws Exception {
        //初始化摘要引擎,指定provider来源及摘要算法
        MessageDigest messageDigest = MessageDigest.getInstance("MD5", "SUN");
        byte[] bytes = new String("comeonboby").getBytes();
        messageDigest.update(bytes);
        //执行消息摘要
        byte[] bytesFinal = messageDigest.digest();
        System.out.println("摘要:" + Arrays.toString(bytesFinal));
        messageDigest.update(bytesFinal);
        //转换成十六进制字符串
        int j = 0;
        for (int i = 0; i < bytesFinal.length; i++) {
            String hex = Integer.toHexString(bytesFinal[i] & 0xFF);
            if (hex.length() < 2) {
                hex = "0" + hex;
            }
            System.out.print(hex.toUpperCase());
            j++;
        }
    }

2、对称加密(以AES为例子)
带随机源**加密:

 //content:待加密内容
 //strkey:**随机源字符串
 //chiperAlogrithm:加密器算法
 public static byte[] encryptWithRandom(byte[] content, String strKey, String chiperAlgorithm) {
        try {
            //获取**随机源,传入随机源算法
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            //随机源偏移
            random.setSeed(strKey.getBytes("UTF-8"));
            //**生成器,**算法这里直接传入AES
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            //生成128位的AES**,AES**只有128位、192位、256位 三类
            keyGenerator.init(128, random);
            //构建秘***规范
            SecretKeySpec key = new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");     
            //构建加密器,传入加密器规则,包括算法\工作模式\填充模式,这里传入AES的话,默认为ECB/PKCS5Padding
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            //初始化,传入加密MODE
            cipher.init(Cipher.ENCRYPT_MODE, key);
            //加密
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            logger.error("AES加密异常", e);
            throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES加密异常");
        }
    }

带随机源**解密:

 //content:待解密内容
 //strkey:**随机源字符串
 //chiperAlogrithm:解密器算法
 public static byte[] encryptWithRandom(byte[] content, String strKey, String chiperAlgorithm) {
        try {
            //获取**随机源,传入随机源算法
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            //随机源偏移
            random.setSeed(strKey.getBytes("UTF-8"));
            //**生成器,**算法这里直接传入AES
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            //生成128位的AES**,AES**只有128位、192位、256位 三类
            keyGenerator.init(128, random);
            //构建秘***规范
            SecretKeySpec key = new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");     
            //构建解密器,传入加密器规则,包括算法\工作模式\填充模式,这里传入AES的话,默认为ECB/PKCS5Padding
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            //初始化,传入解密MODE
            cipher.init(Cipher.DECRYPT_MODE, key);
            //解密
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            logger.error("AES解密异常", e);
            throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES解密异常");
        }
    }

不带随机源加密:

//content:待加密内容
//strKey:**
//chiperAlgorithm:加密器算法
public static byte[] encrypt(byte[] content, String strKey, String chiperAlgorithm) {
        try {
            //生成**规范
            SecretKeySpec secretKeySpec = new SecretKeySpec(strKey.getBytes("UTF-8", "AES");     
            //构建加密器
            Cipher cipher = Cipher.getInstance(chiperAlgorithm);
            //初始化加密器,传入加密MODE
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            //加密
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            logger.error("AES加密异常", e);
            throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES加密异常");
        }
    }

不带随机源解密:

//content:待解密内容
//strKey:**
//chiperAlgorithm:解密器算法
public static byte[] encrypt(byte[] content, String strKey, String chiperAlgorithm) {
        try {
            //生成**规范
            SecretKeySpec secretKeySpec = new SecretKeySpec(strKey.getBytes("UTF-8", "AES");     
            //构建解密器
            Cipher cipher = Cipher.getInstance(chiperAlgorithm);
            //初始化加密器,传入解密MODE
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            //解密
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            logger.error("AES解密异常", e);
            throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES解密异常");
        }
    }

3、RSA加签与验签

public void rsaTest() throws Exception {
        //构建加签参数
        Map<String, String> params = new HashMap<String, String>();
        params.put("version", "1.0");
        params.put("app_id", "yfbm70058763e2017120101");
        params.put("mContractNo", "20171206000000108009");
        params.put("merchantNo", "70058763");
        params.put("sign_type", "RSA2");
        params.put("signkey_index", "0001");
        params.put("timestamp", "20171211102406");
        params.put("cardInfo", "349B6AC92254D9C7B0B1523F95DF7C6A4D9AF29505781DC9B1A745D7A6CD37849B573F211AF24BBCB350BCDFA09693C04D81C8446827D6A09C4FF01EBE74670CF78D4DAE4308FE66343399950829D53DD412E1499A1F9C5FCD03381B678898AF8073D3C52CDB5E409D284CFCDC606BC13D1993BFACDB22CD34CC4BE5E40E1E45F77DE7AADD91E7F36D858D57C5767C5A668FB65E9C28C31A8F41E22000EC1D62E8E104C97F704C3F210E28FFB82BFB827DDA2B59DF7202148E8C607682CA21EB0CB4CA25DEC4DEACCDBE6758A8010116F792BEEC2D3A1DE3F2E4F0086E37AC258F79E24CBCABEB2A69BEEC6E6F6AD54943BCA11E37FAE63A70E90BFC45EF5335");
        params.put("requestTime", "20171211102406");
        params.put("service", "suning.fosps.eps.signfacade.singlebankcardsign");
        //对参数进行消息摘要计算
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        messageDigest.update(map2String(params, "signkey_index", "sign_type").getBytes("UTF-8"));
        //RSA私钥---Base64字符串
        String base64PrimaryKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALLf5WqaIRA9FCC6FN94n9HqCBlfjTZ4/KO1NpoZoyO+EOAO11eEryPBg8+HooTbqCXmP1oecETa4QIVnMZ8TgDfz8f77DZfF1KeqWGUxSosh8RMq1B2zn0UOAk4O4vBFwqrOOF1aU+MhQ5DeLQAYXn2gPgqg5PM96H6DfDyZKlFAgMBAAECgYByQnDianfqTom36gWBRiUYypzH0HB8tkXzMMMjJnM+Vp+i7/gAUKIrfeZ7v1FB+qnrI6ueHklqwkHuue1+IFMWTFRkIMvxanXX3bTj832LrswpKkhCYITDBb8L4f70tFYZWrAnYD1xmjN0yHut5LJ46MlPlpejHQLrK69QHHoRQQJBAN2KJwZUw1OIONPTmxqpGJHgz+7/fR2c+YcjGkLH1cn/LF5ET7jm+cbfpXcHZK4eATJ7L4N9SFsfbCnA2jWP0RUCQQDOsstS/pfJ8QPds69roDeEIxMfYRsw4ys+peJJsh47wwjHKgpCFY8g6KbsUwmRuYcd0Q5u8/zWDc114Qjk5aNxAkEA2g+uMfElAgfHx9k1hpyC7rQWd+1LPebRRk8q/iitKtLc3TzoK9xOZ46j0/GXDDvEeef+8LJUkjzvvnlxT99rsQJAQgPCgmBDlECAjpcryIDkGjSlj9kQuR1km16ZlhXoKAgTTqCzpAWEr+r+HO4sWTla2QACzxbnwmmoHCTiFVDuUQJAGMKTtk2h3S6gvn2Co+V7d24L6EIDGSWhR+divx9Za2SA7ZPKj7KCP0BUJOC+3qqko1nO/l2i15MVATHlUJ7KOQ==";
        //RSA公钥---Base64字符串
        String base64publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCy3+VqmiEQPRQguhTfeJ/R6ggZX402ePyjtTaaGaMjvhDgDtdXhK8jwYPPh6KE26gl5j9aHnBE2uECFZzGfE4A38/H++w2XxdSnqlhlMUqLIfETKtQds59FDgJODuLwRcKqzjhdWlPjIUOQ3i0AGF59oD4KoOTzPeh+g3w8mSpRQIDAQAB";
        //生成PKCS8规范
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(base64PrimaryKey));
        //生产X509规范
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(base64publicKey));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        //构建签名类,签名算法为SHA1WithRSA
        Signature signature = Signature.getInstance("SHA1WithRSA");
        //初始化为加签状态,传入私钥
        signature.initSign(privateKey);
        byte[] digestByte = messageDigest.digest();
        String digest = toHexString(digestByte);
        System.out.println("md5摘要:" + digest);
        byte[] digestdata = digest.getBytes("UTF-8");
        signature.update(digestdata);
        //加签
        byte[] bytes = signature.sign();
        String base64Sign = Base64.encode(bytes).trim();
        System.out.println("sign值:" + base64Sign);
        //初始化为验签状态,传入公钥
        signature.initVerify(publicKey);
        signature.update(digestdata);
        //验签
        System.out.println("验签结果:" + signature.verify(Base64.decode(base64Sign)));
    }

通过**对生成器生产**对,简易版加签与验签:

 public void signAndVerify() throws Exception {
        byte[] data = "mylove".getBytes();
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        Signature signature = Signature.getInstance(keyPairGenerator.getAlgorithm());
        signature.initSign(keyPair.getPrivate());
        signature.update(data);
        byte[] sign = signature.sign();
        System.out.println("签名:" + toHexString(sign));
        //初始化**---更新---加签或验签   这三步顺序不能变
        signature.initVerify(keyPair.getPublic());
        signature.update(data);
        boolean result = signature.verify(sign);
        System.out.println("验签结果:" + result);
    }