更新时间:2024-01-18 GMT+08:00

构建程序

本例提供了为文件加/解密的程序包,使用空白模板创建函数,用户可以使用示例代码学习使用。

创建程序包

本例使用Java8语言实现加/解密的功能,有关函数开发的过程请参考Java函数开发。本例不再介绍业务功能实现的代码,样例代码目录如图1所示。

图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服务。

  1. 登录函数工作流控制台,在左侧导航栏选择“函数 > 函数列表”,进入函数列表界面。
  2. 单击“创建函数”,进入创建函数流程。
  3. 填写函数配置信息。

    输入基础配置信息,完成后单击“创建函数”。

    • 函数名称:输入“fss_examples_dew”
    • 委托名称:选择创建委托中创建的“serverless_trust”
    • 运行时语言:选择“Java8”

  4. 进入fss_examples_dew函数详情页,配置如下信息。

    1. 在“代码”页签,代码选择“上传自JAR文件”,上传样例代码编译后的jar包,上传成功后单击“确定”。
    2. 在“代码”页签,单击“部署”,等待部署完成。
    3. 在“设置 > 常规设置”页签,设置如下信息,完成后单击“保存”。
      • 内存:选择“128”
      • 执行超时时间:输入“3”
      • 函数执行入口:默认“com.huawei.kms.FileEncryptAndDecrypt.encrypt”
      • 所属应用:默认“default”
      • 描述:输入“文件加解密”
    4. 在“设置 > 环境变量”页签,输入环境信息,完成后单击“保存”。

      dew_endpoint:dew服务的endpoint地址

      dew_key_id:用户主密钥ID。

      input_bucket: 输入文件对应的obs桶。

      output_bucket: 加解密后上传的obs桶。

      obs_endpoint: obs服务对应的endpoint。

      表1 环境变量

      环境变量

      说明

      dew_endpoint

      DEW服务终端节点,获取地址请参考地区和终端节点。。

      dew_key_id

      用户主密钥ID。

      input_bucket

      存放输入文件的OBS桶。

      output_bucket

      存放加密后上传文件的OBS桶。

      obs_endpoint

      OBS服务终端节点,获取地址请参考地区和终端节点