Exemplo de operações offline - AWS Key Management Service

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Exemplo de operações offline

Após baixar a chave pública do seu par de chaves do KMS assimétricas, você poderá compartilhá-lo com outras pessoas e usá-lo para realizar operações offline.

AWS CloudTrail registros que registram todas as AWS KMS operações, incluindo solicitação, resposta, data, hora e usuário autorizado, não registram o uso da chave pública fora do AWS KMS.

Este tópico fornece exemplos de operações off-line e detalhes que as ferramentas AWS KMS fornecem para facilitar as operações off-line.

Derivar segredos compartilhados offline

Você pode baixar a chave pública do seu par de chaves ECC para uso em operações offline, ou seja, operações fora do AWS KMS.

O seguinte passo a passo do OpenSSL demonstra um método de derivar um segredo compartilhado fora do uso da chave pública de um par AWS KMS de chaves ECC KMS e de uma chave privada criada com o OpenSSL.

  1. Crie um par de chaves ECC no OpenSSL e prepare-o para uso com o. AWS KMS

    // Create an ECC key pair in OpenSSL and save the private key in openssl_ecc_key_priv.pem export OPENSSL_CURVE_NAME="P-256" export KMS_CURVE_NAME="ECC_NIST_P256" export OPENSSL_KEY1_PRIV_PEM="openssl_ecc_key1_priv.pem" openssl ecparam -name ${OPENSSL_CURVE_NAME} -genkey -out ${OPENSSL_KEY1_PRIV_PEM} // Derive the public key from the private key export OPENSSL_KEY1_PUB_PEM="openssl_ecc_key1_pub.pem" openssl ec -in ${OPENSSL_KEY1_PRIV_PEM} -pubout -outform pem \ -out ${OPENSSL_KEY1_PUB_PEM} // View the PEM file containing the public key and extract the public key as a // Base64 encoded string into OPENSSL_KEY1_PUB_BASE64 for use with AWS KMS export OPENSSL_KEY1_PUB_BASE64=`cat ${OPENSSL_KEY1_PUB_PEM} | \ tee /dev/stderr | grep -v "PUBLIC KEY" | tr -d "\n"`
  2. Crie um par de chaves de acordo de chave ECC AWS KMS e prepare-o para uso com o OpenSSL.

    // Create a KMS key on the same curve as the key pair from step 1 // with a key usage of KEY_AGREEMENT // Save its ARN in KMS_KEY1_ARN. export KMS_KEY1_ARN=`aws kms create-key --key-spec ${KMS_CURVE_NAME} \ --key-usage KEY_AGREEMENT | tee /dev/stderr | jq -r .KeyMetadata.Arn` // Download the public key and save the Base64-encoded version in KMS_KEY1_PUB_BASE64 export KMS_KEY1_PUB_BASE64=`aws kms get-public-key --key-id ${KMS_KEY1_ARN} | \ tee /dev/stderr | jq -r .PublicKey` // Create a PEM file for the public KMS key for use with OpenSSL export KMS_KEY1_PUB_PEM="aws_kms_ecdh_key1_pub.pem" echo "-----BEGIN PUBLIC KEY-----" > ${KMS_KEY1_PUB_PEM} echo ${KMS_KEY1_PUB_BASE64} | fold -w 64 >> ${KMS_KEY1_PUB_PEM} echo "-----END PUBLIC KEY-----" >> ${KMS_KEY1_PUB_PEM}
  3. Derive o segredo compartilhado no OpenSSL usando a chave privada no OpenSSL e a chave pública do KMS.

    export OPENSSL_SHARED_SECRET1_BIN="openssl_shared_secret1.bin" openssl pkeyutl -derive -inkey ${OPENSSL_KEY1_PRIV_PEM} \ -peerkey ${KMS_KEY1_PUB_PEM} -out ${OPENSSL_SHARED_SECRET1_BIN}

Verificação off-line com pares de SM2 chaves (somente regiões da China)

Para verificar uma assinatura externa AWS KMS com uma chave SM2 pública, você deve especificar a ID distintiva. Quando você passa uma mensagem bruta, MessageType:RAW, para a API Sign, AWS KMS usa o ID distintivo padrão1234567812345678, definido pela OSCCA em GM/T 0009-2012. Você não pode especificar seu próprio ID de distinção no AWS KMS.

No entanto, se você estiver gerando um resumo da mensagem fora do AWS, poderá especificar seu próprio ID distintivo e, em seguida, passar o resumo da mensagem, MessageType:DIGEST, para AWS KMS assinar. Para isso, altere o valor de DEFAULT_DISTINGUISHING_ID na classe SM2OfflineOperationHelper. O ID distintivo especificado pode ser qualquer string de até 8.192 caracteres. Depois de AWS KMS assinar o resumo da mensagem, você precisa do resumo da mensagem ou da mensagem e do ID distintivo usado para computar o resumo para verificá-lo offline.

Importante

O código de referência SM2OfflineOperationHelper foi projetado para ser compatível com o Bouncy Castle versão 1.68. Para obter ajuda com outras versões, entre em contato com bouncycastle.org.

Classe SM2OfflineOperationHelper

Para ajudá-lo com operações off-line com SM2 chaves, a SM2OfflineOperationHelper classe para Java tem métodos que executam as tarefas para você. Essa classe auxiliar pode ser usada como modelo para outros provedores criptográficos.

No interior AWS KMS, as conversões de texto cifrado bruto e os cálculos de resumo de mensagens do SM2 DSA ocorrem automaticamente. Nem todos os provedores de criptografia SM2 implementam da mesma forma. Algumas bibliotecas, como as versões 1.1.1 e posteriores do OpenSSL, executam essas ações automaticamente. AWS KMS confirmou esse comportamento em testes com o OpenSSL versão 3.0. Use a seguinte classe SM2OfflineOperationHelper com bibliotecas, como a Bouncy Castle, que exigem que você faça essas conversões e cálculos manualmente.

A classe SM2OfflineOperationHelper fornece métodos para as seguintes operações:

  • Cálculo de resumo de mensagem

    Para gerar um resumo de mensagens offline que você possa usar para verificação off-line ou que você possa passar AWS KMS para assinar, use o calculateSM2Digest método. O calculateSM2Digest método gera um resumo da mensagem com o algoritmo de SM3 hashing. A GetPublicKeyAPI retorna sua chave pública em formato binário. Você deve analisar a chave binária em um Java PublicKey. Forneça a chave pública analisada com a mensagem. O método combina automaticamente sua mensagem com o ID distintivo padrão, 1234567812345678, mas você pode definir seu próprio ID distintivo alterando o valor de DEFAULT_DISTINGUISHING_ID.

  • Verificar

    Para verificar uma assinatura offline, use o método offlineSM2DSAVerify. O método offlineSM2DSAVerify usa o resumo de mensagem calculado com base no ID distintivo especificado e a mensagem original fornecida para verificar a assinatura digital. A GetPublicKeyAPI retorna sua chave pública em formato binário. Você deve analisar a chave binária em um Java PublicKey. Forneça a chave pública analisada com a mensagem original e a assinatura que você deseja verificar. Para obter mais detalhes, consulte Verificação off-line com pares de SM2 chaves.

  • Encrypt

    Para criptografar texto sem formatação offline, use o método offlineSM2PKEEncrypt. Esse método garante que o texto cifrado esteja em um formato que AWS KMS possa ser descriptografado. O offlineSM2PKEEncrypt método criptografa o texto sem formatação e, em seguida, converte o texto cifrado bruto produzido pelo SM2 PKE no formato ASN.1. A GetPublicKeyAPI retorna sua chave pública em formato binário. Você deve analisar a chave binária em um Java PublicKey. Forneça a chave pública analisada com o texto simples que você deseja criptografar.

    Se não tiver certeza de que a conversão é necessário, use a seguinte operação OpenSSL para testar o formato do texto cifrado. Se a operação falhar, significa que você precisa converter o texto cifrado no formato ASN.1.

    openssl asn1parse -inform DER -in ciphertext.der

Por padrão, a SM2OfflineOperationHelper classe usa o ID distintivo padrão,1234567812345678, ao gerar resumos de mensagens para operações de SM2 DSA.

package com.amazon.kms.utils; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.io.IOException; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.jce.interfaces.ECPublicKey; import java.util.Arrays; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.params.ParametersWithID; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.signers.SM2Signer; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; public class SM2OfflineOperationHelper { // You can change the DEFAULT_DISTINGUISHING_ID value to set your own distinguishing ID, // the DEFAULT_DISTINGUISHING_ID can be any string up to 8,192 characters long. private static final byte[] DEFAULT_DISTINGUISHING_ID = "1234567812345678".getBytes(StandardCharsets.UTF_8); private static final X9ECParameters SM2_X9EC_PARAMETERS = GMNamedCurves.getByName("sm2p256v1"); // ***calculateSM2Digest*** // Calculate message digest public static byte[] calculateSM2Digest(final PublicKey publicKey, final byte[] message) throws NoSuchProviderException, NoSuchAlgorithmException { final ECPublicKey ecPublicKey = (ECPublicKey) publicKey; // Generate SM3 hash of default distinguishing ID, 1234567812345678 final int entlenA = DEFAULT_DISTINGUISHING_ID.length * 8; final byte [] entla = new byte[] { (byte) (entlenA & 0xFF00), (byte) (entlenA & 0x00FF) }; final byte [] a = SM2_X9EC_PARAMETERS.getCurve().getA().getEncoded(); final byte [] b = SM2_X9EC_PARAMETERS.getCurve().getB().getEncoded(); final byte [] xg = SM2_X9EC_PARAMETERS.getG().getXCoord().getEncoded(); final byte [] yg = SM2_X9EC_PARAMETERS.getG().getYCoord().getEncoded(); final byte[] xa = ecPublicKey.getQ().getXCoord().getEncoded(); final byte[] ya = ecPublicKey.getQ().getYCoord().getEncoded(); final byte[] za = MessageDigest.getInstance("SM3", "BC") .digest(ByteBuffer.allocate(entla.length + DEFAULT_DISTINGUISHING_ID.length + a.length + b.length + xg.length + yg.length + xa.length + ya.length).put(entla).put(DEFAULT_DISTINGUISHING_ID).put(a).put(b).put(xg).put(yg).put(xa).put(ya) .array()); // Combine hashed distinguishing ID with original message to generate final digest return MessageDigest.getInstance("SM3", "BC") .digest(ByteBuffer.allocate(za.length + message.length).put(za).put(message) .array()); } // ***offlineSM2DSAVerify*** // Verify digital signature with SM2 public key public static boolean offlineSM2DSAVerify(final PublicKey publicKey, final byte [] message, final byte [] signature) throws InvalidKeyException { final SM2Signer signer = new SM2Signer(); CipherParameters cipherParameters = ECUtil.generatePublicKeyParameter(publicKey); cipherParameters = new ParametersWithID(cipherParameters, DEFAULT_DISTINGUISHING_ID); signer.init(false, cipherParameters); signer.update(message, 0, message.length); return signer.verifySignature(signature); } // ***offlineSM2PKEEncrypt*** // Encrypt data with SM2 public key public static byte[] offlineSM2PKEEncrypt(final PublicKey publicKey, final byte [] plaintext) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException { final Cipher sm2Cipher = Cipher.getInstance("SM2", "BC"); sm2Cipher.init(Cipher.ENCRYPT_MODE, publicKey); // By default, Bouncy Castle returns raw ciphertext in the c1c2c3 format final byte [] cipherText = sm2Cipher.doFinal(plaintext); // Convert the raw ciphertext to the ASN.1 format before passing it to AWS KMS final ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector(); final int coordinateLength = (SM2_X9EC_PARAMETERS.getCurve().getFieldSize() + 7) / 8 * 2 + 1; final int sm3HashLength = 32; final int xCoordinateInCipherText = 33; final int yCoordinateInCipherText = 65; byte[] coords = new byte[coordinateLength]; byte[] sm3Hash = new byte[sm3HashLength]; byte[] remainingCipherText = new byte[cipherText.length - coordinateLength - sm3HashLength]; // Split components out of the ciphertext System.arraycopy(cipherText, 0, coords, 0, coordinateLength); System.arraycopy(cipherText, cipherText.length - sm3HashLength, sm3Hash, 0, sm3HashLength); System.arraycopy(cipherText, coordinateLength, remainingCipherText, 0,cipherText.length - coordinateLength - sm3HashLength); // Build standard SM2PKE ASN.1 ciphertext vector asn1EncodableVector.add(new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(coords, 1, xCoordinateInCipherText)))); asn1EncodableVector.add(new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(coords, xCoordinateInCipherText, yCoordinateInCipherText)))); asn1EncodableVector.add(new DEROctetString(sm3Hash)); asn1EncodableVector.add(new DEROctetString(remainingCipherText)); return new DERSequence(asn1EncodableVector).getEncoded("DER"); } }