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:
- Crie uma CMK no KMS.
- 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.
- Use a DEK de texto não criptografado para criptografar um arquivo de texto não criptografado, gerando um arquivo de texto cifrado.
- 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:- Leia a DEK de texto cifrado e o arquivo de texto cifrado do dispositivo de armazenamento permanente ou do serviço de armazenamento.
- 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.
- 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 |
---|---|
Criar uma DEK. |
|
Criptografar uma DEK com a chave principal especificada. |
|
Descriptografar uma DEK com a chave principal especificada. |
Criptografia de um arquivo local
- Crie uma CMK no console de gerenciamento. Para obter detalhes, consulte Criação de uma CMK.
- 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.
- 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
- 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.
- 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()); } } }