Search in sources :

Example 1 with EncryptionKeyInfo

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;
}
Also used : KeyValue(org.apache.pulsar.common.api.proto.PulsarApi.KeyValue) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) ArrayList(java.util.ArrayList) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) ByteString(com.google.protobuf.ByteString) EncryptionKeyInfo(org.apache.pulsar.client.api.EncryptionKeyInfo) GCMParameterSpec(javax.crypto.spec.GCMParameterSpec) BadPaddingException(javax.crypto.BadPaddingException) ByteBuf(io.netty.buffer.ByteBuf) InvalidKeyException(java.security.InvalidKeyException) ByteBuffer(java.nio.ByteBuffer) CryptoException(org.apache.pulsar.client.api.PulsarClientException.CryptoException) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) ShortBufferException(javax.crypto.ShortBufferException)

Example 2 with EncryptionKeyInfo

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);
}
Also used : BCECPublicKey(org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey) PublicKey(java.security.PublicKey) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) EncryptionKeyInfo(org.apache.pulsar.client.api.EncryptionKeyInfo) ByteString(com.google.protobuf.ByteString) BadPaddingException(javax.crypto.BadPaddingException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) ShortBufferException(javax.crypto.ShortBufferException) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) CryptoException(org.apache.pulsar.client.api.PulsarClientException.CryptoException) PEMException(org.bouncycastle.openssl.PEMException) IOException(java.io.IOException) BadPaddingException(javax.crypto.BadPaddingException) NoSuchProviderException(java.security.NoSuchProviderException) CryptoException(org.apache.pulsar.client.api.PulsarClientException.CryptoException) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) Cipher(javax.crypto.Cipher) CryptoException(org.apache.pulsar.client.api.PulsarClientException.CryptoException) NoSuchProviderException(java.security.NoSuchProviderException)

Example 3 with EncryptionKeyInfo

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();
}
Also used : EncryptionKeyInfo(org.apache.pulsar.client.api.EncryptionKeyInfo) IOException(java.io.IOException) PulsarClient(org.apache.pulsar.client.api.PulsarClient) Map(java.util.Map) CryptoKeyReader(org.apache.pulsar.client.api.CryptoKeyReader)

Example 4 with EncryptionKeyInfo

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();
}
Also used : EncryptionKeyInfo(org.apache.pulsar.client.api.EncryptionKeyInfo) IOException(java.io.IOException) PulsarClient(org.apache.pulsar.client.api.PulsarClient) Map(java.util.Map) CryptoKeyReader(org.apache.pulsar.client.api.CryptoKeyReader)

Example 5 with EncryptionKeyInfo

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);
}
Also used : Message(org.apache.pulsar.client.api.Message) ProducerConfiguration(org.apache.pulsar.client.api.ProducerConfiguration) EncryptionKeyInfo(org.apache.pulsar.client.api.EncryptionKeyInfo) IOException(java.io.IOException) CryptoKeyReader(org.apache.pulsar.client.api.CryptoKeyReader) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) Consumer(org.apache.pulsar.client.api.Consumer) Producer(org.apache.pulsar.client.api.Producer) ConsumerConfiguration(org.apache.pulsar.client.api.ConsumerConfiguration) Map(java.util.Map) Test(org.testng.annotations.Test)

Aggregations

EncryptionKeyInfo (org.apache.pulsar.client.api.EncryptionKeyInfo)10 IOException (java.io.IOException)7 Map (java.util.Map)7 CryptoKeyReader (org.apache.pulsar.client.api.CryptoKeyReader)7 Consumer (org.apache.pulsar.client.api.Consumer)4 Producer (org.apache.pulsar.client.api.Producer)4 PulsarClient (org.apache.pulsar.client.api.PulsarClient)4 ByteString (com.google.protobuf.ByteString)3 InvalidAlgorithmParameterException (java.security.InvalidAlgorithmParameterException)3 InvalidKeyException (java.security.InvalidKeyException)3 ConsumerConfiguration (org.apache.pulsar.client.api.ConsumerConfiguration)3 Message (org.apache.pulsar.client.api.Message)3 ProducerConfiguration (org.apache.pulsar.client.api.ProducerConfiguration)3 PulsarClientException (org.apache.pulsar.client.api.PulsarClientException)3 Test (org.testng.annotations.Test)3 JCommander (com.beust.jcommander.JCommander)2 ParameterException (com.beust.jcommander.ParameterException)2 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 ObjectWriter (com.fasterxml.jackson.databind.ObjectWriter)2 RateLimiter (com.google.common.util.concurrent.RateLimiter)2