2121import io .dapr .config .Property ;
2222import reactor .core .publisher .Flux ;
2323
24+ import java .io .IOException ;
2425import 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 ;
2533import 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 */
4552public 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}
0 commit comments