Updated on 2024-05-28 GMT+08:00

Building a Program

This section provides a file encryption/decryption package. You can create a function with the sample code in this package.

Creating a Deployment Package

This example uses a Java 8 function to encrypt/decrypt files. For details about function development, see Developing Functions in Java. Figure 1 shows the sample code directory. The service code is not described.

Figure 1 Sample code directory

FileEncryptAndDecrypt is the function execution entry point. The entry function in FileEncryptAndDecrypt contains the following code:

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";
        // Initialize OBS class.
        obsClientHandler client = new obsClientHandler();
        client.init(context);
        client.setObjectInfo(objectKey, inputPath, outputPath);
        // Download files from the specified OBS bucket.
        client.downloadFile();
        // Initialize KMS class.
        KmsClientHandler kms = new KmsClientHandler();
        kms.init(context);
        kms.setPath(inputPath, outputPath);
        // Encrypt files.
        kms.encryptFile();
        // Upload files.
        client.uploadFile();
        return "ok";
    }
    public String decrypt(S3ObsTriggerEvent event, Context context){
        objectKey = event.getObjectKey();
        inputPath = "/tmp/" + objectKey;
        outputPath = "/tmp/" + objectKey + ".decrypt";
        // Initialize OBS class.
        obsClientHandler client = new obsClientHandler();
        client.init(context);
        client.setObjectInfo(objectKey, inputPath, outputPath);
        // Download files from the specified OBS bucket.
        client.downloadFile();
        // Initialize KMS class.
        KmsClientHandler kms = new KmsClientHandler();
        kms.init(context);
        kms.setPath(inputPath, outputPath);
        // Encrypt files.
        kms.decryptFile();
        // Upload files.
        client.uploadFile();
        return "ok";
    }
    static class KmsClientHandler {
        // DEW API version. Currently fixed to 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));
// Create a data key.
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);
        }
        /**          //     * Encrypt/Decrypt files.          //     *          //     * @param cipherMode Encryption mode. Options: Cipher.ENCRYPT_MODE and Cipher.DECRYPT_MODE.          //     * @param infile     Files before encryption/decryption.          //     * @param outFile    Files after encryption/decryption.          //     * @param keyPlain   Plaintext key          //     * @param iv         Initialize vector.          //     */         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 {
                // Local path of the files to upload. File names must be specified.
                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);
            }
        }
    }
}
 

Creating a Function

When creating a function, specify an agency with OBS and DEW access permissions so that FunctionGraph can invoke these two services.

  1. Log in to the FunctionGraph console, and choose Functions > Function List in the navigation pane.
  2. Click Create Function.
  3. Click Create from scratch and configure the function information.

    After setting the basic information, click Create.

    • For Function Type, select Event Function.
    • For Function Name, enter fss_examples_dew.
    • For Agency, select serverless_trust.
    • For Runtime, select Java 8.

  4. On the details page of function fss_examples_dew, configure the following information:

    1. On the Code tab, choose Upload > Local JAR, upload the compiled sample code JAR package, and click OK.
    2. Choose Configuration > Basic Settings, set the following parameters, and click Save.
      • For Memory, select 128.
      • For Execution Timeout, enter 3.
      • For Handler, enter com.huawei.kms.FileEncryptAndDecrypt.encrypt.
      • For App, retain the default value default.
      • Description: Enter File encryption and decryption.
    3. Choose Configuration > Environment Variables, set environment variables, and click Save.

      dew_endpoint: DEW endpoint

      dew_key_id: Master key ID

      input_bucket: OBS bucket for storing uploaded files

      output_bucket: OBS bucket for storing encrypted/decrypted files

      obs_endpoint: OBS endpoint

      Table 1 Environment variables

      Environment Variable

      Description

      dew_endpoint

      DEW endpoint. To obtain the DEW endpoint, see Regions and Endpoints.

      dew_key_id

      User master key ID.

      input_bucket

      OBS bucket for storing input files.

      output_bucket

      OBS bucket for storing encrypted and uploaded files.

      obs_endpoint

      OBS endpoint. To obtain the OBS endpoint, see Regions and Endpoints.