构建程序
本例提供了为文件加/解密的程序包,使用空白模板创建函数,用户可以使用示例代码学习使用。
创建程序包
本例使用Java8语言实现加/解密的功能,有关函数开发的过程请参考Java函数开发。本例不再介绍业务功能实现的代码,样例代码目录如图1所示。
其中FileEncryptAndDecrypt为函数执行的入口类,FileEncryptAndDecrypt类中入口函数的代码如下:
package com.huawei.kms;
import com.huawei.services.runtime.Context;
import com.huawei.services.runtime.entity.s3obs.S3ObsTriggerEvent;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.kms.v1.KmsClient;
import com.huaweicloud.sdk.kms.v1.model.*;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.ObsObject;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.file.Files;
import java.security.SecureRandom;
public class FileEncryptAndDecrypt {
private String objectKey;
private String inputPath;
private String outputPath;
public String encrypt(S3ObsTriggerEvent event, Context context){
objectKey = event.getObjectKey();
inputPath = "/tmp/" + objectKey;
outputPath = "/tmp/" + objectKey + ".encrypt";
// 初始化obs类
obsClientHandler client = new obsClientHandler();
client.init(context);
client.setObjectInfo(objectKey, inputPath, outputPath);
// 下载obs桶里面的文件
client.downloadFile();
// 初始化kms类
KmsClientHandler kms = new KmsClientHandler();
kms.init(context);
kms.setPath(inputPath, outputPath);
// 加密文件
kms.encryptFile();
// 上传
client.uploadFile();
return "ok";
}
public String decrypt(S3ObsTriggerEvent event, Context context){
objectKey = event.getObjectKey();
inputPath = "/tmp/" + objectKey;
outputPath = "/tmp/" + objectKey + ".decrypt";
// 初始化obs类
obsClientHandler client = new obsClientHandler();
client.init(context);
client.setObjectInfo(objectKey, inputPath, outputPath);
// 下载obs桶里面的文件
client.downloadFile();
// 初始化kms类
KmsClientHandler kms = new KmsClientHandler();
kms.init(context);
kms.setPath(inputPath, outputPath);
// 加密文件
kms.decryptFile();
// 上传
client.uploadFile();
return "ok";
}
static class KmsClientHandler {
// DEW服务接口版本信息,当前固定为v1.0
private static final String KMS_INTERFACE_VERSION = "v1.0";
private static final String AES_KEY_BIT_LENGTH = "256";
private static final String AES_KEY_BYTE_LENGTH = "32";
private static final String AES_ALG = "AES/GCM/PKCS5Padding";
private static final String AES_FLAG = "AES";
private static final int GCM_TAG_LENGTH = 16;
private static final int GCM_IV_LENGTH = 12;
private String ACCESS_KEY;
private String SECRET_ACCESS_KEY;
private String SECURITY_TOKEN;
private String PROJECT_ID;
private String KMS_ENDPOINT;
private String keyId;
private String cipherText;
private String inputPath;
private String outputPath;
private Context context;
private KmsClient kmsClient = null;
void init(Context context) {
this.context = context;
}
void initKmsClient() {
if (kmsClient == null) {
ACCESS_KEY = context.getSecurityAccessKey();
SECRET_ACCESS_KEY = context.SecuritygetSecretKey();
SECURITY_TOKEN = context.getSecurityToken();
PROJECT_ID = context.getProjectID();
KMS_ENDPOINT = context.getUserData("kms_endpoint");
keyId = context.getUserData("kms_key_id");
cipherText = context.getUserData("cipher_text");
final BasicCredentials auth = new BasicCredentials().withAk(ACCESS_KEY).withSk(SECRET_ACCESS_KEY).withSecurityToken(SECURITY_TOKEN).withProjectId(PROJECT_ID);
kmsClient = kmsClient.newBuilder().withCredential(auth).withEndpoint(KMS_ENDPOINT).build();
}
}
byte[] getEncryptPlainKey() {
final CreateDatakeyRequest createDatakeyRequest = new CreateDatakeyRequest().withVersionId(KMS_INTERFACE_VERSION)
.withBody(new CreateDatakeyRequestBody().withKeyId(keyId).withDatakeyLength(AES_KEY_BIT_LENGTH));
final CreateDatakeyResponse createDatakeyResponse = kmsClient.createDatakey(createDatakeyRequest);
final String cipherText = createDatakeyResponse.getCipherText();
return hexToBytes(createDatakeyResponse.getPlainText());
}
byte[] hexToBytes(String hexString) {
final int stringLength = hexString.length();
assert stringLength > 0;
final byte[] result = new byte[stringLength / 2];
int j = 0;
for (int i = 0; i < stringLength; i += 2) {
result[j++] = (byte) Integer.parseInt(hexString.substring(i, i + 2), 16);
}
return result;
}
public void setPath(String inputPath, String outputPath) {
this.inputPath = inputPath;
this.outputPath = outputPath;
}
public void encryptFile() {
final File outEncryptFile = new File(outputPath);
final File inFile = new File(inputPath);
final byte[] iv = new byte[GCM_IV_LENGTH];
final SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(iv);
doFileFinal(Cipher.ENCRYPT_MODE, inFile, outEncryptFile, getEncryptPlainKey(), iv);
}
byte[] getDecryptPlainKey() {
final CreateDatakeyRequest createDatakeyRequest = new CreateDatakeyRequest().withVersionId(KMS_INTERFACE_VERSION)
.withBody(new CreateDatakeyRequestBody().withKeyId(keyId).withDatakeyLength(AES_KEY_BIT_LENGTH));
// 创建数据密钥
final CreateDatakeyResponse createDatakeyResponse = kmsClient.createDatakey(createDatakeyRequest);
final DecryptDatakeyRequest decryptDatakeyRequest = new DecryptDatakeyRequest().withVersionId(KMS_INTERFACE_VERSION)
.withBody(new DecryptDatakeyRequestBody().withKeyId(keyId).withCipherText(createDatakeyResponse.getCipherText()
).withDatakeyCipherLength(AES_KEY_BYTE_LENGTH));
return hexToBytes(kmsClient.decryptDatakey(decryptDatakeyRequest).getDataKey());
}
public void decryptFile() {
final File outEncryptFile = new File(outputPath);
final File inFile = new File(inputPath);
final byte[] iv = new byte[GCM_IV_LENGTH];
final SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(iv);
doFileFinal(Cipher.DECRYPT_MODE, inFile, outEncryptFile, getDecryptPlainKey(), iv);
}
/** // * 对文件进行加解密 // * // * @param cipherMode 加密模式,可选值为Cipher.ENCRYPT_MODE或者Cipher.DECRYPT_MODE // * @param infile 加解密前的文件 // * @param outFile 加解密后的文件 // * @param keyPlain 明文密钥 // * @param iv 初始化向量 // */ void doFileFinal(int cipherMode, File infile, File outFile, byte[] keyPlain, byte[] iv) {
try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(infile.toPath()));
BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(outFile.toPath()))) {
final byte[] bytIn = new byte[(int) infile.length()];
final int fileLength = bis.read(bytIn);
assert fileLength > 0;
final SecretKeySpec secretKeySpec = new SecretKeySpec(keyPlain, AES_FLAG);
final Cipher cipher = Cipher.getInstance(AES_ALG);
final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(cipherMode, secretKeySpec, gcmParameterSpec);
final byte[] bytOut = cipher.doFinal(bytIn);
bos.write(bytOut);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
static class obsClientHandler {
private ObsClient obsClient = null;
private String inputBucketName;
private String outputBucketName;
private String objectKey;
private Context context;
private String localInPath;
private String localOutPath;
public void init(Context context) {
this.context = context;
}
void initObsclient() {
if (obsClient == null) {
inputBucketName = context.getUserData("input_bucket");
outputBucketName = context.getUserData("output_bucket");
String SECURITY_ACCESS_KEY = context.getSecurityAccessKey();
String SECURITY_SECRET_KEY = context.getSecuritySecretKey();
String SECURITY_TOKEN = context.getSecurityToken();
String OBS_ENDPOINT = context.getUserData("obs_endpoint");
obsClient = new ObsClient(SECURITY_ACCESS_KEY, SECURITY_SECRET_KEY, SECURITY_TOKEN, OBS_ENDPOINT);
}
}
public void setObjectInfo(String objectKey, String inPath, String outPath) {
this.objectKey = objectKey;
localInPath = inPath;
localOutPath = outPath;
}
public void downloadFile() {
initObsclient();
try {
ObsObject obsObject = obsClient.getObject(inputBucketName, objectKey);
InputStream inputStream = obsObject.getObjectContent();
byte[] b = new byte[1024];
int len;
FileOutputStream fileOutputStream = new FileOutputStream("/tmp/" + objectKey);
while ((len = inputStream.read(b)) != -1) {
fileOutputStream.write(b);
}
inputStream.close();
fileOutputStream.close();
} catch (ObsException ex) {
ex.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void uploadFile() {
try {
// 待上传的本地文件路径,需要指定到具体的文件名
FileInputStream fis = new FileInputStream(new File("/tmp/" + objectKey + ".encrypt"));
obsClient.putObject(outputBucketName, objectKey, fis);
fis.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
创建函数
创建函数的时候,必须选择委托包含OBS和DEW访问权限的委托,否则不能使用OBS和DEW服务。
- 登录函数工作流控制台,在左侧导航栏选择“函数 > 函数列表”,进入函数列表界面。
- 单击“创建函数”,进入创建函数流程。
- 选择“创建空白函数”,填写函数配置信息。
输入基础配置信息,完成后单击“创建函数”。
- 函数类型:事件函数。
- 函数名称:输入您自定义的函数名称,此处以“fss_examples_dew”为例。
- 委托名称:选择创建委托中创建的“serverless_trust”。
- 运行时语言:选择“Java8”。
- 进入fss_examples_dew函数详情页,配置如下信息。
- 在“代码”页签,代码选择“上传自JAR文件”,上传样例代码编译后的jar包,上传成功后单击“确定”。
- 在“设置 > 常规设置”页签,设置如下信息,完成后单击“保存”。
- 内存:选择“128”
- 执行超时时间:输入“3”
- 函数执行入口:默认“com.huawei.kms.FileEncryptAndDecrypt.encrypt”
- 所属应用:默认“default”
- 描述:输入“文件加解密”
- 在“设置 > 环境变量”页签,输入环境信息,完成后单击“保存”。
dew_key_id:用户主密钥ID。
input_bucket: 输入文件对应的obs桶。
output_bucket: 加解密后上传的obs桶。
obs_endpoint: obs服务对应的endpoint。
