概述
VMOSCloud 服务端 OpenAPI 为开发者提供了一套 RESTful API,用于管理和操作云手机服务资源。通过这些 API,您可以实现云手机实例的创建、管理、监控等功能,从而更好地集成和扩展您的应用。
获取账号 (AK/SK)
前置准备
在开始使用 API 前,需要获取 Access Key ID 和 Secret Access Key,用于 API 请求鉴权。
操作步骤:
- 登录 VMOSCloud 平台
- 导航至菜单: 开发者 -> API
- 复制对应的密钥信息:
AccessKeyID(即 AK)SecretAccessKey(即 SK)

公共请求参数
接口每次请求时,Headers 中必须包含以下四个参数进行身份验证。
| 参数名 | 类型 | 必填 | 参数描述 | 示例值 |
|---|---|---|---|---|
x-date | string | 必须 | 发送请求的时间戳 使用UTC时间,精确到秒 | 20240301T093700Z |
x-host | string | 必须 | 接口访问域名 | openapi.armcloud.net |
Content-Type | string | 必须 | 资源的 MIME 类型 | application/json |
authorization | string | 必须 | 发送的请求中包含的签名 | 见下方说明 |
Authorization 格式示例:
HMAC-SHA256 Credential={AccessKey}, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature={Signature}
Authorization签名机制
对于每一次 HTTPS 协议请求,会根据访问中的签名信息验证访问请求者的身份。具体由用户账号对应的 AccessKey ID 和 AccessKey Secret(AK/SK)加密验证实现。
手动签名
注意
签名需要对请求参数进行一系列处理,包括排序、拼接、加密等步骤。这种方法提供了更大的灵活性和可定制性,适用于开发者对签名算法有深入理解的情况。然而,手动签名需要开发者编写额外的代码来实现签名过程,可能会增加开发难度和出错的可能性,因此我们依然建议您使用SDK来调用API,尽量避免自行编写签名代码。若您需要了解签名计算的原理和具体过程,可参考以下文档。
手动签名机制要求请求者对请求参数进行哈希值计算,经过加密后同 API 请求一起发送到服务器中,服务器将以同样的机制对收到的请求进行签名计算,并将其与请求者传来的签名进行比对,若签名未通过验证,请求将被拒绝。
获取账号的 Access Key ID 和 Secret Access Key (AK/SK),用于 API 请求鉴权。请联系技术对接人获取
构建规范请求字符串(CanonicalRequest)
String canonicalStringBuilder=
"host:"+*${host}*+"\n"+
"x-date:"+*${xDate}*+"\n"+
"content-type:"+*${contentType}*+"\n"+
"signedHeaders:"+*${signedHeaders}*+"\n"+
"x-content-sha256:"+*${xContentSha256}*;
| 字段 | 解释 |
|---|---|
| host | 请求服务域名。固定为:api.vmoscloud.com |
| x-date | 指代请求 UTC 时间,即请求头公共参数中 X-Date 的取值,使用遵循 ISO 8601 标准的格式:YYYYMMDD'T'HHMMSS'Z' ,例如:20201103T104027Z |
| content-type | 请求或响应正文的媒体类型(application/json) |
| signedHeaders | 参与签名的Header,和CanonicalHeaders包含的Header是一一对应的,目的是指明哪些Header参与签名计算,从而忽略请求被proxy添加的额外Header,其中host、x-date如果存在Header中则必选参与 伪代码如下: SignedHeaders=Lowercase(HeaderName0)+';'+Lowercase(HeaderName1)+";"+...+Lowercase(HeaderNameN) 示例: SignedHeaders=content-type;host;x-content-sha256;x-date |
| x-content-sha256 | hashSHA256(body)注:body要去空格后再去计算hashSHA256 |
构建待签名字符串(StringToSign)
签名字符串主要包含请求以及规范化请求的元数据信息,由签名算法、请求日期、信任状和规范化请求哈希值连接组成。
构建待签名字符串,伪代码如下:
StringToSign=
Algorithm+'\n'+
xDate+'\n'+
CredentialScope+'\n'+
hashSHA256(canonicalStringBuilder.getByte())
| 字段 | 解释 |
|---|---|
| Algorithm | 指代签名的算法,目前仅支持 HMAC-SHA256 的签名算法。 |
| x-date | 指代请求 UTC 时间,即请求头公共参数中 X-Date 的取值,使用遵循 ISO 8601 标准的格式:YYYYMMDD'T'HHMMSS'Z' ,例如:20201103T104027Z |
| CredentialScope | 指代信任状,格式为: ${YYYYMMDD}/${service}/request,其中${YYYYMMDD}取 X-Date 中的日期,${service} 固定为armcloud-paas,request为固定值。参考下方《计算CredentialScope》 |
| CanonicalRequest | 指构建规范请求字符串的结果。 |
计算CredentialScope
String credentialScope = shortXDate+"/"+service+"/request";
shortXDate:短请求时间(x-date截取前8位示例:20201103)
service:服务名(固定填armcloud-paas)
"/request":固定值
Signingkey示例
HMAC哈希操作序列生成的派生签名密钥
byte[]Signingkey=hmacSHA256(hmacSHA256(hmacSHA256(sk.getBytes(),shortXDate),service),”request”);
| 字段 | 解释 |
|---|---|
| sk | 客户密钥 |
| shortXDate | 短请求日期 |
| Service | 服务名暂时固定填armcloud-paas |
Signature示例
signature=HexEncode(hmacSHA256(Signingkey,StringToSign))
Signature生成工具类示例(java)
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
public class PaasSignUtils {
public static final String service = "armcloud-paas";
public static String signature(String contentType, String signedHeaders, String host, String xDate, String sk, byte[] body) throws Exception {
if (body == null) {
body = new byte[0];
}
String xContentSha256 = hashSHA256(body);
String shortXDate = xDate.substring(0, 8);
String canonicalStringBuilder = "host:" + host + "\n" + "x-date:" + xDate + "\n" + "content-type:" + contentType + "\n" + "signedHeaders:" + signedHeaders + "\n" + "x-content-sha256:" + xContentSha256;
String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
String credentialScope = shortXDate + "/" + service + "/request";
String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;
byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, service);
return bytesToHex(hmacSHA256(signKey, signString));
}
public static String hashSHA256(byte[] content) throws Exception {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
return bytesToHex(md.digest(content));
} catch (Exception e) {
throw new Exception("Unable to compute hash while signing request: " + e.getMessage(), e);
}
}
public static byte[] hmacSHA256(byte[] key, String content) throws Exception {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
return mac.doFinal(content.getBytes());
} catch (Exception e) {
throw new Exception("Unable to calculate a request signature: " + e.getMessage(), e);
}
}
private static byte[] genSigningSecretKeyV4(String secretKey, String date, String service) throws Exception {
byte[] kDate = hmacSHA256((secretKey).getBytes(), date);
byte[] kService = hmacSHA256(kDate, service);
return hmacSHA256(kService, "request");
}
public static String bytesToHex(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return "";
}
final StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
接口调用demo示例(java)
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
@Component
public class ApiRequestUtils {
private static final String API_HOST = "api.vmoscloud.com";
private static final String CONTENT_TYPE = "application/json;charset=UTF-8";
private static final String ACCESS_KEY = "Access Key ID";
private static final String SECRET_ACCESS_KEY = "Secret Access Key";
/**
* 测试调用
*/
public static void main(String[] args) {
//POST请求
JSONObject params = new JSONObject();
params.put("taskIds", new int[]{4224});
String url = "https://api.vmoscloud.com/vcpcloud/api/padApi/padTaskDetail";
String result = sendPostRequest(url, params);
System.out.println(result);
//GET请求
// String url = "https://api.vmoscloud.com/vcpcloud/api/padApi/stsToken";
// String result = sendGetRequest(url, null);
}
public static String sendGetRequest(String url, JSONObject params) {
String xDate = DateToUTC(LocalDateTime.now());
StringBuilder urlWithParams = new StringBuilder(url);
// 构建 URL 参数
if (params != null && !params.isEmpty()) {
urlWithParams.append("?");
params.forEach((key, value) ->
urlWithParams.append(key).append("=").append(value).append("&")
);
// 去掉最后的 "&"
urlWithParams.setLength(urlWithParams.length() - 1);
}
HttpGet httpGet = new HttpGet(urlWithParams.toString());
// 设置公共头部
httpGet.setHeader("content-type", CONTENT_TYPE);
httpGet.setHeader("x-host", API_HOST);
httpGet.setHeader("x-date", xDate);
// 生成 Authorization 头部
String authorizationHeader = getAuthorizationHeader(xDate, params == null ? null : params.toJSONString(), SECRET_ACCESS_KEY);
httpGet.setHeader("authorization", authorizationHeader);
// 执行请求
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity responseEntity = response.getEntity();
return EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("Request failed", e);
}
}
/**
* 公共请求方法
*/
public static String sendPostRequest(String url, JSONObject params) {
String xDate = DateToUTC(LocalDateTime.now());
HttpPost httpPost = new HttpPost(url);
// 设置公共头部
httpPost.setHeader("content-type", CONTENT_TYPE);
httpPost.setHeader("x-host", API_HOST);
httpPost.setHeader("x-date", xDate);
// 生成 Authorization 头部
String authorizationHeader = getAuthorizationHeader(xDate, params.toJSONString(), SECRET_ACCESS_KEY);
httpPost.setHeader("authorization", authorizationHeader);
// 设置请求体
StringEntity entity = new StringEntity(params.toJSONString(), StandardCharsets.UTF_8);
httpPost.setEntity(entity);
// 执行请求
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(httpPost)) {
HttpEntity responseEntity = response.getEntity();
return EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("Request failed", e);
}
}
/**
* 使用UTC时间,精确到秒
*
* @param dateTime LocalDateTime
* @return String
*/
public static String DateToUTC(LocalDateTime dateTime) {
// 定义日期时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMdd'T'HHmmss'Z'");
return dateTime.format(formatter);
}
/**
* 获取签名
*/
private static String getSign(String xDate, String sk, String requestBody) throws Exception {
String body = requestBody == null ? null : JSONObject.parseObject(requestBody, Feature.OrderedField).toJSONString();
return PaasSignUtils.signature(CONTENT_TYPE, "content-type;host;x-content-sha256;x-date", API_HOST, xDate, sk, body == null ? null : body.getBytes(StandardCharsets.UTF_8));
}
/**
* 获取Authorization头
*/
private static String getAuthorizationHeader(String currentTimestamp, String body, String sk) {
try {
String sign = getSign(currentTimestamp, sk, body);
return String.format("HMAC-SHA256 Credential=%s, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature=%s", ACCESS_KEY, sign);
} catch (Exception e) {
throw new RuntimeException("Failed to generate signature", e);
}
}
}
接口调用demo示例(易语言)
.版本 2
.支持库 spec
.支持库 e2ee
.程序集 程序集1
.子程序 _启动子程序, 整数型
调用子程序 (&查询实例属性, , , )
返回 (0)
.子程序 查询实例属性
.局部变量 时间型, 日期时间型
.局部变量 存取, 存取键值表
.局部变量 请求存取, 存取键值表
.局部变量 局_网址, 文本型
.局部变量 协议头, 类_POST数据类
.局部变量 局_结果, 字节集
.局部变量 局_返回, 文本型
.局部变量 局_数据, 文本型
.局部变量 加密数据, 文本型
.局部变量 时间值, 文本型
.局部变量 AcceccKey, 文本型
.局部变量 SecretAccessKey, 文本型
.局部变量 SHA256, 文本型
.局部变量 请求提交数据, 文本型
时间型 = 时间_取北京时间 ()
调试输出 (到文本 (时间型))
时间值 = 到文本 (取年份 (时间型)) + 格式化数字 (取月份 (时间型)) + 格式化数字 (取日 (时间型)) + “T” + 格式化数字 (取小时 (时间型)) + 格式化数字 (取分钟 (时间型)) + 格式化数字 (取秒 (时间型)) + “Z” ' 【注意:此处我添加了 格式化数字,确保时间值是两位数】
AcceccKey = “”
SecretAccessKey = “”
请求存取.置值 (“padCode”, “账号下的设备号”)
请求提交数据 = 请求存取.到JSON (假, , , , )
局_网址 = “https://api.vmoscloud.com/vcpcloud/api/padApi/generateSignature”
存取.置值 (“sk”, SecretAccessKey)
存取.置值 (“xdate”, 时间值)
存取.置值 (“body”, 请求提交数据)
局_数据 = 存取.到JSON (假, , , , )
调试输出 (“提交需加密参数”, 局_数据)
协议头.添加 (“host”, “api.vmoscloud.com”)
协议头.添加 (“Content-Type”, “application/json”)
局_结果 = 网页_访问_对象 (局_网址, 1, 局_数据, , , 协议头.获取协议头数据 (), , , , , , , , , , , , , 假)
局_返回 = 编码_Utf8到Ansi (局_结果)
调试输出 (“返回加密结果”, 局_返回)
存取.从JSON载入 (局_返回, , , )
加密数据 = 存取.取文本 (“//data.signature”)
调试输出 (“加密数据”, 加密数据)
SHA256 = “HMAC-SHA256 Credential=” + AcceccKey + “/armcloud-paas/request, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature=” + 加密数据
调试输出 (“SHA256”, SHA256)
协议头.清空 ()
局_网址 = “https://api.vmoscloud.com/vcpcloud/api/padApi/padProperties”
协议头.添加 (“content-type”, “application/json;charset=UTF-8”)
协议头.添加 (“x-date”, 时间值)
协议头.添加 (“x-host”, “api.vmoscloud.com”)
协议头.添加 (“authorization”, SHA256)
调试输出 (“协议头”, 协议头.获取协议头数据 ())
调试输出 (“提交请求参数”, 请求提交数据)
局_结果 = 网页_访问_对象 (局_网址, 1, 请求提交数据, , , 协议头.获取协议头数据 (), , , , , , , , , , , , , 假)
局_返回 = 编码_Utf8到Ansi (局_结果)
调试输出 (“请求返回”, 局_返回)
.子程序 格式化数字, 文本型
.参数 数字, 整数型
.如果 (数字 < 10)
.否则
.如果结束
返回 (“0” + 到文本 (数字))
返回 (到文本 (数字))
接口调用demo示例(python)
import binascii
import datetime
import hmac
import hashlib
import json
import traceback
import requests
def get_signature(data, x_date, host, content_type, signed_headers, sk):
# 给定的JSON数据
# TODO 将JSON数据转换为字符串 (修改的地方,传入的json需要去除空格)
json_string = json.dumps(data, separators=(',', ':'), ensure_ascii = False)
print(json_string)
# 计算SHA-256哈希值
hash_object = hashlib.sha256(json_string.encode())
x_content_sha256 = hash_object.hexdigest()
# 使用f-string构建canonicalStringBuilder
canonical_string_builder = (
f"host:{host}\n"
f"x-date:{x_date}\n"
f"content-type:{content_type}\n"
f"signedHeaders:{signed_headers}\n"
f"x-content-sha256:{x_content_sha256}"
)
# 假设这些变量已经被赋值
# short_x_date = datetime.datetime.now().strftime("%Y%m%d") # 短请求时间,例如:"20240101"
short_x_date = x_date[:8] # 短请求时间,例如:"20240101"
service = "armcloud-paas" # 服务名
# 构建credentialScope
credential_scope = "{}/{}/request".format(short_x_date, service)
# 假设这些变量已经被赋值
algorithm = "HMAC-SHA256"
# 计算canonicalStringBuilder的SHA-256哈希值
hash_sha256 = hashlib.sha256(canonical_string_builder.encode()).hexdigest()
# 构建StringToSign
string_to_sign = (
algorithm + '\n' +
x_date + '\n' +
credential_scope + '\n' +
hash_sha256
)
# 假设这些变量已经被赋值
service = "armcloud-paas" # 服务名
# 第一次hmacSHA256
first_hmac = hmac.new(sk.encode(), digestmod=hashlib.sha256)
first_hmac.update(short_x_date.encode())
first_hmac_result = first_hmac.digest()
# 第二次hmacSHA256
second_hmac = hmac.new(first_hmac_result, digestmod=hashlib.sha256)
second_hmac.update(service.encode())
second_hmac_result = second_hmac.digest()
# 第三次hmacSHA256
signing_key = hmac.new(second_hmac_result, b'request', digestmod=hashlib.sha256).digest()
# 使用signing_key和string_to_sign计算HMAC-SHA256
signature_bytes = hmac.new(signing_key, string_to_sign.encode(), hashlib.sha256).digest()
# 将HMAC-SHA256的结果转换为十六进制编码的字符串
signature = binascii.hexlify(signature_bytes).decode()
return signature
def paas_url_util(url, data, ak, sk):
x_date = datetime.datetime.now().strftime("%Y%m%dT%H%M%SZ")
content_type = "application/json"
signed_headers = f"content-type;host;x-content-sha256;x-date"
ShortDate = x_date[:8]
host = "openapi-hk.armcloud.net"
# 获取signature
signature = get_signature(data, x_date, host, content_type, signed_headers, sk)
url = f"http://openapi-hk.armcloud.net{url}"
payload = json.dumps(data)
headers = {
'Content-Type': content_type,
'x-date': x_date,
'x-host': host,
'authorization': f"HMAC-SHA256 Credential={ak}/{ShortDate}/armcloud-paas/request, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature={signature}"
}
response = requests.request("POST", url, headers=headers, data=payload)
return response.json()
def vmos_url_util(url, data, AccessKey, sk):
x_date = datetime.datetime.now().strftime("%Y%m%dT%H%M%SZ")
content_type = "application/json;charset=UTF-8"
signed_headers = f"content-type;host;x-content-sha256;x-date"
ShortDate = x_date[:8]
host = "api.vmoscloud.com"
# 获取signature
signature = get_signature(data, x_date, host, content_type, signed_headers, sk)
url = f"https://api.vmoscloud.com{url}"
payload = json.dumps(data, ensure_ascii = False)
headers = {
'content-type': "application/json;charset=UTF-8",
'x-date': x_date,
'x-host': "api.vmoscloud.com",
'authorization': f"HMAC-SHA256 Credential={AccessKey}, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature={signature}"
}
response = requests.request("POST", url, headers=headers, data=payload)
return response.json()
#根据查询条件分页获取实例列表信息/vcpcloud/api/padApi/infos
pad_infos_url='/vcpcloud/api/padApi/padTaskDetail'
pad_infos_body={"taskIds":[4224]}
#vmos接口调用
print(vmos_url_util(pad_infos_url, pad_infos_body, 'Access Key ID','Secret Access Key'))
Signature生成工具类示例(node)
const CryptoJS = require("crypto-js");
const moment = require("moment");
/**
* Class for generating HMAC-SHA256 signatures for API requests to Vmos cloud services.
*/
class VmosAPISigner {
constructor(accessKeyId, secretAccessKey) {
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.contentType = "application/json;charset=UTF-8";
this.host = "api.vmoscloud.com";
this.service = "armcloud-paas";
this.algorithm = "HMAC-SHA256";
}
// Generate authentication headers for API requests
signRequest(requestOptions) {
const { method, path, queryParams = {}, body = null } = requestOptions;
// Process request parameters
let params = "";
if (method === "POST" && body) {
params = typeof body === "string" ? body : JSON.stringify(body);
} else if (method === "GET" && Object.keys(queryParams).length > 0) {
params = new URLSearchParams(queryParams).toString();
}
// Generate timestamp
const xDate = moment().utc().format("YYYYMMDDTHHmmss[Z]");
const shortXDate = xDate.substring(0, 8);
const credentialScope = `${shortXDate}/${this.service}/request`;
// Build canonical request string
const canonicalString = [
`host:${this.host}`,
`x-date:${xDate}`,
`content-type:${this.contentType}`,
`signedHeaders:content-type;host;x-content-sha256;x-date`,
`x-content-sha256:${CryptoJS.SHA256(params).toString()}`,
].join("\n");
// Calculate signature
const stringToSign = [
this.algorithm,
xDate,
credentialScope,
CryptoJS.SHA256(canonicalString).toString(),
].join("\n");
const kDate = CryptoJS.HmacSHA256(shortXDate, this.secretAccessKey);
const kService = CryptoJS.HmacSHA256(this.service, kDate);
const signKey = CryptoJS.HmacSHA256("request", kService);
// Generate final signature
const sign = CryptoJS.HmacSHA256(stringToSign, signKey);
const signature = sign.toString(CryptoJS.enc.Hex);
// Construct authorization header
const authorization = [
`HMAC-SHA256 Credential=${this.accessKeyId}/${credentialScope}`,
`SignedHeaders=content-type;host;x-content-sha256;x-date`,
`Signature=${signature}`,
].join(", ");
// Return signed request headers
return {
"x-date": xDate,
"x-host": this.host,
authorization: authorization,
"content-type": this.contentType,
};
}
}
接口调用demo示例(node)
const CryptoJS = require("crypto-js");
const moment = require("moment");
const axios = require("axios");
axios.interceptors.request.use(
(config) => {
// Convert Content-Type header to lowercase
if (config.headers["Content-Type"]) {
config.headers["content-type"] = config.headers["Content-Type"];
delete config.headers["Content-Type"];
}
return config;
},
(error) => {
// Handle request errors
return Promise.reject(error);
}
);
/**
* Class for generating HMAC-SHA256 signatures for API requests to Vmos cloud services.
*/
class VmosAPISigner {
constructor(accessKeyId, secretAccessKey) {
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.contentType = "application/json;charset=UTF-8";
this.host = "api.vmoscloud.com";
this.service = "armcloud-paas";
this.algorithm = "HMAC-SHA256";
}
// Generate authentication headers for API requests
signRequest(requestOptions) {
const { method, path, queryParams = {}, body = null } = requestOptions;
// Process request parameters
let params = "";
if (method === "POST" && body) {
params = typeof body === "string" ? body : JSON.stringify(body);
} else if (method === "GET" && Object.keys(queryParams).length > 0) {
params = new URLSearchParams(queryParams).toString();
}
// Generate timestamp
const xDate = moment().utc().format("YYYYMMDDTHHmmss[Z]");
const shortXDate = xDate.substring(0, 8);
const credentialScope = `${shortXDate}/${this.service}/request`;
// Build canonical request string
const canonicalString = [
`host:${this.host}`,
`x-date:${xDate}`,
`content-type:${this.contentType}`,
`signedHeaders:content-type;host;x-content-sha256;x-date`,
`x-content-sha256:${CryptoJS.SHA256(params).toString()}`,
].join("\n");
// Calculate signature
const stringToSign = [
this.algorithm,
xDate,
credentialScope,
CryptoJS.SHA256(canonicalString).toString(),
].join("\n");
const kDate = CryptoJS.HmacSHA256(shortXDate, this.secretAccessKey);
const kService = CryptoJS.HmacSHA256(this.service, kDate);
const signKey = CryptoJS.HmacSHA256("request", kService);
// Generate final signature
const sign = CryptoJS.HmacSHA256(stringToSign, signKey);
const signature = sign.toString(CryptoJS.enc.Hex);
// Construct authorization header
const authorization = [
`HMAC-SHA256 Credential=${this.accessKeyId}/${credentialScope}`,
`SignedHeaders=content-type;host;x-content-sha256;x-date`,
`Signature=${signature}`,
].join(", ");
// Return signed request headers
return {
"x-date": xDate,
"x-host": this.host,
authorization: authorization,
"content-type": this.contentType,
};
}
}
// 使用示例
async function makeSignedRequest() {
const signer = new VmosAPISigner(
"", // Access Key ID
"" // Secret Access Key
);
const baseURL = "https://api.vmoscloud.com";
// Example GET request configuration
const getRequest = {
method: "GET",
path: "/vcpcloud/api/padApi/getProxys",
queryParams: { page: 1, rows: 10 },
};
// Example POST request configuration
const postRequest = {
method: "POST",
path: "/vcpcloud/api/padApi/userPadList",
body: { padCode: "AC32010790572" },
};
await axios({
baseURL: baseURL,
method: getRequest.method,
url: getRequest.path,
headers: signer.signRequest(getRequest),
params: getRequest.queryParams,
}).then((response) => {
console.log("getRequest 响应:", response.data);
});
await axios({
baseURL: baseURL,
method: postRequest.method,
url: postRequest.path,
headers: signer.signRequest(postRequest),
data: postRequest.body,
}).then((response) => {
console.log("postRequest 响应:", response.data);
});
}
// Run example requests
makeSignedRequest();
Signature生成工具类示例(go)
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
type VmosAPISigner struct {
AccessKeyId string
SecretAccessKey string
ContentType string
Host string
Service string
Algorithm string
}
func NewVmosAPISigner(accessKeyId, secretAccessKey string) *VmosAPISigner {
return &VmosAPISigner{
AccessKeyId: accessKeyId,
SecretAccessKey: secretAccessKey,
ContentType: "application/json;charset=UTF-8",
Host: "api.vmoscloud.com",
Service: "armcloud-paas",
Algorithm: "HMAC-SHA256",
}
}
func sha256Hex(data string) string {
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:])
}
func hmacSHA256(key []byte, data string) []byte {
h := hmac.New(sha256.New, key)
h.Write([]byte(data))
return h.Sum(nil)
}
func (s *VmosAPISigner) SignRequest(method, path string,
queryParams map[string]string,
body interface{}) map[string]string {
var paramStr string
if method == http.MethodPost && body != nil {
bodyBytes, _ := json.Marshal(body)
paramStr = string(bodyBytes)
} else if method == http.MethodGet && len(queryParams) > 0 {
var queryParts []string
for k, v := range queryParams {
queryParts = append(queryParts, url.QueryEscape(k)+"="+url.QueryEscape(v))
}
sort.Strings(queryParts)
paramStr = strings.Join(queryParts, "&")
}
xDate := time.Now().UTC().Format("20060102T150405Z")
shortDate := xDate[:8]
credentialScope := fmt.Sprintf("%s/%s/request", shortDate, s.Service)
// Canonical string
canonicalString := fmt.Sprintf(
"host:%s\nx-date:%s\ncontent-type:%s\nsignedHeaders:content-type;host;x-content-sha256;x-date\nx-content-sha256:%s",
s.Host,
xDate,
s.ContentType,
sha256Hex(paramStr),
)
// String to sign
stringToSign := fmt.Sprintf(
"%s\n%s\n%s\n%s",
s.Algorithm,
xDate,
credentialScope,
sha256Hex(canonicalString),
)
kDate := hmacSHA256([]byte(s.SecretAccessKey), shortDate)
kService := hmacSHA256(kDate, s.Service)
signKey := hmacSHA256(kService, "request")
signature := hex.EncodeToString(hmacSHA256(signKey, stringToSign))
authorization := fmt.Sprintf(
"HMAC-SHA256 Credential=%s/%s, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature=%s",
s.AccessKeyId,
credentialScope,
signature,
)
return map[string]string{
"x-date": xDate,
"x-host": s.Host,
"authorization": authorization,
"content-type": s.ContentType,
}
}
接口调用demo示例(go)
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
type VmosAPISigner struct {
AccessKeyId string
SecretAccessKey string
ContentType string
Host string
Service string
Algorithm string
}
func NewVmosAPISigner(accessKeyId, secretAccessKey string) *VmosAPISigner {
return &VmosAPISigner{
AccessKeyId: accessKeyId,
SecretAccessKey: secretAccessKey,
ContentType: "application/json;charset=UTF-8",
Host: "api.vmoscloud.com",
Service: "armcloud-paas",
Algorithm: "HMAC-SHA256",
}
}
func sha256Hex(data string) string {
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:])
}
func hmacSHA256(key []byte, data string) []byte {
h := hmac.New(sha256.New, key)
h.Write([]byte(data))
return h.Sum(nil)
}
func (s *VmosAPISigner) SignRequest(method, path string,
queryParams map[string]string,
body interface{}) map[string]string {
var paramStr string
if method == http.MethodPost && body != nil {
bodyBytes, _ := json.Marshal(body)
paramStr = string(bodyBytes)
} else if method == http.MethodGet && len(queryParams) > 0 {
var queryParts []string
for k, v := range queryParams {
queryParts = append(queryParts, url.QueryEscape(k)+"="+url.QueryEscape(v))
}
sort.Strings(queryParts)
paramStr = strings.Join(queryParts, "&")
}
xDate := time.Now().UTC().Format("20060102T150405Z")
shortDate := xDate[:8]
credentialScope := fmt.Sprintf("%s/%s/request", shortDate, s.Service)
// Canonical string
canonicalString := fmt.Sprintf(
"host:%s\nx-date:%s\ncontent-type:%s\nsignedHeaders:content-type;host;x-content-sha256;x-date\nx-content-sha256:%s",
s.Host,
xDate,
s.ContentType,
sha256Hex(paramStr),
)
// String to sign
stringToSign := fmt.Sprintf(
"%s\n%s\n%s\n%s",
s.Algorithm,
xDate,
credentialScope,
sha256Hex(canonicalString),
)
kDate := hmacSHA256([]byte(s.SecretAccessKey), shortDate)
kService := hmacSHA256(kDate, s.Service)
signKey := hmacSHA256(kService, "request")
signature := hex.EncodeToString(hmacSHA256(signKey, stringToSign))
authorization := fmt.Sprintf(
"HMAC-SHA256 Credential=%s/%s, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature=%s",
s.AccessKeyId,
credentialScope,
signature,
)
return map[string]string{
"x-date": xDate,
"x-host": s.Host,
"authorization": authorization,
"content-type": s.ContentType,
}
}
func sendRequest(method, path string, queryParams map[string]string, body interface{}, signer *VmosAPISigner) {
baseURL := "https://api.vmoscloud.com"
// Build URL
fullURL := baseURL + path
if method == http.MethodGet && len(queryParams) > 0 {
values := url.Values{}
for k, v := range queryParams {
values.Add(k, v)
}
fullURL += "?" + values.Encode()
}
// Prepare body
var bodyReader io.Reader
if method == http.MethodPost && body != nil {
bodyBytes, _ := json.Marshal(body)
bodyReader = bytes.NewReader(bodyBytes)
}
// Sign
headers := signer.SignRequest(method, path, queryParams, body)
// Create request
req, err := http.NewRequest(method, fullURL, bodyReader)
if err != nil {
fmt.Println("Failed to create request:", err)
return
}
for k, v := range headers {
req.Header[k] = []string{v}
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Request failed:", err)
return
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
fmt.Printf("[%s] %s\n", method, string(respBody))
}
func main() {
signer := NewVmosAPISigner(
"", // Access Key ID
"", // Secret Access Key
)
// Example GET request
getParams := map[string]string{
"page": "1",
"rows": "10",
}
sendRequest("GET", "/vcpcloud/api/padApi/getProxys", getParams, nil, signer)
// Example POST request
postBody := map[string]string{
"padCode": "AC32010790572",
}
sendRequest("POST", "/vcpcloud/api/padApi/userPadList", nil, postBody, signer)
}
Signature生成工具类示例(php)
<?php
class VmosAPISigner
{
private $accessKeyId;
private $secretAccessKey;
private $contentType = "application/json;charset=UTF-8";
private $host = "api.vmoscloud.com";
private $service = "armcloud-paas";
private $algorithm = "HMAC-SHA256";
// Constructor for VmosAPISigner
public function __construct($accessKeyId, $secretAccessKey)
{
$this->accessKeyId = $accessKeyId;
$this->secretAccessKey = $secretAccessKey;
}
// Generate authentication headers for API requests
public function signRequest($method, $path, $queryParams = [], $body = null)
{
$params = "";
if (strtoupper($method) === "POST" && $body !== null) {
$params = is_string($body) ? $body : json_encode($body, JSON_UNESCAPED_UNICODE);
} elseif (strtoupper($method) === "GET" && !empty($queryParams)) {
$params = http_build_query($queryParams);
}
$xDate = gmdate("Ymd\THis\Z");
$shortXDate = substr($xDate, 0, 8);
$credentialScope = "$shortXDate/{$this->service}/request";
$xContentSha256 = hash("sha256", $params);
$canonicalString = implode("\n", [
"host:{$this->host}",
"x-date:$xDate",
"content-type:{$this->contentType}",
"signedHeaders:content-type;host;x-content-sha256;x-date",
"x-content-sha256:$xContentSha256"
]);
$hashedCanonicalString = hash("sha256", $canonicalString);
$stringToSign = implode("\n", [
$this->algorithm,
$xDate,
$credentialScope,
$hashedCanonicalString
]);
$kDate = hash_hmac("sha256", $shortXDate, $this->secretAccessKey, true);
$kService = hash_hmac("sha256", $this->service, $kDate, true);
$signKey = hash_hmac("sha256", "request", $kService, true);
$signature = hash_hmac("sha256", $stringToSign, $signKey);
$authorization = implode(", ", [
"{$this->algorithm} Credential={$this->accessKeyId}/$credentialScope",
"SignedHeaders=content-type;host;x-content-sha256;x-date",
"Signature=$signature"
]);
return [
"x-date: $xDate",
"x-host: {$this->host}",
"authorization: $authorization",
"content-type: {$this->contentType}"
];
}
}
接口调用demo示例(php)
<?php
class VmosAPISigner
{
private $accessKeyId;
private $secretAccessKey;
private $contentType = "application/json;charset=UTF-8";
private $host = "api.vmoscloud.com";
private $service = "armcloud-paas";
private $algorithm = "HMAC-SHA256";
// Constructor for VmosAPISigner
public function __construct($accessKeyId, $secretAccessKey)
{
$this->accessKeyId = $accessKeyId;
$this->secretAccessKey = $secretAccessKey;
}
// Generate authentication headers for API requests
public function signRequest($method, $path, $queryParams = [], $body = null)
{
$params = "";
if (strtoupper($method) === "POST" && $body !== null) {
$params = is_string($body) ? $body : json_encode($body, JSON_UNESCAPED_UNICODE);
} elseif (strtoupper($method) === "GET" && !empty($queryParams)) {
$params = http_build_query($queryParams);
}
$xDate = gmdate("Ymd\THis\Z");
$shortXDate = substr($xDate, 0, 8);
$credentialScope = "$shortXDate/{$this->service}/request";
$xContentSha256 = hash("sha256", $params);
$canonicalString = implode("\n", [
"host:{$this->host}",
"x-date:$xDate",
"content-type:{$this->contentType}",
"signedHeaders:content-type;host;x-content-sha256;x-date",
"x-content-sha256:$xContentSha256"
]);
$hashedCanonicalString = hash("sha256", $canonicalString);
$stringToSign = implode("\n", [
$this->algorithm,
$xDate,
$credentialScope,
$hashedCanonicalString
]);
$kDate = hash_hmac("sha256", $shortXDate, $this->secretAccessKey, true);
$kService = hash_hmac("sha256", $this->service, $kDate, true);
$signKey = hash_hmac("sha256", "request", $kService, true);
$signature = hash_hmac("sha256", $stringToSign, $signKey);
$authorization = implode(", ", [
"{$this->algorithm} Credential={$this->accessKeyId}/$credentialScope",
"SignedHeaders=content-type;host;x-content-sha256;x-date",
"Signature=$signature"
]);
return [
"x-date: $xDate",
"x-host: {$this->host}",
"authorization: $authorization",
"content-type: {$this->contentType}"
];
}
}
function makeSignedRequest()
{
$signer = new VmosAPISigner(
"", // Access Key ID
"" // Secret Access Key
);
$baseURL = "https://api.vmoscloud.com";
// Example GET request
$getPath = "/vcpcloud/api/padApi/getProxys";
$getParams = ["page" => 1, "rows" => 10];
$getHeaders = $signer->signRequest("GET", $getPath, $getParams);
$getUrl = $baseURL . $getPath . '?' . http_build_query($getParams);
$getCurl = curl_init($getUrl);
curl_setopt($getCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($getCurl, CURLOPT_HTTPHEADER, $getHeaders);
curl_setopt($getCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($getCurl, CURLOPT_SSL_VERIFYHOST, false);
$getResponse = curl_exec($getCurl);
curl_close($getCurl);
echo "GET Response:\n" . $getResponse . "\n";
// Example POST request
$postPath = "/vcpcloud/api/padApi/userPadList";
$postData = ["padCode" => "AC32010790572"];
$postHeaders = $signer->signRequest("POST", $postPath, [], $postData);
$postCurl = curl_init($baseURL . $postPath);
curl_setopt($postCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($postCurl, CURLOPT_POST, true);
curl_setopt($postCurl, CURLOPT_HTTPHEADER, $postHeaders);
curl_setopt($postCurl, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));
curl_setopt($postCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($postCurl, CURLOPT_SSL_VERIFYHOST, false);
$postResponse = curl_exec($postCurl);
if (curl_errno($postCurl)) {
echo "cURL Error: \n" . curl_error($postCurl) . "\n";
} else {
$httpCode = curl_getinfo($postCurl, CURLINFO_HTTP_CODE);
echo "POST Response HTTP Status: $httpCode\n";
echo "POST Response:\n$postResponse\n";
}
curl_close($postCurl);
}
// Execute the signature request
makeSignedRequest();
Signature生成工具类示例(.net)
using System;
using System.Net.Http;
using System.Text;
using System.Security.Cryptography;
using System.Text.Json;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using System.Security.Cryptography;
public class VmosAPISigner
{
private readonly string accessKeyId;
private readonly string secretAccessKey;
private readonly string contentType = "application/json;charset=utf-8";
private readonly string host = "api.vmoscloud.com";
private readonly string service = "armcloud-paas";
private readonly string algorithm = "HMAC-SHA256";
public VmosAPISigner(string accessKeyId, string secretAccessKey)
{
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
}
public Dictionary<string, string> SignRequest(string method, string path, Dictionary<string, string>? queryParams = null, object? body = null)
{
string paramsString = "";
if (method == "POST" && body != null)
{
paramsString = JsonSerializer.Serialize(body);
}
else if (method == "GET" && queryParams != null)
{
var query = new FormUrlEncodedContent(queryParams).ReadAsStringAsync().Result;
paramsString = query;
}
var utcNow = DateTime.UtcNow;
var xDate = utcNow.ToString("yyyyMMdd'T'HHmmss'Z'");
var shortXDate = utcNow.ToString("yyyyMMdd");
var credentialScope = $"{shortXDate}/{service}/request";
// Hash body or params
var payloadHash = SHA256Hex(paramsString);
// Canonical string
var canonicalString = string.Join("\n", new[]
{
$"host:{host}",
$"x-date:{xDate}",
$"content-type:{contentType}",
$"signedHeaders:content-type;host;x-content-sha256;x-date",
$"x-content-sha256:{payloadHash}"
});
// Create string to sign
var stringToSign = string.Join("\n", new[]
{
algorithm,
xDate,
credentialScope,
SHA256Hex(canonicalString)
});
// Derive signing key
var kDate = HmacSHA256(shortXDate, secretAccessKey);
var kService = HmacSHA256(service, kDate);
var signKey = HmacSHA256("request", kService);
var signature = ByteArrayToHex(HmacSHA256(stringToSign, signKey));
var authorization = string.Join(", ", new[]
{
$"{algorithm} Credential={accessKeyId}/{credentialScope}",
"SignedHeaders=content-type;host;x-content-sha256;x-date",
$"Signature={signature}"
});
return new Dictionary<string, string>
{
{ "x-date", xDate },
{ "x-host", host },
{ "authorization", authorization },
{ "content-type", contentType }
};
}
private static string SHA256Hex(string data)
{
using var sha256 = SHA256.Create();
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(data));
return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
}
private static byte[] HmacSHA256(string data, string key)
{
return HmacSHA256(data, Encoding.UTF8.GetBytes(key));
}
private static byte[] HmacSHA256(string data, byte[] key)
{
using var hmac = new HMACSHA256(key);
return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private static string ByteArrayToHex(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
}
}
接口调用demo示例(.net)
Signer.cs
using System;
using System.Net.Http;
using System.Text;
using System.Security.Cryptography;
using System.Text.Json;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using System.Security.Cryptography;
public class VmosAPISigner
{
private readonly string accessKeyId;
private readonly string secretAccessKey;
private readonly string contentType = "application/json;charset=utf-8";
private readonly string host = "api.vmoscloud.com";
private readonly string service = "armcloud-paas";
private readonly string algorithm = "HMAC-SHA256";
public VmosAPISigner(string accessKeyId, string secretAccessKey)
{
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
}
public Dictionary<string, string> SignRequest(string method, string path, Dictionary<string, string>? queryParams = null, object? body = null)
{
string paramsString = "";
if (method == "POST" && body != null)
{
paramsString = JsonSerializer.Serialize(body);
}
else if (method == "GET" && queryParams != null)
{
var query = new FormUrlEncodedContent(queryParams).ReadAsStringAsync().Result;
paramsString = query;
}
var utcNow = DateTime.UtcNow;
var xDate = utcNow.ToString("yyyyMMdd'T'HHmmss'Z'");
var shortXDate = utcNow.ToString("yyyyMMdd");
var credentialScope = $"{shortXDate}/{service}/request";
// Hash body or params
var payloadHash = SHA256Hex(paramsString);
// Canonical string
var canonicalString = string.Join("\n", new[]
{
$"host:{host}",
$"x-date:{xDate}",
$"content-type:{contentType}",
$"signedHeaders:content-type;host;x-content-sha256;x-date",
$"x-content-sha256:{payloadHash}"
});
// Create string to sign
var stringToSign = string.Join("\n", new[]
{
algorithm,
xDate,
credentialScope,
SHA256Hex(canonicalString)
});
// Derive signing key
var kDate = HmacSHA256(shortXDate, secretAccessKey);
var kService = HmacSHA256(service, kDate);
var signKey = HmacSHA256("request", kService);
var signature = ByteArrayToHex(HmacSHA256(stringToSign, signKey));
var authorization = string.Join(", ", new[]
{
$"{algorithm} Credential={accessKeyId}/{credentialScope}",
"SignedHeaders=content-type;host;x-content-sha256;x-date",
$"Signature={signature}"
});
return new Dictionary<string, string>
{
{ "x-date", xDate },
{ "x-host", host },
{ "authorization", authorization },
{ "content-type", contentType }
};
}
private static string SHA256Hex(string data)
{
using var sha256 = SHA256.Create();
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(data));
return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
}
private static byte[] HmacSHA256(string data, string key)
{
return HmacSHA256(data, Encoding.UTF8.GetBytes(key));
}
private static byte[] HmacSHA256(string data, byte[] key)
{
using var hmac = new HMACSHA256(key);
return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private static string ByteArrayToHex(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
}
}
Request.cs
using System.Net.Http;
using System.Threading.Tasks;
using System.Text;
using System.Text.Json;
using System.Net.Http.Headers;
class Program
{
static async Task Main()
{
var signer = new VmosAPISigner(
"", // Access Key ID
"" // Secret Access Key
);
using var client = new HttpClient { BaseAddress = new Uri("https://api.vmoscloud.com") };
// Example GET request
var getPath = "/vcpcloud/api/padApi/getProxys";
var getParams = new Dictionary<string, string>
{
{ "page", "1" },
{ "rows", "10" }
};
var getHeaders = signer.SignRequest("GET", getPath, getParams);
var getQuery = new FormUrlEncodedContent(getParams).ReadAsStringAsync().Result;
var getRequest = new HttpRequestMessage(HttpMethod.Get, $"{getPath}?{getQuery}");
foreach (var h in getHeaders)
{
getRequest.Headers.TryAddWithoutValidation(h.Key, h.Value);
}
var getHttpContent = new StringContent("", Encoding.UTF8, "application/json");
getRequest.Content = getHttpContent;
var getResponse = await client.SendAsync(getRequest);
Console.WriteLine("GET Response: " + await getResponse.Content.ReadAsStringAsync() + "\n");
// Example POST request
var postPath = "/vcpcloud/api/padApi/userPadList";
var postBody = new { padCode = "AC32010790572" };
var postHeaders = signer.SignRequest("POST", postPath, null, postBody);
var postRequest = new HttpRequestMessage(HttpMethod.Post, postPath);
foreach (var h in postHeaders) postRequest.Headers.TryAddWithoutValidation(h.Key, h.Value);
postRequest.Content = new StringContent(JsonSerializer.Serialize(postBody), Encoding.UTF8, "application/json");
var postResponse = await client.SendAsync(postRequest);
Console.WriteLine("POST Response: " + await postResponse.Content.ReadAsStringAsync() + "\n");
}
}
数据加解密示例
Java AES GCM 解密
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
public class AESUtils {
private static final String AES = "AES";
private static final String AES_CIPHER_ALGORITHM = "AES/GCM/NoPadding";
private static final int GCM_TAG_LENGTH = 16;
private static final int GCM_IV_LENGTH = 12;
/**
* Generates a SecretKeySpec from a given string key
*/
private static SecretKeySpec getKeyFromPassword(String password) throws NoSuchAlgorithmException {
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] key = sha.digest(password.getBytes());
return new SecretKeySpec(key, AES);
}
/**
* Generates a new Initialization Vector (IV)
*/
public static byte[] generateIv() {
byte[] iv = new byte[GCM_IV_LENGTH];
new SecureRandom().nextBytes(iv);
return iv;
}
/**
* Encrypts a plain text using AES algorithm and returns both the cipher text and IV
*/
public static String encrypt(String input, String key) {
try {
SecretKeySpec secretKeySpec = getKeyFromPassword(key);
byte[] iv = generateIv();
Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
byte[] cipherText = cipher.doFinal(input.getBytes());
// Encode IV and cipher text to Base64 and concatenate them with a separator
String ivString = Base64.getEncoder().encodeToString(iv);
String cipherTextString = Base64.getEncoder().encodeToString(cipherText);
return ivString + ":" + cipherTextString;
} catch (Exception e) {
log.error("encrypt error >>>input:{} key:{}", input, key, e);
return null;
}
}
/**
* Decrypts an encrypted text using AES algorithm
*/
public static String decrypt(String encryptedData, String key) {
try {
SecretKeySpec secretKeySpec = getKeyFromPassword(key);
// Split the encrypted data into IV and cipher text
String[] parts = encryptedData.split(":");
String ivString = parts[0];
String cipherTextString = parts[1];
byte[] iv = Base64.getDecoder().decode(ivString);
byte[] cipherText = Base64.getDecoder().decode(cipherTextString);
Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
byte[] plainText = cipher.doFinal(cipherText);
return new String(plainText);
} catch (Exception e) {
log.error("decrypt error >>>encryptedData:{} key:{}", encryptedData, key, e);
return null;
}
}
/**
* Encodes the input byte array to a Base64 string
*/
public static String encodeToString(byte[] input) {
return Base64.getEncoder().encodeToString(input);
}
// Encodes the input string to a Base64 string
public static String encodeToString(String input) {
return Base64.getEncoder().encodeToString(input.getBytes());
}
/**
* Decodes the input Base64 string to a byte array
*/
public static byte[] decodeToBytes(String input) {
return Base64.getDecoder().decode(input);
}
/**
* Decodes the input Base64 string to a regular string
*/
public static String decodeToString(String input) {
byte[] decodedBytes = Base64.getDecoder().decode(input);
return new String(decodedBytes);
}
/**
* Encodes the input byte array to a Base64 byte array
*/
public static byte[] encodeToBytes(byte[] input) {
return Base64.getEncoder().encode(input);
}
/**
* Decodes the input Base64 byte array to a byte array
*/
public static byte[] decodeToBytes(byte[] input) {
return Base64.getDecoder().decode(input);
}
public static void main(String[] args) throws Exception {
String key = "AC22030010001"; // 任意字符串作为密钥
// Decrypt the cipher text
String decryptedText = decrypt("iMzQUI7SwzSD0kGJ:4FZ1fn1Jdd5Z4j2ehn/F3VSUVWBwLFQZH/HOCjLAI95r", key);
System.out.println("Decrypted text: " + decryptedText);
}
}