Java:接口参数加密

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

一、参数加密

二、参数解密

三、生成公钥私钥 


一、参数加密

public static String buildRequest(String params, String privateKey, String publicKey) {
    // 时间戳
    String timestamp = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
    // 构建签名
    TreeMap<String, String> map = new TreeMap<>();
    map.put("params", params);
    map.put("timestamp", timestamp);

    // 待签名明文
    String plain = toSortedString(map); 
    // 做md5摘要处理
    String md5 = MD5.digest(plain, StandardCharsets.UTF_8);
    try {
        // 签名
        String sign = sign(md5, privateKey);
        map.put("sign", sign);
        String aesKey = generateAesKey();  // 生成16位AES密钥
        params = encryptAES(params, aesKey);
        map.replace("params", params);   // 对params进行AES加密, 并替换进map

        // 对AES密钥进行RSA加密, 并将加密后的AES密钥加入map
        aesKey = encryptRSA(aesKey, publicKey);
        map.put("key", aesKey); // 用公钥加密
    }catch (Exception e){
        log.error("商户API签名失败,请检查具体的原因",e);
    }
    
    return JSON.toJSONString(map);
}

private static String toSortedString(TreeMap<String, String> map) {
    StringBuilder sb = new StringBuilder();
    Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
    while (true) {
        Map.Entry<String, String> entry = it.next();
        sb.append(entry.getKey()).append('=').append(entry.getValue());
        if (it.hasNext()) {
            sb.append('&');
        } else {
            break;
        }
    }
    return sb.toString();
}
/**
 * RSA签名
 * @param data
 * @param privateKeyStr
 * @return
 */
public static String sign(String data, String privateKeyStr) throws Exception {
    log.info("sign data:{},privateKeyStr:{}",data,privateKeyStr);
    PrivateKey privateKey = getPrivateKey(privateKeyStr);
    Signature signature = Signature.getInstance(algorithmStr);
    signature.initSign(privateKey);
    signature.update(data.getBytes(StandardCharsets.UTF_8));
    return new String(Base64.encodeBase64(signature.sign()));
}

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

/**
 * 生成16位不重复的随机数,含数字+大小写
 * 作为AES密钥使用
 */
private static String generateAesKey() {
    StringBuilder uid = new StringBuilder ();
    //产生16位的强随机数
    Random rd = new SecureRandom ();
    for (int i = 0; i < 16; i++) {
        int type = rd.nextInt (3);
        switch (type) {
            case 0:
                uid.append (rd.nextInt (10));
                break;
            case 1:
                uid.append ((char) (rd.nextInt (25) + 65));
                break;
            case 2:
                uid.append ((char) (rd.nextInt (25) + 97));
                break;
            default:
                break;
        }
    }
    return uid.toString ();
}

/**
 * AES加密
 *
 * @param content 需要加密的内容
 * @param strKey  加密秘钥
 * @return 加密后的比特流
 */
private static String encryptAES(String content, String strKey) throws Exception {
    SecretKeySpec key = new SecretKeySpec (strKey.getBytes (), "AES"); //NOSONAR
    Cipher cipher = Cipher.getInstance ("AES");
    byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
    cipher.init (Cipher.ENCRYPT_MODE, key);
    return byte2hex(cipher.doFinal(byteContent));
}

/**
 * byte[]转16进制string
 * @param b
 * @return
 */
private static String byte2hex(byte[] b) {
    StringBuilder hs = new StringBuilder ();
    for (byte bi : b) {
        String temp = Integer.toHexString (bi & 0XFF);
        if (temp.length () == 1) {
            hs.append ("0");
        }
        hs.append (temp);
    }
    return hs.toString ().toUpperCase ();
}

/**
 * RSA加密
 * @param data
 * @param publicKeyStr
 * @return
 */
public static String encryptRSA(String data, String publicKeyStr) throws Exception {
    
    // 对数据加密
    PublicKey publicKey = getPublicKey(publicKeyStr);
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init (Cipher.ENCRYPT_MODE, publicKey);
    return byte2hex(cipher.doFinal (data.getBytes ()));
}

加密原理:

生成一个随机串,用该随机串对请求参数进行非对称加密,然后再对该随机串进行对称加密,生成签名和验签过程中,对参数进行了排序。

二、参数解密

public static String parseRequest(String strReq, String privateKey, String publicKey) {
    //log.info("params:{},privateKey:{},publicKey:{}",strReq,privateKey,publicKey);
    JSONObject obj = JSON.parseObject(strReq);
    String params = obj.getString("params"); // 用 aes加密后的密文
    String aesKey = obj.getString("key"); // 用公钥加密的密文
    String sign = obj.getString("sign");
    String timestamp = obj.getString("timestamp");
    try {
        // 对AESkey进行RSA解密
        aesKey = decryptRSA(aesKey, privateKey);  // 解密之后的aesKey明文
        // 对params进行AES解密
        params = decryptAES(params, aesKey);  // 用aes解密为明文

        // 构建验签明文
        TreeMap<String, String> map = new TreeMap<>();
        map.put("params", params);
        map.put("timestamp", timestamp);
        String plain = toSortedString(map);
        // 做md5摘要
        String md5 = MD5.digest(plain, StandardCharsets.UTF_8);
        // 验签
        boolean passed = verify(md5, publicKey, sign);
        if (!passed) {
            throw new RuntimeException("merchantAPI 验签失败");
        }
    }catch (Exception e){
        log.error("商户API验签失败,请检查具体的原因",e);
    }
    return params;
}

/**
 * RSA解密
 * @param message
 * @param privateKeyStr
 * @return
 */
public static String decryptRSA(String message, String privateKeyStr) throws Exception {
    PrivateKey privateKey = getPrivateKey(privateKeyStr);
    byte[] bytes = hex2byte(message);
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(2, privateKey);
    byte[] result = cipher.doFinal(bytes);
    return new String(result);
}

/**
 * AES解密
 *
 * @param content 待解密内容
 * @param strKey  解密密钥
 * @return 解密后的
 */
private static String decryptAES(String content, String strKey) throws Exception {
    SecretKeySpec key = new SecretKeySpec (strKey.getBytes (), "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init (Cipher.DECRYPT_MODE, key);
    return new String(cipher.doFinal(hex2byte(content)));
}

/**
 * 验签
 * @param sign
 * @param md5
 * @param publicKeyStr
 * @return
 */
public static boolean verify(String md5, String publicKeyStr,String sign) throws Exception {
    log.info("verify data:{},publicKeyStr:{},sign:{}",md5,publicKeyStr,sign);
    PublicKey publicKey = getPublicKey(publicKeyStr);
    byte[] signBytes = Base64.decodeBase64(sign);
    Signature signature = Signature.getInstance(algorithmStr);
    signature.initVerify(publicKey);
    signature.update(md5.getBytes(StandardCharsets.UTF_8));
    return signature.verify(signBytes);
}

/**
 * 公钥字符串转PrivateKey实例
 *
 * @param publicKey 公钥字符串
 * @return
 */
public static PublicKey getPublicKey(String publicKey) throws Exception {
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    byte[] decodedKey =Base64.decodeBase64(publicKey.getBytes());
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
    return keyFactory.generatePublic(keySpec);
}

三、生成公钥私钥 

/**
 * 获取密钥对
 *
 * @return 密钥对
 */
public static KeyPair getKeyPair() {
    KeyPair keyPair = null;
    try {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(1024);
        keyPair = generator.generateKeyPair();
    } catch (Exception e) {
        log.error("getKeyPair: ", e);
    }
    return keyPair;
}

public static void testGenerateKeyPair() {
    // 生成密钥对
    KeyPair keyPair = getKeyPair();
    String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
    String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
    System.out.println("私钥:" + privateKey);
    System.out.println("公钥:" + publicKey);
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java Web中,可以通过POST方法将加密字符串发送到web接口,同时可以获取QueryString参数和Header参数。 以下是一个简单的示例代码,演示如何在Spring Boot中接收加密字符串,同时获取QueryString参数和Header参数: ```java import org.springframework.web.bind.annotation.*; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; @RestController public class MyController { @RequestMapping(value = "/my-api", method = RequestMethod.POST) public String myApi(@RequestBody String encryptedData, @RequestHeader("MyHeader") String myHeader, @RequestParam("MyParam") String myParam) throws Exception { //解密加密字符串 String decryptedData = decryptData(encryptedData, "my-secret-key"); //打印Header参数和QueryString参数 System.out.println("MyHeader: " + myHeader); System.out.println("MyParam: " + myParam); //将解密后的数据存储到数据库或进行其他操作 //TODO: do something with decrypted data //返回响应 return "OK"; } //使用AES算法解密数据 private String decryptData(String encryptedData, String secretKey) throws Exception { Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); byte[] decryptedBytes = cipher.doFinal(Base64.getMimeDecoder().decode(encryptedData.getBytes(StandardCharsets.UTF_8))); return new String(decryptedBytes, StandardCharsets.UTF_8); } } ``` 这个示例中使用的是AES算法解密加密字符串。你需要将“my-secret-key”替换为你的真实密钥,并根据实际情况修改解密算法和密钥长度。同时,你需要将“MyHeader”和“MyParam”替换为你的真实Header参数和QueryString参数的名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值