Skip to content

Commit e719567

Browse files
committed
add component
Signed-off-by: sirivarma <siri.varma@outlook.com>
1 parent b0611b9 commit e719567

File tree

9 files changed

+1417
-154
lines changed

9 files changed

+1417
-154
lines changed

.github/workflows/validate.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ jobs:
113113
run: sleep 30 && docker logs dapr_scheduler && nc -vz localhost 50006
114114
- name: Install jars
115115
run: ./mvnw clean install -DskipTests -q
116+
- name: Validate crypto example
117+
working-directory: ./examples
118+
run: |
119+
mm.py ./src/main/java/io/dapr/examples/crypto/README.md
116120
- name: Validate workflows example
117121
working-directory: ./examples
118122
run: |
@@ -185,9 +189,6 @@ jobs:
185189
working-directory: ./examples
186190
run: |
187191
mm.py ./src/main/java/io/dapr/examples/pubsub/stream/README.md
188-
- name: Validate crypto example
189-
working-directory: ./examples
190-
run: |
191-
mm.py ./src/main/java/io/dapr/examples/crypto/README.md
192+
192193
193194

examples/components/crypto/localstorage.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ spec:
77
version: v1
88
metadata:
99
# Path to the directory containing keys (PEM files)
10-
# On Linux/Mac: ~/.dapr/keys
11-
# On Windows: %USERPROFILE%\.dapr\keys
10+
# This path is relative to where the dapr run command is executed
1211
- name: path
13-
value: "${HOME}/.dapr/keys"
12+
value: "./components/crypto/keys"

examples/src/main/java/io/dapr/examples/crypto/CryptoExample.java

Lines changed: 68 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,53 +21,58 @@
2121
import io.dapr.config.Property;
2222
import reactor.core.publisher.Flux;
2323

24+
import java.io.IOException;
2425
import java.nio.charset.StandardCharsets;
26+
import java.nio.file.Files;
27+
import java.nio.file.Path;
28+
import java.nio.file.Paths;
29+
import java.security.KeyPair;
30+
import java.security.KeyPairGenerator;
31+
import java.security.NoSuchAlgorithmException;
32+
import java.util.Base64;
2533
import java.util.Map;
2634

2735
/**
2836
* CryptoExample demonstrates using the Dapr Cryptography building block
2937
* to encrypt and decrypt data using a cryptography component.
30-
*
38+
*
3139
* <p>This example shows:
3240
* <ul>
3341
* <li>Encrypting plaintext data with a specified key and algorithm</li>
3442
* <li>Decrypting ciphertext data back to plaintext</li>
35-
* <li>Working with streaming data for large payloads</li>
43+
* <li>Automatic key generation if keys don't exist</li>
3644
* </ul>
37-
*
45+
*
3846
* <p>Prerequisites:
3947
* <ul>
4048
* <li>Dapr installed and initialized</li>
4149
* <li>A cryptography component configured (e.g., local storage crypto)</li>
42-
* <li>A key pair available for the crypto component</li>
4350
* </ul>
4451
*/
4552
public class CryptoExample {
4653

47-
// The crypto component name as defined in the component YAML file
4854
private static final String CRYPTO_COMPONENT_NAME = "localstoragecrypto";
49-
50-
// The key name to use for encryption/decryption
51-
private static final String KEY_NAME = "mykey";
52-
53-
// The key wrap algorithm - RSA-OAEP-256 for RSA keys
54-
private static final String KEY_WRAP_ALGORITHM = "RSA-OAEP-256";
55+
private static final String KEY_NAME = "rsa-private-key";
56+
private static final String KEY_WRAP_ALGORITHM = "RSA";
57+
private static final String KEYS_DIR = "components/crypto/keys";
5558

5659
/**
5760
* The main method demonstrating encryption and decryption with Dapr.
5861
*
5962
* @param args Command line arguments (unused).
6063
*/
61-
public static void main(String[] args) {
64+
public static void main(String[] args) throws Exception {
65+
// Generate keys if they don't exist
66+
generateKeysIfNeeded();
67+
6268
Map<Property<?>, String> overrides = Map.of(
6369
Properties.HTTP_PORT, "3500",
6470
Properties.GRPC_PORT, "50001"
6571
);
6672

6773
try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) {
6874

69-
// Original message to encrypt
70-
String originalMessage = "Hello, Dapr Cryptography! This is a secret message.";
75+
String originalMessage = "This is a secret message";
7176
byte[] plainText = originalMessage.getBytes(StandardCharsets.UTF_8);
7277

7378
System.out.println("=== Dapr Cryptography Example ===");
@@ -83,19 +88,9 @@ public static void main(String[] args) {
8388
KEY_WRAP_ALGORITHM
8489
);
8590

86-
// Collect encrypted data from the stream
8791
byte[] encryptedData = client.encrypt(encryptRequest)
8892
.collectList()
89-
.map(chunks -> {
90-
int totalSize = chunks.stream().mapToInt(chunk -> chunk.length).sum();
91-
byte[] result = new byte[totalSize];
92-
int pos = 0;
93-
for (byte[] chunk : chunks) {
94-
System.arraycopy(chunk, 0, result, pos, chunk.length);
95-
pos += chunk.length;
96-
}
97-
return result;
98-
})
93+
.map(CryptoExample::combineChunks)
9994
.block();
10095

10196
System.out.println("Encryption successful!");
@@ -109,36 +104,70 @@ public static void main(String[] args) {
109104
Flux.just(encryptedData)
110105
);
111106

112-
// Collect decrypted data from the stream
113107
byte[] decryptedData = client.decrypt(decryptRequest)
114108
.collectList()
115-
.map(chunks -> {
116-
int totalSize = chunks.stream().mapToInt(chunk -> chunk.length).sum();
117-
byte[] result = new byte[totalSize];
118-
int pos = 0;
119-
for (byte[] chunk : chunks) {
120-
System.arraycopy(chunk, 0, result, pos, chunk.length);
121-
pos += chunk.length;
122-
}
123-
return result;
124-
})
109+
.map(CryptoExample::combineChunks)
125110
.block();
126111

127112
String decryptedMessage = new String(decryptedData, StandardCharsets.UTF_8);
128113
System.out.println("Decryption successful!");
129114
System.out.println("Decrypted message: " + decryptedMessage);
130115
System.out.println();
131116

132-
// Verify the message matches
133117
if (originalMessage.equals(decryptedMessage)) {
134-
System.out.println("✓ Success! The decrypted message matches the original.");
118+
System.out.println("SUCCESS: The decrypted message matches the original.");
135119
} else {
136-
System.out.println("✗ Error! The decrypted message does not match the original.");
120+
System.out.println("ERROR: The decrypted message does not match the original.");
137121
}
138122

139123
} catch (Exception e) {
140124
System.err.println("Error during crypto operations: " + e.getMessage());
141125
throw new RuntimeException(e);
142126
}
143127
}
128+
129+
/**
130+
* Generates RSA key pair if the key file doesn't exist.
131+
*/
132+
private static void generateKeysIfNeeded() throws NoSuchAlgorithmException, IOException {
133+
Path keysDir = Paths.get(KEYS_DIR);
134+
Path keyFile = keysDir.resolve(KEY_NAME + ".pem");
135+
136+
if (Files.exists(keyFile)) {
137+
System.out.println("Using existing key: " + keyFile.toAbsolutePath());
138+
return;
139+
}
140+
141+
System.out.println("Generating RSA key pair...");
142+
Files.createDirectories(keysDir);
143+
144+
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
145+
keyGen.initialize(4096);
146+
KeyPair keyPair = keyGen.generateKeyPair();
147+
148+
String privateKeyPem = "-----BEGIN PRIVATE KEY-----\n"
149+
+ Base64.getMimeEncoder(64, "\n".getBytes()).encodeToString(keyPair.getPrivate().getEncoded())
150+
+ "\n-----END PRIVATE KEY-----\n";
151+
152+
String publicKeyPem = "-----BEGIN PUBLIC KEY-----\n"
153+
+ Base64.getMimeEncoder(64, "\n".getBytes()).encodeToString(keyPair.getPublic().getEncoded())
154+
+ "\n-----END PUBLIC KEY-----\n";
155+
156+
Files.writeString(keyFile, privateKeyPem + publicKeyPem);
157+
System.out.println("Key generated: " + keyFile.toAbsolutePath());
158+
}
159+
160+
/**
161+
* Combines byte array chunks into a single byte array.
162+
*/
163+
private static byte[] combineChunks(java.util.List<byte[]> chunks) {
164+
int totalSize = chunks.stream().mapToInt(chunk -> chunk.length).sum();
165+
byte[] result = new byte[totalSize];
166+
int pos = 0;
167+
for (byte[] chunk : chunks) {
168+
System.arraycopy(chunk, 0, result, pos, chunk.length);
169+
pos += chunk.length;
170+
}
171+
return result;
172+
}
144173
}

examples/src/main/java/io/dapr/examples/crypto/README.md

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -43,31 +43,9 @@ cd examples
4343

4444
Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized.
4545

46-
### Setting Up the Cryptography Component
47-
48-
Before running the examples, you need to set up a cryptography component. This example uses the local storage crypto component.
49-
50-
1. Create a directory for your keys:
51-
52-
```bash
53-
mkdir -p ~/.dapr/keys
54-
```
55-
56-
2. Generate an RSA key pair (you can use OpenSSL):
57-
58-
```bash
59-
# Generate a 4096-bit RSA private key
60-
openssl genrsa -out ~/.dapr/keys/mykey 4096
61-
62-
# Extract the public key
63-
openssl rsa -in ~/.dapr/keys/mykey -pubout -out ~/.dapr/keys/mykey.pub
64-
```
65-
66-
The component configuration file is already provided in `./components/crypto/localstorage.yaml`.
67-
6846
### Running the Example
6947

70-
This example uses the Java SDK Dapr client to **Encrypt and Decrypt** data.
48+
This example uses the Java SDK Dapr client to **Encrypt and Decrypt** data. The example automatically generates RSA keys if they don't exist.
7149

7250
#### Example 1: Basic Crypto Example
7351

@@ -76,13 +54,13 @@ This example uses the Java SDK Dapr client to **Encrypt and Decrypt** data.
7654
```java
7755
public class CryptoExample {
7856
private static final String CRYPTO_COMPONENT_NAME = "localstoragecrypto";
79-
private static final String KEY_NAME = "mykey";
80-
private static final String KEY_WRAP_ALGORITHM = "RSA-OAEP-256";
57+
private static final String KEY_NAME = "rsa-private-key";
58+
private static final String KEY_WRAP_ALGORITHM = "RSA";
8159

8260
public static void main(String[] args) {
8361
try (DaprPreviewClient client = new DaprClientBuilder().buildPreviewClient()) {
84-
85-
String originalMessage = "Hello, Dapr Cryptography!";
62+
63+
String originalMessage = "This is a secret message";
8664
byte[] plainText = originalMessage.getBytes(StandardCharsets.UTF_8);
8765

8866
// Encrypt the message
@@ -92,7 +70,7 @@ public class CryptoExample {
9270
KEY_NAME,
9371
KEY_WRAP_ALGORITHM
9472
);
95-
73+
9674
byte[] encryptedData = client.encrypt(encryptRequest)
9775
.collectList()
9876
.map(chunks -> /* combine chunks */)
@@ -103,7 +81,7 @@ public class CryptoExample {
10381
CRYPTO_COMPONENT_NAME,
10482
Flux.just(encryptedData)
10583
);
106-
84+
10785
byte[] decryptedData = client.decrypt(decryptRequest)
10886
.collectList()
10987
.map(chunks -> /* combine chunks */)
@@ -118,7 +96,7 @@ Use the following command to run this example:
11896
<!-- STEP
11997
name: Run Crypto Example
12098
expected_stdout_lines:
121-
- "== APP == ✓ Success! The decrypted message matches the original."
99+
- "== APP == SUCCESS: The decrypted message matches the original."
122100
background: true
123101
output_match_mode: substring
124102
sleep: 10
@@ -145,17 +123,17 @@ dapr run --resources-path ./components/crypto --app-id crypto-app --dapr-http-po
145123

146124
```
147125
=== Dapr Cryptography Example ===
148-
Original message: Hello, Dapr Cryptography! This is a secret message.
126+
Original message: This is a secret message
149127
150128
Encrypting message...
151129
Encryption successful!
152130
Encrypted data length: 512 bytes
153131
154132
Decrypting message...
155133
Decryption successful!
156-
Decrypted message: Hello, Dapr Cryptography! This is a secret message.
134+
Decrypted message: This is a secret message
157135
158-
✓ Success! The decrypted message matches the original.
136+
SUCCESS: The decrypted message matches the original.
159137
```
160138

161139
### Supported Key Wrap Algorithms

0 commit comments

Comments
 (0)