View a markdown version of this page

Esempio di operazioni offline - AWS Key Management Service

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Esempio di operazioni offline

Dopo aver scaricato la chiave pubblica della coppia di chiavi KMS asimmetrica, puoi condividerla con altri e utilizzarla per eseguire operazioni offline.

AWS CloudTrail i registri che registrano tutte le AWS KMS operazioni, incluse la richiesta, la risposta, la data, l'ora e l'utente autorizzato, non registrano l'uso della chiave pubblica all'esterno. AWS KMS

Questo argomento fornisce esempi di operazioni offline e descrive in dettaglio gli strumenti AWS KMS forniti per semplificare le operazioni offline.

Derivazione offline di segreti condivisi

Puoi scaricare la chiave pubblica della tua coppia di chiavi ECC per utilizzarla in operazioni offline, ovvero operazioni esterne. AWS KMS

La seguente procedura dettagliata di OpenSSL illustra un metodo per derivare un segreto condiviso senza AWS KMS utilizzare la chiave pubblica di una coppia di chiavi ECC KMS e una chiave privata creata con OpenSSL.

  1. Crea una coppia di chiavi ECC in OpenSSL e preparala per l'uso con. 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. Crea una coppia di chiavi ECC key agreement AWS KMS e preparala per l'uso con 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. Ricava un segreto condiviso in OpenSSL utilizzando la chiave privata in OpenSSL e la chiave pubblica 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 ML-DSA offline con coppie di chiavi

AWS KMS supporta una variante di ML-DSA firma protetta, come descritto nella sezione 3.4 dello standard Federal Information Processing Standards (FIPS) 204 per messaggi fino a 4 KB byte.

Per firmare messaggi di dimensioni superiori a 4 KB, è necessario eseguire la fase di pre-elaborazione dei messaggi all'esterno di. AWS KMS Questa fase di hashing crea un messaggio rappresentativo di 64 byte μm, come definito in NIST FIPS 204, sezione 6.2.

AWS KMS ha un tipo di messaggio chiamato EXTERNAL_MU per messaggi di dimensioni superiori a 4 KB. Quando si utilizza questo valore al posto del tipo di RAW messaggio, AWS KMS:

  • Presuppone che tu abbia già eseguito la fase di hashing

  • Salta il processo di hashing interno

  • Funziona con messaggi di qualsiasi dimensione

Quando si verifica un messaggio, il metodo utilizzato dipende dalla limitazione delle dimensioni del sistema o della libreria esterna e dal supporto del rappresentante del messaggio a 64 byte μ:

  • Se il messaggio è più piccolo della restrizione di dimensione, utilizza il tipo di messaggio. RAW

  • Se il messaggio è più grande della restrizione di dimensione, usa il rappresentante μnel sistema esterno.

Le sezioni seguenti mostrano come firmare i messaggi utilizzando AWS KMS e verificare i messaggi utilizzando OpenSSL. Forniamo esempi per entrambi i messaggi al di sotto e al di sopra del limite di 4 KB imposto da. AWS KMS OpenSSL non impone un limite alla dimensione dei messaggi per la verifica.

Per entrambi gli esempi, devi prima ottenere la chiave pubblica da. AWS KMS Utilizzando il seguente comando AWS CLI :

aws kms get-public-key \ --key-id _<1234abcd-12ab-34cd-56ef-1234567890ab>_ \ --output text \ --query PublicKey | base64 --decode > public_key.der

Dimensione del messaggio inferiore a 4 KB

Per i messaggi inferiori a 4 KB, utilizzare il tipo di RAW messaggio con AWS KMS. Sebbene sia possibile utilizzarloEXTERNAL_MU, non è necessario per i messaggi entro il limite di dimensione.

Usa il AWS CLI comando seguente per firmare il messaggio:

aws kms sign \ --key-id _<1234abcd-12ab-34cd-56ef-1234567890ab>_ \ --message 'your message' \ --message-type RAW \ --signing-algorithm ML_DSA_SHAKE_256 \ --output text \ --query Signature | base64 --decode > ExampleSignature.bin

Per verificare questo messaggio usando OpenSSL usa il seguente comando:

echo -n 'your message' | ./openssl dgst -verify public_key.der -signature ExampleSignature.bin

Dimensione del messaggio superiore a 4 KB

Per firmare messaggi di dimensioni superiori a 4 KB, utilizza il tipo di EXTERNAL_MU messaggio. Quando lo usiEXTERNAL_MU, esegui il pre-hashing del messaggio esternamente a un rappresentante di 64 byte μcome definito nella sezione 6.2 del NIST FIPS 204 e lo trasmetti alle operazioni di firma o verifica. Nota che questo è diverso dal "Pre-hash MLDSA» o definito nella sezione 5.4 del NIST FIPS 204. HashML-DSA

  1. Innanzitutto, costruisci un prefisso per il messaggio. Il prefisso contiene un separatore di dominio, la lunghezza di qualsiasi contesto e il contesto. L'impostazione predefinita per il separatore di dominio e la lunghezza del contesto è zero.

  2. Anteponi il prefisso del messaggio al messaggio.

  3. Usa SHAKE256 per eseguire l'hashing della chiave pubblica e anteporla al risultato del passaggio 2.

  4. Infine, esegui l'hashing del risultato del passaggio 3 per produrre un file da 64 byte. EXTERNAL_MU

L'esempio seguente utilizza OpenSSL 3.5 per costruire: EXTERNAL_MU

{ openssl asn1parse -inform DER -in public_key.der -strparse 17 -noout -out - 2>/dev/null | openssl dgst -provider default -shake256 -xoflen 64 -binary; printf '\x00\x00'; echo -n "your message" } | openssl dgst -provider default -shake256 -xoflen 64 -binary > mu.bin

Dopo aver creato il mu.bin file, chiama l' AWS KMS API con il seguente comando per firmare il messaggio:

aws kms sign \ --key-id _<1234abcd-12ab-34cd-56ef-1234567890ab>_ \ --message fileb://mu.bin \ --message-type EXTERNAL_MU \ --signing-algorithm ML_DSA_SHAKE_256 \ --output text \ --query Signature | base64 --decode > ExampleSignature.bin

La firma risultante è la stessa del messaggio originale. RAW È possibile utilizzare lo stesso comando OpenSSL 3.5 per verificare il messaggio:

echo -n 'your message' | ./openssl dgst -verify public_key.der -signature ExampleSignature.bin

Verifica offline con coppie di chiavi SM2 (solo regioni della Cina)

Per verificare una firma all'esterno AWS KMS con una chiave pubblica SM2, è necessario specificare l'ID distintivo. Quando si passa un messaggio non elaborato MessageType:RAW, all'API Sign viene AWS KMS utilizzato l'ID distintivo predefinito1234567812345678, definito dall'OSCCA nel 0009-2012. GM/T Non puoi specificare il tuo ID distintivo all’interno di AWS KMS.

Tuttavia, se stai generando un digest del messaggio al di fuori di AWS, puoi specificare il tuo ID distintivo, quindi passare il digest del messaggio a, to sign. MessageType:DIGEST AWS KMS A tale scopo, modifica il valore DEFAULT_DISTINGUISHING_ID in classe SM2OfflineOperationHelper. L'ID distintivo specificato può essere qualsiasi stringa lunga fino a 8.192 caratteri. Dopo aver AWS KMS firmato il digest del messaggio, è necessario il digest del messaggio o il messaggio e l'ID distintivo utilizzati per calcolare il digest per verificarlo offline.

Importante

Il codice di riferimento SM2OfflineOperationHelper è progettato per essere compatibile con Bouncy Castle versione 1.68. Per assistenza con altre versioni, contatta bouncycastle.org.

Classe SM2OfflineOperationHelper

Per aiutarvi nelle operazioni offline con le chiavi SM2, la SM2OfflineOperationHelper classe per Java dispone di metodi che eseguono le attività al posto vostro. È possibile utilizzare questa classe helper come modello per altri fornitori di crittografia.

All'interno AWS KMS, le conversioni di testo cifrato non elaborato e i calcoli del riepilogo dei messaggi SM2DSA avvengono automaticamente. Non tutti i fornitori di crittografia implementano SM2 allo stesso modo. Alcune librerie, come OpenSSL 1.1.1 e successive, eseguono queste azioni automaticamente. AWS KMS ha confermato questo comportamento durante i test con OpenSSL versione 3.0. Utilizza la seguente classe SM2OfflineOperationHelper con librerie, come Bouncy Castle, che richiedono di eseguire manualmente queste conversioni e calcoli.

La classe SM2OfflineOperationHelper fornisce metodi per le seguenti operazioni offline:

  • Calcolo del digest del messaggio

    Per generare un riepilogo dei messaggi offline che puoi utilizzare per la verifica offline o che puoi passare AWS KMS per firmare, usa il metodo. calculateSM2Digest Il metodo calculateSM2Digest genera un digest dei messaggi con l'algoritmo di hashing SM3. L'GetPublicKeyAPI restituisce la tua chiave pubblica in formato binario. È necessario analizzare la chiave binaria in un Java PublicKey. Fornisci il messaggio alla chiave pubblica analizzata. Il metodo combina automaticamente il tuo messaggio con l'ID distintivo predefinito, 1234567812345678, ma è possibile impostare il proprio ID distintivo modificando il valore DEFAULT_DISTINGUISHING_ID.

  • Verify

    Per verificare la firma offline, usa il metodo offlineSM2DSAVerify. Il metodo offlineSM2DSAVerify utilizza il digest del messaggio calcolato dall'ID distintivo specificato e il messaggio originale fornito per verificare la firma digitale. L'GetPublicKeyAPI restituisce la chiave pubblica in formato binario. È necessario analizzare la chiave binaria in un Java PublicKey. Fornisci alla chiave pubblica analizzata il messaggio originale e la firma che desideri verificare. Per ulteriori dettagli, consulta .Offline verification with SM2 key pairs (verifica offline con coppie di chiavi SM2).

  • Encrypt

    Per crittografare il testo normale offline utilizza il metodo offlineSM2PKEEncrypt. Questo metodo assicura che il testo cifrato sia in un formato AWS KMS decifrabile. Il offlineSM2PKEEncrypt metodo crittografa il testo in chiaro e quindi converte il testo cifrato non elaborato prodotto da SM2PKE nel formato. ASN.1 L'API restituisce la chiave pubblica in formato binario. GetPublicKey È necessario analizzare la chiave binaria in un Java PublicKey. Fornisci alla chiave pubblica analizzata il testo normale che desideri crittografare.

    Se non sei sicuro di dover eseguire la conversione, usa la seguente operazione OpenSSL per testare il formato del tuo testo criptato. Se l'operazione fallisce, è necessario convertire il testo cifrato nel formato. ASN.1

    openssl asn1parse -inform DER -in ciphertext.der

Per impostazione predefinita, la classe SM2OfflineOperationHelper usa l'ID distintivo predefinito, 1234567812345678, quando si generano digest di messaggi per le operazioni SM2DSA.

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"); } }