需求
python服务发起加密http请求网关,网关验签解密后路由返回加密结果,python服务解密得到明文
请求加密
- 生成随机字符 s,[a-z][A-z][0-9] 16位 ,例如:s=2zQ6EldkFtqfVm1T
- 生成当前时间戳毫秒数(unix 时间戳)t,例如:t=1641784404645
- 生成一个待加密字符串k:s=2zQ6EldkFtqfVm1T&t=1641784404645
- 使用公钥加密生成密文(RSA/ECB/PKCS1Padding)m:m=RSA(公钥,k)
- 将生成的时间戳t, 密文m 放入请求头中 X-TIMESTAMP = t,X-CIPHER = m
- query参数不用加密,requestBody参数AES(AES/ECB/PKCS5Padding)加密
请求体res=Base64.encode(AES.crypt(json,s)),s为第一步随机字符
响应解密
- 使用公钥解密响应体header X-CIPHER,得到加密前字符串k,获取到随机字符s,与时间戳t
- 获取json= AES.decrypt(Base64.decode(res),s)
- 若返回http状态码为200,响应体则加密,其他状态码则不加密为明文
java代码
@Slf4j
public class EncryptUtil {
public static final String RSA = "RSA";
public static final String RSA_ECB_NO_PADDING = "RSA/ECB/PKCS1Padding";
public static final String AES_ECB_PKCS_5_PADDING = "AES/ECB/PKCS5Padding";
public static final String AES = "AES";
private EncryptUtil() {
throw new IllegalStateException("Utility class");
}
public static String rsaPublicEncrypt(String publicKey, String data) {
if (StringUtils.isBlank(data)) {
return "";
}
try {
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] bytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.encodeBase64String(bytes);
} catch (Exception e) {
log.error("rsaPublicEncrypt error", e);
}
return null;
}
public static String rsaPublicDecrypt(String publicKey, String data) {
if (StringUtils.isBlank(data)) {
return "";
}
try {
byte[] dataBytes = Base64.decodeBase64(data);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(dataBytes));
} catch (Exception e) {
log.error("rsaPublicDecrypt error", e);
}
return null;
}
public static String rsaPrivateEncrypt(String privateKey, String data) {
if (StringUtils.isBlank(data)) {
return "";
}
try {
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] bytes = cipher.doFinal(data.getBytes());
return Base64.encodeBase64String(bytes);
} catch (Exception e) {
log.error("rsaPrivateEncrypt error", e);
}
return null;
}
public static String rsaPrivateDecrypt(String privateKey, String data) {
if (StringUtils.isBlank(data)) {
return "";
}
try {
byte[] dataBytes = Base64.decodeBase64(data);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(RSA_ECB_NO_PADDING);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(dataBytes));
} catch (Exception e) {
log.error("rsaPrivateDecrypt error", e);
}
return null;
}
public static String aesEncrypt(String data, String key) {
if (StringUtils.isBlank(data)) {
return "";
}
try {
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(), AES));
return Base64.encodeBase64String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
log.error("aesDecryptData error", e);
}
return "";
}
public static String aesDecrypt(String data, String key) {
if (StringUtils.isBlank(data)) {
return "";
}
try {
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), AES));
return new String(cipher.doFinal(Base64.decodeBase64(data)));
} catch (Exception e) {
log.error("aesDecryptData error", e);
}
return "";
}
public static String getRandomString(int length) {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; ++i) {
int number = random.nextInt(62);
sb.append(str.charAt(number));
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
String text = "123456789?qqq=fff131&qeqe=1eda&qeqee=ce2de2d";
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String privateKeyStr = Base64.encodeBase64String(privateKey.getEncoded());
String publicKeyStr = Base64.encodeBase64String(publicKey.getEncoded());
String salt = getRandomString(16);
log.info("timestamp={}\nprivateKeyStr=\n{}\npublicKey=\n{}\nsalt={}", System.currentTimeMillis(), privateKeyStr, publicKeyStr, salt);
String pass = rsaPublicEncrypt(publicKeyStr, text);
String dePass2 = rsaPrivateDecrypt(privateKeyStr, pass);
Assert.isTrue(text.equals(dePass2));
String pass2 = rsaPrivateEncrypt(privateKeyStr, text);
String dePass = rsaPublicDecrypt(publicKeyStr, pass2);
Assert.isTrue(text.equals(dePass));
text = "{\n" +
" \"id\": \"24561f9d788ddd14457a51be9e761687\",\n" +
" \"spiderGroupId\": \"spider-e12hvrum\"\n" +
"}";
String aesData = aesEncrypt(text, salt);
String aesDecryptData = aesDecrypt(aesData, salt);
Assert.isTrue(JSONUtil.parseObj(text).equals(JSONUtil.parseObj(aesDecryptData)));
String rsaData = rsaPrivateEncrypt(privateKeyStr, text);
String rsaPrivateDecrypt = rsaPublicDecrypt(publicKeyStr, rsaData);
Assert.isTrue(JSONUtil.parseObj(text).equals(JSONUtil.parseObj(rsaPrivateDecrypt)));
String rsaPublicEncrypt = rsaPublicEncrypt(publicKeyStr, text);
String rsaPrivateDecrypt2 = rsaPrivateDecrypt(privateKeyStr, rsaPublicEncrypt);
Assert.isTrue(JSONUtil.parseObj(text).equals(JSONUtil.parseObj(rsaPrivateDecrypt2)));
}
}
Python代码
import base64
import json
import random
import time
from urllib import parse
import requests
from Crypto.Cipher import AES, PKCS1_v1_5
from Crypto.PublicKey import RSA
from rsa import PublicKey, transform, core
def aes_encrypt(key, message):
padding = lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16)
txt = AES.new(key.encode(encoding="utf8"), AES.MODE_ECB).encrypt(padding(message).encode(encoding="utf8"))
return base64.b64encode(txt)
def aes_decrypt(key, message):
unpadding = lambda s: s[:-ord(s[len(s) - 1:])]
base64_decrypted = base64.decodebytes(message.encode(encoding='utf-8'))
string = str(AES.new(key.encode(encoding="utf8"), AES.MODE_ECB).decrypt(base64_decrypted), encoding='utf-8')
return unpadding(string)
def decrypt_by_public_key(publickey, message):
rsa_public_key = PublicKey.load_pkcs1_openssl_der(base64.b64decode(publickey))
text_str = transform.bytes2int(base64.b64decode(message))
final_text = transform.int2bytes(core.decrypt_int(text_str, rsa_public_key.e, rsa_public_key.n))
final_qr_code = final_text[final_text.index(0) + 1:]
return final_qr_code.decode()
def encrypt_by_public_key(publickey, message):
byte = PKCS1_v1_5.new(RSA.importKey(base64.b64decode(publickey))).encrypt(message.encode(encoding="utf8"))
return base64.b64encode(byte).decode(encoding="utf8")
def heart_report():
public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6RGEIxotJEcvM6MPtDd0p9UM3Hg5Js+0ylK4tPachKaE+KlzAMUSUfSo4iSIDBTN52jv80h0CU/+nHio/c2NRn6jXecI1kI0xATW678A7uC7Py4CAH/hvQH2WssuPbQDLttLcAG/7XrykPz1lqs5gCOSIblzM9lY9CpVE/ZVX7i2XWz4Njfw1EmTia6jWJSpeD9yeVxCqukmTf3c+f1m5Wla2/pNHoboirL8W3v/00zxjPw/2GEGpr4DhPhZO6Hxs3RJWwi0JS/iT6F4dd/2TPnxPqo/tqE2u+kwxyxLbShuYZPWZDM2X7UMsmQsulDQuO2kajlkzdX/2SsnnEenqQIDAQAB'
data = {
"spiderGroupId": "String",
"podName": "String",
"threadId": "1",
"taskStatus": "running"
}
stamp = int(round(time.time() * 1000))
password = ''.join(random.sample('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 16))
headers = {
"X-TIMESTAMP": str(stamp),
"X-CIPHER": str(encrypt_by_public_key(public_key, 's={}&t={}'.format(password, stamp))),
"Content-Type": "application/json; charset=UTF-8"
}
response = requests.post(url="http://localhost:8081/spider-platform/spider/health/report",
data=aes_encrypt(password, json.dumps(data)), headers=headers, timeout=(10, 10))
if response.status_code == 200:
key = response.headers.get('X-CIPHER')
text = decrypt_by_public_key(public_key, key)
pass_str = parse.parse_qs(text)['s'][0]
result = aes_decrypt(pass_str, response.text)
print(json.dumps(json.loads(result), indent=4, ensure_ascii=False))
else:
print(response.text)