调用说明
前置条件
获取账号的 Access Key ID 和 Secret Access Key (AK/SK),用于 API 请求鉴权。请联系技术对接人获取
公共请求参数
接口每次请求时,Headers中必须包含以下四个参数进行身份验证,否则接口无法正常请求。
| 参数名 | 类型 | 示例值 | 参数描述 |
|---|---|---|---|
| x-date | string | 20240301T093700Z | 发送请求的时间戳,使用UTC时间,精确到秒 |
| x-host | string | api.owlproxy.com | 接口访问域名 |
| authorization | string | HMAC-SHA256 Credential={AccessKey}, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature={Signature} | 发送的请求中包含的签名 |
| Content-Type | string | application/json | 资源的MIME类型 |
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.owlproxy.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();
}
}
接口调用示例(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.owlproxy.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 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);
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);
}
}
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));
}
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);
}
}
}
接口调用示例(Python)
import binascii
import datetime
import hmac
import hashlib
import json
import requests
def get_signature(data, x_date, host, content_type, signed_headers, sk):
json_string = json.dumps(data, separators=(',', ':'), ensure_ascii = False)
hash_object = hashlib.sha256(json_string.encode())
x_content_sha256 = hash_object.hexdigest()
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 = x_date[:8]
service = "armcloud-paas"
credential_scope = "{}/{}/request".format(short_x_date, service)
algorithm = "HMAC-SHA256"
hash_sha256 = hashlib.sha256(canonical_string_builder.encode()).hexdigest()
string_to_sign = (
algorithm + '\n' +
x_date + '\n' +
credential_scope + '\n' +
hash_sha256
)
first_hmac = hmac.new(sk.encode(), digestmod=hashlib.sha256)
first_hmac.update(short_x_date.encode())
first_hmac_result = first_hmac.digest()
second_hmac = hmac.new(first_hmac_result, digestmod=hashlib.sha256)
second_hmac.update(service.encode())
second_hmac_result = second_hmac.digest()
signing_key = hmac.new(second_hmac_result, b'request', digestmod=hashlib.sha256).digest()
signature_bytes = hmac.new(signing_key, string_to_sign.encode(), hashlib.sha256).digest()
signature = binascii.hexlify(signature_bytes).decode()
return signature
def owl_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.owlproxy.com"
signature = get_signature(data, x_date, host, content_type, signed_headers, sk)
url = f"https://api.owlproxy.com{url}"
payload = json.dumps(data, ensure_ascii = False)
headers = {
'content-type': "application/json;charset=UTF-8",
'x-date': x_date,
'x-host': "api.owlproxy.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()
接口调用示例(Node.js)
const CryptoJS = require("crypto-js");
const moment = require("moment");
const axios = require("axios");
class OwlAPISigner {
constructor(accessKeyId, secretAccessKey) {
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.contentType = "application/json;charset=UTF-8";
this.host = "api.owlproxy.com";
this.service = "armcloud-paas";
this.algorithm = "HMAC-SHA256";
}
signRequest(requestOptions) {
const { method, path, queryParams = {}, body = null } = requestOptions;
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();
}
const xDate = moment().utc().format("YYYYMMDDTHHmmss[Z]");
const shortXDate = xDate.substring(0, 8);
const credentialScope = `${shortXDate}/${this.service}/request`;
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");
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);
const sign = CryptoJS.HmacSHA256(stringToSign, signKey);
const signature = sign.toString(CryptoJS.enc.Hex);
const authorization = [
`HMAC-SHA256 Credential=${this.accessKeyId}/${credentialScope}`,
`SignedHeaders=content-type;host;x-content-sha256;x-date`,
`Signature=${signature}`,
].join(", ");
return {
"x-date": xDate,
"x-host": this.host,
authorization: authorization,
"content-type": this.contentType,
};
}
}
接口调用示例(Go)
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
type OwlAPISigner struct {
AccessKeyId string
SecretAccessKey string
ContentType string
Host string
Service string
Algorithm string
}
func NewOwlAPISigner(accessKeyId, secretAccessKey string) *OwlAPISigner {
return &OwlAPISigner{
AccessKeyId: accessKeyId,
SecretAccessKey: secretAccessKey,
ContentType: "application/json;charset=UTF-8",
Host: "api.owlproxy.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 *OwlAPISigner) 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)
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),
)
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,
}
}
接口调用示例(PHP)
<?php
class OwlAPISigner
{
private $accessKeyId;
private $secretAccessKey;
private $contentType = "application/json;charset=UTF-8";
private $host = "api.owlproxy.com";
private $service = "armcloud-paas";
private $algorithm = "HMAC-SHA256";
public function __construct($accessKeyId, $secretAccessKey)
{
$this->accessKeyId = $accessKeyId;
$this->secretAccessKey = $secretAccessKey;
}
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}"
];
}
}
接口调用示例(C#/.NET)
using System;
using System.Net.Http;
using System.Text;
using System.Security.Cryptography;
using System.Text.Json;
using System.Collections.Generic;
public class OwlAPISigner
{
private readonly string accessKeyId;
private readonly string secretAccessKey;
private readonly string contentType = "application/json;charset=utf-8";
private readonly string host = "api.owlproxy.com";
private readonly string service = "armcloud-paas";
private readonly string algorithm = "HMAC-SHA256";
public OwlAPISigner(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";
var payloadHash = SHA256Hex(paramsString);
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}"
});
var stringToSign = string.Join("\n", new[]
{
algorithm,
xDate,
credentialScope,
SHA256Hex(canonicalString)
});
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();
}
}
数据加解密示例
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;
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);
}
public static byte[] generateIv() {
byte[] iv = new byte[GCM_IV_LENGTH];
new SecureRandom().nextBytes(iv);
return 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());
String ivString = Base64.getEncoder().encodeToString(iv);
String cipherTextString = Base64.getEncoder().encodeToString(cipherText);
return ivString + ":" + cipherTextString;
} catch (Exception e) {
return null;
}
}
public static String decrypt(String encryptedData, String key) {
try {
SecretKeySpec secretKeySpec = getKeyFromPassword(key);
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) {
return null;
}
}
}