【接口数据安全 AES非对称加密和RSA对称加密详解附demo】

接口数据安全

为了防止前端传递的支付金额被篡改,可以采取以下几种措施:

服务端计算金额:前端传递的支付金额仅作为参考,实际的支付金额由服务端计算生成。前端传递的金额仅用于显示和校验,而实际支付的金额由服务端根据业务逻辑计算得出,以确保金额的准确性。

使用加密算法:前端将支付金额使用加密算法进行加密,然后将加密后的数据传递给服务端进行解密和校验。这样可以防止中间过程中金额被篡改。常用的加密算法包括对称加密算法(如AES、SM4)和非对称加密算法(如RSA)。

校验数据完整性:除了校验金额,还可以校验其他关键数据的完整性,例如订单号、用户ID等。可以使用数字签名技术对数据进行签名,并在服务端进行验证。这样可以确保数据在传输过程中没有被篡改。

HTTPS协议:使用HTTPS协议进行数据传输,确保数据在传输过程中的安全性和完整性。HTTPS使用加密通道进行数据传输,可以有效防止中间人攻击和数据篡改。

需要注意的是,前端传递的数据始终是不可信的,因此在服务端对接收到的数据进行严格的校验和验证是非常重要的。以上措施可以增加支付数据的安全性和完整性,但并不能完全防止所有的攻击,因此综合考虑安全性和业务需求,选择合适的防护措施是非常重要的。

1、AES对称加密(AES默认的加密模式是AES/ECB,填充方式是PKCS7Padding)

ECB模式进行加解密,这种模式下可能存在安全性问题。在实际使用中,建议使用更安全的模式,如CBC模式,并在加密过程中使用随机生成的初始化向量(IV)来增加安全性

1.1AES/ECB/PKCS5Padding 算法/模式/补码方式 加密案例

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AESUtil {
    private static final String AES_ALGORITHM = "AES";
    private static final String AES_TRANSFORMATION = "AES/ECB/PKCS5Padding";

    public static String encrypt(String data, String key) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
        Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    public static String decrypt(String encryptedData, String key) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
        Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}

public class Main {
    public static void main(String[] args) {
        try {
            String originalData = "Hello, World!";
            String key = "0123456789abcdef";
            String encryptedData = AESUtil.encrypt(originalData, key);
            String decryptedData = AESUtil.decrypt(encryptedData, key);

            System.out.println("Original Data: " + originalData);
            System.out.println("Encrypted Data: " + encryptedData);
            System.out.println("Decrypted Data: " + decryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1.2 AES/CBC/NoPadding //“算法/模式/补码方式” 加密demo

import java.util.Random;
import java.util.UUID;
 
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Base64;
 
/**
 * AES 128bit 加密解密工具类
 */
public class AesEncryptUtil {
	//使用AES-128-CBC加密模式,key需要为16位,key和iv可以相同!
	
	/**
	 * 加密方法
	 * @param data  要加密的数据
	 * @param key 加密key
	 * @param iv 加密iv
	 * @return 加密的结果
	 * @throws Exception
	 */
	public static String encrypt(String data, String key, String iv) throws Exception {
		try {
 
			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");//"算法/模式/补码方式"
			int blockSize = cipher.getBlockSize();
 
			byte[] dataBytes = data.getBytes();
			int plaintextLength = dataBytes.length;
			if (plaintextLength % blockSize != 0) {
				plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
			}
 
			byte[] plaintext = new byte[plaintextLength];
			System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
 
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
 
			cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
			byte[] encrypted = cipher.doFinal(plaintext);	// 加密
 
			return new Base64().encodeToString(encrypted); 	//通过Base64转码返回
 
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
 
	/**
	 * 解密方法
	 * @param data 要解密的数据
	 * @param key  解密key
	 * @param iv 解密iv
	 * @return 解密的结果
	 * @throws Exception
	 */
	public static String desEncrypt(String data, String key, String iv) throws Exception {
		try {
			byte[] encrypted1 = new Base64().decode(data);
 
			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
 
			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); //使用密钥初始化,设置为解密模式
 
			byte[] original = cipher.doFinal(encrypted1);	//执行操作
			String originalString = new String(original);
			return originalString;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	  *   用于生成一组16位随机数 key
	 * @return
	 */
	public static String getRandomStringKey() {
		int hashCodeValue = UUID.randomUUID().hashCode();
		if(hashCodeValue < 0) hashCodeValue = -hashCodeValue;
		return String.format("%016d",hashCodeValue);//左边补0,16位,进制(d,x)
	}
	
	/**
	  *   用于生成16位的随机数 iv
	 * @return
	 */
    public static String getRandomStringIv(){
		String base = "abcdefghijklmnopqrstuvwxyz0123456789";   
		Random random=new Random();
		StringBuffer key = new StringBuffer();
		for(int i=0;i<16;i++){ 
			int keyNumber = random.nextInt(base.length());   
			key.append(base.charAt(keyNumber));
		}  
		return key.toString();
	}
	
	
	/**
	* 测试
	*/
	public static void main(String args[]) throws Exception {
		String data = "admin123";
		String key = getRandomStringKey();
		String iv = getRandomStringIv();
 
		String enData = encrypt(data, key, iv);
 
		System.out.println(key);
		System.out.println(iv);
		System.out.println(enData);
		System.out.println(desEncrypt(enData, key, iv));
	}
}

2、RSA非对称加密(RSA默认的加密模式是RSA/ECB/PKCS1Padding。)

这是微信apiv3敏感信息的自定义加密的一个demo。微信支付sdk里面有加密的实现了(推荐)
链接: 微信敏感信息加密
https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/min-gan-xin-xi-jia-mi

public static String rsaEncryptOAEP(String message, X509Certificate certificate)
    throws IllegalBlockSizeException, IOException {
  try {
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());

    byte[] data = message.getBytes("utf-8");
    byte[] cipherdata = cipher.doFinal(data);
    return Base64.getEncoder().encodeToString(cipherdata);
  } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
    throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
  } catch (InvalidKeyException e) {
    throw new IllegalArgumentException("无效的证书", e);
  } catch (IllegalBlockSizeException | BadPaddingException e) {
    throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
  }

这是chatgpt写的一段rsa加密

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import java.util.Base64;

public class RSAEncryptionDemo {

    public static String encrypt(String data, String publicKey) throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    public static String decrypt(String encryptedData, String privateKey) throws Exception {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, key);

        byte[] decryptedData = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        try {
            // 生成密钥对
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            // 将密钥转换成Base64字符串,用于传输和存储
            String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
            String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());

            String originalData = "Hello, World!";
            String encryptedData = encrypt(originalData, publicKeyStr);
            String decryptedData = decrypt(encryptedData, privateKeyStr);

            System.out.println("Original Data: " + originalData);
            System.out.println("Encrypted Data: " + encryptedData);
            System.out.println("Decrypted Data: " + decryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
双向 RSA + AES 加密是一种常见的加密方式,其中使用 RSA 算法加密 AES 密钥,然后使用 AES 算法加密数据。在 C# 中,可以使用 `RSACryptoServiceProvider` 类和 `AesCryptoServiceProvider` 类来实现此加密方式。以下是一个简单的示例: ```csharp using System; using System.IO; using System.Security.Cryptography; using System.Text; class Program { static void Main(string[] args) { string plainText = "Hello, world!"; byte[] encryptedData = Encrypt(plainText); string decryptedText = Decrypt(encryptedData); Console.WriteLine("Original text: {0}", plainText); Console.WriteLine("Encrypted data: {0}", Convert.ToBase64String(encryptedData)); Console.WriteLine("Decrypted text: {0}", decryptedText); } static byte[] Encrypt(string plainText) { byte[] aesKey = GenerateAesKey(); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] encryptedAesKey = rsa.Encrypt(aesKey, true); // 使用 RSA 加密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.GenerateIV(); using (var memoryStream = new MemoryStream()) { memoryStream.Write(aes.IV, 0, aes.IV.Length); using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) { byte[] plainData = Encoding.UTF8.GetBytes(plainText); cryptoStream.Write(plainData, 0, plainData.Length); cryptoStream.FlushFinalBlock(); } byte[] encryptedData = memoryStream.ToArray(); byte[] result = new byte[encryptedAesKey.Length + encryptedData.Length]; Buffer.BlockCopy(encryptedAesKey, 0, result, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, 0, result, encryptedAesKey.Length, encryptedData.Length); return result; } } } } static string Decrypt(byte[] encryptedData) { byte[] encryptedAesKey = new byte[128]; // RSA 加密 AES 密钥得到的密文长度为 128 字节 byte[] encryptedDataOnly = new byte[encryptedData.Length - encryptedAesKey.Length]; Buffer.BlockCopy(encryptedData, 0, encryptedAesKey, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, encryptedAesKey.Length, encryptedDataOnly, 0, encryptedDataOnly.Length); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] aesKey = rsa.Decrypt(encryptedAesKey, true); // 使用 RSA 解密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.IV = encryptedDataOnly.Take(aes.IV.Length).ToArray(); using (var memoryStream = new MemoryStream()) { using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write)) { cryptoStream.Write(encryptedDataOnly, aes.IV.Length, encryptedDataOnly.Length - aes.IV.Length); cryptoStream.FlushFinalBlock(); } byte[] decryptedData = memoryStream.ToArray(); return Encoding.UTF8.GetString(decryptedData); } } } } static byte[] GenerateAesKey() { using (var aes = new AesCryptoServiceProvider()) { aes.GenerateKey(); return aes.Key; } } } ``` 上面的代码中,首先调用 `GenerateAesKey` 方法生成 AES 密钥,然后使用 RSA 算法加密 AES 密钥。加密时,先将 AES 密钥使用 RSA 加密,然后使用 AES 算法加密数据。具体来说,将 AES 密钥和 IV 都写入 `MemoryStream` 对象中,然后使用 `CryptoStream` 对象将数据写入 `MemoryStream` 对象中。最后将密文和 RSA 加密AES 密钥一起返回。 解密时,先从密文中取出 RSA 加密AES 密钥,然后使用 RSA 算法解密 AES 密钥。解密时,先从密文中取出 AES 的 IV 值,然后使用 `CryptoStream` 对象将数据解密。最后将解密后的文本返回。 注意,上面的示例仅用于演示 RSA + AES 加密的基本原理,实际使用中还需要考虑安全性等因素。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值