Este conteúdo foi traduzido por máquina para sua conveniência e a Huawei Cloud não pode garantir que o conteúdo foi traduzido com precisão. Para exibir o conteúdo original, use o link no canto superior direito para mudar para a página em inglês.
Atualizado em 2024-09-14 GMT+08:00

Criptografia ou descriptografia de uma grande quantidade de dados

Cenário

Se você quiser criptografar ou descriptografar grandes volumes de dados, como imagens, vídeos e arquivos de banco de dados, poderá usar a criptografia de envelope, que permite criptografar e descriptografar arquivos sem precisar transferir uma grande quantidade de dados pela rede.

Processos de criptografia e descriptografia

  • Criptografia de dados de grande porte
    Figura 1 Criptografar um arquivo local

    O processo é o seguinte:

    1. Crie uma CMK no KMS.
    2. Chame a API create-datakey do KMS para criar uma DEK. Uma DEK de texto não criptografado e uma DEK de texto cifrado serão geradas. A DEK de texto cifrado é gerada quando você usa uma CMK para criptografar a DEK de texto não criptografado.
    3. Use a DEK de texto não criptografado para criptografar um arquivo de texto não criptografado, gerando um arquivo de texto cifrado.
    4. Armazene a DEK de texto cifrado e o arquivo de texto cifrado juntos em um dispositivo de armazenamento permanente ou um serviço de armazenamento.
  • Descriptografia de dados de grande porte
    Figura 2 Descriptografar um arquivo local

    O processo é o seguinte:
    1. Leia a DEK de texto cifrado e o arquivo de texto cifrado do dispositivo de armazenamento permanente ou do serviço de armazenamento.
    2. Chame a API decrypt-datakey do KMS e use a CMK correspondente (aquela usada para criptografar a DEK) para descriptografar a DEK de texto cifrado. Então você obtém a DEK de texto não criptografado.

      Se a CMK for excluída, a descriptografia falhará. Mantenha corretamente suas CMKs.

    3. Use a DEK de texto não criptografado para descriptografar o arquivo de texto cifrado.

APIs relacionadas à criptografia de envelope

Você pode usar as seguintes APIs para criptografar e descriptografar dados.

API

Descrição

Criação de uma DEK

Criar uma DEK.

Criptografia de uma DEK

Criptografar uma DEK com a chave principal especificada.

Descriptografia de uma DEK

Descriptografar uma DEK com a chave principal especificada.

Criptografia de um arquivo local

  1. Crie uma CMK no console de gerenciamento. Para obter detalhes, consulte Criação de uma CMK.
  2. Prepare informações básicas de autenticação.
    • ACCESS_KEY: chave de acesso do ID da Huawei
    • SECRET_ACCESS_KEY: chave de acesso secreta da Huawei ID
    • PROJECT_ID: ID do projeto de um site da HUAWEI CLOUD. Para obter detalhes, consulte Projeto.
    • KMS_ENDPOINT: ponto de extremidade para acessar o KMS. Para obter detalhes, consulte Pontos de extremidade.
    • Haverá riscos de segurança se a AK/SK usada para autenticação for gravada diretamente no código. Criptografe a AK/SK no arquivo de configuração ou nas variáveis de ambiente para armazenamento.
    • Neste exemplo, a AK/SK armazenada nas variáveis de ambiente é usada para autenticação de identidade. Configure as variáveis de ambiente HUAWEICLOUD_SDK_AK e HUAWEICLOUD_SDK_SK primeiro no ambiente local.
  3. Criptografe um arquivo local.

    O código de exemplo é o seguinte.

    • CMK é o ID da chave criada no console de gerenciamento da HUAWEI CLOUD.
    • O arquivo de dados de texto não criptografado é FirstPlainFile.jpg.
    • O arquivo de dados gerado após a criptografia é SecondEncryptFile.jpg.
      import com.huaweicloud.sdk.core.auth.BasicCredentials;
      import com.huaweicloud.sdk.kms.v1.KmsClient;
      import com.huaweicloud.sdk.kms.v1.model.CreateDatakeyRequest;
      import com.huaweicloud.sdk.kms.v1.model.CreateDatakeyRequestBody;
      import com.huaweicloud.sdk.kms.v1.model.CreateDatakeyResponse;
      import com.huaweicloud.sdk.kms.v1.model.DecryptDatakeyRequest;
      import com.huaweicloud.sdk.kms.v1.model.DecryptDatakeyRequestBody;
      
      import javax.crypto.Cipher;
      import javax.crypto.spec.GCMParameterSpec;
      import javax.crypto.spec.SecretKeySpec;
      import java.io.BufferedInputStream;
      import java.io.BufferedOutputStream;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.nio.file.Files;
      import java.security.SecureRandom;
      
      /**
      * Use a DEK to encrypt and decrypt files.
      * To enable the assert syntax, add -ea to enable VM_OPTIONS.
       */
      public class FileStreamEncryptionExample {
      
          private static final String ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_AK");
          private static final String SECRET_ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_SK");
          private static final String PROJECT_ID = "<ProjectID>";
          private static final String KMS_ENDPOINT = "<KmsEndpoint>";
      
      //Version of the KMS interface. Currently, the value is fixed to v1.0.
          private static final String KMS_INTERFACE_VERSION = "v1.0";
      
          /**
           * AES algorithm flags:
           * - AES_KEY_BIT_LENGTH: bit length of the AES256 key
            * - AES_KEY_BYTE_LENGTH: byte length of the AES256 key
           * - AES_ALG: AES256 algorithm. In this example, the Group mode is GCM and the padding mode is PKCS5Padding.
           * - AES_FLAG: AES algorithm flag
           * - GCM_TAG_LENGTH: GCM tag length
           * - GCM_IV_LENGTH: length of the GCM initial vector
           */
          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;
      
          public static void main(final String[] args) {
              // ID of the CMK you created on the HUAWEI CLOUD management console
              final String keyId = args[0];
      
              encryptFile(keyId);
          }
      
          /**
           * Using a DEK to encrypt and decrypt a file
           *
           * @param keyId: user CMK ID
           */
          static void encryptFile(String keyId) {
              // 1. Prepare the authentication information for accessing HUAWEI CLOUD.
              final BasicCredentials auth = new BasicCredentials().withAk(ACCESS_KEY).withSk(SECRET_ACCESS_KEY)
                      .withProjectId(PROJECT_ID);
      
              // 2. Initialize the SDK and transfer the authentication information and the address for the KMS to access the client.
              final KmsClient kmsClient = KmsClient.newBuilder().withCredential(auth).withEndpoint(KMS_ENDPOINT).build();
      
              // 3. Assemble the request message for creating a DEK.
              final CreateDatakeyRequest createDatakeyRequest = new CreateDatakeyRequest().withVersionId(KMS_INTERFACE_VERSION)
                      .withBody(new CreateDatakeyRequestBody().withKeyId(keyId).withDatakeyLength(AES_KEY_BIT_LENGTH));
      
              // 4. Create a DEK.
              final CreateDatakeyResponse createDatakeyResponse = kmsClient.createDatakey(createDatakeyRequest);
      
              // 5. Receive the created DEK information.
              // It is recommended that the ciphertext key and key ID be stored locally so that the plaintext key can be easily obtained for data decryption.
              // The plaintext key should be used immediately after being created. Before using it, convert the hexadecimal plaintext key to a byte array.
              final String cipherText = createDatakeyResponse.getCipherText();
              final byte[] plainKey = hexToBytes(createDatakeyResponse.getPlainText());
      
              // 6. Prepare the file to be encrypted.
              // inFile: file to be encrypted
              // outEncryptFile: file generated after encryption
              
              final File inFile = new File("FirstPlainFile.jpg");
              final File outEncryptFile = new File("SecondEncryptFile.jpg");
      
              // 7. If the AES algorithm is used for encryption, you can create an initial vector.
              final byte[] iv = new byte[GCM_IV_LENGTH];
              final SecureRandom secureRandom = new SecureRandom();
              secureRandom.nextBytes(iv);
      
              // 8. Encrypt the file and store the encrypted file.
              doFileFinal(Cipher.ENCRYPT_MODE, inFile, outEncryptFile, plainKey, iv);
      
          }
      
          /**
           * Encrypting and decrypting a file
           *
           * @param cipherMode: Encryption mode. It can be Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE.
           * @param infile: file to be encrypted or decrypted
           * @param outFile: file generated after encryption and decryption
           * @param keyPlain: plaintext key
           * @param iv: initial vector
           */
          static void doFileFinal(int cipherMode, File infile, File outFile, byte[] keyPlain, byte[] iv) {
      
              try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(infile));
                   BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile))) {
                  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());
              }
          }
      
      }

Descriptografia de um arquivo local

  1. Prepare informações básicas de autenticação.
    • ACCESS_KEY: chave de acesso do ID da Huawei
    • SECRET_ACCESS_KEY: chave de acesso secreta da Huawei ID
    • PROJECT_ID: ID do projeto de um site da HUAWEI CLOUD. Para obter detalhes, consulte Projeto.
    • KMS_ENDPOINT: ponto de extremidade para acessar o KMS. Para obter detalhes, consulte Pontos de extremidade.
    • Haverá riscos de segurança se a AK/SK usada para autenticação for gravada diretamente no código. Criptografe a AK/SK no arquivo de configuração ou nas variáveis de ambiente para armazenamento.
    • Neste exemplo, a AK/SK armazenada nas variáveis de ambiente é usada para autenticação de identidade. Configure as variáveis de ambiente HUAWEICLOUD_SDK_AK e HUAWEICLOUD_SDK_SK primeiro no ambiente local.
  2. Descriptografe um arquivo local.

    O código de exemplo é o seguinte.

    • CMK é o ID da chave criada no console de gerenciamento da HUAWEI CLOUD.
    • O arquivo de dados gerado após a criptografia é SecondEncryptFile.jpg.
    • O arquivo de dados gerado após a criptografia e descriptografia é ThirdDecryptFile.jpg.
      import com.huaweicloud.sdk.core.auth.BasicCredentials;
      import com.huaweicloud.sdk.kms.v1.KmsClient;
      import com.huaweicloud.sdk.kms.v1.model.CreateDatakeyRequest;
      import com.huaweicloud.sdk.kms.v1.model.CreateDatakeyRequestBody;
      import com.huaweicloud.sdk.kms.v1.model.CreateDatakeyResponse;
      import com.huaweicloud.sdk.kms.v1.model.DecryptDatakeyRequest;
      import com.huaweicloud.sdk.kms.v1.model.DecryptDatakeyRequestBody;
      
      import javax.crypto.Cipher;
      import javax.crypto.spec.GCMParameterSpec;
      import javax.crypto.spec.SecretKeySpec;
      import java.io.BufferedInputStream;
      import java.io.BufferedOutputStream;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.nio.file.Files;
      import java.security.SecureRandom;
      
      /**
      * Use a DEK to encrypt and decrypt files.
      * To enable the assert syntax, add -ea to enable VM_OPTIONS.
       */
      public class FileStreamEncryptionExample {
      
          private static final String ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_AK");
          private static final String SECRET_ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_SK");
          private static final String PROJECT_ID = "<ProjectID>";
          private static final String KMS_ENDPOINT = "<KmsEndpoint>";
      
      
      //Version of the KMS interface. Currently, the value is fixed to v1.0.
          private static final String KMS_INTERFACE_VERSION = "v1.0";
      
          /**
           * AES algorithm flags:
           * - AES_KEY_BIT_LENGTH: bit length of the AES256 key
            * - AES_KEY_BYTE_LENGTH: byte length of the AES256 key
           * - AES_ALG: AES256 algorithm. In this example, the Group mode is GCM and the padding mode is PKCS5Padding.
           * - AES_FLAG: AES algorithm flag
           * - GCM_TAG_LENGTH: GCM tag length
           * - GCM_IV_LENGTH: length of the GCM initial vector
           */
          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;
      
          public static void main(final String[] args) {
              // ID of the CMK you created on the HUAWEI CLOUD management console
              final String keyId = args[0];
              // // Returned ciphertext DEK after DEK creation
              final String cipherText = args[1];
      
              decryptFile(keyId, cipherText);
          }
      
          /**
           * Using a DEK to encrypt and decrypt a file
           *
           * @param keyId: user CMK ID
           * @param cipherText: ciphertext data key
           */
          static void decryptFile(String keyId, String cipherText) {
              // 1. Prepare the authentication information for accessing HUAWEI CLOUD.
              final BasicCredentials auth = new BasicCredentials().withAk(ACCESS_KEY).withSk(SECRET_ACCESS_KEY)
                      .withProjectId(PROJECT_ID);
      
              // 2. Initialize the SDK and transfer the authentication information and the address for the KMS to access the client.
              final KmsClient kmsClient = KmsClient.newBuilder().withCredential(auth).withEndpoint(KMS_ENDPOINT).build();
      
              // 3. Prepare the file to be encrypted.
              // inFile: file to be encrypted
              // outEncryptFile: file generated after encryption
              // outDecryptFile: file generated after encryption and decryption
              final File inFile = new File("FirstPlainFile.jpg");
              final File outEncryptFile = new File("SecondEncryptFile.jpg");
              final File outDecryptFile = new File("ThirdDecryptFile.jpg");
      
              // 4. Use the same initial vector for AES encryption and decryption.
              final byte[] iv = new byte[GCM_IV_LENGTH];
              
              // 5. Assemble the request message for decrypting the DEK. cipherText is the ciphertext DEK returned after DEK creation.
              final DecryptDatakeyRequest decryptDatakeyRequest = new DecryptDatakeyRequest()
                      .withVersionId(KMS_INTERFACE_VERSION).withBody(new DecryptDatakeyRequestBody()
                              .withKeyId(keyId).withCipherText(cipherText).withDatakeyCipherLength(AES_KEY_BYTE_LENGTH));
      
              // 6. Decrypt the DEK and convert the returned hexadecimal plaintext key into a byte array.
              final byte[] decryptDataKey = hexToBytes(kmsClient.decryptDatakey(decryptDatakeyRequest).getDataKey());
      
              // 7. Decrypt the file and store the decrypted file.
      // iv at the end of the statement is the initial vector created in the encryption example.
              doFileFinal(Cipher.DECRYPT_MODE, outEncryptFile, outDecryptFile, decryptDataKey, iv);
      
              // 8. Compare the original file with the decrypted file.
              assert getFileSha256Sum(inFile).equals(getFileSha256Sum(outDecryptFile));
      
          }
      
          /**
           * Encrypting and decrypting a file
           *
           * @param cipherMode: Encryption mode. It can be Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE.
           * @param infile: file to be encrypted or decrypted
           * @param outFile: file generated after encryption and decryption
           * @param keyPlain: plaintext key
           * @param iv: initial vector
           */
          static void doFileFinal(int cipherMode, File infile, File outFile, byte[] keyPlain, byte[] iv) {
      
              try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(infile));
                   BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile))) {
                  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());
              }
          }
      
          /**
      * Converting a hexadecimal string to a byte array
           *
           * @param hexString: a hexadecimal string
           * @return: byte array
           */
          static 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;
          }
      
          /**
           * Calculate the SHA256 digest of the file.
           *     
           * @param file
           * @return SHA256 digest
           */    
           static String getFileSha256Sum(File file) {
              int length;
              MessageDigest sha256;
              byte[] buffer = new byte[1024];
              try {
                  sha256 = MessageDigest.getInstance("SHA-256");
              } catch (NoSuchAlgorithmException e) {
                  throw new RuntimeException(e.getMessage());
              }
              try (FileInputStream inputStream = new FileInputStream(file)) {
                  while ((length = inputStream.read(buffer)) != -1) {
                      sha256.update(buffer, 0, length);
                  }
                  return new BigInteger(1, sha256.digest()).toString(16);
              } catch (IOException e) {
                  throw new RuntimeException(e.getMessage());
              }
          }
      }