前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微服务架构 | 数据加密有哪些常用的加密方式?(二)

微服务架构 | 数据加密有哪些常用的加密方式?(二)

作者头像
码农架构
发布2021-10-27 15:01:48
1.6K0
发布2021-10-27 15:01:48
举报
文章被收录于专栏:码农架构码农架构

导读:前一篇文章中有提到对称加密之DES加密与解密以及非对称加密之RSA加密与解密。本篇继续接着上篇的话题聊聊微服务的加密方式

一、背景


上一篇文章中有两处错误简单做了调整,还以一点就是代码上的调整未做更新非对称加密之AES加密与解密。写错应该是RSA。

▐ 非对称加密之AES加密与解密

  • 加密过程是通过Encoding指定不同的代码页,把字符转成不同代码页对应的编码,表现为byte[ ]
  • 解密过程是加密时Encoding 使用的代码页,把byte[ ]形式的明文转为适当的字符串明文
代码语言:javascript
复制
/** RSA加解密处理组件 */
public class RsaEncryptProvider{

    public static final String RSA = "RSA";

    public static final String CHARSET_NAME = "UTF-8";
    /**
     * RSA私钥
     */
    private byte[] privateCodeByte;

    /**
     * RSA公钥
     */
    private byte[] publicCodeByte;
}

RSA公钥加密

代码语言:javascript
复制
public String encrypt(String encryptStr) {
    String outStr = null;
    try {
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(RSA).generatePublic(new X509EncodedKeySpec(publicCodeByte));
        //RSA加密
        Cipher cipher = Cipher.getInstance(RSA);
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        outStr = Base64.getEncoder().encodeToString(cipher.doFinal(encryptStr.getBytes(CHARSET_NAME)));
    } catch (InvalidKeySpecException e) {
        log.error("无效的密钥规范", e);
    } catch (NoSuchAlgorithmException e) {
        log.error("无效的算法", e);
    } catch (NoSuchPaddingException e) {
        log.error("无效的算法", e);
    } catch (InvalidKeyException e) {
        log.error("无效的密钥", e);
    } catch (IllegalBlockSizeException e) {
        log.error("非法块大小", e);
    } catch (BadPaddingException e) {
        log.error("错误填充异常", e);
    } catch (UnsupportedEncodingException e) {
        log.error("不支持的编码异常", e);
    }
    return outStr;
}

RSA私钥解密

代码语言:javascript
复制
public String decrypt(String decryptStr) {
    String outStr = null;
    try {
        //64位解码加密后的字符串
        byte[] inputByte = Base64.getDecoder().decode(decryptStr.getBytes(CHARSET_NAME));
        //私钥
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(RSA).generatePrivate(new PKCS8EncodedKeySpec(privateCodeByte));
        //RSA解密
        Cipher cipher = Cipher.getInstance(RSA);
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        outStr = new String(cipher.doFinal(inputByte));
    } catch (Exception e) {
        log.error("RSA解密失败", e);
    }
    return outStr;
}

二、非对称加密之RSA加密与解密


▐ 随机生成密钥对

基于RSA算法生成对象返回一个 KeyPairGenerator 对象,它为指定的算法生成公钥/私钥对。此方法遍历已注册安全提供程序的列表,从最喜欢的提供程序开始。返回一个新的 KeyPairGenerator 对象,该对象封装了来自支持指定算法的第一个 Provider 的 KeyPairGeneratorSpi 实现。

请注意,可以通过Security.getProviders()方法检索已注册提供程序的列表

代码语言:javascript
复制
public static void genKeyPair() throws NoSuchAlgorithmException {
    // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    // 初始化密钥对生成器,密钥大小为96-1024位
    keyPairGen.initialize(1024, new SecureRandom());
    // 生成一个密钥对,保存在keyPair中
    KeyPair keyPair = keyPairGen.generateKeyPair();
    // 得到私钥
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
    // 得到公钥
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    String publicKeyString = new String(Hex.encode(publicKey.getEncoded()));
    // 得到私钥字符串
    String privateKeyString = new String(Hex.encode((privateKey.getEncoded())));
    // 将公钥和私钥保存到Map
    //0表示公钥
    System.out.println("公钥 16进制:"+publicKeyString);
    //1表示私钥
    System.out.println("私钥 16进制:"+privateKeyString);
}

生成结果

代码语言:javascript
复制
公钥 16进制:30819f300d06092a864886f70d010101050003818d0030818902818100ac8192db5b48d3037ea88fc419f17b9a1cabea6ff18707f9bdc52f67a87b1246b3ff04bb0e96b795f9d58cd5c83b6f6938fe7d9b74b07f7b54d3fc8784783fd9b026b1ec59565429521bbbfa3b45780e3367061ddb20a4b302393aabc22ea6fb6302ad4f4e4ff86a9592decc61ca6888b2b429d2541b354920271b78ef094e6b0203010001
私钥 16进制:30820276020100300d06092a864886f70d0101010500048202603082025c02010002818100ac8192db5b48d3037ea88fc419f17b9a1cabea6ff18707f9bdc52f67a87b1246b3ff04bb0e96b795f9d58cd5c83b6f6938fe7d9b74b07f7b54d3fc8784783fd9b026b1ec59565429521bbbfa3b45780e3367061ddb20a4b302393aabc22ea6fb6302ad4f4e4ff86a9592decc61ca6888b2b429d2541b354920271b78ef094e6b020301000102818005383a7856afc26ac5a7560a49faab91c332547aa4a5405187337336c0bb509741150350a1a55fd2b2e78a4661b3a2b05d601deed93e09ed7268a3a87a12a563e517cb7aca04e9f53b4b1180dce3b40e9d2acc930f603d000c53d14be31533b8e28d34ed8506e012ad01c9f0c8db77509157ae4041831032dfe42a796bb0eb99024100e190a43b11431830f6542dd64d7c773c3b1004835d6ffd1bc74446d28eaaab81e8b34b14cae756765ef695cc3a27cd08916d299ad9b41ba1908006759b9c9c3d024100c3c832cc11c3747ef97f6a84b37d3adf7f106c62992636b902f229342a779d38e4cdb5460242aa462e07b36e8f238daec743b26113fcc2e8be617390cb91f7c70240666d88264a706d4bce8feb40a56f1fb5fa1c0bf09b3d7f725dca635eb9ea46777773f3643dbf4f43f15b882a753e1d9d066ccbb7c5a443e7d9f648f89ef13f0102403d0b24db800663425be4a07fb3bf2e26156637851e9f4d9cae10774c6e99510a363cf57258ae148d4138e1776d65f67d32602734219943e471c7ccd2aec65a6d02410092289958fb783b3868d5c7b7140116185682d61a56a2ff1253b293d55203a6df26cb3e9ddb617eb1c2cab9d37b889660d3ee0f234e16da863b5269af74bbb9bf
▐ 加密和解密
代码语言:javascript
复制
public static void encryptAndDecrypt() {
    //生成公钥和私钥
    String p = "30819f300d06092a864886f70d010101050003818d0030818902818100ac8192db5b48d3037ea88fc419f17b9a1cabea6ff18707f9bdc52f67a87b1246b3ff04bb0e96b795f9d58cd5c83b6f6938fe7d9b74b07f7b54d3fc8784783fd9b026b1ec59565429521bbbfa3b45780e3367061ddb20a4b302393aabc22ea6fb6302ad4f4e4ff86a9592decc61ca6888b2b429d2541b354920271b78ef094e6b0203010001";
    String pr = "30820276020100300d06092a864886f70d0101010500048202603082025c02010002818100ac8192db5b48d3037ea88fc419f17b9a1cabea6ff18707f9bdc52f67a87b1246b3ff04bb0e96b795f9d58cd5c83b6f6938fe7d9b74b07f7b54d3fc8784783fd9b026b1ec59565429521bbbfa3b45780e3367061ddb20a4b302393aabc22ea6fb6302ad4f4e4ff86a9592decc61ca6888b2b429d2541b354920271b78ef094e6b020301000102818005383a7856afc26ac5a7560a49faab91c332547aa4a5405187337336c0bb509741150350a1a55fd2b2e78a4661b3a2b05d601deed93e09ed7268a3a87a12a563e517cb7aca04e9f53b4b1180dce3b40e9d2acc930f603d000c53d14be31533b8e28d34ed8506e012ad01c9f0c8db77509157ae4041831032dfe42a796bb0eb99024100e190a43b11431830f6542dd64d7c773c3b1004835d6ffd1bc74446d28eaaab81e8b34b14cae756765ef695cc3a27cd08916d299ad9b41ba1908006759b9c9c3d024100c3c832cc11c3747ef97f6a84b37d3adf7f106c62992636b902f229342a779d38e4cdb5460242aa462e07b36e8f238daec743b26113fcc2e8be617390cb91f7c70240666d88264a706d4bce8feb40a56f1fb5fa1c0bf09b3d7f725dca635eb9ea46777773f3643dbf4f43f15b882a753e1d9d066ccbb7c5a443e7d9f648f89ef13f0102403d0b24db800663425be4a07fb3bf2e26156637851e9f4d9cae10774c6e99510a363cf57258ae148d4138e1776d65f67d32602734219943e471c7ccd2aec65a6d02410092289958fb783b3868d5c7b7140116185682d61a56a2ff1253b293d55203a6df26cb3e9ddb617eb1c2cab9d37b889660d3ee0f234e16da863b5269af74bbb9bf";
    RsaEncryptProvider rsaEncryptProvider = new RsaEncryptProvider(Hex.decode(pr), Hex.decode(p));
    //加密字符串
    String message = "1";
    System.out.println("原密码:" + message);
    String rsaEn = rsaEncryptProvider.encrypt(message);
    System.out.println("RSA加密:" + rsaEn);
    String urlEn = URLEncoder.encode(rsaEn, "utf-8");
    System.out.println("url编码:" + urlEn);
    // 解码
    rsaEn = URLDecoder.decode(urlEn, "utf-8");
    message = rsaEncryptProvider.decrypt(rsaEn);
    System.out.println("还原后的字符串为:" + message);
    Md5EncryptProvider md5EncryptProvider = new Md5EncryptProvider(null);
    System.out.println("MD5:" + md5EncryptProvider.encrypt(message));
}

三、AES加密与解密


高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:

  • 明文P:没有经过加密的数据。
  • 密钥K:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
  • AES加密函数:设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。
  • 密文C:经加密函数处理后的数据
  • AES解密函数:设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。

实际中,一般是通过RSA加密AES的密钥,传输到接收方,接收方解密得到AES密钥,然后发送方和接收方用AES密钥来通信。先前有一篇文章中提到服务之间的安全问题

Spring Cloud中如何保证各个微服务之间调用的安全性?

服务之间的应用名通过AES加密,被调用放通过密钥对X-SERVICE-NAME进行解密,来确定服务是否允许被集成调用。感兴趣的可以查阅了解

▐ 加密
代码语言:javascript
复制
/** 加密 */
public String encrypt(String encryptStr) {
    synchronized (this.encryptor) {
        try {
            encryptor.init(Cipher.ENCRYPT_MODE, secretKey, ivParam);
            byte[] encodes = Base64.getEncoder().encode(encryptor.doFinal(encryptStr.getBytes(CHARSET_DEFAULT)));
            return HexUtils.toHexString(encodes);
        } catch (Exception e) {
            log.error(ENCRYPT_AES + "加密出错", e);
        }
    }
    return null;
}
▐ 解密
代码语言:javascript
复制
/** 解密 */
public String decrypt(String decryptStr) {
    synchronized (this.decryptor) {
        try {
            decryptor.init(Cipher.DECRYPT_MODE, secretKey, ivParam);
            return new String(decryptor.doFinal(Base64.getDecoder().decode(HexUtils.fromHexString(decryptStr))), CHARSET_DEFAULT);
        } catch (Exception e) {
            log.error(ENCRYPT_AES + "解密出错", e);
        }
    }
    return null;
}

四、总结


本文主要上一篇文章中非对称加密之RSA加密与解密,进行修订和调整和对AES加密和解密的补充。总结本篇文章希望对从事相关业务线的同学能够有所帮助或者启发

- END -

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-10-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ▐ 加密和解密
  • ▐ 加密
  • ▐ 解密
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档