use of org.apache.pulsar.client.api.EncryptionKeyInfo in project incubator-pulsar by apache.
the class MessageCrypto method encrypt.
/*
* Encrypt the payload using the data key and update message metadata with the keyname & encrypted data key
*
* @param encKeys One or more public keys to encrypt data key
*
* @param msgMetadata Message Metadata
*
* @param payload Message which needs to be encrypted
*
* @return encryptedData if success
*/
public synchronized ByteBuf encrypt(Set<String> encKeys, CryptoKeyReader keyReader, MessageMetadata.Builder msgMetadata, ByteBuf payload) throws PulsarClientException {
if (encKeys.isEmpty()) {
return payload;
}
// Update message metadata with encrypted data key
for (String keyName : encKeys) {
if (encryptedDataKeyMap.get(keyName) == null) {
// Attempt to load the key. This will allow us to load keys as soon as
// a new key is added to producer config
addPublicKeyCipher(keyName, keyReader);
}
EncryptionKeyInfo keyInfo = encryptedDataKeyMap.get(keyName);
if (keyInfo != null) {
if (keyInfo.getMetadata() != null && !keyInfo.getMetadata().isEmpty()) {
List<KeyValue> kvList = new ArrayList<KeyValue>();
keyInfo.getMetadata().forEach((key, value) -> {
kvList.add(KeyValue.newBuilder().setKey(key).setValue(value).build());
});
msgMetadata.addEncryptionKeys(EncryptionKeys.newBuilder().setKey(keyName).setValue(ByteString.copyFrom(keyInfo.getKey())).addAllMetadata(kvList).build());
} else {
msgMetadata.addEncryptionKeys(EncryptionKeys.newBuilder().setKey(keyName).setValue(ByteString.copyFrom(keyInfo.getKey())).build());
}
} else {
// We should never reach here.
log.error("{} Failed to find encrypted Data key for key {}.", logCtx, keyName);
}
}
// Create gcm param
// TODO: Replace random with counter and periodic refreshing based on timer/counter value
secureRandom.nextBytes(iv);
GCMParameterSpec gcmParam = new GCMParameterSpec(tagLen, iv);
// Update message metadata with encryption param
msgMetadata.setEncryptionParam(ByteString.copyFrom(iv));
ByteBuf targetBuf = null;
try {
// Encrypt the data
cipher.init(Cipher.ENCRYPT_MODE, dataKey, gcmParam);
ByteBuffer sourceNioBuf = payload.nioBuffer(payload.readerIndex(), payload.readableBytes());
int maxLength = cipher.getOutputSize(payload.readableBytes());
targetBuf = PooledByteBufAllocator.DEFAULT.buffer(maxLength, maxLength);
ByteBuffer targetNioBuf = targetBuf.nioBuffer(0, maxLength);
int bytesStored = cipher.doFinal(sourceNioBuf, targetNioBuf);
targetBuf.writerIndex(bytesStored);
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | ShortBufferException e) {
targetBuf.release();
log.error("{} Failed to encrypt message. {}", logCtx, e);
throw new PulsarClientException.CryptoException(e.getMessage());
}
payload.release();
return targetBuf;
}
use of org.apache.pulsar.client.api.EncryptionKeyInfo in project incubator-pulsar by apache.
the class MessageCrypto method addPublicKeyCipher.
private void addPublicKeyCipher(String keyName, CryptoKeyReader keyReader) throws CryptoException {
if (keyName == null || keyReader == null) {
throw new PulsarClientException.CryptoException("Keyname or KeyReader is null");
}
// Read the public key and its info using callback
EncryptionKeyInfo keyInfo = keyReader.getPublicKey(keyName, null);
PublicKey pubKey;
try {
pubKey = loadPublicKey(keyInfo.getKey());
} catch (Exception e) {
String msg = logCtx + "Failed to load public key " + keyName + ". " + e.getMessage();
log.error(msg);
throw new PulsarClientException.CryptoException(msg);
}
Cipher dataKeyCipher = null;
byte[] encryptedKey;
try {
// Encrypt data key using public key
if (RSA.equals(pubKey.getAlgorithm())) {
dataKeyCipher = Cipher.getInstance(RSA_TRANS, BouncyCastleProvider.PROVIDER_NAME);
} else if (ECDSA.equals(pubKey.getAlgorithm())) {
dataKeyCipher = Cipher.getInstance(ECIES, BouncyCastleProvider.PROVIDER_NAME);
} else {
String msg = logCtx + "Unsupported key type " + pubKey.getAlgorithm() + " for key " + keyName;
log.error(msg);
throw new PulsarClientException.CryptoException(msg);
}
dataKeyCipher.init(Cipher.ENCRYPT_MODE, pubKey);
encryptedKey = dataKeyCipher.doFinal(dataKey.getEncoded());
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException e) {
log.error("{} Failed to encrypt data key {}. {}", logCtx, keyName, e.getMessage());
throw new PulsarClientException.CryptoException(e.getMessage());
}
EncryptionKeyInfo eki = new EncryptionKeyInfo(encryptedKey, keyInfo.getMetadata());
encryptedDataKeyMap.put(keyName, eki);
}
use of org.apache.pulsar.client.api.EncryptionKeyInfo in project incubator-pulsar by apache.
the class SampleCryptoProducer method main.
public static void main(String[] args) throws PulsarClientException, InterruptedException, IOException {
class RawFileKeyReader implements CryptoKeyReader {
String publicKeyFile = "";
String privateKeyFile = "";
RawFileKeyReader(String pubKeyFile, String privKeyFile) {
publicKeyFile = pubKeyFile;
privateKeyFile = privKeyFile;
}
@Override
public EncryptionKeyInfo getPublicKey(String keyName, Map<String, String> keyMeta) {
EncryptionKeyInfo keyInfo = new EncryptionKeyInfo();
try {
// Read the public key from the file
keyInfo.setKey(Files.readAllBytes(Paths.get(publicKeyFile)));
} catch (IOException e) {
log.error("Failed to read public key from file {}", publicKeyFile, e);
}
return keyInfo;
}
@Override
public EncryptionKeyInfo getPrivateKey(String keyName, Map<String, String> keyMeta) {
EncryptionKeyInfo keyInfo = new EncryptionKeyInfo();
try {
// Read the private key from the file
keyInfo.setKey(Files.readAllBytes(Paths.get(privateKeyFile)));
} catch (IOException e) {
log.error("Failed to read private key from file {}", privateKeyFile, e);
}
return keyInfo;
}
}
PulsarClient pulsarClient = PulsarClient.builder().serviceUrl("http://127.0.0.1:8080").build();
// Setup the CryptoKeyReader with the file name where public/private key is kept
Producer<byte[]> producer = pulsarClient.newProducer().topic("persistent://my-property/use/my-ns/my-topic").cryptoKeyReader(new RawFileKeyReader("test_ecdsa_pubkey.pem", "test_ecdsa_privkey.pem")).addEncryptionKey("myappkey").create();
for (int i = 0; i < 10; i++) {
producer.send("my-message".getBytes());
}
pulsarClient.close();
}
use of org.apache.pulsar.client.api.EncryptionKeyInfo in project incubator-pulsar by apache.
the class SampleCryptoConsumer method main.
public static void main(String[] args) throws PulsarClientException, InterruptedException {
class RawFileKeyReader implements CryptoKeyReader {
String publicKeyFile = "";
String privateKeyFile = "";
RawFileKeyReader(String pubKeyFile, String privKeyFile) {
publicKeyFile = pubKeyFile;
privateKeyFile = privKeyFile;
}
@Override
public EncryptionKeyInfo getPublicKey(String keyName, Map<String, String> keyMeta) {
// Read the public key from the file
EncryptionKeyInfo keyInfo = new EncryptionKeyInfo();
try {
keyInfo.setKey(Files.readAllBytes(Paths.get(publicKeyFile)));
} catch (IOException e) {
log.error("Failed to read public key from file {}", publicKeyFile, e);
}
return keyInfo;
}
@Override
public EncryptionKeyInfo getPrivateKey(String keyName, Map<String, String> keyMeta) {
// Read the private key from the file
EncryptionKeyInfo keyInfo = new EncryptionKeyInfo();
try {
keyInfo.setKey(Files.readAllBytes(Paths.get(privateKeyFile)));
} catch (IOException e) {
log.error("Failed to read private key from file {}", privateKeyFile, e);
}
return keyInfo;
}
}
// Create pulsar client
PulsarClient pulsarClient = PulsarClient.builder().serviceUrl("http://127.0.0.1:8080").build();
Consumer<byte[]> consumer = pulsarClient.newConsumer().topic("persistent://my-property/use/my-ns/my-topic").subscriptionName("my-subscription-name").cryptoKeyReader(new RawFileKeyReader("test_ecdsa_pubkey.pem", "test_ecdsa_privkey.pem")).subscribe();
Message<byte[]> msg = null;
for (int i = 0; i < 10; i++) {
msg = consumer.receive();
// process the messsage
log.info("Received: {}", new String(msg.getData()));
}
// Acknowledge the consumption of all messages at once
consumer.acknowledgeCumulative(msg);
pulsarClient.close();
}
use of org.apache.pulsar.client.api.EncryptionKeyInfo in project incubator-pulsar by apache.
the class V1_ProducerConsumerTest method testEncryptionFailure.
@Test(groups = "encryption")
public void testEncryptionFailure() throws Exception {
log.info("-- Starting {} test --", methodName);
class EncKeyReader implements CryptoKeyReader {
EncryptionKeyInfo keyInfo = new EncryptionKeyInfo();
@Override
public EncryptionKeyInfo getPublicKey(String keyName, Map<String, String> keyMeta) {
String CERT_FILE_PATH = "./src/test/resources/certificate/public-key." + keyName;
if (Files.isReadable(Paths.get(CERT_FILE_PATH))) {
try {
keyInfo.setKey(Files.readAllBytes(Paths.get(CERT_FILE_PATH)));
return keyInfo;
} catch (IOException e) {
log.error("Failed to read certificate from {}", CERT_FILE_PATH);
}
}
return null;
}
@Override
public EncryptionKeyInfo getPrivateKey(String keyName, Map<String, String> keyMeta) {
String CERT_FILE_PATH = "./src/test/resources/certificate/private-key." + keyName;
if (Files.isReadable(Paths.get(CERT_FILE_PATH))) {
try {
keyInfo.setKey(Files.readAllBytes(Paths.get(CERT_FILE_PATH)));
return keyInfo;
} catch (IOException e) {
log.error("Failed to read certificate from {}", CERT_FILE_PATH);
}
}
return null;
}
}
final int totalMsg = 10;
ProducerConfiguration producerConf = new ProducerConfiguration();
Message msg = null;
Set<String> messageSet = Sets.newHashSet();
ConsumerConfiguration conf = new ConsumerConfiguration();
conf.setSubscriptionType(SubscriptionType.Exclusive);
Consumer consumer = pulsarClient.subscribe("persistent://my-property/use/my-ns/myenc-topic1", "my-subscriber-name", conf);
// 1. Invalid key name
producerConf.addEncryptionKey("client-non-existant-rsa.pem");
producerConf.setCryptoKeyReader(new EncKeyReader());
try {
pulsarClient.createProducer("persistent://my-property/use/myenc-ns/myenc-topic1", producerConf);
Assert.fail("Producer creation should not suceed if failing to read key");
} catch (Exception e) {
// ok
}
// 2. Producer with valid key name
producerConf = new ProducerConfiguration();
producerConf.setCryptoKeyReader(new EncKeyReader());
producerConf.addEncryptionKey("client-rsa.pem");
Producer producer = pulsarClient.createProducer("persistent://my-property/use/my-ns/myenc-topic1", producerConf);
for (int i = 0; i < totalMsg; i++) {
String message = "my-message-" + i;
producer.send(message.getBytes());
}
// 3. KeyReder is not set by consumer
// Receive should fail since key reader is not setup
msg = consumer.receive(5, TimeUnit.SECONDS);
Assert.assertNull(msg, "Receive should have failed with no keyreader");
// 4. Set consumer config to consume even if decryption fails
conf.setCryptoFailureAction(ConsumerCryptoFailureAction.CONSUME);
consumer.close();
consumer = pulsarClient.subscribe("persistent://my-property/use/my-ns/myenc-topic1", "my-subscriber-name", conf);
int msgNum = 0;
try {
// Receive should proceed and deliver encrypted message
msg = consumer.receive(5, TimeUnit.SECONDS);
String receivedMessage = new String(msg.getData());
String expectedMessage = "my-message-" + msgNum++;
Assert.assertNotEquals(receivedMessage, expectedMessage, "Received encrypted message " + receivedMessage + " should not match the expected message " + expectedMessage);
consumer.acknowledgeCumulative(msg);
} catch (Exception e) {
Assert.fail("Failed to receive message even aftet ConsumerCryptoFailureAction.CONSUME is set.");
}
// 5. Set keyreader and failure action
conf.setCryptoFailureAction(ConsumerCryptoFailureAction.FAIL);
consumer.close();
// Set keyreader
conf.setCryptoKeyReader(new EncKeyReader());
consumer = pulsarClient.subscribe("persistent://my-property/use/my-ns/myenc-topic1", "my-subscriber-name", conf);
for (int i = msgNum; i < totalMsg - 1; i++) {
msg = consumer.receive(5, TimeUnit.SECONDS);
String receivedMessage = new String(msg.getData());
log.debug("Received message: [{}]", receivedMessage);
String expectedMessage = "my-message-" + i;
testMessageOrderAndDuplicates(messageSet, receivedMessage, expectedMessage);
}
// Acknowledge the consumption of all messages at once
consumer.acknowledgeCumulative(msg);
consumer.close();
// 6. Set consumer config to discard if decryption fails
consumer.close();
ConsumerConfiguration conf2 = new ConsumerConfiguration();
conf2.setSubscriptionType(SubscriptionType.Exclusive);
conf2.setCryptoFailureAction(ConsumerCryptoFailureAction.DISCARD);
consumer = pulsarClient.subscribe("persistent://my-property/use/my-ns/myenc-topic1", "my-subscriber-name", conf2);
// Receive should proceed and discard encrypted messages
msg = consumer.receive(5, TimeUnit.SECONDS);
Assert.assertNull(msg, "Message received even aftet ConsumerCryptoFailureAction.DISCARD is set.");
log.info("-- Exiting {} test --", methodName);
}
Aggregations