JMeter中BeanShell编写RSA/AES加解密代码报错问题
报错原因
- 直接触发语法错误的是代码中的双引号全部被转义为HTML实体
",BeanShell解释器无法识别该转义字符,解析到对应位置时会出现大括号匹配失败,最终抛出Encountered "}"的解析错误。 - BeanShell是轻量级脚本解释器,不支持在脚本内声明
package,也不需要将业务逻辑包裹在自定义的public class结构中,外层类的多余大括号会直接被判定为非法语法,加剧解析错误。 - 现有代码存在隐性兼容问题:JDK自带的JCE组件默认不支持
AES/CBC/PKCS7Padding加密模式,即使语法修正后,运行时也会抛出无对应加密算法的错误;另外现有generateIv方法生成的是全0固定IV,不符合CBC模式的安全规范,大概率和服务端加解密逻辑不匹配。 - 现有代码未实现需求中要求的「RSA公钥加密随机串R1」的逻辑,无法直接完成完整加解密流程。
修正方案
- 移除原有代码中的
package声明、外层Crypto类的包裹结构,将所有"替换为正常英文双引号。 - 引入BouncyCastle加密组件解决PKCS7Padding的支持问题,补充RSA加密R1的逻辑,修正IV生成逻辑为随机生成,最终可直接在BeanShell前置处理器/取样器中运行的代码如下:
import java.security.SecureRandom; import java.util.Base64; import java.util.UUID; import java.security.KeyFactory; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.PublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; // 注册BouncyCastle加密提供者 if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { Security.addProvider(new BouncyCastleProvider()); } // 生成16位随机IV static IvParameterSpec generateIv() { byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); return new IvParameterSpec(iv); } // AES-CBC-PKCS7加密 static String aesEncrypt(String input, String secretKey, IvParameterSpec iv) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES"), iv); byte[] cipherText = cipher.doFinal(input.getBytes("UTF-8")); return Base64.getEncoder().encodeToString(cipherText); } // RSA公钥加密 static String rsaEncrypt(String plainText, String publicKeyStr) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes("UTF-8"))); } // 生成32位随机密钥R1 String R1 = UUID.randomUUID().toString().replace("-", ""); IvParameterSpec iv = generateIv(); // 替换为自身业务的RSA公钥,需去掉头尾的BEGIN/END PUBLIC KEY标识,仅保留中间Base64字符串 String rsaPublicKey = "替换为实际RSA公钥"; // RSA加密R1 String encryptedKey = rsaEncrypt(R1, rsaPublicKey); // 替换为实际待加密的请求体,可通过vars.get("变量名")引用JMeter中已存储的请求数据 String requestBody = "待加密请求体内容"; // AES加密请求体 String encryptedBody = aesEncrypt(requestBody, R1, iv); // 将加密结果存入JMeter变量,后续请求可直接通过${变量名}引用 vars.put("encryptedKey", encryptedKey); vars.put("iv", Base64.getEncoder().encodeToString(iv.getIV())); vars.put("encryptedBody", encryptedBody);
注意事项
- 需提前将对应版本的BouncyCastle jar包(命名格式为
bcprov-jdk15on-xxx.jar)放入JMeter安装目录的lib文件夹下,放入后重启JMeter才可正常加载。 - 代码中RSA加密的填充模式为
PKCS1Padding,如果你的服务端使用其他填充模式,需对应修改Cipher.getInstance中的算法参数,和服务端逻辑保持一致。 - 若追求更高的压测性能,建议将BeanShell替换为JSR223测试元件+Groovy语言,可避免BeanShell的解释执行性能损耗,语法兼容度也更高。
内容的提问来源于stack exchange,提问作者Bhavya Dutta
相关产品推荐
相关产品推荐

