3 -【 API 开放平台安全设计 】- 3 接口安全加密传输

1 URL 转码

1.1 什么是 URL 转码

不管是以何种方式传递 url 时,如果要传递的 url 中包含特殊字符,如想要传递一个 +,但是这个 + 会被 url 会被编码成空格,想要传递 &,被 url 处理成分隔符。

尤其是当传递的 url 是经过 Base64 加密或者 RSA 加密后的,存在特殊字符时,这里的特殊字符一旦被 url 处理,就不是原先你加密的结果了。

url 特殊符号及对应的编码:

符号 url 中的含义 编码
+ URL+ 号表示空格 %2B
空格 URL 中的空格可以用 + 号或者编码 %20
/ 分隔目录和子目录 %2F
? 分隔实际的 URL参数 %3F
% 指定特殊字符 %25
# 表示书签 %23
& URL 中指定的参数间的分隔符 %26
= URL 中指定参数的值 %3D

1.2 URLEncodeURLDecode

接受参数案例 tranIndex

@RestController
public class TranController {

	// 接受客户端参数
	@RequestMapping("/tranIndex")
	public String tranIndex(String name) {
		System.out.println("name:" + name);
		return name;
	}
}

客户端访问结果:

3 -【 API 开放平台安全设计 】- 3 接口安全加密传输

传入 + 参数变为了空格。

解决办法:将 + 变为 %2B

3 -【 API 开放平台安全设计 】- 3 接口安全加密传输

1.3 Java 代码处理转码

URLEncoder.encodedecode

String encode = URLEncoder.encode("1+1", "UTF-8");
String decode = URLDecoder.decode(encode, "UTF-8");
System.out.println("encode:" + encode + ",decode:" + decode);

Http 接口参数编码处理:

String url = "http://127.0.0.1:8080/tranIndex?";
// 参数转码
String strParam = "name=" + URLEncoder.encode("1+1", "utf-8");
String newUrl = url + strParam;
String result = HttpClientUtils.httpGet(newUrl);
System.out.println("result:" + result);

2 单向散列加密

主要运用地方是存储密码

散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度。加密性强的散列一定是不可逆的,这就意味着 通过散列结果,无法推出任何部分的原始信息。任何输入信息的变化,哪怕仅一位,都将导致散列结果的明显变化,这称之为雪崩效应。散列还应该是防冲突的,即找不出具有相同散列结果的两条信息。具有这些特性的散列结果就可以用于验证信息是否被修改。

单向散列函数一般用于产生消息摘要,密钥加密等,常见的有:

  1. MD5(Message Digest Algorithm 5):是 RSA 数据安全公司开发的一种单向散列算法,非可逆,相同的明文产生相同的密文。
  2. SHA(Secure Hash Algorithm):可以对任意长度的数据运算生成一个160位的数值;

SHA-1MD5 的比较:
因为二者均由 MD4 导出,SHA-1MD5 彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:

  1. 对强行供给的安全性:最显著和最重要的区别是 SHA-1 摘要比 MD5 摘要长32 位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对 MD5 是2128数量级的操作,而对 SHA-1 则是2160数量级的操作。这样,SHA-1 对强行攻击有更大的强度。
  2. 对密码分析的安全性:由于 MD5 的设计,易受密码分析的攻击,SHA-1 显得不易受这样的攻击。
  3. 速度:在相同的硬件上,SHA-1 的运行速度比 MD5 慢。

1、特征:雪崩效应、定长输出和不可逆。
2、作用是:确保数据的完整性。
3、加密算法:md5(标准密钥长度128位)、sha1(标准密钥长度160位)、md4、CRC-32
4、加密工具:md5sum、sha1sum、openssl dgst。
5、计算某个文件的hash值,例如:md5sum/shalsum FileName,openssl dgst –md5/-sha

1.1 MD5加密

1.1.1 在线MD5解密与加密

http://www.cmd5.com/

1.1.2 Java操作MD5加密

1.1.3 MD5加盐实现方式

一般使用的加盐:
md5(Password+UserName),即将用户名和密码字符串相加再MD5,这样的MD5摘要基本上不可反查。

但有时候用户名可能会发生变化,发生变化后密码即不可用了(验证密码实际上就是再次计算摘要的过程)。

因此我们做了一个非常简单的加盐算法,每次保存密码到数据库时,都生成一个随机16位数字,将这16位数字和密码相加再求MD5摘要,然后在摘要中再将这16位数字按规则掺入形成一个48位的字符串。

在验证密码时再从48位字符串中按规则提取16位数字,和用户输入的密码相加再MD5。按照这种方法形成的结果肯定是不可直接反查的,且同一个密码每次保存时形成的摘要也都是不同的。

代码如下:

/**
 * MD5加盐加密
 */
public class PasswordUtil {
	/**
	 * 生成含有随机盐的密码
	 */
	public static String generate(String password) {
		Random r = new Random();
		StringBuilder sb = new StringBuilder(16);
		sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
		int len = sb.length();
		if (len < 16) {
			for (int i = 0; i < 16 - len; i++) {
				sb.append("0");
			}
		}
		String salt = sb.toString();
		password = md5Hex(password + salt);
		char[] cs = new char[48];
		for (int i = 0; i < 48; i += 3) {
			cs[i] = password.charAt(i / 3 * 2);
			char c = salt.charAt(i / 3);
			cs[i + 1] = c;
			cs[i + 2] = password.charAt(i / 3 * 2 + 1);
		}
		return new String(cs);
	}

	/**
	 * 校验密码是否正确
	 */
	public static boolean verify(String password, String md5) {
		char[] cs1 = new char[32];
		char[] cs2 = new char[16];
		for (int i = 0; i < 48; i += 3) {
			cs1[i / 3 * 2] = md5.charAt(i);
			cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
			cs2[i / 3] = md5.charAt(i + 1);
		}
		String salt = new String(cs2);
		return md5Hex(password + salt).equals(new String(cs1));
	}

	/**
	 * 获取十六进制字符串形式的MD5摘要
	 */
	public static String md5Hex(String src) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			byte[] bs = md5.digest(src.getBytes());
			return new String(new Hex().encode(bs));
		} catch (Exception e) {
			return null;
		}
	}

	public static void main(String[] args) {
		// 加密+加盐
		String password1 = generate("admin");
		System.out.println("结果:" + password1 + "   长度:" + password1.length());
		// 解码
		System.out.println(verify("admin", password1));
		// 加密+加盐
		String password2 = generate("admin");
		System.out.println("结果:" + password2 + "   长度:" + password2.length());
		// 解码
		System.out.println(verify("admin", password2));
	}
}

3 信息加密技术

目的:防止抓包篡改请求

3.1 对称加密

对称密码技术:发件人和收件人使用其 共同拥有的单个密钥,这种密钥既用于加密,也用于解密,叫做机密密钥(也称为对称密钥或会话密钥)。

能够提供信息机密性(没有密钥信息不能被解密)、完整性(被改变的信息不能被解密)的服务。

对称式密码学又称:单钥密码学、秘密密钥密码学、会话密钥密码学、私钥密码学、共享秘钥密码学

3.1.1 常见的对称式加密技术

  • DES(数据加密标准):分组式加密,算法源于Lucifer,作为NIST对称式加密标准;64位(有效位56位、校验8位),分组算法
  • 3DES:128位,分组算法
  • IDEA(国际数据加密算法):128位,比DES快,分组算法
  • Blowfish:32-448位,算法公开,分组算法
  • RC4:流密码,密钥长度可变
  • RC5:分组密码,密钥长度可变,最大2048位
  • Rijndael:128位/196位/256位
  • AES(高级加密标准):DES升级版,算法出自Rinjindael

3.1.2 对称密码的优点

用户只需记忆一个密钥,就可用于加密、解密;

与非对称加密方法相比,加密解密的计算量小,速度快,简单易用,适合于对海量数据进行加密处理 。

3.1.3 对称密码的缺点

如果密钥交换不安全,密钥的安全性就会丧失。特别是在电子商务环境下,当客户是未知的、不可信的实体时,如何使客户安全地获得密钥就成为一大难题。

如果用户较多情况下的密钥管理问题。N*(N-1)/2

如果密钥多个用户被共享,不能提供抗抵赖性

3.1.4 对称密码案例

假设 Alice 和 Bob 是认识的,两人为了保证通信消息不被其它人截取,预先约定了一个密码,用来加密在他们之间传送的消息,这样即使有人截取了消息没有密码也无法知道消息的内容。由此便实现了机密性。

3 -【 API 开放平台安全设计 】- 3 接口安全加密传输

3.1.5 基于 DES 实现加密和解密

DES 加密工具类

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.SecureRandom;

/**
 * @author :yang-windows
 * @Title : E8
 * @Package :com.snow.utils
 * @Description : DES加密解密工具类
 *                DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,
 *                后来被美国*正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,
 *                24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。
 *                注意:DES加密和解密过程中,密钥长度都必须是8的倍数
 * @date :2020/4/16 23:56
 */
public class DESUtil {
    
    /**
     * 加密
     *
     * @param datasource :byte[]
     * @param password   :String
     * @return           :byte[]
     */
    public static byte[] encrypt(byte[] datasource, String password) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            // 创建一个密匙工厂,然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            // Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance("DES");
            // 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            // 现在,获取数据并加密
            // 正式执行加密操作
            return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     *
     * @param src      :byte[]
     * @param password :String
     * @return         :byte[]
     * @throws Exception
     */
    public static byte[] decrypt(byte[] src, String password) throws Exception {
        // DES算法要求有一个可信任的随机数源
        SecureRandom random = new SecureRandom();
        // 创建一个DESKeySpec对象
        DESKeySpec desKey = new DESKeySpec(password.getBytes());
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的
        // Cipher
        // 对象
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES");
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, random);
        // 真正开始解密操作
        return cipher.doFinal(src);
    }
}

DES加解密案例

public class Main {
    // 1.配置密钥
    private static String PASSWORD = "95880288";

    public static void main(String[] args) throws Exception {

        // 2.需要加密的内容
        String content = "yangshuo";
        // 3.使用DES 加密
        byte[] encryptContent = DESUtil.encrypt(content.getBytes(), PASSWORD);
        System.out.println("加密后内容:" + new String(encryptContent));
        // 4.使用DES 解密
        byte[] decrypt = DESUtil.decrypt(encryptContent, PASSWORD);
        System.out.println("解密后内容:" + new String(decrypt));
    }
}

控制台打印:

加密后内容:j!�l��`i<�|fzQ&
解密后内容:yangshuo

3.3 移动 APP 接口安全设计

  • HTTPS传输
  • 使用令牌
  • 使用非对称加密

不能使用对称加密

会被反编译 APK 拿到密匙

3.4 非对称加密

使用一对密钥:一个用于加密信息,另一个则用于解密信息。

两个密钥之间存在着相互依存关系:即用其中任一个密钥加密的信息只能用另一个密钥进行解密。

其中加密密钥不同于解密密钥,公钥加密私钥解密,反之也可私钥加密公钥解密。

密钥依据性质划分,将其中的一个向外界公开,称为公钥;另一个则自己保留,称为私钥。公钥(Public key)常用于数据加密(用对方公钥加密)或签名验证(用对方公钥解密),私钥(Private key)常用于数据解密(发送方用接收方公钥加密)或数字签名(用自己私钥加密)。

  • 机密性
  • 完整性
  • 抗抵赖性

3 -【 API 开放平台安全设计 】- 3 接口安全加密传输

  1. 使用过程:
    乙方生成两把密钥(公钥和私钥)
    甲方获取乙方的公钥,然后用它对信息加密。
    乙方得到加密后的信息,用私钥解密,乙方也可用私钥加密字符串
    甲方获取乙方私钥加密数据,用公钥解密
  • 优点:难破解
  • 缺点:加密速度慢

常用算法:

  • RSA
  • Elgamal
  • 背包算法
  • Rabin
  • D-H
  • ECC(椭圆曲线加密算法)

应用场景:

  • 第三方支付对接
  • 核心金融机构

3.4.1 RSA 工具类

package com.weavernorth.sa.utils;

import org.apache.commons.net.util.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author :yang-windows
 * @Title : E8
 * @Package :com.weavernorth.sa.utils
 * @Description : RSA加解密工具类
 * @date :2020/4/17 0:22
 */
public class RSAUtil {

    public static String publicKey; // 公钥
    public static String privateKey; // 私钥

    /**
     * 生成公钥和私钥
     */
    public static void generateKey() {
        // 1.初始化秘钥
        KeyPairGenerator keyPairGenerator;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            SecureRandom sr = new SecureRandom(); // 随机数生成器
            keyPairGenerator.initialize(512, sr); // 设置512位长的秘钥
            KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 开始创建
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 进行转码
            publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
            // 进行转码
            privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 私钥匙加密或解密
     *
     * @param content
     * @param privateKeyStr
     * @return
     */
    public static String encryptByprivateKey(String content, String privateKeyStr, int opmode) {
        // 私钥要用PKCS8进行处理
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
        KeyFactory keyFactory;
        PrivateKey privateKey;
        Cipher cipher;
        byte[] result;
        String text = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            // 还原Key对象
            privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(opmode, privateKey);
            if (opmode == Cipher.ENCRYPT_MODE) { // 加密
                result = cipher.doFinal(content.getBytes());
                text = Base64.encodeBase64String(result);
            } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
                result = cipher.doFinal(Base64.decodeBase64(content));
                text = new String(result, "UTF-8");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return text;
    }

    /**
     * 公钥匙加密或解密
     *
     * @param content
     * @param publicKeyStr
     * @return
     */
    public static String encryptByPublicKey(String content, String publicKeyStr, int opmode) {
        // 公钥要用X509进行处理
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
        KeyFactory keyFactory;
        PublicKey publicKey;
        Cipher cipher;
        byte[] result;
        String text = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            // 还原Key对象
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(opmode, publicKey);
            if (opmode == Cipher.ENCRYPT_MODE) { // 加密
                result = cipher.doFinal(content.getBytes());
                text = Base64.encodeBase64String(result);
            } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
                result = cipher.doFinal(Base64.decodeBase64(content));
                text = new String(result, "UTF-8");
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return text;
    }

}

3.5.2 使用公钥加密和私钥解密案例

package com.weavernorth.sa.utils;

import org.apache.commons.net.util.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author :yang-windows
 * @Title : E8
 * @Package :com.weavernorth.sa.utils
 * @Description : RSA加解密工具类
 * @date :2020/4/17 0:22
 */
public class RSAUtil {

    public static String publicKey; // 公钥
    public static String privateKey; // 私钥

    /**
     * 生成公钥和私钥
     */
    public static void generateKey() {
        // 1.初始化秘钥
        KeyPairGenerator keyPairGenerator;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            SecureRandom sr = new SecureRandom(); // 随机数生成器
            keyPairGenerator.initialize(512, sr); // 设置512位长的秘钥
            KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 开始创建
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 进行转码
            publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
            // 进行转码
            privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 私钥匙加密或解密
     *
     * @param content
     * @param privateKeyStr
     * @return
     */
    public static String encryptByprivateKey(String content, String privateKeyStr, int opmode) {
        // 私钥要用PKCS8进行处理
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
        KeyFactory keyFactory;
        PrivateKey privateKey;
        Cipher cipher;
        byte[] result;
        String text = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            // 还原Key对象
            privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(opmode, privateKey);
            if (opmode == Cipher.ENCRYPT_MODE) { // 加密
                result = cipher.doFinal(content.getBytes());
                text = Base64.encodeBase64String(result);
            } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
                result = cipher.doFinal(Base64.decodeBase64(content));
                text = new String(result, "UTF-8");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return text;
    }

    /**
     * 公钥匙加密或解密
     *
     * @param content
     * @param publicKeyStr
     * @return
     */
    public static String encryptByPublicKey(String content, String publicKeyStr, int opmode) {
        // 公钥要用X509进行处理
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
        KeyFactory keyFactory;
        PublicKey publicKey;
        Cipher cipher;
        byte[] result;
        String text = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            // 还原Key对象
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(opmode, publicKey);
            if (opmode == Cipher.ENCRYPT_MODE) { // 加密
                result = cipher.doFinal(content.getBytes());
                text = Base64.encodeBase64String(result);
            } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
                result = cipher.doFinal(Base64.decodeBase64(content));
                text = new String(result, "UTF-8");
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return text;
    }

}

3.5.3 使用私钥加密和公钥解密案例

import javax.crypto.Cipher;

public class Main {

    public static void main(String[] args) throws Exception {

        /**
         * 注意: 私钥加密必须公钥解密 公钥加密必须私钥解密
         */
        System.out.println("-------------生成两对秘钥,分别发送方和接收方保管-------------");
        RSAUtil.generateKey();
        System.out.println("公钥匙给接收方:" + RSAUtil.publicKey);
        System.out.println("私钥给发送方:" + RSAUtil.privateKey);

        System.out.println("-------------第一个栗子,私钥加密公钥解密-------------");
        String textsr = "早啊,你吃早饭了吗?O(∩_∩)O~";
        // 私钥加密
        String cipherText = RSAUtil.encryptByprivateKey(textsr,
        RSAUtil.privateKey, Cipher.ENCRYPT_MODE);
        System.out.println("发送方用私钥加密后:" + cipherText);
        // 公钥解密
        String text = RSAUtil.encryptByPublicKey(cipherText,
        RSAUtil.publicKey, Cipher.DECRYPT_MODE);
        System.out.println("接收方用公钥解密后:" + text);

        System.out.println("-------------第二个栗子,公钥加密私钥解密-------------");
        // 公钥加密
        String textsr1 = "吃过啦!你吃了吗?O(∩_∩)O~";

        String cipherText1 = RSAUtil.encryptByPublicKey(textsr1, RSAUtil.publicKey, Cipher.ENCRYPT_MODE);
        System.out.println("接收方用公钥加密后:" + cipherText1);
        // 私钥解密
        String text1 = RSAUtil.encryptByprivateKey(cipherText1, RSAUtil.privateKey, Cipher.DECRYPT_MODE);
        System.out.print("发送方用私钥解密后:" + text1);
    }
}

控制台打印:

-------------生成两对秘钥,分别发送方和接收方保管-------------
公钥匙给接收方:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ82+6q5mGQEeQVDf7QU4CEuUbaNLQsxfHDUIllav7Hq
OyujKtnFgOjr6zTXirz0YIItkBNNWb+XiU4L3Iv9kO0CAwEAAQ==

私钥给发送方:MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAnzb7qrmYZAR5BUN/tBTgIS5Rto0t
CzF8cNQiWVq/seo7K6Mq2cWA6OvrNNeKvPRggi2QE01Zv5eJTgvci/2Q7QIDAQABAkADV8Qw8XSh
pPZlheVIgqeyCqbsjkpD0eYq+ElAVwdvVNMuXGipnGlEsi0TXVfqBQF4ziF4W6lByQNsA7MFuNaB
AiEAzn/5V2DC2fGw1CdKNV/rsfViRCiZXO/o8OQaYv5Yxm8CIQDFYVIxm8mO8h/4QTHuyMUONorf
i/shAd1BJyFILC5sYwIgbwMdaHv8RG5KQcNdgZQvgVwJl9q7l9rhv57hEJbr4sECIFZo48XqENRu
tYZGbGjAJlyxjhyNuLRbj5RdYBmrletHAiAiIQBxA8gN1FMT4gvoQlL0xiBFtAE/+VWIeedrOebS
8Q==

-------------第一个栗子,私钥加密公钥解密-------------
发送方用私钥加密后:hPaOOVQvFZ0/S29I11kaZHQAFf56lifWeUHZJUaw9UFd45iuYX6y7hYqIr1uA74R3pOdQvX8n5xf
lYRLrHni0A==

接收方用公钥解密后:早啊,你吃早饭了吗?O(∩_∩)O~
-------------第二个栗子,公钥加密私钥解密-------------
接收方用公钥加密后:KJTRJrn3cNcxQUtPRB9bwqDg/99XSyV9z1aJFXJ48r+O+2iC2XCXJcyUFEiiI5CYvhC4e3sW6XV/
YiSx7/faVQ==

发送方用私钥解密后:吃过啦!你吃了吗?O(∩_∩)O~
Process finished with exit code 0

3.5 基于令牌方式隐藏参数

@RestController
public class PayController extends BaseApiService {
	
	@Autowired
	private BaseRedisService baseRedisService;
	
	private static long timeToken = 15 * 60l;

	@RequestMapping("/pay")
	public ResponseBase pay(String token) {
		// 获取提交参数 数据库保存.,
		if (StringUtils.isEmpty(token)) {
			return setResultError("token 不能为空!");
		}
		String reuslt = (String) baseRedisService.getString(token);
		if (StringUtils.isEmpty(reuslt)) {
			return setResultError("参数不能空!");
		}
		System.out.println("获取提交的参数reuslt:" + reuslt);
		return setResultSuccess("获取提交的参数reuslt:" + reuslt);
	}

	@RequestMapping("/getPayToken")
	public String pay(Long userId, Long money) {
		String payToken = UUID.randomUUID().toString();
		baseRedisService.setString(payToken, userId + "-" + money, timeToken);
		return payToken;
	}

}
上一篇:根据序列号加密生产4*4的密码,如:X9PL-TERY-NOZN-GMF1


下一篇:2020ccpc威海 G.Caesar Cipher (hash+线段树)