构建程序
本例提供了为文件加/解密的程序包,使用空白模板创建函数,用户可以使用示例代码学习使用。
创建程序包
本例使用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 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.getAccessKey(); SECRET_ACCESS_KEY = context.getSecretKey(); 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).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 ACCESS_KEY = context.getAccessKey(); String SECRET_ACCESS_KEY = context.getSecretKey(); String OBS_ENDPOINT = context.getUserData("obs_endpoint"); obsClient = new ObsClient(ACCESS_KEY, SECRET_ACCESS_KEY, 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。