Amazon Connect – это телефонная платформа Amazon, позволяющая клиентам создавать потоки вызовов, которые собирают данные от вызывающего абонента с помощью распознавания речи или ввода DTMF. Иногда собирается конфиденциальная информация, такая как номера кредитных карт. Connect предоставляет механизм шифрования конфиденциальных данных, пока они хранятся в службе Connect, но для обработки этих данных в рамках соответствующей интеграции лямбда-функций они должны быть расшифрованы.
Руководство и справочная реализация Amazon
Amazon предоставляет справочную реализацию в своей документации по этой функции здесь: https://docs.aws.amazon.com/connect/latest/adminguide/encrypt-data.html
Этот пост является дополнением к этой документации.
Обзор
Amazon Connect использует шифрование с открытым/закрытым ключом, используя AWS Encryption SDK для обеспечения поддержки во всем диапазоне языков, поддерживаемых этим SDK (Java, Javascript, Python и C). В то время как вам нужно будет создать и загрузить сертификат и открытый ключ для подключения к использованию, алгоритмы шифрования не настраиваются – он всегда будет использовать:
- OAEP: Оптимальное заполнение асимметричного шифрования, описывает схему добавления рандомизированного заполнения к сообщению перед шифрованием
- Шифрование RSA в режиме ECB: Это шифр с открытым/закрытым ключом в режиме блочного шифрования. Connect зашифрует данные с помощью открытого ключа.
- SHA-512: Использует алгоритм SHA-512 для создания хэша сообщения, чтобы можно было обнаружить подделку сообщения.
- MGF1: Функция генерации маски 1, часть стандарта RSA/OAEP, определенного в RFC 3447.
Это означает, очевидно, что вы должны поддерживать эти алгоритмы для расшифровки данных.
Поддержка в AWS Encryption SDK
Вы могли бы ожидать, что алгоритмы, выбранные Amazon Connect, будут поддерживаться всеми SDK для шифрования AWS. Это не так – вот краткое изложение:
- C – Нет, не поддерживает длину хэша SHA-512 для RSA/OAEP
- Java – Да, AWS предоставляет пример кода
- Javascript – Да, сообщение в блоге AWS для этой функции имеет реализацию javascript в связанном стеке CloudFormation.
- Python – Похоже, так и должно быть с помощью алгоритма переноса RSA_OAEP_SHA512_MGF1 .
Пример кода дешифрования Java
Здесь я взял образец расшифровки AWS Java и немного переработал его.
// DecryptSample.java import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoResult; import com.amazonaws.encryptionsdk.jce.JceMasterKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.util.*; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.*; import java.security.*; import java.security.interfaces.*; import java.security.spec.*; public class DecryptionSample { private static final String PROVIDER = "AmazonConnect"; private static final String WRAPPING_ALGORITHM = "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"; public static void main(String[] args) throws IOException, GeneralSecurityException { String keyFile = args[0]; // path to PEM encoded private key to use for decryption String keyId = args[1]; // this is the id used for key in your contact flow String cypherText = args[2]; // the Base64 encoded cypher text decrypt(keyFile, keyId, cypherText); } public static void decrypt(String privateKeyFile, String keyId, String cypherText) throws IOException, GeneralSecurityException { Security.addProvider(new BouncyCastleProvider()); byte[] cypherBytes = Base64.getDecoder().decode(cypherText); String privateKeyPem = new String(Files.readAllBytes(Paths.get(privateKeyFile)), Charset.forName("UTF-8")); RSAPrivateKey privateKey = getPrivateKey(privateKeyPem); AwsCrypto awsCrypto = new AwsCrypto(); JceMasterKey decMasterKey = JceMasterKey.getInstance(null,privateKey, PROVIDER, keyId, WRAPPING_ALGORITHM); CryptoResultresult = awsCrypto.decryptData(decMasterKey, cypherBytes); String plainText = new String(result.getResult()); System.out.format("Decrypted: %s\n", plainText); } public static RSAPrivateKey getPrivateKey(String privateKeyPem) throws IOException, GeneralSecurityException { String privateKeyBase64 = privateKeyPem.replaceAll("-----.*-----\n","").replaceAll("\n", ""); byte[] decoded = Base64.getDecoder().decode(privateKeyBase64); KeyFactory kf = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded); RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(keySpec); return privKey; } }
Важные моменты
private static final String PROVIDER = "AmazonConnect"; String keyId = args[1]; // this is the id used for key in your contact flow JceMasterKey decMasterKey = JceMasterKey.getInstance(null,privateKey, PROVIDER, keyId, WRAPPING_ALGORITHM);
При расшифровке зашифрованного текста AWS Encryption SDK требует, чтобы вы использовали того же поставщика и идентификаторы ключей, которые использовались при шифровании при получении ключевого контекста. Amazon Connect всегда будет использовать Amazon Connect
в качестве значения поставщика. Идентификатор ключа /устанавливается вами при создании действия ввода клиента магазина в потоке вызовов. В этом примере кода мы передаем
keyId в качестве параметра командной строки.
Заставить этот образец работать
- Сохраните код как
DecryptSample.java
- Получить банки зависимостей
wget https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.9/commons-lang3-3.9.jar wget https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15to18/1.64/bcprov-jdk15to18-1.64.jar wget https://repo1.maven.org/maven2/com/amazonaws/aws-encryption-sdk-java/1.6.1/aws-encryption-sdk-java-1.6.1.jar
- скомпилируйте код
javac -cp bcprov-jdk15to18-164.jar:aws-encryption-sdk-java-1.6.1.jar DecryptionSample.java
- запустите его с помощью
java -cp bcprov-jdk15to18-164.jar:aws-encryption-sdk-java-1.6.1.jar:commons-lang3-3.9.jar:. Образец расшифровки [параметры]
Вам понадобится сертификат и пара открытых/закрытых ключей. Сначала создайте сертификат и закрытый ключ:
openssl req -batch -x509 -sha256 -nodes -newkey rsa:4096 -keyout blog.connect.private.key -days 730 -out blog.connect.certificate.pem
Затем создайте извлеките открытый ключ:
openssl x509 -pubkey -noout -in blog.connect.certificate.pem > blog.connect.public.key
Шифрование
Вот пример кода Java для выполнения шифрования, как это сделал бы Amazon Connect.
// EncryptionSample.java import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoResult; import com.amazonaws.encryptionsdk.jce.JceMasterKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.util.*; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.*; import java.security.*; import java.security.interfaces.*; import java.security.spec.*; public class EncryptionSample { private static final String PROVIDER = "AmazonConnect"; private static final String WRAPPING_ALGORITHM = "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"; public static void main(String[] args) throws IOException, GeneralSecurityException { String keyFile = args[0]; // path to PEM encoded public key to use for encryption String keyId = args[1]; // this is the key id to identify the key used String plainText = args[2]; // this is the plain text to encypher encrypt(keyFile, keyId, plainText); } public static void encrypt(String publicKeyFile, String keyId, String plainText) throws IOException, GeneralSecurityException { Security.addProvider(new BouncyCastleProvider()); String publicKeyPem = new String(Files.readAllBytes(Paths.get(publicKeyFile)), Charset.forName("UTF-8")); RSAPublicKey publicKey = getPublicKey(publicKeyPem); AwsCrypto awsCrypto = new AwsCrypto(); JceMasterKey encMasterKey = JceMasterKey.getInstance(publicKey, null, PROVIDER, keyId, WRAPPING_ALGORITHM); byte[] plainBytes = plainText.getBytes(); CryptoResultresult = awsCrypto.encryptData(encMasterKey, plainBytes); String b64Result = Base64.getEncoder().encodeToString(result.getResult()); System.out.println(b64Result); } public static RSAPublicKey getPublicKey(String publicKeyPem) throws IOException, GeneralSecurityException { String publicKeyBase64 = publicKeyPem.replaceAll("-----.*-----\n","").replaceAll("\n", ""); byte[] decoded = Base64.getDecoder().decode(publicKeyBase64); KeyFactory kf = KeyFactory.getInstance("RSA"); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded); RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(keySpec); return pubKey; } }
Шаг компиляции такой же, как и для приведенного выше кода: javac -cp bcprov-jdk15to18-164.jar:aws-encryption-sdk-java-1.6.1.jar EncryptionSample.java
Собирая все это воедино
Как только вы скомпилируете код и получите пару открытых/закрытых ключей, мы сможем его опробовать:
# assign ciphertext output to a variable CIPHERTEXT=$(java -cp bcprov-jdk15to18-164.jar:aws-encryption-sdk-java-1.6.1.jar:commons-lang3-3.9.jar:. EncryptionSample blog.connect.public.key my-key-id 4444333322221111) # inspect $CIPHERTEXT with: echo $CIPHERTEXT # try decryption java -cp bcprov-jdk15to18-164.jar:aws-encryption-sdk-java-1.6.1.jar:commons-lang3-3.9.jar:. DecryptionSample blog.connect.private.key my-key-id "$CIPHERTEXT" # should result in: # Decrypted: 4444333322221111
Вывод
В этом посте рассматривалась взаимосвязь между функцией шифрования клиентского ввода Amazon Connects и SDK для шифрования, используемым для ее реализации.
Был представлен элементарный Java-код, имитирующий функциональность шифрования Amazon Connect, и сопутствующий код для его расшифровки.
Оригинал: “https://dev.to/bonybrown/decrypting-aws-connect-encrytped-data-40n8”