Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Setelah mengunduh kunci publik dari key pair 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, tanggapan, 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 membuat operasi offline lebih mudah.
Topik
Menurunkan rahasia bersama secara offline
Anda dapat mengunduh kunci publik key pair ECC Anda untuk digunakan dalam operasi offline, yaitu operasi di luar. AWS KMS
Panduan OpenSSL
-
Buat key pair ECC di OpenSSL dan persiapkan untuk digunakan. 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"`
-
Buat key pair 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}
-
Dapatkan shared secret di OpenSSL menggunakan private key di OpenSSL dan public KMS key.
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 SM2 kunci (hanya Wilayah Tiongkok)
Untuk memverifikasi tanda tangan di luar AWS KMS dengan kunci SM2 publik, Anda harus menentukan ID pembeda. Saat Anda meneruskan pesan mentah, ke Sign API MessageType:RAW
, AWS KMS menggunakan ID pembeda default, yang ditentukan oleh OSCCA di GM/T 0009-2012. 1234567812345678
Anda tidak dapat menentukan ID pembeda Anda sendiri di dalamnya AWS KMS.
Namun, jika Anda membuat intisari pesan di luar AWS, Anda dapat menentukan ID pembeda Anda sendiri, lalu meneruskan intisari pesan MessageType:DIGEST
, untuk AWS KMS menandatangani. Untuk melakukan ini, ubah DEFAULT_DISTINGUISHING_ID
nilai di SM2OfflineOperationHelper
kelas. ID pembeda yang Anda tentukan dapat berupa string apa pun hingga 8,192 karakter. Setelah AWS KMS menandatangani intisari pesan, Anda memerlukan intisari pesan atau pesan dan ID pembeda yang digunakan untuk menghitung intisari untuk memverifikasinya secara offline.
penting
Kode SM2OfflineOperationHelper
referensi dirancang agar kompatibel dengan Bouncy Castle
SM2OfflineOperationHelper
kelas
Untuk membantu Anda dengan operasi offline dengan SM2 kunci, 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 intisari pesan SM2 DSA terjadi secara otomatis. Tidak semua penyedia kriptografi menerapkan dengan SM2 cara yang sama. Beberapa pustaka, seperti OpenSSLSM2OfflineOperationHelper
kelas berikut dengan pustaka, seperti Bouncy Castle
SM2OfflineOperationHelper
Kelas menyediakan metode untuk operasi offline berikut:
-
- Perhitungan intisari pesan
-
Untuk menghasilkan intisari pesan secara offline yang dapat Anda gunakan untuk verifikasi offline, atau yang dapat diteruskan AWS KMS ke tanda tangan, gunakan
calculateSM2Digest
metode ini.calculateSM2Digest
Metode ini menghasilkan intisari pesan dengan algoritma SM3 hashing. 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 nilainya.DEFAULT_DISTINGUISHING_ID
-
- Verifikasi
-
Untuk memverifikasi tanda tangan secara offline, gunakan
offlineSM2DSAVerify
metode ini.offlineSM2DSAVerify
Metode ini menggunakan intisari 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 diuraikan dengan pesan asli dan tanda tangan yang ingin Anda verifikasi. Untuk detail selengkapnya, lihat Verifikasi offline dengan pasangan SM2 kunci.
-
- Enkripsi
-
Untuk mengenkripsi plaintext offline, gunakan metode ini.
offlineSM2PKEEncrypt
Metode ini memastikan ciphertext dalam format AWS KMS dapat mendekripsi.offlineSM2PKEEncrypt
Metode mengenkripsi plaintext, dan kemudian mengonversi ciphertext mentah yang dihasilkan oleh PKE ke format ASN.1. SM2 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 default1234567812345678
, saat menghasilkan intisari pesan untuk operasi 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");
}
}