View a markdown version of this page

Contoh operasi offline - AWS Key Management Service

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Contoh operasi offline

Setelah mengunduh kunci publik dari pasangan kunci KMS asimetris Anda, Anda dapat membagikannya dengan orang lain dan menggunakannya untuk melakukan operasi offline.

AWS CloudTrail log yang mencatat setiap AWS KMS operasi, termasuk permintaan, respons, tanggal, waktu, dan pengguna yang berwenang, tidak mencatat penggunaan kunci publik di luar AWS KMS.

Topik ini memberikan contoh operasi offline dan detail yang AWS KMS disediakan alat untuk mempermudah operasi offline.

Memperoleh rahasia bersama secara offline

Anda dapat mengunduh kunci publik dari pasangan kunci ECC Anda untuk digunakan dalam operasi offline, yaitu operasi di luar. AWS KMS

Panduan OpenSSL berikut menunjukkan satu metode untuk memperoleh rahasia bersama di luar AWS KMS menggunakan kunci publik dari pasangan kunci ECC KMS dan kunci pribadi yang dibuat dengan OpenSSL.

  1. Buat pasangan kunci ECC di OpenSSL dan persiapkan untuk digunakan dengan. 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. Buat pasangan kunci perjanjian kunci ECC AWS KMS dan persiapkan untuk digunakan dengan 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. Dapatkan rahasia bersama di OpenSSL menggunakan kunci pribadi di OpenSSL dan kunci KMS publik.

    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}

Verifikasi offline dengan pasangan ML-DSA kunci

AWS KMS mendukung varian ML-DSA penandatanganan lindung nilai, seperti yang dijelaskan dalam Standar Pemrosesan Informasi Federal (FIPS) 204 bagian 3.4 standar untuk pesan hingga 4 KB byte.

Untuk menandatangani pesan yang lebih besar dari 4 KB, Anda melakukan langkah pra-pemrosesan pesan di luar. AWS KMS Langkah hashing ini membuat perwakilan pesan 64-byte μ, seperti yang didefinisikan dalam NIST FIPS 204, bagian 6.2.

AWS KMS memiliki jenis pesan yang dipanggil EXTERNAL_MU untuk pesan yang lebih besar dari 4 KB. Bila Anda menggunakan ini sebagai pengganti jenis RAW pesan, AWS KMS:

  • Mengasumsikan Anda telah melakukan langkah hashing

  • Melewati proses hashing internalnya

  • Bekerja dengan pesan dari berbagai ukuran

Saat Anda memverifikasi pesan, metode yang Anda gunakan bergantung pada batasan ukuran sistem atau pustaka eksternal dan apakah metode tersebut mendukung perwakilan pesan 64-byte μ:

  • Jika pesan lebih kecil dari batasan ukuran, gunakan jenis RAW pesan.

  • Jika pesan lebih besar dari batasan ukuran, gunakan perwakilan μ di sistem eksternal.

Bagian berikut menunjukkan cara menandatangani pesan menggunakan AWS KMS dan memverifikasi pesan menggunakan OpenSSL. Kami memberikan contoh untuk pesan di bawah dan di atas batas ukuran pesan 4 KB yang diberlakukan oleh AWS KMS. OpenSSL tidak memberlakukan batasan ukuran pesan untuk verifikasi.

Untuk kedua contoh, pertama-tama dapatkan kunci publik dari AWS KMS. Gunakan perintah AWS CLI berikut:

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

Ukuran pesan kurang dari 4KB

Untuk pesan di bawah 4 KB, gunakan jenis RAW pesan dengan AWS KMS. Meskipun Anda dapat menggunakanEXTERNAL_MU, itu tidak perlu untuk pesan dalam batas ukuran.

Gunakan AWS CLI perintah berikut untuk menandatangani pesan:

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

Untuk memverifikasi pesan ini menggunakan OpenSSL gunakan perintah berikut:

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

Ukuran pesan lebih dari 4KB

Untuk menandatangani pesan yang lebih besar dari 4KB, gunakan jenis EXTERNAL_MU pesan. Saat Anda menggunakanEXTERNAL_MU, Anda melakukan pre-hash pesan secara eksternal ke perwakilan 64-byte μ seperti yang didefinisikan dalam NIST FIPS 204 bagian 6.2 dan meneruskannya ke operasi penandatanganan atau verifikasi. Perhatikan bahwa ini berbeda dari "Pre-hash MLDSA” atau HashML-DSA didefinisikan dalam NIST FIPS 204 bagian 5.4.

  1. Pertama, buat awalan pesan. Awalan berisi pemisah domain, panjang konteks apa pun, dan konteksnya. Default untuk pemisah domain dan panjang konteks adalah nol.

  2. Tambahkan awalan pesan ke pesan.

  3. Gunakan SHAKE256 untuk hash kunci publik dan menambahkannya ke hasil langkah 2.

  4. Akhirnya, hash hasil langkah 3 untuk menghasilkan 64-byteEXTERNAL_MU.

Contoh berikut menggunakan OpenSSL 3.5 untuk membangun: 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

Setelah Anda membuat mu.bin file, panggil AWS KMS API dengan perintah berikut untuk menandatangani pesan:

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

Tanda tangan yang dihasilkan sama dengan RAW tanda tangan pada pesan asli. Anda dapat menggunakan perintah OpenSSL 3.5 yang sama untuk memverifikasi pesan:

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

Verifikasi offline dengan pasangan kunci SM2 (hanya Wilayah China)

Untuk memverifikasi tanda tangan di luar AWS KMS dengan kunci publik SM2, Anda harus menentukan ID pembeda. Saat Anda meneruskan pesan mentah, MessageType:RAW, ke S ign API, AWS KMS menggunakan ID pembeda default,1234567812345678, yang ditentukan oleh OSCCA di GM/T 0009-2012. Anda tidak dapat menentukan ID pembeda Anda sendiri di dalamnya AWS KMS.

Namun, jika Anda membuat ringkasan pesan di luar AWS, Anda dapat menentukan ID pembeda Anda sendiri, lalu meneruskan ringkasan pesan, MessageType:DIGEST, AWS KMS untuk ditandatangani. Untuk melakukan ini, ubah DEFAULT_DISTINGUISHING_ID nilai di SM2OfflineOperationHelper kelas. ID pembeda yang Anda tentukan dapat berupa string apa pun dengan panjang hingga 8.192 karakter. Setelah AWS KMS menandatangani ringkasan pesan, Anda memerlukan ringkasan pesan atau pesan dan ID pembeda yang digunakan untuk menghitung ringkasan untuk memverifikasinya secara offline.

penting

Kode SM2OfflineOperationHelper referensi dirancang agar kompatibel dengan Bouncy Castle versi 1.68. Untuk bantuan dengan versi lain, hubungi bouncy castle.org.

SM2OfflineOperationHelper kelas

Untuk membantu Anda dengan operasi offline dengan kunci SM2, SM2OfflineOperationHelper kelas untuk Java memiliki metode yang melakukan tugas untuk Anda. Anda dapat menggunakan kelas pembantu ini sebagai model untuk penyedia kriptografi lainnya.

Di dalamnya AWS KMS, konversi ciphertext mentah dan perhitungan ringkasan pesan SM2DSA terjadi secara otomatis. Tidak semua penyedia kriptografi menerapkan SM2 dengan cara yang sama. Beberapa pustaka, seperti OpenSSL versi 1.1.1 dan yang lebih baru, melakukan tindakan ini secara otomatis. AWS KMS mengkonfirmasi perilaku ini dalam pengujian dengan OpenSSL versi 3.0. Gunakan SM2OfflineOperationHelper kelas berikut dengan pustaka, seperti Bouncy Castle, yang mengharuskan Anda melakukan konversi dan perhitungan ini secara manual.

SM2OfflineOperationHelperKelas menyediakan metode untuk operasi offline berikut:

  • Perhitungan ringkasan pesan

    Untuk membuat ringkasan pesan offline yang dapat Anda gunakan untuk verifikasi offline, atau yang dapat Anda lanjutkan AWS KMS untuk menandatangani, gunakan calculateSM2Digest metode ini. calculateSM2DigestMetode ini menghasilkan ringkasan pesan dengan algoritma hashing SM3. GetPublicKeyAPI mengembalikan kunci publik Anda dalam format biner. Anda harus mengurai kunci biner menjadi Java PublicKey. Berikan kunci publik yang diurai dengan pesan. Metode ini secara otomatis menggabungkan pesan Anda dengan ID pembeda default1234567812345678, tetapi Anda dapat mengatur ID pembeda Anda sendiri dengan mengubah nil DEFAULT_DISTINGUISHING_ID ainya.

  • Verifikasi

    Untuk memverifikasi tanda tangan secara offline, gunakan offlineSM2DSAVerify metode ini. offlineSM2DSAVerifyMetode ini menggunakan ringkasan pesan yang dihitung dari ID pembeda yang ditentukan, dan pesan asli yang Anda berikan untuk memverifikasi tanda tangan digital. GetPublicKeyAPI mengembalikan kunci publik Anda dalam format biner. Anda harus mengurai kunci biner menjadi Java PublicKey. Berikan kunci publik yang diurai dengan pesan asli dan tanda tangan yang ingin Anda verifikasi. Untuk detail selengkapnya, lihat Verifikasi offline dengan pasangan kunci SM2.

  • Enkripsi

    Untuk mengenkripsi plaintext offline, gunakan offlineSM2PKEEncrypt metode ini. Metode ini memastikan ciphertext dalam format AWS KMS dapat mendekripsi. offlineSM2PKEEncryptMetode mengenkripsi plaintext, dan kemudian mengubah ciphertext mentah yang dihasilkan oleh SM2PKE ke format. ASN.1 GetPublicKeyAPI mengembalikan kunci publik Anda dalam format biner. Anda harus mengurai kunci biner menjadi Java PublicKey. Berikan kunci publik yang diurai dengan plaintext yang ingin Anda enkripsi.

    Jika Anda tidak yakin apakah Anda perlu melakukan konversi, gunakan operasi OpenSSL berikut untuk menguji format ciphertext Anda. Jika operasi gagal, Anda perlu mengonversi ciphertext ke format. ASN.1

    openssl asn1parse -inform DER -in ciphertext.der

Secara default, SM2OfflineOperationHelper kelas menggunakan ID pembeda default,1234567812345678, saat membuat ringkasan pesan untuk operasi 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"); } }