是否存在可生成并签名EC密钥对的API端点?实现设备授权模拟自动化
自动化EC密钥生成与TAN签名方案(适配Postman/JMeter)
1. 自托管本地API(安全首选)
因为涉及密钥生成和签名,本地部署API可避免密钥泄露风险,用Python FastAPI快速搭建:
步骤实现
- 安装依赖:
pip install fastapi uvicorn cryptography - 编写API代码(
main.py):from fastapi import FastAPI from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.backends import default_backend import base64 app = FastAPI() key_store = {} # 生产环境建议替换为密钥管理服务(如AWS KMS、HashiCorp Vault) @app.post("/generate-ec-keypair") def generate_keypair(key_id: str = "default"): # 生成P-256(secp256r1)曲线密钥对,与你之前用的网页工具一致 private_key = ec.generate_private_key(ec.SECP256R1(), default_backend()) public_key = private_key.public_key() # 序列化为PEM格式 private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() ).decode("utf-8") public_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ).decode("utf-8") key_store[key_id] = {"private": private_key, "public": public_pem} return {"public_key": public_pem, "key_id": key_id} @app.post("/sign-tan") def sign_tan(key_id: str = "default", tan: str = ""): if key_id not in key_store: return {"error": "先调用生成密钥接口创建密钥对"} private_key = key_store[key_id]["private"] # SHA-256withECDSA签名,匹配网页工具算法 signature = private_key.sign(tan.encode(), ec.ECDSA(hashes.SHA256())) return {"signature": base64.b64encode(signature).decode("utf-8")} - 启动服务:
uvicorn main:app --host 0.0.0.0 --port 8000 - Postman/JMeter调用:
- 生成密钥对:POST请求
http://localhost:8000/generate-ec-keypair,可选传key_id区分多设备 - 签名TAN:POST请求
http://localhost:8000/sign-tan,携带key_id和tan参数,返回的signature直接用于授权
- 生成密钥对:POST请求
2. Postman内置脚本(无需额外API)
直接用Postman脚本集成jsrsasign库(和你之前的网页工具同源):
- 配置脚本依赖:
进入Postman设置 → 脚本 → 添加CDN链接:https://kjur.github.io/jsrsasign/jsrsasign-all-min.js - 生成密钥对脚本(预请求脚本):
// 生成secp256r1曲线密钥对 const kp = KEYUTIL.generateKeypair("EC", "secp256r1"); const privateKeyPem = KEYUTIL.getPEM(kp.prvKeyObj); const publicKeyPem = KEYUTIL.getPEM(kp.pubKeyObj); // 存入环境变量 pm.environment.set("ec_private_key", privateKeyPem); pm.environment.set("ec_public_key", publicKeyPem); - 签名TAN脚本(预请求脚本):
const tan = pm.environment.get("sms_tan"); const privateKey = KEYUTIL.getKey(pm.environment.get("ec_private_key")); const sig = new KJUR.crypto.Signature({"alg": "SHA256withECDSA"}); sig.init(privateKey); sig.updateString(tan); const hexSignature = sig.sign(); // 转为Base64格式,匹配网页工具输出 const b64Signature = hextob64(hexSignature); pm.environment.set("tan_signature", b64Signature);
3. JMeter JSR223脚本(Groovy)
利用JMeter内置的BouncyCastle库实现:
- 生成密钥对脚本(JSR223 PreProcessor):
import org.bouncycastle.jce.provider.BouncyCastleProvider import java.security.Security Security.addProvider(new BouncyCastleProvider()) // 生成secp256r1密钥对 def keyGen = java.security.KeyPairGenerator.getInstance("EC", "BC") keyGen.initialize(new java.security.spec.ECGenParameterSpec("secp256r1")) def keyPair = keyGen.generateKeyPair() // 存入JMeter变量 vars.put("ec_public_key", new String(java.util.Base64.getEncoder().encode(keyPair.getPublic().getEncoded()))) vars.put("ec_private_key", new String(java.util.Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()))) - 签名TAN脚本(JSR223 PreProcessor):
import org.bouncycastle.jce.provider.BouncyCastleProvider import java.security.Security import org.bouncycastle.crypto.signers.ECDSASigner import org.bouncycastle.crypto.digests.SHA256Digest import java.util.Base64 Security.addProvider(new BouncyCastleProvider()) def tan = vars.get("sms_tan") def privateKeyBytes = Base64.getDecoder().decode(vars.get("ec_private_key")) def privateKey = java.security.KeyFactory.getInstance("EC", "BC").generatePrivate(new java.security.spec.PKCS8EncodedKeySpec(privateKeyBytes)) // SHA-256withECDSA签名 def signer = new ECDSASigner() signer.init(true, privateKey) def digest = new SHA256Digest() def tanBytes = tan.getBytes("UTF-8") digest.update(tanBytes, 0, tanBytes.length) def hash = new byte[digest.getDigestSize()] digest.doFinal(hash, 0) def signatureBytes = signer.generateSignature(hash) // 转为Base64 def b64Signature = Base64.getEncoder().encodeToString(signatureBytes) vars.put("tan_signature", b64Signature)
内容的提问来源于stack exchange,提问作者Karthik Ravindran
相关产品推荐
相关产品推荐

